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).

Files at this revision

API Documentation at this revision

Comitter:
Wolfgang Betz
Date:
Fri Dec 16 12:06:21 2016 +0100
Parent:
42:92a60a905ee7
Child:
44:aedd63cb0ce3
Commit message:
Backup commit!

Changed in this revision

source/SimpleSpirit1.cpp Show annotated file Show diff for this revision Revisions of this file
source/libs/Contiki_STM32_Library/spirit1-config.h Show annotated file Show diff for this revision Revisions of this file
source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Irq.h Show annotated file Show diff for this revision Revisions of this file
--- a/source/SimpleSpirit1.cpp	Fri Dec 02 10:51:18 2016 +0100
+++ b/source/SimpleSpirit1.cpp	Fri Dec 16 12:06:21 2016 +0100
@@ -51,7 +51,7 @@
 
 	/* configure spi */
 	_spi.format(8, 0); /* 8-bit, mode = 0, [order = SPI_MSB] only available in mbed3 */
-	_spi.frequency(1000000); // 1MHz // betzw - NOTE: higher frequencies lead to instability of Spirit1
+	_spi.frequency(100000); // 100kHz // betzw: heuristic value // betzw - NOTE: high frequencies lead to instability of Spirit1
 
 	/* install irq handler */
 	_irq.mode(PullUp);
@@ -138,6 +138,8 @@
 	};
 	spirit_gpio_init(&x_gpio_init);
 
+// #ifdef RX_FIFO_THR_AO_CSMA_WA
+	// betzw - TODO: enabling CSMA/CA seems to be incompatible with TX FIFO usage (to be investigated)
 	/* Setup CSMA/CA */
 	CsmaInit x_csma_init = {
 			S_ENABLE,         // enable persistent mode
@@ -148,9 +150,12 @@
 			8                 // BU prescaler
 	};
 	csma_ca_init(&x_csma_init);
+// #endif
 
 #ifdef RX_FIFO_THR_AO_CSMA_WA
 	linear_fifo_set_almost_full_thr_rx(SPIRIT_MAX_FIFO_LEN-(MAX_PACKET_LEN+1));
+#else
+	linear_fifo_set_almost_full_thr_rx(20); // betzw: heuristic value
 #endif
 
 #ifdef USE_STANDBY_STATE
@@ -185,18 +190,18 @@
 
 	pkt_basic_set_payload_length(payload_len); // set desired payload len
 
-#ifdef RX_FIFO_THR_AO_CSMA_WA
+// #ifdef RX_FIFO_THR_AO_CSMA_WA
 	// betzw - TODO: enabling CSMA/CA seems to be incompatible with TX FIFO usage (to be investigated)
 	csma_ca_state(S_ENABLE); // enable CSMA/CA
-#endif
+// #endif
 
 	int i = 0;
 	int remaining = payload_len;
 	const uint8_t *buffer = (const uint8_t*)payload;
 	bool tx_triggered = false;
