+ All Categories
Home > Technology > Let's Have an IEEE 802.15.4 over LoRa Linux Device Driver for IoT

Let's Have an IEEE 802.15.4 over LoRa Linux Device Driver for IoT

Date post: 22-Jan-2018
Category:
Upload: jian-hong-pan
View: 685 times
Download: 3 times
Share this document with a friend
79
Let's Have an IEEE 802.15.4 over LoRa Linux Device Driver for IoT SX1278 Transceiver in LoRa Mode for Example Jian-Hong Pan (StarNight) @ 2017.11.28 Taiwan Linux Kernel Hackers
Transcript

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

Link Budgetdb

m

TX Power

RX Power

TX Antenna

RX Antenna

Connector

Connector

Free Space

distance

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

After transmits,

transceiver also receives

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

Load SX1278 as an

SPI protocol driver

with Device Tree configuration

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

Have test applications

over 6LoWPAN over SX1278

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

Thank you ~

Q & A


Recommended