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:
0:4fb29d9ee571
Child:
2:45642c5198a2
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SimpleSpirit1.h	Thu Oct 13 15:41:39 2016 +0200
@@ -0,0 +1,238 @@
+/*** Mbed Includes ***/
+#include "mbed.h"
+
+
+/*** Cube Includes ***/
+#include "SPIRIT_Radio.h"
+#include "SPIRIT_Management.h"
+#include "SPIRIT_Commands.h"
+#include "MCU_Interface.h"
+
+
+/*** Contiki Lib Includes ***/
+#include "spirit1.h"
+#include "st-lib.h"
+#include "spirit1-config.h"
+#include "spirit1-const.h"
+
+
+/*** Missing Cube External Declarations ***/
+extern "C" void SpiritManagementSetFrequencyBase(uint32_t);
+
+
+/*** 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 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 (falling)
+    DigitalOut _chip_select; // PB_6 ('1' == chip unselected)
+    DigitalOut _shut_down; // PA_10 ('1' == shut_down) 
+    DigitalOut _led; // PB_4 (optional)
+
+    /** Static Variables from Cube Implementation **/
+    /*
+     * The buffers which hold incoming data.
+     * The +1 because of the first byte,
+     * which will contain the length of the packet.
+     */
+    uint8_t spirit_rxbuf[MAX_PACKET_LEN+1];
+    uint8_t spirit_txbuf[MAX_PACKET_LEN+1-SPIRIT_MAX_FIFO_LEN];
+    volatile unsigned int spirit_on;
+
+
+    /** Low Level Instance Variables **/
+    unsigned int _nr_of_irq_disables;
+
+    /** Low Level Ins
+    	return *_singleton;
+     * tance Methods **/
+    void disable_irq(void) {
+    	_irq.disable_irq();
+    	_nr_of_irq_disables++;
+    	MBED_ASSERT(_nr_of_irq_disables != 0);
+    }
+
+    void enable_irq(void) {
+    	MBED_ASSERT(_nr_of_irq_disables > 0);
+    	if(--_nr_of_irq_disables == 0)
+    		_irq.enable_irq();
+    }
+
+    void chip_select() { _chip_select = 0; }
+    void chip_unselect() { _chip_select = 1; }
+
+    void enter_shutdown() { _shut_down = 1; }
+    void exit_shutdown() {
+    	_shut_down = 0;
+    	wait_ms(2); // wait two milliseconds (to allow Spirit1 a proper boot-up sequence)
+    }
+
+    void cs_to_sclk_delay(void) {
+    	wait_us(1); // heuristic value
+    }
+
+    /** Radio Instance Methods **/
+    void radio_set_xtal_freq(uint32_t freq) {
+    	SpiritRadioSetXtalFrequency(freq);
+    }
+
+    void radio_set_pa_level_dbm(uint8_t cIndex, float fPowerdBm) {
+    	SpiritRadioSetPALeveldBm(cIndex, fPowerdBm);
+    }
+
+    void radio_set_pa_level_max_index(uint8_t cIndex) {
+    	SpiritRadioSetPALevelMaxIndex(cIndex);
+    }
+
+    uint8_t radio_init(SRadioInit *init_struct) {
+    	return SpiritRadioInit(init_struct);
+    }
+    
+    void radio_persisten_rx(SpiritFunctionalState xNewState) {
+    	SpiritRadioPersistenRx(xNewState);
+    }
+
+    void radio_afc_freeze_on_sync(SpiritFunctionalState xNewState) {
+    	SpiritRadioAFCFreezeOnSync(xNewState);
+    }
+
+    /** Packet System Instance Methods **/
+    void pkt_basic_init(PktBasicInit* pxPktBasicInit) {
+    	SpiritPktBasicInit(pxPktBasicInit);
+    }
+
+    /** IRQ Instance Methods **/
+    void irq_de_init(SpiritIrqs* pxIrqInit) {
+    	SpiritIrqDeInit(pxIrqInit);
+    }
+
+    void irq_clear_status(void) {
+    	SpiritIrqClearStatus();
+    }
+
+    void irq_set_status(IrqList xIrq, SpiritFunctionalState xNewState) {
+    	SpiritIrq(xIrq, xNewState);
+    }
+
+    /** Management Instance Methods **/
+    void mgmt_set_freq_base(uint32_t freq) {
+    	SpiritManagementSetFrequencyBase(freq);
+    }
+
+    /** Spirit GPIO Instance Methods **/
+    void spirit_gpio_init(SGpioInit* pxGpioInitStruct) {
+    	SpiritGpioInit(pxGpioInitStruct);
+    }
+
+	/** Qi Instance Methods **/
+    void qi_set_sqi_threshold(SqiThreshold xSqiThr) {
+    	SpiritQiSetSqiThreshold(xSqiThr);
+    }
+
+    void qi_sqi_check(SpiritFunctionalState xNewState) {
+    	SpiritQiSqiCheck(xNewState);
+    }
+
+    void qi_set_rssi_threshold_dbm(int nDbmValue) {
+    	SpiritQiSetRssiThresholddBm(nDbmValue);
+    }
+
+    /** Timer Instance Methods **/
+    void timer_set_rx_timeout_stop_condition(RxTimeoutStopCondition xStopCondition) {
+    	SpiritTimerSetRxTimeoutStopCondition(xStopCondition);
+    }
+
+    void timer_set_rx_timeout_counter(uint8_t cCounter) {
+    	SpiritTimerSetRxTimeoutCounter(cCounter);
+    }
+
+    void timer_set_infinite_rx_timeout(void) {
+    	timer_set_rx_timeout_counter(0);
+    }
+
+    /** Command Instance Methods**/
+    void cmd_strobe_command(uint8_t cmd) {
+    	SpiritCmdStrobeCommand((SpiritCmd)cmd);
+    }
+
+    /** Friend Functions **/
+    friend StatusBytes SdkEvalSpiWriteRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer);
+    friend StatusBytes SdkEvalSpiReadRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer);
+    friend StatusBytes SdkEvalSpiCommandStrobes(uint8_t cCommandCode);
+    friend StatusBytes SdkEvalSpiWriteFifo(uint8_t cNbBytes, uint8_t* pcBuffer);
+    friend StatusBytes SdkEvalSpiReadFifo(uint8_t cNbBytes, uint8_t* pcBuffer);
+
+    /** Sdk Instance Methods **/
+    StatusBytes SdkEvalSpiWriteRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer);
+    StatusBytes SdkEvalSpiReadRegisters(uint8_t cRegAddress, uint8_t cNbBytes, uint8_t* pcBuffer);
+    StatusBytes SdkEvalSpiCommandStrobes(uint8_t cCommandCode);
+    StatusBytes SdkEvalSpiWriteFifo(uint8_t cNbBytes, uint8_t* pcBuffer);
+    StatusBytes SdkEvalSpiReadFifo(uint8_t cNbBytes, uint8_t* pcBuffer);
+
+    /** Helper Instance Methods **/
+    void chip_sync_select() {
+    	disable_irq();
+    	chip_select();
+    	cs_to_sclk_delay();
+    }
+
+    void chip_sync_unselect() {
+    	chip_unselect();
+    	enable_irq();
+    }
+
+    /** Constructor **/
+    SimpleSpirit1(PinName mosi, PinName miso, PinName sclk,
+		  PinName irq, PinName cs, PinName sdn,
+		  PinName led);
+
+    /** Destructor **/
+    ~SimpleSpirit1(void); // should never be called!
+
+public:
+    static SimpleSpirit1& CreateInstance(PinName mosi, PinName miso, PinName sclk,
+    		PinName irq, PinName cs, PinName sdn,
+			PinName led = NC) {
+
+    	if(_singleton == NULL) {
+    		_singleton = new SimpleSpirit1(mosi, miso, sclk,
+    				irq, cs, sdn, led);
+    	} else {
+    		error("SimpleSpirit1 singleton already created!");
+    	}
+
+    	return *_singleton;
+    }
+
+    static SimpleSpirit1& Instance() {
+    	if(_singleton == NULL) {
+    		error("SimpleSpirit1 must be created before used!");
+    	}
+
+    	return *_singleton;
+    }
+
+    /** Attach a function to be called when a SPI interrupt occurs
+     *
+     *  @param func A pointer to a void function, or 0 to set as none
+     *
+     *  @note  Function 'func' will be executed in interrupt context!
+     *  @note  This function enables the SPI interrupt!
+     */
+    void attach_irq(Callback<void()> &func) {
+    	_irq.fall(func);
+    	enable_irq();
+    }
+};