+	int8_t fifo_available = (3*SPIRIT_MAX_FIFO_LEN/4) - linear_fifo_read_num_elements_tx_fifo(); // betzw: heuristic value
 	do {
-		uint8_t fifo_available = SPIRIT_MAX_FIFO_LEN - linear_fifo_read_num_elements_tx_fifo();
-		uint8_t to_send = (remaining > fifo_available) ? fifo_available : remaining;
+		int8_t to_send = (remaining > fifo_available) ? fifo_available : remaining;
 
 		/* Fill FIFO Buffer */
 		if(to_send > 0) {
@@ -210,6 +215,7 @@
 
 		i += to_send;
 		remaining -= to_send;
+		fifo_available = SPIRIT_MAX_FIFO_LEN - linear_fifo_read_num_elements_tx_fifo();
 	} while(remaining != 0);
 
 	_spirit_tx_started = true;
@@ -223,7 +229,11 @@
 
 	_spirit_tx_started = false; // in case of state timeout
 
+// #ifdef RX_FIFO_THR_AO_CSMA_WA
+	// betzw - TODO: enabling CSMA/CA seems to be incompatible with TX FIFO usage (to be investigated)
 	csma_ca_state(S_DISABLE); // disable CSMA/CA
+// #endif
+
 	cmd_strobe(SPIRIT1_STROBE_RX); // Return to RX state
 
 	return RADIO_TX_OK;
@@ -333,6 +343,9 @@
 
 	/* Checks if the RX buffer is empty */
 	if(IS_RXBUF_EMPTY()) {
+#ifndef NDEBUG
+		debug("\n\rBuffer is empty\n\r");
+#endif
 		set_ready_state();
 
 		cmd_strobe(SPIRIT1_STROBE_RX);
@@ -447,8 +460,8 @@
 	if((x_irq_status.IRQ_RX_FIFO_ERROR) || (x_irq_status.IRQ_RX_DATA_DISC)) {
 #ifdef DEBUG_IRQ
 		uint32_t *tmp = (uint32_t*)&x_irq_status;
-		debug("\n\r%s (%d): irq=%x", __func__, __LINE__, *tmp);
-		debug_if(!((*tmp) & (IRQ_RX_FIFO_ERROR_MASK | IRQ_RX_DATA_DISC_MASK)), "\n\rAssert failed in: %s (%d)", __func__, __LINE__);
+		debug("\n\r%s (%d): irq=%x\n\r", __func__, __LINE__, *tmp);
+		debug_if(!((*tmp) & (IRQ_RX_FIFO_ERROR_MASK | IRQ_RX_DATA_DISC_MASK)), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__);
 #endif
 		rx_timeout_handler();
 		if(_spirit_tx_started) {
@@ -467,10 +480,9 @@
 	if(x_irq_status.IRQ_TX_FIFO_ERROR) {
 #ifdef DEBUG_IRQ
 		uint32_t *tmp = (uint32_t*)&x_irq_status;
-		debug("\n\r%s (%d): irq=%x", __func__, __LINE__, *tmp);
-		debug_if(!((*tmp) & IRQ_TX_FIFO_ERROR_MASK), "\n\rAssert failed in: %s (%d)", __func__, __LINE__);
+		debug("\n\r%s (%d): irq=%x\n\r", __func__, __LINE__, *tmp);
+		debug_if(!((*tmp) & IRQ_TX_FIFO_ERROR_MASK), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__);
 #endif
-		csma_ca_state(S_DISABLE); // disable CSMA/CA
 		if(_spirit_tx_started) {
 			_spirit_tx_started = false;
 			/* call user callback */
@@ -488,7 +500,7 @@
 #ifdef DEBUG_IRQ
 		uint32_t *tmp = (uint32_t*)&x_irq_status;
 		debug_if(!_spirit_tx_started, "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__);
-		debug_if(!((*tmp) & IRQ_TX_DATA_SENT_MASK), "\n\rAssert failed in: %s (%d)", __func__, __LINE__);
+		debug_if(!((*tmp) & IRQ_TX_DATA_SENT_MASK), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__);
 #endif
 
 		_spirit_tx_started = false;
@@ -499,61 +511,88 @@
 		}
 	}
 
-	/* RX FIFO almost full */
-	if(x_irq_status.IRQ_RX_FIFO_ALMOST_FULL) {
-#ifdef DEBUG_IRQ
-		uint32_t *tmp = (uint32_t*)&x_irq_status;
-		debug_if(!((*tmp) & IRQ_RX_FIFO_ALMOST_FULL_MASK), "\n\rAssert failed in: %s (%d)", __func__, __LINE__);
-#endif
-		uint8_t fifo_available = linear_fifo_read_num_elements_rx_fifo();
-		unsigned int remaining = MAX_PACKET_LEN - _spirit_rx_pos;
-		if(fifo_available > remaining) {
-#ifdef DEBUG_IRQ
-			uint32_t *tmp = (uint32_t*)&x_irq_status;
-			debug("\n\r%s (%d): irq=%x", __func__, __LINE__, *tmp);
-#endif
-			rx_timeout_handler();
-		} else {
-			spi_read_linear_fifo(fifo_available, &spirit_rx_buf[_spirit_rx_pos]);
-			_spirit_rx_pos += fifo_available;
-			if(!_is_receiving) {
-				_is_receiving = true;
-				start_rx_timeout();
-			}
-		}
-	}
-
 	/* The IRQ_RX_DATA_READY notifies a new packet arrived */
 	if(x_irq_status.IRQ_RX_DATA_READY) {
 #ifdef DEBUG_IRQ
 		uint32_t *tmp = (uint32_t*)&x_irq_status;
-		debug_if(!((*tmp) & IRQ_RX_DATA_READY_MASK), "\n\rAssert failed in: %s (%d)", __func__, __LINE__);
+		debug_if(!((*tmp) & IRQ_RX_DATA_READY_MASK), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__);
 #endif
-		_is_receiving = false; // Finished receiving
-		stop_rx_timeout();
 
-		spirit_rx_len = pkt_basic_get_received_pkt_length();
+		if(!_is_receiving) { // spurious irq?!?
+#ifdef DEBUG_IRQ
+			debug("\n\r%s (%d): irq=%x\n\r", __func__, __LINE__, *tmp);
+#endif
+		} else {
+			_is_receiving = false; // Finished receiving
+			stop_rx_timeout();
+
+			spirit_rx_len = pkt_basic_get_received_pkt_length();
 
 #ifdef DEBUG_IRQ
-		debug_if(!(spirit_rx_len <= MAX_PACKET_LEN), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__);
+			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;) {
-			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;
+			for(; _spirit_rx_pos < spirit_rx_len;) {
+				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;
+				}
 			}
+
+			cmd_strobe(SPIRIT1_STROBE_FRX);
+
+			last_rssi = qi_get_rssi(); //MGR
+			last_sqi  = qi_get_sqi();  //MGR
+
+			/* call user callback */
+			if(_current_irq_callback) {
+				_current_irq_callback(RX_DONE);
+			}
+
+			/* Disable handling of other RX flags */
+			x_irq_status.IRQ_RX_FIFO_ALMOST_FULL = S_RESET;
 		}
+	}
 
-		cmd_strobe(SPIRIT1_STROBE_FRX);
+	/* RX FIFO almost full */
+	if(x_irq_status.IRQ_RX_FIFO_ALMOST_FULL) {
+#ifdef DEBUG_IRQ
+		uint32_t *tmp = (uint32_t*)&x_irq_status;
+		debug_if(!((*tmp) & IRQ_RX_FIFO_ALMOST_FULL_MASK), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__);
+#endif
+		if(!_is_receiving) { // spurious irq?!?
+#ifdef DEBUG_IRQ
+			debug("\n\r%s (%d): irq=%x\n\r", __func__, __LINE__, *tmp);
+#endif
+		} else {
+			uint8_t fifo_available = linear_fifo_read_num_elements_rx_fifo();
+			spi_read_linear_fifo(fifo_available, &spirit_rx_buf[_spirit_rx_pos]);
+			_spirit_rx_pos += fifo_available;
+
+#if 1
+			spirit_rx_len = pkt_basic_get_received_pkt_length();
 
-		last_rssi = qi_get_rssi(); //MGR
-		last_sqi  = qi_get_sqi();  //MGR
+#ifdef DEBUG_IRQ
+			debug_if(!(spirit_rx_len <= MAX_PACKET_LEN), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__);
+#endif
+
+			if((spirit_rx_len > 0) && (_spirit_rx_pos >= spirit_rx_len)) { // already received everything
+				_is_receiving = false; // Finished receiving
+				stop_rx_timeout();
+
+				cmd_strobe(SPIRIT1_STROBE_FRX);
 
-		/* call user callback */
-		if(_current_irq_callback) {
-			_current_irq_callback(RX_DONE);
+				last_rssi = qi_get_rssi(); //MGR
+				last_sqi  = qi_get_sqi();  //MGR
+
+				/* call user callback */
+				if(_current_irq_callback) {
+					_current_irq_callback(RX_DONE);
+				}
+			}
+#endif // 0
+
 		}
 	}
 
@@ -561,7 +600,7 @@
 	if(x_irq_status.IRQ_VALID_SYNC) {
 #ifdef DEBUG_IRQ
 		uint32_t *tmp = (uint32_t*)&x_irq_status;
-		debug_if(!((*tmp) & IRQ_VALID_SYNC_MASK), "\n\rAssert failed in: %s (%d)", __func__, __LINE__);
+		debug_if(!((*tmp) & IRQ_VALID_SYNC_MASK), "\n\rAssert failed in: %s (%d)\n\r", __func__, __LINE__);
 #endif
 		/* betzw - NOTE: there is a race condition between Spirit1 receiving packets and
 		 *               the MCU trying to send a packet, which gets resolved in favor of
@@ -570,7 +609,7 @@
 		if(_spirit_tx_started) {
 #ifdef DEBUG_IRQ
 			uint32_t *tmp = (uint32_t*)&x_irq_status;
-			debug("\n\r%s (%d): irq=%x", __func__, __LINE__, *tmp);
+			debug("\n\r%s (%d): irq=%x\n\r", __func__, __LINE__, *tmp);
 #endif
 		} else {
 			_is_receiving = true;
--- a/source/libs/Contiki_STM32_Library/spirit1-config.h	Fri Dec 02 10:51:18 2016 +0100
+++ b/source/libs/Contiki_STM32_Library/spirit1-config.h	Fri Dec 16 12:06:21 2016 +0100
@@ -49,7 +49,7 @@
  * Furthermore, enable this macro if you want to use CSMA/CA.
  * NOTE: this enables just a workaround!!!
  */
-#define RX_FIFO_THR_AO_CSMA_WA
+// #define RX_FIFO_THR_AO_CSMA_WA
 
 /**    
  * The MAX_PACKET_LEN is an arbitrary value used to define the two array
@@ -60,7 +60,7 @@
 #ifdef RX_FIFO_THR_AO_CSMA_WA
 #define MAX_PACKET_LEN              (SPIRIT_MAX_FIFO_LEN-1)
 #else
-#define MAX_PACKET_LEN              (255) // betzw - WAS: SPIRIT_MAX_FIFO_LEN, but LEN_WIDTH is set to 7 so the variable payload length is from 0 to 255 bytes
+#define MAX_PACKET_LEN              (255) // betzw - WAS: SPIRIT_MAX_FIFO_LEN, but LEN_WIDTH is set to 7 so the variable payload length is theoretically from 0 to 255 bytes
 #endif
 
 /*---------------------------------------------------------------------------*/
--- a/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Irq.h	Fri Dec 02 10:51:18 2016 +0100
+++ b/source/libs/spirit1/SPIRIT1_Library/Inc/SPIRIT_Irq.h	Fri Dec 16 12:06:21 2016 +0100
@@ -211,7 +211,7 @@
 } SpiritIrqs;
 
 // betzw: uint32_t masks
-#define IRQ_RX_FIFO_ALMOST_FULL_MASK	(0x00040000) /* (1<<17) */
+#define IRQ_RX_FIFO_ALMOST_FULL_MASK	(0x00020000) /* (1<<16) */
 #define IRQ_VALID_SYNC_MASK				(0x00200000) /* (1<<21) */
 #define IRQ_RX_DATA_READY_MASK			(0x01000000) /* (1<<24) */
 #define IRQ_RX_DATA_DISC_MASK			(0x02000000) /* (1<<25) */