Prototype RF driver for STM Sub-1 GHz RF expansion board based on the SPSGRF-868 module for STM32 Nucleo.
Prototype RF Driver for STM Sub-1 GHz RF Expansion Boards based on the SPSGRF-868 and SPSGRF-915 Modules for STM32 Nucleo
Currently supported boards:
Note, in order to use expansion board X-NUCLEO-IDS01A4 in mbed you need to perform the following HW modifications on the board:
- Unmount resistor
R4 - Mount resistor
R7
Furthermore, on some Nucleo development boards (e.g. the NUCLEO_F429ZI), in order to be able to use Ethernet together with these Sub-1 GHz RF expansion boards, you need to compile this driver with macro SPIRIT1_SPI_MOSI=PB_5 defined, while the development board typically requires some HW modification as e.g. described here!
This driver can be used together with the 6LoWPAN stack (a.k.a. Nanostack).
Revision 6:f5d01793bf86, committed 2016-10-19
- Comitter:
- Wolfgang Betz
- Date:
- Wed Oct 19 10:04:00 2016 +0200
- Parent:
- 5:c9c5bc673c64
- Child:
- 7:e90fa8f6bc6c
- Commit message:
- First simple Sender->Receiver example
Changed in this revision
| SimpleSpirit1.cpp | Show annotated file Show diff for this revision Revisions of this file |
| SimpleSpirit1.h | Show annotated file Show diff for this revision Revisions of this file |
--- a/SimpleSpirit1.cpp Tue Oct 18 11:45:43 2016 +0200
+++ b/SimpleSpirit1.cpp Wed Oct 19 10:04:00 2016 +0200
@@ -5,8 +5,11 @@
/*** Macros from Cube Implementation ***/
#define CLEAR_TXBUF() (spirit_tx_len = 0)
-#define CLEAR_RXBUF() (spirit_rx_len = 0)
#define IS_RXBUF_EMPTY() (spirit_rx_len == 0)
+#define CLEAR_RXBUF() do { \
+ spirit_rx_len = 0; \
+ _spirit_rx_pos = 0; \
+ } while(0)
#ifndef NDEBUG
#include <stdio.h>
@@ -134,6 +137,7 @@
irq_set_status(RX_DATA_DISC, S_ENABLE);
irq_set_status(TX_FIFO_ERROR, S_ENABLE);
irq_set_status(RX_FIFO_ERROR, S_ENABLE);
+ irq_set_status(RX_FIFO_ALMOST_FULL, S_ENABLE);
/* Configure Spirit1 */
radio_persisten_rx(S_ENABLE);
@@ -147,8 +151,9 @@
/* Puts the SPIRIT1 in STANDBY mode (125us -> rx/tx) */
cmd_strobe(SPIRIT1_STROBE_STANDBY);
spirit_on = OFF;
+ CLEAR_TXBUF();
CLEAR_RXBUF();
- CLEAR_TXBUF();
+ _spirit_rx_err = false;
/* Configure the radio to route the IRQ signal to its GPIO 3 */
SGpioInit x_gpio_init = {
@@ -227,6 +232,7 @@
wait_us(SABORT_WAIT_US);
cmd_strobe(SPIRIT1_STROBE_READY);
BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_READY, 1);
+ cmd_strobe(SPIRIT1_STROBE_FRX);
cmd_strobe(SPIRIT1_STROBE_RX);
BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, 1);
enable_spirit_irq();
@@ -261,7 +267,7 @@
return RADIO_TX_OK;
}
-int SimpleSpirit1::send(const void *payload, unsigned short payload_len) {
+int SimpleSpirit1::send(const void *payload, unsigned int payload_len) {
/* Checks if the payload length is supported */
if(payload_len > MAX_PACKET_LEN) {
return RADIO_TX_ERR;
@@ -299,8 +305,6 @@
remaining -= to_send;
} while(remaining != 0);
- PRINTF("betzw(%s, %d): #fifo=%d\n", __FILE__, __LINE__, linear_fifo_read_num_elements_tx_fifo());
-
BUSYWAIT_UNTIL(SPIRIT1_STATUS() != SPIRIT1_STATE_TX, 50);
MBED_ASSERT(linear_fifo_read_num_elements_tx_fifo() == 0);
@@ -378,6 +382,7 @@
}
/* now we go to Rx */
+ cmd_strobe(SPIRIT1_STROBE_FRX);
cmd_strobe(SPIRIT1_STROBE_RX);
BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, 5);
if(SPIRIT1_STATUS() != SPIRIT1_STATE_RX) {
@@ -385,6 +390,8 @@
while(1);
//return 1;
}
+ CLEAR_RXBUF();
+ _spirit_rx_err = false;
/* Enables the mcu to get IRQ from the SPIRIT1 */
spirit_on = ON;
@@ -417,27 +424,32 @@
return mcstate;
}
-int SimpleSpirit1::read(void *buf, unsigned short bufsize)
+int SimpleSpirit1::read(void *buf, unsigned int bufsize)
{
PRINTF("READ IN\n");
+ disable_spirit_irq();
+
/* Checks if the RX buffer is empty */
if(IS_RXBUF_EMPTY()) {
- disable_spirit_irq();
CLEAR_RXBUF();
cmd_strobe(SPIRIT1_STROBE_SABORT);
wait_us(SABORT_WAIT_US);
cmd_strobe(SPIRIT1_STROBE_READY);
BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_READY, 1);
+ cmd_strobe(SPIRIT1_STROBE_FRX);
cmd_strobe(SPIRIT1_STROBE_RX);
BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, 1);
+ _spirit_rx_err = false;
PRINTF("READ OUT RX BUF EMPTY\n");
enable_spirit_irq();
return 0;
}
if(bufsize < spirit_rx_len) {
- /* If buf has the correct size */
+ enable_spirit_irq();
+
+ /* If buf has the correct size */
PRINTF("TOO SMALL BUF\n");
return 0;
} else {
@@ -452,6 +464,8 @@
bufsize = spirit_rx_len;
CLEAR_RXBUF();
+ enable_spirit_irq();
+
PRINTF("READ OUT\n");
return bufsize;
@@ -459,7 +473,6 @@
}
-/*---------------------------------------------------------------------------*/
int SimpleSpirit1::channel_clear(void)
{
float rssi_value;
@@ -479,16 +492,17 @@
cmd_strobe(SPIRIT1_STROBE_SABORT);
/* SpiritCmdStrobeSabort();*/
irq_clear_status();
- enable_spirit_irq();
{
uint32_t timeout = _busywait_timer.read_us() + 5000;
do {
mgmt_refresh_status();
} while((st_lib_g_x_status.MC_STATE != MC_STATE_READY) && (((uint32_t)_busywait_timer.read_us()) < timeout));
if(st_lib_g_x_status.MC_STATE != MC_STATE_READY) {
+ enable_spirit_irq();
return 1;
}
}
+ enable_spirit_irq();
/* Stores the RSSI value */
rssi_value = qi_get_rssi_dbm();
@@ -497,9 +511,14 @@
if(spirit_state==OFF) {
off();
} else {
+ disable_spirit_irq();
+ cmd_strobe(SPIRIT1_STROBE_FRX);
cmd_strobe(SPIRIT1_STROBE_RX);
/* SpiritCmdStrobeRx();*/
BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, 5);
+ CLEAR_RXBUF();
+ _spirit_rx_err = false;
+ enable_spirit_irq();
}
PRINTF("CHANNEL CLEAR OUT\n");
@@ -531,69 +550,100 @@
irq_get_status(&x_irq_status);
irq_clear_status();
- if(x_irq_status.IRQ_RX_FIFO_ERROR) {
+ /* Reception errors */
+ if((x_irq_status.IRQ_RX_FIFO_ERROR) || (x_irq_status.IRQ_RX_DATA_DISC) || (x_irq_status.IRQ_RX_TIMEOUT)) {
receiving_packet = 0;
+ _spirit_rx_err = true;
+ CLEAR_RXBUF();
cmd_strobe(SPIRIT1_STROBE_FRX);
- return;
}
+ /* Transmission error */
if(x_irq_status.IRQ_TX_FIFO_ERROR) {
+ error("IRQ_TX_FIFO_ERROR should never happen!\n");
receiving_packet = 0;
cmd_strobe(SPIRIT1_STROBE_FTX);
- return;
}
/* The IRQ_VALID_SYNC is used to notify a new packet is coming */
if(x_irq_status.IRQ_VALID_SYNC) {
receiving_packet = 1;
+ _spirit_rx_err = false;
+ CLEAR_RXBUF();
+ }
+
+ /* RX FIFO almost full */
+ if(x_irq_status.IRQ_RX_FIFO_ALMOST_FULL) {
+ if(_spirit_rx_err) {
+ cmd_strobe(SPIRIT1_STROBE_FRX);
+ } else {
+ uint8_t fifo_available = linear_fifo_read_num_elements_rx_fifo();
+ unsigned int remaining = MAX_PACKET_LEN - _spirit_rx_pos;
+ if(fifo_available > remaining) {
+ receiving_packet = 0;
+ _spirit_rx_err = true;
+ CLEAR_RXBUF();
+ cmd_strobe(SPIRIT1_STROBE_FRX);
+ } else {
+ spi_read_linear_fifo(fifo_available, &spirit_rx_buf[_spirit_rx_pos]);
+ _spirit_rx_pos += fifo_available;
+ }
+ }
}
/* The IRQ_TX_DATA_SENT notifies the packet received. Puts the SPIRIT1 in RX */
if(x_irq_status.IRQ_TX_DATA_SENT) {
+ cmd_strobe(SPIRIT1_STROBE_FRX);
cmd_strobe(SPIRIT1_STROBE_RX);
/* SpiritCmdStrobeRx();*/
CLEAR_TXBUF();
- return;
+ CLEAR_RXBUF();
+ _spirit_rx_err = false;
}
/* The IRQ_RX_DATA_READY notifies a new packet arrived */
if(x_irq_status.IRQ_RX_DATA_READY) {
- spirit_rx_len = pkt_basic_get_received_pkt_length();
+ if(_spirit_rx_err) {
+ receiving_packet = 0;
+ _spirit_rx_err = false;
+ CLEAR_RXBUF();
+ cmd_strobe(SPIRIT1_STROBE_FRX);
+ } else {
+ spirit_rx_len = pkt_basic_get_received_pkt_length();
+ unsigned int remaining = 0;
+ uint8_t fifo_available = 0;
+ uint8_t to_receive = 0;
+
+ MBED_ASSERT(spirit_rx_len <= MAX_PACKET_LEN);
- for(int i = 0; i < spirit_rx_len; ) {
- uint8_t fifo_available = linear_fifo_read_num_elements_rx_fifo();
- if(fifo_available > 0)
- spi_read_linear_fifo(fifo_available, &spirit_rx_buf[i]);
- i += fifo_available;
- }
+ for(; _spirit_rx_pos < spirit_rx_len;) {
+ remaining = spirit_rx_len - _spirit_rx_pos;
+ fifo_available = linear_fifo_read_num_elements_rx_fifo();
+ to_receive = (remaining < fifo_available) ? remaining : fifo_available;
+ if(to_receive > 0) {
+ spi_read_linear_fifo(to_receive, &spirit_rx_buf[_spirit_rx_pos]);
+ _spirit_rx_pos += to_receive;
+ }
+ }
- cmd_strobe(SPIRIT1_STROBE_FRX);
+ cmd_strobe(SPIRIT1_STROBE_FRX);
- last_rssi = qi_get_rssi(); //MGR
- last_lqi = qi_get_lqi(); //MGR
+ last_rssi = qi_get_rssi(); //MGR
+ last_lqi = qi_get_lqi(); //MGR
- receiving_packet = 0;
+ receiving_packet = 0;
#if NULLRDC_CONF_802154_AUTOACK
- if (spirit_rxbuf[0] == ACK_LEN) {
- /* For debugging purposes we assume this is an ack for us */
- just_got_an_ack = 1;
- }
+ if (spirit_rxbuf[0] == ACK_LEN) {
+ /* For debugging purposes we assume this is an ack for us */
+ just_got_an_ack = 1;
+ }
#endif /* NULLRDC_CONF_802154_AUTOACK */
- /* call user callback */
- if(_current_irq_callback) {
- _current_irq_callback();
- }
-
- return;
- }
-
- if(x_irq_status.IRQ_RX_DATA_DISC)
- {
- /* RX command - to ensure the device will be ready for the next reception */
- if(x_irq_status.IRQ_RX_TIMEOUT) {
- cmd_strobe_flush_rx_fifo();
- }
+ /* call user callback */
+ if(_current_irq_callback) {
+ _current_irq_callback();
+ }
+ }
}
}
--- a/SimpleSpirit1.h Tue Oct 18 11:45:43 2016 +0200
+++ b/SimpleSpirit1.h Wed Oct 19 10:04:00 2016 +0200
@@ -55,12 +55,15 @@
* The +1 because of the first byte,
* which will contain the length of the packet.
*/
- uint8_t spirit_rx_buf[MAX_PACKET_LEN];
uint16_t spirit_tx_len;
uint16_t spirit_rx_len;
- volatile unsigned int spirit_on;
+ uint16_t _spirit_rx_pos;
+ bool _spirit_rx_err;
+ uint8_t spirit_rx_buf[MAX_PACKET_LEN];
+
+ /** Status Variables from Cube Implementation **/
volatile uint8_t receiving_packet;
- int packet_is_prepared;
+ volatile unsigned int spirit_on;
int just_got_an_ack;
uint16_t last_rssi; //MGR
uint16_t last_lqi; //MGR
@@ -291,6 +294,25 @@
/** Destructor **/
~SimpleSpirit1(void); // should never be called!
+private:
+ /*** Original Contiki APIs & Variables ***/
+ /** Variable(s) for Original API(s) **/
+ int packet_is_prepared;
+
+ /** Prepare the radio with a packet to be sent. **/
+ int prepare_contiki(const void *payload, unsigned short payload_len);
+
+ /** Send the packet that has previously been prepared. **/
+ int transmit_contiki(unsigned short payload_len);
+
+ /** Prepare & Transmit */
+ int send_contiki(const void *payload, unsigned short payload_len) {
+ if(prepare_contiki(payload, payload_len) == RADIO_TX_ERR) {
+ return RADIO_TX_ERR;
+ }
+ return transmit_contiki(payload_len);
+ }
+
public:
static SimpleSpirit1& CreateInstance(PinName mosi, PinName miso, PinName sclk,
PinName irq, PinName cs, PinName sdn,
@@ -315,7 +337,7 @@
return *_singleton;
}
- /** Attach a function to be called when by the Spirit Irq handler when packet has arrived
+ /** Attach a function to be called by the Spirit Irq handler when packet has arrived
*
* @param func A void() callback, or 0 to set as none
*
@@ -329,24 +351,10 @@
int on(void);
int off(void);
- /** Prepare the radio with a packet to be sent. **/
- int prepare_contiki(const void *payload, unsigned short payload_len);
-
- /** Send the packet that has previously been prepared. **/
- int transmit_contiki(unsigned short payload_len);
-
- /** Prepare & Transmit */
- int send_contiki(const void *payload, unsigned short payload_len) {
- if(prepare_contiki(payload, payload_len) == RADIO_TX_ERR) {
- return RADIO_TX_ERR;
- }
- return transmit_contiki(payload_len);
- }
-
- int send(const void *payload, unsigned short payload_len);
+ int send(const void *payload, unsigned int payload_len);
/** Read into Buffer **/
- int read(void *buf, unsigned short bufsize);
+ int read(void *buf, unsigned int bufsize);
/** Perform a Clear-Channel Assessment (CCA) to find out if there is
a packet in the air or not.
X-NUCLEO-IDS01A4 Sub-1GHz RF Expansion Board