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).
Diff: SimpleSpirit1.cpp
- Revision:
- 25:2ec45788f28c
- Parent:
- 24:03e351bfc9c9
- Child:
- 26:45dae8d48029
--- a/SimpleSpirit1.cpp Thu Nov 10 15:25:59 2016 +0100
+++ b/SimpleSpirit1.cpp Mon Nov 14 11:26:03 2016 +0100
@@ -4,7 +4,7 @@
#define SPIRIT_GPIO_IRQ (SPIRIT_GPIO_3)
-#define SPIRIT1_STATUS() (arch_refresh_status() & SPIRIT1_STATE_STATEBITS)
+#define SPIRIT1_STATUS() (((uint16_t)refresh_state()) & SPIRIT1_STATE_STATEBITS)
#define BUSYWAIT_UNTIL(cond, millisecs) \
do { \
@@ -17,6 +17,7 @@
#define st_lib_spirit_irqs SpiritIrqs
+#define STATE_TIMEOUT (1000)
/*** Class Implementation ***/
/** Static Class Variables **/
@@ -119,9 +120,8 @@
timer_set_rx_timeout_stop_condition(SQI_ABOVE_THRESHOLD);
timer_set_infinite_rx_timeout();
radio_afc_freeze_on_sync(S_ENABLE);
+ calibration_rco(S_ENABLE);
- /* Puts the SPIRIT1 in STANDBY mode (125us -> rx/tx) */
- cmd_strobe(SPIRIT1_STROBE_STANDBY);
spirit_on = OFF;
CLEAR_TXBUF();
CLEAR_RXBUF();
@@ -151,6 +151,9 @@
#ifdef RX_FIFO_THR_WA
linear_fifo_set_almost_full_thr_rx(SPIRIT_MAX_FIFO_LEN-(MAX_PACKET_LEN+1));
#endif
+
+ /* Puts the SPIRIT1 in STANDBY mode (125us -> rx/tx) */
+ cmd_strobe(SPIRIT1_STROBE_STANDBY);
}
int SimpleSpirit1::send(const void *payload, unsigned int payload_len) {
@@ -159,12 +162,17 @@
return RADIO_TX_ERR;
}
+#ifndef NDEBUG
+ debug_if(SPIRIT1_STATUS() != SPIRIT1_STATE_RX, "\n\rassert failed in: %s (%d): state=%x\n\r", __func__, __LINE__, SPIRIT1_STATUS()>>1);
+#endif
+
disable_spirit_irq();
/* Reset State to Ready */
set_ready_state();
cmd_strobe(SPIRIT1_STROBE_FTX); // flush TX FIFO buffer
+
#ifndef NDEBUG
debug_if(!(linear_fifo_read_num_elements_tx_fifo() == 0), "\n\rassert failed in: %s (%d)\n\r", __func__, __LINE__);
#endif
@@ -200,9 +208,10 @@
enable_spirit_irq();
- BUSYWAIT_UNTIL(SPIRIT1_STATUS() != SPIRIT1_STATE_TX, 50);
+ BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, STATE_TIMEOUT);
+
#ifndef NDEBUG
- // debug_if(!(linear_fifo_read_num_elements_tx_fifo() == 0), "\n\rassert failed in: %s (%d)\n\r", __func__, __LINE__);
+ debug_if(SPIRIT1_STATUS() != SPIRIT1_STATE_RX, "\n\rassert failed in: %s (%d): state=%x\n\r", __func__, __LINE__, SPIRIT1_STATUS()>>1);
#endif
return RADIO_TX_OK;
@@ -210,16 +219,31 @@
/** Set Ready State **/
void SimpleSpirit1::set_ready_state(void) {
+ uint16_t state;
+
disable_spirit_irq();
_is_receiving = false;
stop_rx_timeout();
- if(SPIRIT1_STATUS() == SPIRIT1_STATE_STANDBY) {
+ state = SPIRIT1_STATUS();
+ if(state == SPIRIT1_STATE_STANDBY) {
cmd_strobe(SPIRIT1_STROBE_READY);
- } else if(SPIRIT1_STATUS() == SPIRIT1_STATE_RX) {
+ } else if(state == SPIRIT1_STATE_RX) {
cmd_strobe(SPIRIT1_STROBE_SABORT);
+ } else if(state != SPIRIT1_STATE_READY) {
+#ifndef NDEBUG
+ debug("\n\rassert failed in: %s (%d): state=%x\n\r", __func__, __LINE__, state>>1);
+#endif
}
+
+ BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_READY, STATE_TIMEOUT);
+ if(SPIRIT1_STATUS() != SPIRIT1_STATE_READY) {
+ error("\n\rSpirit1: failed to become ready (%x) => pls. reset!\n\r", SPIRIT1_STATUS()>>1);
+ enable_spirit_irq();
+ return;
+ }
+
irq_clear_status();
enable_spirit_irq();
@@ -231,26 +255,13 @@
disable_spirit_irq();
/* first stop rx/tx */
- cmd_strobe(SPIRIT1_STROBE_SABORT);
-
- /* Clear any pending irqs */
- irq_clear_status();
-
- BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_READY, 3000);
- if(SPIRIT1_STATUS() != SPIRIT1_STATE_READY) {
-#ifndef NDEBUG
- debug("\n\rSpirit1: failed off->ready\n\r");
-#endif
- return 1;
- }
+ set_ready_state();
/* Puts the SPIRIT1 in STANDBY */
cmd_strobe(SPIRIT1_STROBE_STANDBY);
- BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_STANDBY, 3000);
+ BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_STANDBY, STATE_TIMEOUT);
if(SPIRIT1_STATUS() != SPIRIT1_STATE_STANDBY) {
-#ifndef NDEBUG
- debug("\n\rSpirit1: failed off->standby\n\r");
-#endif
+ error("\n\rSpirit1: failed to enter standby (%x)\n\r", SPIRIT1_STATUS()>>1);
return 1;
}
@@ -267,28 +278,18 @@
}
int SimpleSpirit1::on(void) {
- cmd_strobe(SPIRIT1_STROBE_SABORT);
if(spirit_on == OFF) {
- /* ensure we are in READY state as we go from there to Rx */
- cmd_strobe(SPIRIT1_STROBE_READY);
- BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_READY, 3000);
- if(SPIRIT1_STATUS() != SPIRIT1_STATE_READY) {
-#ifndef NDEBUG
- debug("\n\rSpirit1: failed to turn on\n\r");
-#endif
- return 1;
+ set_ready_state();
+
+ /* now we go to Rx */
+ cmd_strobe(SPIRIT1_STROBE_RX);
+
+ BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, STATE_TIMEOUT);
+ if(SPIRIT1_STATUS() != SPIRIT1_STATE_RX) {
+ error("\n\rSpirit1: failed to enter rx (%x) => retry\n\r", SPIRIT1_STATUS()>>1);
}
- /* now we go to Rx */
cmd_strobe(SPIRIT1_STROBE_FRX);
- cmd_strobe(SPIRIT1_STROBE_RX);
- BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, 3000);
- if(SPIRIT1_STATUS() != SPIRIT1_STATE_RX) {
-#ifndef NDEBUG
- debug("\n\rSpirit1: failed to enter rx\n\r");
-#endif
- return 1;
- }
CLEAR_RXBUF();
_spirit_rx_err = false;
_is_receiving = false;
@@ -302,27 +303,17 @@
enable_spirit_irq();
}
+#ifndef NDEBUG
+ debug_if(SPIRIT1_STATUS() != SPIRIT1_STATE_RX, "\n\rassert failed in: %s (%d): state=%x\n\r", __func__, __LINE__, SPIRIT1_STATUS()>>1);
+#endif
+
return 0;
}
-uint16_t SimpleSpirit1::arch_refresh_status(void) {
- uint16_t mcstate;
- uint8_t header[2];
- header[0]=READ_HEADER;
- header[1]=MC_STATE1_BASE;
-
- /* Puts the SPI chip select low to start the transaction */
- chip_sync_select();
+uint8_t SimpleSpirit1::refresh_state(void) {
+ uint8_t mcstate;
- /* Write the aHeader bytes and read the SPIRIT1 status bytes */
- mcstate = _spi.write(header[0]);
- mcstate = mcstate<<8;
-
- /* Write the aHeader bytes and read the SPIRIT1 status bytes */
- mcstate |= _spi.write(header[1]);
-
- /* Puts the SPI chip select high to end the transaction */
- chip_sync_unselect();
+ SpiritSpiReadRegisters(MC_STATE0_BASE, 1, &mcstate);
return mcstate;
}
@@ -334,12 +325,11 @@
/* Checks if the RX buffer is empty */
if(IS_RXBUF_EMPTY()) {
CLEAR_RXBUF();
- cmd_strobe(SPIRIT1_STROBE_SABORT);
- cmd_strobe(SPIRIT1_STROBE_READY);
- BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_READY, 3000);
+ set_ready_state();
+
cmd_strobe(SPIRIT1_STROBE_FRX);
cmd_strobe(SPIRIT1_STROBE_RX);
- BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, 3000);
+ BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, STATE_TIMEOUT);
_spirit_rx_err = false;
_is_receiving = false;
stop_rx_timeout();
@@ -383,23 +373,14 @@
spirit_state = OFF;
}
+#ifndef NDEBUG
+ debug_if(SPIRIT1_STATUS() != SPIRIT1_STATE_RX, "\n\rassert failed in: %s (%d): state=%x\n\r", __func__, __LINE__, SPIRIT1_STATUS()>>1);
+#endif
+
disable_spirit_irq();
/* Reset State to Ready */
set_ready_state();
- {
- uint32_t timeout = us_ticker_read() + 5000;
- do {
- mgmt_refresh_status();
- } 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();
-#ifndef NDEBUG
- debug("\n\rSpirit1: channel clear failed\n\r");
-#endif
- return 1;
- }
- }
/* Stores the RSSI value */
rssi_value = qi_get_rssi_dbm();
@@ -409,16 +390,29 @@
/* Puts the SPIRIT1 in its previous state */
if(spirit_state==OFF) {
off();
+#ifndef NDEBUG
+ debug_if(SPIRIT1_STATUS() != SPIRIT1_STATE_STANDBY, "\n\rassert failed in: %s (%d): state=%x\n\r", __func__, __LINE__, SPIRIT1_STATUS()>>1);
+#endif
} else {
disable_spirit_irq();
- cmd_strobe(SPIRIT1_STROBE_FRX);
+
+ set_ready_state();
+
cmd_strobe(SPIRIT1_STROBE_RX);
- BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, 10);
+ BUSYWAIT_UNTIL(SPIRIT1_STATUS() == SPIRIT1_STATE_RX, STATE_TIMEOUT);
+ if(SPIRIT1_STATUS() != SPIRIT1_STATE_RX) {
+ error("\n\rSpirit1: (#2) failed to enter rx (%x) => retry\n\r", SPIRIT1_STATUS()>>1);
+ }
+
CLEAR_RXBUF();
_spirit_rx_err = false;
_is_receiving = false;
stop_rx_timeout();
enable_spirit_irq();
+
+#ifndef NDEBUG
+ debug_if(SPIRIT1_STATUS() != SPIRIT1_STATE_RX, "\n\rassert failed in: %s (%d): state=%x\n\r", __func__, __LINE__, SPIRIT1_STATUS()>>1);
+#endif
}
/* Checks the RSSI value with the threshold */
@@ -440,7 +434,6 @@
/* get interrupt source from radio */
irq_get_status(&x_irq_status);
- // betzw - WAS: irq_clear_status(); BUT already cleared by get status!
/* Reception errors */
if((x_irq_status.IRQ_RX_FIFO_ERROR) || (x_irq_status.IRQ_RX_DATA_DISC) || (x_irq_status.IRQ_RX_TIMEOUT)) {
@@ -469,6 +462,7 @@
#endif
csma_ca_state(S_DISABLE); // disable CSMA/CA
cmd_strobe(SPIRIT1_STROBE_FTX);
+ cmd_strobe(SPIRIT1_STROBE_RX);
if(_spirit_tx_started) {
_spirit_tx_started = false;
CLEAR_TXBUF();
@@ -548,18 +542,13 @@
cmd_strobe(SPIRIT1_STROBE_FRX);
} else {
spirit_rx_len = pkt_basic_get_received_pkt_length();
- unsigned int remaining = 0;
- // uint8_t fifo_available = 0; // betzw: optimized out in favor of a request less to SPIRIT device
- uint8_t to_receive = 0;
#ifndef NDEBUG
debug_if(!(spirit_rx_len <= MAX_PACKET_LEN), "\n\rassert failed in: %s (%d)\n\r", __func__, __LINE__);
#endif
for(; _spirit_rx_pos < spirit_rx_len;) {
- remaining = spirit_rx_len - _spirit_rx_pos;
- // fifo_available = linear_fifo_read_num_elements_rx_fifo(); // betzw: optimized out in favor of a request less to SPIRIT device
- to_receive = remaining; // betzw - WAS: (remaining < fifo_available) ? remaining : fifo_available;
+ uint8_t to_receive = spirit_rx_len - _spirit_rx_pos;
if(to_receive > 0) {
spi_read_linear_fifo(to_receive, &spirit_rx_buf[_spirit_rx_pos]);
_spirit_rx_pos += to_receive;
X-NUCLEO-IDS01A4 Sub-1GHz RF Expansion Board