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 7:e90fa8f6bc6c, committed 2016-10-21
- Comitter:
- Wolfgang Betz
- Date:
- Fri Oct 21 14:56:55 2016 +0200
- Parent:
- 6:f5d01793bf86
- Child:
- 8:10967c884e38
- Commit message:
- Use 'us_ticker_read' directly
Changed in this revision
--- a/SimpleSpirit1.cpp Wed Oct 19 10:04:00 2016 +0200
+++ b/SimpleSpirit1.cpp Fri Oct 21 14:56:55 2016 +0200
@@ -11,6 +11,7 @@
_spirit_rx_pos = 0; \
} while(0)
+#define NDEBUG
#ifndef NDEBUG
#include <stdio.h>
#define PRINTF(...) printf(__VA_ARGS__)
@@ -33,8 +34,8 @@
#define BUSYWAIT_UNTIL(cond, millisecs) \
do { \
- uint32_t start = _busywait_timer.read_us(); \
- while (!(cond) && ((((uint32_t)(_busywait_timer.read_us())) - start) < ((uint32_t)millisecs)*1000U)); \
+ uint32_t start = us_ticker_read(); \
+ while (!(cond) && ((us_ticker_read() - start) < ((uint32_t)millisecs)*1000U)); \
} while(0)
extern volatile SpiritStatus g_xStatus;
@@ -46,7 +47,6 @@
/*** Class Implementation ***/
/** Static Class Variables **/
SimpleSpirit1 *SimpleSpirit1::_singleton = NULL;
-Timer SimpleSpirit1::_busywait_timer;
/** Constructor **/
SimpleSpirit1::SimpleSpirit1(PinName mosi, PinName miso, PinName sclk,
@@ -70,9 +70,6 @@
_spi.format(8, 0); /* 8-bit, mode = 0, [order = SPI_MSB] only available in mbed3 */
_spi.frequency(5000000); // 5MHz
- /* start timer */
- _busywait_timer.start();
-
/* install irq handler */
_irq.fall(Callback<void()>(this, &SimpleSpirit1::IrqHandler));
@@ -153,6 +150,7 @@
spirit_on = OFF;
CLEAR_TXBUF();
CLEAR_RXBUF();
+ _spirit_tx_started = false;
_spirit_rx_err = false;
/* Configure the radio to route the IRQ signal to its GPIO 3 */
@@ -228,6 +226,7 @@
CLEAR_RXBUF();
disable_spirit_irq();
irq_clear_status();
+ receiving_packet = 0;
cmd_strobe(SPIRIT1_STROBE_SABORT);
wait_us(SABORT_WAIT_US);
cmd_strobe(SPIRIT1_STROBE_READY);
@@ -243,9 +242,9 @@
#if NULLRDC_CONF_802154_AUTOACK
if (wants_an_ack) {
- rtimer_txdone = _busywait_timer.read_us();
+ rtimer_txdone = us_ticker_read();
BUSYWAIT_UNTIL(just_got_an_ack, 2);
- rtimer_rxack = _busywait_timer.read_us();
+ rtimer_rxack = us_ticker_read();
if(just_got_an_ack) {
ACKPRINTF("debug_ack: ack received after %u us\n",
@@ -305,11 +304,13 @@
remaining -= to_send;
} while(remaining != 0);
+ _spirit_tx_started = true;
+
+ enable_spirit_irq();
+
BUSYWAIT_UNTIL(SPIRIT1_STATUS() != SPIRIT1_STATE_TX, 50);
MBED_ASSERT(linear_fifo_read_num_elements_tx_fifo() == 0);
- enable_spirit_irq();
-
return RADIO_TX_OK;
}
@@ -317,15 +318,15 @@
void SimpleSpirit1::set_ready_state(void) {
PRINTF("READY IN\n");
- irq_clear_status();
disable_spirit_irq();
if(SPIRIT1_STATUS() == SPIRIT1_STATE_STANDBY) {
cmd_strobe(SPIRIT1_STROBE_READY);
} else if(SPIRIT1_STATUS() == SPIRIT1_STATE_RX) {
+ receiving_packet = 0;
cmd_strobe(SPIRIT1_STROBE_SABORT);
- irq_clear_status();
}
+ irq_clear_status();
enable_spirit_irq();
@@ -339,6 +340,7 @@
disable_spirit_irq();
/* first stop rx/tx */
+ receiving_packet = 0;
cmd_strobe(SPIRIT1_STROBE_SABORT);
/* Clear any pending irqs */
@@ -360,6 +362,7 @@
spirit_on = OFF;
_nr_of_irq_disables = 1;
+ _spirit_tx_started = false;
CLEAR_TXBUF();
CLEAR_RXBUF();
}
@@ -391,6 +394,7 @@
//return 1;
}
CLEAR_RXBUF();
+ receiving_packet = 0;
_spirit_rx_err = false;
/* Enables the mcu to get IRQ from the SPIRIT1 */
@@ -433,6 +437,7 @@
/* Checks if the RX buffer is empty */
if(IS_RXBUF_EMPTY()) {
CLEAR_RXBUF();
+ receiving_packet = 0;
cmd_strobe(SPIRIT1_STROBE_SABORT);
wait_us(SABORT_WAIT_US);
cmd_strobe(SPIRIT1_STROBE_READY);
@@ -487,26 +492,26 @@
spirit_state = OFF;
}
- /* */
disable_spirit_irq();
- cmd_strobe(SPIRIT1_STROBE_SABORT);
- /* SpiritCmdStrobeSabort();*/
- irq_clear_status();
+
+ /* Reset State to Ready */
+ set_ready_state();
{
- uint32_t timeout = _busywait_timer.read_us() + 5000;
+ uint32_t timeout = us_ticker_read() + 5000;
do {
mgmt_refresh_status();
- } while((st_lib_g_x_status.MC_STATE != MC_STATE_READY) && (((uint32_t)_busywait_timer.read_us()) < timeout));
+ } while((st_lib_g_x_status.MC_STATE != MC_STATE_READY) && (us_ticker_read() < 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();
+ enable_spirit_irq();
+
/* Puts the SPIRIT1 in its previous state */
if(spirit_state==OFF) {
off();
@@ -531,12 +536,7 @@
}
}
-int SimpleSpirit1::incoming_packet(void)
-{
- return receiving_packet;
-}
-
-int SimpleSpirit1::pending_packet(void)
+int SimpleSpirit1::get_pending_packet(void)
{
PRINTF("PENDING PACKET\n");
return !IS_RXBUF_EMPTY();
@@ -556,6 +556,14 @@
_spirit_rx_err = true;
CLEAR_RXBUF();
cmd_strobe(SPIRIT1_STROBE_FRX);
+ if(_spirit_tx_started) {
+ _spirit_tx_started = false;
+ CLEAR_TXBUF();
+ /* call user callback */
+ if(_current_irq_callback) {
+ _current_irq_callback(-1); // betzw - TODO: define enums for callback values
+ }
+ }
}
/* Transmission error */
@@ -563,6 +571,14 @@
error("IRQ_TX_FIFO_ERROR should never happen!\n");
receiving_packet = 0;
cmd_strobe(SPIRIT1_STROBE_FTX);
+ if(_spirit_tx_started) {
+ _spirit_tx_started = false;
+ CLEAR_TXBUF();
+ /* call user callback */
+ if(_current_irq_callback) {
+ _current_irq_callback(-1); // betzw - TODO: define enums for callback values
+ }
+ }
}
/* The IRQ_VALID_SYNC is used to notify a new packet is coming */
@@ -570,6 +586,14 @@
receiving_packet = 1;
_spirit_rx_err = false;
CLEAR_RXBUF();
+ if(_spirit_tx_started) { // betzw - TOCHECK: is this really correct to be done here?
+ _spirit_tx_started = false;
+ CLEAR_TXBUF();
+ /* call user callback */
+ if(_current_irq_callback) {
+ _current_irq_callback(-1); // betzw - TODO: define enums for callback values
+ }
+ }
}
/* RX FIFO almost full */
@@ -593,12 +617,20 @@
/* The IRQ_TX_DATA_SENT notifies the packet received. Puts the SPIRIT1 in RX */
if(x_irq_status.IRQ_TX_DATA_SENT) {
+ MBED_ASSERT(_spirit_tx_started);
+
cmd_strobe(SPIRIT1_STROBE_FRX);
cmd_strobe(SPIRIT1_STROBE_RX);
/* SpiritCmdStrobeRx();*/
CLEAR_TXBUF();
CLEAR_RXBUF();
_spirit_rx_err = false;
+ _spirit_tx_started = false;
+
+ /* call user callback */
+ if(_current_irq_callback) {
+ _current_irq_callback(0); // betzw - TODO: define enums for callback values
+ }
}
/* The IRQ_RX_DATA_READY notifies a new packet arrived */
@@ -642,7 +674,7 @@
/* call user callback */
if(_current_irq_callback) {
- _current_irq_callback();
+ _current_irq_callback(1); // betzw - TODO: define enums for callback values
}
}
}
--- a/SimpleSpirit1.h Wed Oct 19 10:04:00 2016 +0200
+++ b/SimpleSpirit1.h Fri Oct 21 14:56:55 2016 +0200
@@ -25,29 +25,38 @@
extern "C" void SpiritManagementSetFrequencyBase(uint32_t);
+/*** UnlockedSPI for Performance (due to singleton) ***/
+class UnlockedSPI : public SPI {
+public:
+ UnlockedSPI(PinName mosi, PinName miso, PinName sclk) :
+ SPI(mosi, miso, sclk) { }
+ virtual void lock() { }
+ virtual void unlock() { }
+};
+
+
/*** A Simple Spirit1 Class ***/
class SimpleSpirit1 { // NOTE: must be a singleton (due to mix of MBED/CUBE code)!!!
protected:
static SimpleSpirit1 *_singleton;
/** Communication Interface Instance Variables **/
- SPI _spi; // betzw - NOTE: Arduino pins are valid only for NUCLEO-F401RE
- // mosi: PA_7 (D11)
- // miso: PA_6 (D12)
- // sclk: PB_3 (D3) or
- // PA_5 (D13) (only in case you unmount R4 & mount R7,
- // (note: in this case you may not use LED1 on some platforms)
- // bits: 8-bit
- // mode: 0
- // ordr: MSB
- // freq: max 10MHz
+ UnlockedSPI _spi; // betzw - NOTE: Arduino pins are valid only for NUCLEO-F401RE
+ // mosi: PA_7 (D11)
+ // miso: PA_6 (D12)
+ // sclk: PB_3 (D3) or
+ // PA_5 (D13) (only in case you unmount R4 & mount R7,
+ // (note: in this case you may not use LED1 on some platforms)
+ // bits: 8-bit
+ // mode: 0
+ // ordr: MSB
+ // freq: max 10MHz
InterruptIn _irq; // PC_7 (D9) (falling)
DigitalOut _chip_select; // PB_6 (D10) ('1' == chip unselected)
DigitalOut _shut_down; // PA_10 (D2) ('1' == shut_down)
DigitalOut _led; // PB_4 (D5) (optional)
- static Timer _busywait_timer;
- Callback<void()> _current_irq_callback;
+ Callback<void(int)> _current_irq_callback;
/** Static Variables from Cube Implementation **/
/*
@@ -56,6 +65,7 @@
* which will contain the length of the packet.
*/
uint16_t spirit_tx_len;
+ bool _spirit_tx_started;
uint16_t spirit_rx_len;
uint16_t _spirit_rx_pos;
bool _spirit_rx_err;
@@ -199,7 +209,8 @@
}
float qi_get_rssi_dbm() {
- return (-120.0+((float)(SpiritQiGetRssi()-20))/2);
+ last_rssi = SpiritQiGetRssi();
+ return (-120.0+((float)(last_rssi-20))/2);
}
uint8_t qi_get_rssi() {
@@ -343,7 +354,7 @@
*
* @note Function 'func' will be executed in interrupt context!
*/
- void attach_irq_callback(Callback<void()> func) {
+ void attach_irq_callback(Callback<void(int)> func) {
_current_irq_callback = func;
}
@@ -351,6 +362,7 @@
int on(void);
int off(void);
+ /** Send a Buffer **/
int send(const void *payload, unsigned int payload_len);
/** Read into Buffer **/
@@ -363,8 +375,20 @@
int channel_clear(void);
/** Check if the radio driver is currently receiving a packet */
- int incoming_packet(void);
+ int get_receiving_packet(void) {
+ return receiving_packet;
+ }
/** Check if the radio driver has just received a packet **/
- int pending_packet(void);
+ int get_pending_packet(void);
+
+ /** Get latest value of RSSI **/
+ uint16_t get_last_rssi(void) {
+ return last_rssi;
+ }
+
+ /** Get latest value of LQI **/
+ uint16_t get_last_lqi(void) {
+ return last_lqi;
+ }
};
--- a/mbed_lib.json Wed Oct 19 10:04:00 2016 +0200
+++ b/mbed_lib.json Fri Oct 21 14:56:55 2016 +0200
@@ -1,4 +1,14 @@
{
- "name": "myspirit1",
+ "name": "spirit1",
+ "config": {
+ "mac-address-0": "0x0",
+ "mac-address-1": "0x0",
+ "mac-address-2": "0x0",
+ "mac-address-3": "0x0",
+ "mac-address-4": "0x0",
+ "mac-address-5": "0x0",
+ "mac-address-6": "0x0",
+ "mac-address-7": "0x0"
+ },
"macros": ["USE_STM32F4XX_NUCLEO", "X_NUCLEO_IDS01A4", "SPIRIT_USE_FULL_ASSERT"]
}
X-NUCLEO-IDS01A4 Sub-1GHz RF Expansion Board