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:
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;