Upload
jian-hong-pan
View
690
Download
3
Embed Size (px)
Citation preview
Let's Have anIEEE 802.15.4 over LoRa Linux Device Driver for IoTSX1278 Transceiver in LoRa Mode for Example
Jian-Hong Pan (StarNight)@ 2017.11.28 Taiwan Linux Kernel Hackers
Outline
● History
● OSI 7 Layers
○ LoRa / LoRaWAN
○ IEEE 802.15.4
● Hardware
○ LoRa Transceiver
■ State Machine
■ FIFO Data Buffer
● Approaches
○ File Operations
○ IEEE 802.15.4
● Driver Implementaion
○ Used APIs in Driver
○ The Driver Introduction
○ Device Tree & Tests
● Summary
Who am I
潘建宏 / Jian-Hong Pan (StarNight)
I come from Taiwan !
You can find me at ~
http://www.slideshare.net/chienhungpan/
GitHub : starnight
Facebook : Jian-Hong Pan
Email : starnight [AT] g.ncu.edu.tw
History
● The Physics of the IoT○ by David Mikolas @ Taipei.py 2016.06.30○ https://www.youtube.com/watch?v=iVlXt6RbgCE#t=18m30s
● 科技農夫陳幸延──農田裡的開源自造者○ The Scientific Farmer, Yan -- A Maker in the Farm○ by 顏理謙, BUSINESS NEXT - 2016.06.10
● Location Aware Sensor System (LASS)○ LASS環境感測網路系統 http://lass-net.org/
● 【科技農夫共創微氣候新農耕模式】年輕小農靠開源翻轉傳
統農業○ [Scientific farmers creates the new farming methods and utensils] Young
farmers strengthen traditional agriculture with Open Source○ by 何維涓, iThome - 2017.08.19
Wireless Technology
● Features○ Long distance (coverage)○ Short data message○ Power consumption issue
● Low-Rate Wireless Personal Area Networks (LR-WPANs)○ IEEE 802.15.4
● Low-Power Wide-Area Network (LPWAN)○ LoRa○ Ultra Narrow Band:
■ Sigfox, NB-IoT ...
Gateway or Edge
Internet
End-Device
End-Device
End-Device
Outdoor Wireless
measurement / control
From LPWAN - The Benefits of LPWAN Technology vs Other IoT Connectivity Options,written by Calum McClelland on iotforall.com
Bandwidth - Range of Wireless
LoRa
OSI 7 Layers
Reference: Wikipedia OSI model https://en.wikipedia.org/wiki/OSI_model
Physical
Data Link
Network
Transport
Session
Presentation
Application
HTTP Sockets
HTML
HTTP Web API
TCP
IP
Link neighbors
Controlled by
Application
Controlled by OS
Electrics, Lines / Radio
Socket APIs
LoRa
LoRa is the physical (PHY) layer or the wireless modulation utilized to create the long range communication link.
● Chirp spread spectrum (CSS) radio modulation
● Good link budget
● Low data rate
● Could be quite low power consumption
● Radio frequency should be usedaccording to regional laws
Reference: LoRaWAN™ 101 – A Technical Introduction by LoRa Alliance - November, 2015What is LoRa? by LINK LABS - February 14, 2015
LoRaWAN
LoRaWAN is a media access control (MAC) layer protocol for managing communication between LPWAN gateways and end-node devices, maintained by the LoRa Alliance.
● Star topology
● Uplink - Downlink
● Over LoRa or FSK
Reference: Wikipedia LPWAN https://en.wikipedia.org/wiki/LPWANLoRaWAN™ Specification V1.0.2 by LoRa Alliance - July, 2016, P.12
● Classes○ Class A: Base line○ Class B: Beacon○ Class C: Continuous
LoRa Physical Message Formats
Preamble PHDR PHDR_CRC PHYPayload CRC
Preamble PHDR PHDR_CRC PHYPayload
Uplink Message:
Downlink Message:
Preamble, PHDR, PHDR_CRC and CRC are inserted by the radio transceiver
Reference: LoRaWAN™ Specification V1.0.2 by LoRa Alliance - July, 2016, P.11
IEEE 802.15.4
IEEE 802.15.4 is a technical standard which defines the operation of low-rate wireless personal area networks (LR-WPANs). It specifies the physical (PHY) layer and media access control (MAC) for LR-WPANs.
Reference: Wikipedia IEEE 802.15.4 https://en.wikipedia.org/wiki/IEEE_802.15.4
Cluster tree networkStar topology Peer to peer topology
PAN Coordinator Full-Function Device (FFD) Reduced-Function Device (RFD)
Comparison
LoRaWAN Star Topology
LoRa Good Link Budget
IEEE 802.15.4 MAC
Cluster Tree Network
IEEE 802.15.4 PHY
Normal Link Budget
Application
Presentation
Session
Transport
Network
MAC Layer
PHY Layer
LR-WPAN LPWAN
Combine Both Advantages
Application
Presentation
Session
Transport
Network
MAC Layer IEEE 802.15.4 MAC Cluster Tree Network
PHY Layer LoRa Good Link Budget
TCP/UDP
6LoWPAN
Socket APIs
LoRa acts as an IEEE 802.15.4 PHY
Cluster Tree Network &Good Link Budget
Internet
PAN Coordinator
Full-Function Device (FFD)
Reduced-Function Device (FFD)
LoRa
Each node can have a IPv6address, if it has 6LoWPAN
LoRaTransceiver
Hardware
SX127X
SPI
Main Board
Raspberry Pi
SPI_CE1
SPI BUS
LoRaTransceiver
SX127X
SPI
Main Board
Raspberry Pi
SPI_CE1
SPI BUS
One of LoRa Transceiver
Semtech - SX1276/77/78/79 for example http://www.semtech.com/images/datasheet/sx1276.pdf
● 168 dB maximum link budget● High sensitivity: down to -148 dBm● LoRa and FSK/OOK mode● SPI interface
Part Number Frequency Range Spreading Factor Bandwidth Effective Bitrate Est. Sensitivity
SX1276 137 - 1020 MHz 6 - 12 7.8 - 500 kHz .018 - 37.5 kbps -111 to -148 dBm
SX1277 137 - 1020 MHz 6 - 9 7.8 - 500 kHz .011 - 37.5 kbps -111 to -139 dBm
SX1278 137 - 525 MHz 6 - 12 7.8 - 500 kHz .018 - 37.5 kbps -111 to -148 dBm
SX1279 137 - 960MHz 6 - 12 7.8 - 500 kHz .018 - 37.5 kbps -111 to -148 dBm
State Machine of SX127X Transceiver
SLEEP
STANDBY
TX RXSINGLE
Set by command
Set by command
TX is completed /Set by command
RX is completed /RX timeout /
RX CRC error /Set by command
Only focus on used states
SX127X Transceiver’s IRQ Flags
Bit Flag
7 RxTimeout
6 RxDone
5 PayloadCrcError
4 ValidHeader
3 TxDone
2 CadDone
1 FhssChangeChannel
0 CadDetected
Reference: Semtech SX1276/77/78/79 datasheet, P.111, Figure 8. LoRaTM Mode Register Map
RegIrqFlags (0x12)
SX127X Transceiver Linux Device Driver
● File Operation Interface○ https://github.com/starnight/LoRa/tree/file-ops
○ File + SPI
○ As a character device node: /dev/loraSPIX.X
○ read/write from/to the FIFO data buffer, ioctl sets transceiver’s parameter
● IEEE 802.15.4 Interface○ https://github.com/starnight/LoRa
○ IEEE 802.15.4 MAC + SPI
○ As a WPAN network interface
○ socket with 6LoWPAN over IEEE 802.15.4 MAC
Used APIs in Driver
● SPI○ The communication bus with
SX127X transceiver
● regmap○ The common wrapper of low
rate buses, like SPI, I2C ...
● IEEE 802.15.4○ The LR-WPAN module in
kernel
● Timer & Interrupt○ Used for polling the state of
the transciver periodically
● workqueue○ The work scheduled by
timer interrupt service routine
○ The work should check and do some things according to the state of transceiver
● Spin lock○ Lock the state flags in the
driver of the transceiver
● Device Tree○ Set parameters with the
configuration in device tree, if Open Firmware is enabled
Flow Charts of Driver Module Init & Exit
module_init
register SX1278 as an SPI driver
End
unregister SX1278 SPI driver
End
module_exit
Register SX1278 as SPI Protocol Driver/* The SPI driver which acts as a protocol driver in this kernel module. */static struct spi_driver sx1278_spi_driver = {
.driver = {.name = __DRIVER_NAME,.owner = THIS_MODULE,
#ifdef CONFIG_OF.of_match_table = of_match_ptr(sx1278_dt_ids),
#endif#ifdef CONFIG_ACPI
.acpi_match_table = ACPI_PTR(sx1278_acpi_ids),#endif
},.probe = sx1278_spi_probe,.remove = sx1278_spi_remove,.id_table = sx1278_spi_ids,
};
/* Register SX1278 kernel module. */module_spi_driver(sx1278_spi_driver);
Note: spi_match_device
Matched by Open Firmware
Matched by ACPI
Matched by SPI Bus
Device Tree
Macro
of, acpi, id _match_table/* The compatible chip array. */#ifdef CONFIG_OFstatic const structof_device_id sx1278_dt_ids[] = {
{ .compatible = "semtech,sx1276" },{ .compatible = "semtech,sx1277" },{ .compatible = "semtech,sx1278" },{ .compatible = "semtech,sx1279" },{ .compatible = "sx1278" },{},
};MODULE_DEVICE_TABLE(of, sx1278_dt_ids);#endif
/* The compatible ACPI device array. */#ifdef CONFIG_ACPIstatic const structacpi_device_id sx1278_acpi_ids[] = {
{ .id = "sx1278" },{},
};MODULE_DEVICE_TABLE(acpi, sx1278_acpi_ids);#endif
/* The compatible SPI device id array. */static const structspi_device_id sx1278_spi_ids[] = {
{ .name = "sx1278" },{},
};MODULE_DEVICE_TABLE(spi, sx1278_spi_ids);
Flow Chart of Probing an SPI Device
Have a block of memory to hold the IEEE 802.15.4
compatible hardware
Set the LoRa PHY as SPI deivce’s privata data End
Probe an SPI device
Have a regmap wrapper for the SPI bus to transceiver
Set the RF channels & output power
Set the IEEE 802.15.4 address
Register the LoRa PHY as an IEEE 802.15.4 hardware
Set the timer interrupt & the work going to be scheduled
Initial the LoRa PHY
sx12
78_i
eee_
add_
one
SPI Probe Device Callback Functionstatic int sx1278_spi_probe(struct spi_device *spi){
struct ieee802154_hw *hw;struct sx1278_phy *phy;int err;
hw = ieee802154_alloc_hw(sizeof(*phy), &sx1278_ops);...
phy = hw->priv;phy->hw = hw;hw->parent = &spi->dev;phy->map = devm_regmap_init_spi(spi, &sx1278_regmap_config);
/* Set the SPI device's driver data for later usage. */spi_set_drvdata(spi, phy);
err = sx1278_ieee_add_one(phy);...
}
Allocate a block of memory to hold the data of IEEE 802.15.4 compatible hardware
static const struct ieee802154_ops sx1278_ops = {
.owner = THIS_MODULE,
.xmit_async = sx1278_ieee_xmit,
.ed = sx1278_ieee_ed,
.set_channel = sx1278_ieee_set_channel,
.set_txpower = sx1278_ieee_set_txpower,
.start = sx1278_ieee_start,
.stop = sx1278_ieee_stop,
.set_promiscuous_mode = sx1278_ieee_set_promiscuous_mode,
};
The entry points ofIEEE 802.15.4 actions
IEEE 802.15.4 Ops. of SX1278 Driver
struct sx1278_phy phy
cfg802154_registered_device
Block Memory of IEEE 802.15.4 Device
struct wpan_phy wpan_phy
struct ieee802154_local *local = wpan_phy.priv
struct wpan_phy *phy
ieee802154_ops *ops
struct ieee802154_hw hw
struct wpan_phy *phy
void *priv
struct device *parent
struct regmap *map
struct ieee802154_hw *hw
sx1278_ops
regmap
device of SPI
pointed by IEEE 802.15.4 moduleieee802154_alloc_hw
pointed by SX1278 driversx1278_spi_probe
SPI Probe Device Callback Functionstatic int sx1278_spi_probe(struct spi_device *spi){
struct ieee802154_hw *hw;struct sx1278_phy *phy;int err;
hw = ieee802154_alloc_hw(sizeof(*phy), &sx1278_ops);...
phy = hw->priv;phy->hw = hw;hw->parent = &spi->dev;phy->map = devm_regmap_init_spi(spi, &sx1278_regmap_config);
/* Set the SPI device's driver data for later usage. */spi_set_drvdata(spi, phy);
err = sx1278_ieee_add_one(phy);...
}
Allocate a block of memory to hold the data of IEEE 802.15.4 compatible hardware
Have a regmap wrapping the SPI bus to the transceiver
Set the phy as the driver data of the SPI device
struct sx1278_phystruct sx1278_phy {
struct ieee802154_hw *hw;struct regmap *map;
bool suspended;u8 opmode;struct timer_list timer;struct work_struct irqwork;
/* Lock the RX and TX actions. */spinlock_t buf_lock;struct sk_buff *tx_buf;u8 tx_delay;bool one_to_be_sent;bool post_tx_done;bool is_busy;
};
Register SX1278 as IEEE 802.15.4 PHYstatic int sx1278_ieee_add_one(struct sx1278_phy *phy){
struct ieee802154_hw *hw = phy->hw;int err;
/* Define channels could be used. */hw->phy->supported.channels[0] = sx1278_ieee_channel_mask(hw);/* SX1278 phy channel 11 as default */hw->phy->current_channel = 11;
/* Define RF power. */hw->phy->supported.tx_powers = sx1278_powers;hw->phy->supported.tx_powers_size = ARRAY_SIZE(sx1278_powers);hw->phy->transmit_power = sx1278_powers[12];
ieee802154_random_extended_addr(&hw->phy->perm_extended_addr);...
Set usable RF channels of the SX127X transceiver
Set usable RF output powers of the SX127X transceiver
Generates a random extended address of IEEE 802.15.4 MAC
Register SX1278 as IEEE 802.15.4 PHYContinue ...
hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_RX_OMIT_CKSUM | IEEE802154_HW_PROMISCUOUS;
err = ieee802154_register_hw(hw);...
INIT_WORK(&phy->irqwork, sx1278_timer_irqwork);
init_timer(&phy->timer);phy->timer.expires = jiffies_64 + HZ;phy->timer.function = sx1278_timer_isr;phy->timer.data = (unsigned long)phy;
spin_lock_init(&phy->buf_lock);
err = init_sx127x(phy->map);...
}
Do/Not do generate frame check sum
Register SX1278 as an IEEE 802.15.4 PHY
Bind the function to the work which is going to be scheduled by the timer ISR
Initial settings of the timer including the timer ISR
The argument phy going to be passed into timer ISR
Flow Chart of Probing an SPI Device
Have the LoRa PHY from SPI device’s privata data
End
Remove an SPI device
Delete and stop the timer
Flush the work scheduled by timer ISR
Unregister the IEEE 802.15.4 hardware
Free the IEEE 802.15.4 hardware
sx12
78_i
eee_
dele
te
SPI Remove Device Callback Functionstatic int sx1278_spi_remove(struct spi_device *spi){
struct sx1278_phy *phy = spi_get_drvdata(spi);
sx1278_ieee_del(phy);
return 0;}
static voidsx1278_ieee_del(struct sx1278_phy *phy){
if (!phy)return;
del_timer(&phy->timer);flush_work(&phy->irqwork);
ieee802154_unregister_hw(phy->hw);ieee802154_free_hw(phy->hw);
}
Get the phy from the SPI device’s driver data
Stop timing and delete the timer
Wait for irqwork to finish executing the last queueing instance
Unregister and free the IEEE 802.15.4 compatible device
Polling the State of SX127X Periodically
SLEEP
STANDBY
TX RXSINGLE
Set by command
Set by command
TX is completed /Set by command
RX is completed /RX timeout /
RX CRC error /Set by command
Polling whenTimer Interrupted !!!
Polling when Timer Interrupted
1. When to start the timer?a. The IEEE 802.15.4 interface is becoming up.
2. When to stop the timer?a. The IEEE 802.15.4 interface is becoming down.
3. Timer interrupt is an interrupt, so there should not be any long time block in the interrupt service routine.a. Polling the SX127X transceiver’s state will need SPI transferring.b. SPI locks the system when it is transfering the SPI message
synchronously.c. Schedule a work to workqueue in timer’s interrupt service routine!!!
IEEE 802.15.4 Interface Up & Down static const struct ieee802154_ops sx1278_ops = {
.owner = THIS_MODULE,
.xmit_async = sx1278_ieee_xmit,
.ed = sx1278_ieee_ed,
.set_channel = sx1278_ieee_set_channel,
.set_txpower = sx1278_ieee_set_txpower,
.start = sx1278_ieee_start,
.stop = sx1278_ieee_stop,
.set_promiscuous_mode = sx1278_ieee_set_promiscuous_mode,
};
ip link set <interface> up
ip link set <interface> down
IEEE 802.15.4 Interface Upstatic int sx1278_ieee_start(struct ieee802154_hw *hw){
struct sx1278_phy *phy = hw->priv;
dev_dbg(regmap_get_device(phy->map), "interface up\n");
sx1278_ieee_set_channel(hw, 0, hw->phy->current_channel);phy->suspended = false;sx127X_start_loramode(phy->map);phy->opmode = sx127X_get_mode(phy->map);add_timer(&phy->timer);
return 0;}
Set the RF using channel and frequency
Set the SX127X transceiver in LoRa mode
Get the SX127X transceiver operating mode
Enable timer
IEEE 802.15.4 Interface Downstatic void sx1278_ieee_stop(struct ieee802154_hw *hw){
struct sx1278_phy *phy = hw->priv;
dev_dbg(regmap_get_device(phy->map), "interface down\n");
phy->suspended = true;del_timer(&phy->timer);sx127X_set_state(phy->map, SX127X_SLEEP_MODE);
}
Disable timer
Make the SX127X transceiver go to sleep
Schedule a work into workqueue in ISR
static void sx1278_timer_isr(unsigned long arg){ struct sx1278_phy *phy = (struct sx1278_phy *)arg;
schedule_work(&phy->irqwork);}
Push the work into workqueue
static void sx1278_timer_irqwork(struct work_struct *work){ struct sx1278_phy *phy;
phy = container_of(work, struct sx1278_phy, irqwork); sx1278_ieee_statemachine(phy->hw);}
Get container structure of work
Do polling the SX127X’s state
When the work is scheduled to be executing
Do Polling SX127X Transceiver’s State
SLEEP
TX RXSINGLE
Set by command
Set by command: sx1278_ieee_xmit register one new frame going to be sent
TX is completed /Set by command
RX is completed /RX timeout /
RX CRC error /Set by command
Set by command: sx1278_ieee_rx tries to receive a new frame
STANDBY
Do Polling SX127X Transceiver’s Statevoid sx1278_ieee_statemachine(struct ieee802154_hw *hw){
struct sx1278_phy *phy = hw->priv;u8 flags;u8 state;bool do_next_rx = false;
flags = sx127X_get_loraallflag(phy->map);state = sx127X_get_state(phy->map);
Should be one or composed of:● SX127X_FLAG_RXTIMEOUT● SX127X_FLAG_PAYLOADCRCERROR● SX127X_FLAG_RXDONE● SX127X_FLAG_TXDONE
Should be one of:● SX127X_SLEEP_MODE● SX127X_STANDBY_MODE● SX127X_TX_MODE● SX127X_RXSINGLE_MODE
if (flags & (SX127X_FLAG_RXTIMEOUT | SX127X_FLAG_PAYLOADCRCERROR)) {sx127X_clear_loraflag(phy->map, SX127X_FLAG_RXTIMEOUT
| SX127X_FLAG_PAYLOADCRCERROR| SX127X_FLAG_RXDONE);
spin_lock(&phy->buf_lock);phy->is_busy = false;spin_unlock(&phy->buf_lock);do_next_rx = true;
} else if (flags & SX127X_FLAG_RXDONE) {sx1278_ieee_rx_complete(phy->hw);sx127X_clear_loraflag(phy->map, SX127X_FLAG_RXDONE);do_next_rx = true;
}
Check the SX127X transceiver is receiving time out or CRC error
Check the SX127X transceiver is already received a new frame
if (flags & SX127X_FLAG_TXDONE) {sx1278_ieee_tx_complete(phy->hw);sx127X_clear_loraflag(phy->map, SX127X_FLAG_TXDONE);phy->tx_delay = 10;do_next_rx = true;
}
if (phy->one_to_be_sent &&(state == SX127X_STANDBY_MODE) &&(phy->tx_delay == 0)) {if (!sx1278_ieee_tx(phy->hw))
do_next_rx = false;}
Check the SX127X transceiver is already transmit a frame out
Check the SX127X transceiver1. Have a new frame going to be
transmit2. Can try to transmit the new frame
a. Is not busy → standbyb. Transmit delay is enough
if (do_next_rx)sx1278_ieee_rx(phy->hw);
if (phy->tx_delay > 0)phy->tx_delay -= 1;
if (!phy->suspended) {phy->timer.expires = jiffies_64 + 1;add_timer(&phy->timer);
}}
Ask transceiver try to do receiving again, if it is not busy
Enable the timer again, if the interface is still enabled
Wait for polling SX127X transceiver’s state next time
Decrease the counter of transmission delay
Do Polling SX127X Transceiver’s State
SLEEP
TX RXSINGLE
Set by command
Set by command insx1278_ieee_statemachine
TX is completed /Set by command
RX is completed /RX timeout /
RX CRC error /Set by command
Set by command: sx1278_ieee_rx tries to receive a new frame
STANDBY
sx1278_ieee_xmit register a new frame going to be sent
IEEE 802.15.4 Xmit static const struct ieee802154_ops sx1278_ops = {
.owner = THIS_MODULE,
.xmit_async = sx1278_ieee_xmit,
.ed = sx1278_ieee_ed,
.set_channel = sx1278_ieee_set_channel,
.set_txpower = sx1278_ieee_set_txpower,
.start = sx1278_ieee_start,
.stop = sx1278_ieee_stop,
.set_promiscuous_mode = sx1278_ieee_set_promiscuous_mode,
};
ieee802154_tx in IEEE 802.15.4 module
Register a New Frame going to be Sentstatic int sx1278_ieee_xmit(struct ieee802154_hw *hw, struct sk_buff *skb){
struct sx1278_phy *phy = hw->priv;int ret;
...spin_lock(&phy->buf_lock);if (phy->tx_buf) {
ret = -EBUSY;} else {
phy->tx_buf = skb;phy->one_to_be_sent = true;phy->post_tx_done = false;ret = 0;
}spin_unlock(&phy->buf_lock);
return ret;}
Check no pending frame going to be sent
Register the new frame going to be sent
void sx1278_ieee_statemachine(struct ieee802154_hw *hw){
...if (flags & SX127X_FLAG_TXDONE) {
sx1278_ieee_tx_complete(phy->hw);sx127X_clear_loraflag(phy->map, SX127X_FLAG_TXDONE);phy->tx_delay = 10;do_next_rx = true;
}
if (phy->one_to_be_sent &&(state == SX127X_STANDBY_MODE) &&(phy->tx_delay == 0)) {if (!sx1278_ieee_tx(phy->hw))
do_next_rx = false;}...
}
Do Xmit a Frame during Polling State
Do Xmit a Frameint sx1278_ieee_tx(struct ieee802154_hw *hw){
struct sx1278_phy *phy = hw->priv;struct sk_buff *tx_buf = phy->tx_buf;bool do_tx = false;
…if (!phy->post_tx_done) {
sx127X_sendloradata(phy->map, tx_buf->data, tx_buf->len);phy->post_tx_done = true;
}
Prepare and write the new frame’s data to SX127X transceiver’s TX FIFO
Xmit a Frame after Fill SX127X TX FIFOspin_lock(&phy->buf_lock);if (!phy->is_busy) {
phy->is_busy = true;do_tx = true;phy->one_to_be_sent = false;
}spin_unlock(&phy->buf_lock);
if (do_tx) {/* Set chip as TX state and transfer the data in FIFO. */phy->opmode = (phy->opmode & 0xF8) | SX127X_TX_MODE;regmap_write_async(phy->map, SX127X_REG_OP_MODE, phy->opmode);return 0;
} else {…return -EBUSY;
}}
Change the SX127X transceiver to TX state and start TX action
TX FIFO of SX127X Transceiver
PayloadLength
Reference: Semtech SX1276/77/78/79 datasheet, P.34, Figure 8. LoRaTM Data Buffer
FifoTxBaseAddr
SPIRead/WriteFifoAddrPtr
256 bytes FIFO
Filling SX127X Transceiver’s TX FIFOsize_t sx127X_sendloradata(struct regmap *map, u8 *buf, size_t len){
u8 base_adr;u8 blen;
/* Set chip FIFO pointer to FIFO TX base. */base_adr = SX127X_FIFO_TX_BASE_ADDRESS;regmap_raw_write(map, SX127X_REG_FIFO_ADDR_PTR, &base_adr, 1);
/* Write payload synchronously to fill the FIFO of the chip. */blen = (len <= IEEE802154_MTU) ? len : IEEE802154_MTU;regmap_raw_write(map, SX127X_REG_FIFO, buf, blen);
/* Set the FIFO payload length. */regmap_raw_write(map, SX127X_REG_PAYLOAD_LENGTH, &blen, 1);
return blen;}
Set FIFO address going to write start with
Fill TX payload in to FIFO
Set TX payload length
void sx1278_ieee_statemachine(struct ieee802154_hw *hw){
...if (flags & SX127X_FLAG_TXDONE) {
sx1278_ieee_tx_complete(phy->hw);sx127X_clear_loraflag(phy->map, SX127X_FLAG_TXDONE);phy->tx_delay = 10;do_next_rx = true;
}
if (phy->one_to_be_sent &&(state == SX127X_STANDBY_MODE) &&(phy->tx_delay == 0)) {if (!sx1278_ieee_tx(phy->hw))
do_next_rx = false;}...
}
Xmit Finished during Polling State
Response Xmit a Frame is Finishedstatic int sx1278_ieee_tx_complete(struct ieee802154_hw *hw){
struct sx1278_phy *phy = hw->priv;struct sk_buff *skb = phy->tx_buf;
dev_dbg(regmap_get_device(phy->map), "%s\n", __func__);
ieee802154_xmit_complete(hw, skb, false);
spin_lock(&phy->buf_lock);phy->is_busy = false;phy->tx_buf = NULL;spin_unlock(&phy->buf_lock);
return 0;}
Response to IEEE 802.15.4 module that the new frame is already sent
Do Polling SX127X Transceiver’s State
SLEEP
TX RXSINGLE
Set by command
Set by command: sx1278_ieee_xmit register one new frame going to be sent
TX is completed /Set by command
RX is completed /RX timeout /
RX CRC error /Set by command
Set by command: sx1278_ieee_rx tries to receive a new frame
STANDBY
void sx1278_ieee_statemachine(struct ieee802154_hw *hw){
…
if (do_next_rx)sx1278_ieee_rx(phy->hw);
...}
Try to Receive during Polling State
Change SX127X to RX Modeint sx1278_ieee_rx(struct ieee802154_hw *hw){
…spin_lock(&phy->buf_lock);if (!phy->is_busy) {
phy->is_busy = true;do_rx = true;
} else {do_rx = false;
}spin_unlock(&phy->buf_lock);
if (do_rx) {sx127X_set_state(phy->map, SX127X_RXSINGLE_MODE);return 0;
} else {…return -EBUSY;
}}
Change the SX127X transceiver to RX state and try to receive only one frame
Do Receive during Polling Statevoid sx1278_ieee_statemachine(struct ieee802154_hw *hw){
…
if (flags & (SX127X_FLAG_RXTIMEOUT | SX127X_FLAG_PAYLOADCRCERROR)) {...
} else if (flags & SX127X_FLAG_RXDONE) {sx1278_ieee_rx_complete(phy->hw);sx127X_clear_loraflag(phy->map, SX127X_FLAG_RXDONE);do_next_rx = true;
}
...}
RX FIFO of SX127X Transceiver
LoRa Modem
RegFifoRxCurrentAddr
FifoRxBytesNb
PayloadLength
FifoRxBaseAddr
Reference: Semtech SX1276/77/78/79 datasheet, P.34, Figure 8. LoRaTM Data Buffer
FifoTxBaseAddr
SPIRead/WriteFifoAddrPtr
256 bytes FIFO
Do Receive a New Incoming Framestatic int sx1278_ieee_rx_complete(struct ieee802154_hw *hw){
struct sx1278_phy *phy = hw->priv;struct sk_buff *skb;…s32 rssi;s32 range = SX1278_IEEE_ENERGY_RANGE;…skb = dev_alloc_skb(IEEE802154_MTU);…len = sx127X_get_loralastpktpayloadlen(phy->map);sx127X_readloradata(phy->map, skb_put(skb, len), len);
/* LQI: IEEE 802.15.4-2011 8.2.6 Link quality indicator. */rssi = sx127X_get_loralastpktrssi(phy->map);rssi = (rssi > 0) ? 0 : rssi;lqi = ((s32)255 * (rssi + range) / range) % 255;
ieee802154_rx_irqsafe(hw, skb, lqi);...
}
Allocate a sk_buff to hold a new coming frame
Get last packet’s payload length
Read last RX packet as the new coming frame
Calculate the link quality indicator
Tell IEEE 802.15.4 module that there is a new incoming frame
Reading SX127X Transceiver’s RX FIFOssize_t sx127X_readloradata(struct regmap *map, u8 *buf, size_t len){ u8 start_adr; int ret;
/* Set chip FIFO pointer to FIFO last packet address. */ start_adr = SX127X_FIFO_RX_BASE_ADDRESS; regmap_raw_write(map, SX127X_REG_FIFO_ADDR_PTR, &start_adr, 1);
/* Read LoRa packet payload. */ len = (len <= IEEE802154_MTU) ? len : IEEE802154_MTU; ret = regmap_raw_read(map, SX127X_REG_FIFO, buf, len);
return (ret >= 0) ? len : ret;}
Set FIFO address going to read start with
Read a received payload from RX FIFO
Do Polling SX127X Transceiver’s State
SLEEP
TX RXSINGLE
Set by command
Set by command: sx1278_ieee_xmit register one new frame going to be sent
TX is completed /Set by command
RX is completed /RX timeout /
RX CRC error /Set by command
Set by command: sx1278_ieee_rx tries to receive a new frame
STANDBY
Device Tree Overlay Examplesx1278@0 {
compatible = "semtech,sx1278";
spi-max-frequency = <15200>;
reg = <0>;
clock-frequency = <32000000>;
center-carrier-frq = <434000000>;
minimal-RF-channel = /bits/ 8 <11>;
maximum-RF-channel = /bits/ 8 <11>;
};
SX1278 Device Tree Properties● Required properties:
○ compatible: should be "semtech,sx1276", "semtech,sx1277", "semtech,sx1278" or "semtech,sx1279" depends on your transceiver board
○ spi-max-frequency: maximal bus speed, should be set something under or equal 10000000 Hz
○ reg: the chipselect index
○ clock-frequency: the external crystal oscillator frequency in Hz of the transceiver
○ center-carrier-frq: the RF center carrier frequency in Hz
● Optional properties:○ rf-bandwidth: the RF bandwidth in Hz
○ minimal-RF-channel: the minimal RF channel number
○ maximum-RF-channel: the maximum RF channel number
○ spreading-factor: the spreading factor of Chirp Spread Spectrum modulation
Client - Server Test Application
These applications communicate through UDP/IPv6 socket in simple client-server model.
Client Server
Client send a data string to server
Server send the capitalized data string to client
Capitalized data string
6LoWPAN module & SX1278 driver
Application
ClientPresentation
Session
Transport UDP
Network IPv6
MAC Layer IEEE 802.15.4 MAC
PHY Layer LoRa
Server
UDP
IPv6
IEEE 802.15.4 MAC
LoRa
SX1278 driver
6LoWPAN module
socket
Have lowpan interface from wpan# Private Area Network IDpanid="0xbeef"# Index of the wpan interfacei=0
# Set the PANID of the wpan interfaceiwpan dev wpan${i} set pan_id $panid# Create a lowpan interface over the wpan interfaceip link add link wpan${i} name lowpan${i} type lowpan# Bring up the wpan and lowpan interfacesip link set wpan${i} upip link set lowpan${i} up
linux-wpan/wpan-tools: Userspace tools for Linux IEEE 802.15.4 stackiwpan: based on the wireless iw tool.
● Server
○ server <listening IPv6 address> <listening port>
● Client
○ client <src IPv6 address> <dst IPv6 address> <dst port> <data string>
Hardware for Demo
LoRaTransceiver
SX1276
SPI
LoRaTransceiver
SX1276
SPI
Main Board
Raspberry Pi
SPI_CE0
SPI_CE1
SPI BUS
Summary
● LoRa is a Low Power Wide Area Network(LPWAN) communitcation technology.
● Here is an IEEE 802.15.4 MAC over LoRa PHY Linux device driver.
● Pros
○ 6LoWPAN support for IEEE 802.15.4 → IPv6 for each node○ Extending the coverage area by cluster tree network with the LoRa long
communication distance of each edge is possible
● Cons
○ Extremely low data rate○ As an external kernel module, because it is not LoRaWAN over LoRa
Reference
● LoRaWAN™ What is it?
● LoRaWAN™ Specification V1.0.2 from LoRa™ Alliance
● Wikipedia - LPWAN
● IEEE Std 802.15.4-2015 from IEEE
● Wikipedia - IEEE 802.15.4
● Semtech SX1276/77/78/79 datasheet
● Linux IEEE 802.15.4 Documentation
● Loopback IEEE 802.15.4 interface: fakelb.c