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.h
- Revision:
- 34:edda6a7238ec
- Parent:
- 33:c226804be492
- Child:
- 35:f3f444c379d0
--- a/SimpleSpirit1.h Mon Nov 21 13:26:17 2016 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,467 +0,0 @@
-/*** Mbed Includes ***/
-#include "mbed.h"
-#include "mbed_debug.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 "spirit1-config.h"
-#include "spirit1-const.h"
-
-
-// betzw: enable beyond macro if you want debug messages also from IRQ handler
-#define DEBUG_IRQ
-
-
-/*** Macros from Cube Implementation ***/
-#define CLEAR_TXBUF() (spirit_tx_len = 0)
-#define IS_RXBUF_EMPTY() (spirit_rx_len == 0)
-#define CLEAR_RXBUF() do { \
- spirit_rx_len = 0; \
- _spirit_rx_pos = 0; \
- } while(0)
-
-
-/*** Macros from Cube Implementation ***/
-/* transceiver state. */
-#define ON 0
-#define OFF 1
-
-
-/*** Missing Cube External Declarations ***/
-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 ~UnlockedSPI() {}
- virtual void lock() { }
- virtual void unlock() { }
-};
-
-
-/*** A Simple Spirit1 Class ***/
-// NOTE: must be a singleton (due to mix of MBED/CUBE code)!!!
-// NOTE: implementation is IRQ-save but (intentionally) NOT thread-safe!!!
-class SimpleSpirit1 {
- protected:
- static SimpleSpirit1 *_singleton;
-
- /** Communication Interface Instance Variables **/
- 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)
-
- Callback<void(int)> _current_irq_callback;
- Timeout _rx_receiving_timeout;
-
- void rx_timeout_handler(void) {
- set_ready_state();
- cmd_strobe(SPIRIT1_STROBE_RX);
-#ifdef DEBUG_IRQ
- debug("\n\r%s (%d)\n\r", __func__, __LINE__);
-#endif
- }
-
- void start_rx_timeout(void) {
- _rx_receiving_timeout.attach_us(Callback<void()>(this, &SimpleSpirit1::rx_timeout_handler), 500 * 1000); // 500ms
- }
-
- void stop_rx_timeout(void) {
- _rx_receiving_timeout.detach();
- }
-
- /** 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.
- */
- volatile uint16_t spirit_tx_len;
- volatile bool _spirit_tx_started;
- volatile uint16_t spirit_rx_len;
- volatile uint16_t _spirit_rx_pos;
- volatile bool _spirit_rx_err;
- uint8_t spirit_rx_buf[MAX_PACKET_LEN];
- volatile bool _is_receiving;
-
- /** Status Variables from Cube Implementation **/
- unsigned int spirit_on;
- uint8_t last_rssi; //MGR
- uint8_t last_sqi; //MGR
-
- /** Low Level Instance Variables **/
- unsigned int _nr_of_irq_disables;
-
- /** Low Level Instance Methods **/
- void disable_spirit_irq(void) {
- _irq.disable_irq();
- _nr_of_irq_disables++;
-#ifndef NDEBUG
- debug_if(_nr_of_irq_disables == 0, "\n\rassert failed in: %s (%d)\n\r", __func__, __LINE__);
-#endif
- }
-
- void enable_spirit_irq(void) {
-#ifndef NDEBUG
- debug_if(_nr_of_irq_disables == 0, "\n\rassert failed in: %s (%d)\n\r", __func__, __LINE__);
-#endif
- 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;
- wait_ms(5); // wait 5 milliseconds (to allow Spirit1 to shut down)
- }
-
- void exit_shutdown() {
- _shut_down = 0;
- wait_ms(10); // wait 10 milliseconds (to allow Spirit1 a proper boot-up sequence)
- }
-
- void cs_to_sclk_delay(void) {
- wait_us(1); // heuristic value
- }
-
- /**
- * @brief Write and read a buffer to/from the SPI peripheral device at the same time
- * in 8-bit data mode using synchronous SPI communication.
- * @param[in] pBufferToWrite pointer to the buffer of data to send.
- * @param[out] pBufferToRead pointer to the buffer to read data into.
- * @param[in] NumBytes number of bytes to read and write.
- * @retval 0 if ok.
- * @retval -1 if data format error.
- * @note When using the SPI in Interrupt-mode, remember to disable interrupts
- * before calling this function and to enable them again after.
- */
- void spi_write_read(uint8_t* pBufferToWrite, uint8_t* pBufferToRead, uint16_t NumBytes)
- {
- /* Read and write data at the same time. */
- for (int i = 0; i < NumBytes; i++) {
- pBufferToRead[i] = _spi.write(pBufferToWrite[i]);
- }
- }
-
- /** 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_persistent_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);
- }
-
- void pkt_basic_set_payload_length(uint16_t nPayloadLength) {
- SpiritPktBasicSetPayloadLength(nPayloadLength);
- }
-
- uint16_t pkt_basic_get_received_pkt_length(void) {
- return SpiritPktBasicGetReceivedPktLength();
- }
-
- /** 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);
- }
-
- void irq_get_status(SpiritIrqs* pxIrqStatus) {
- SpiritIrqGetStatus(pxIrqStatus);
- }
-
- /** Management Instance Methods **/
- void mgmt_set_freq_base(uint32_t freq) {
- SpiritManagementSetFrequencyBase(freq);
- }
-
- void mgmt_refresh_status(void) {
- SpiritRefreshStatus();
- }
-
- /** 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);
- }
-
- float qi_get_rssi_dbm() {
- last_rssi = qi_get_rssi();
- return get_last_rssi_dbm();
- }
-
- uint8_t qi_get_rssi() {
- return SpiritQiGetRssi();
- }
-
- uint8_t qi_get_sqi() {
- return SpiritQiGetSqi();
- }
-
- /** 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);
- }
-
- /** CSMA/CA Instance Methods **/
- void csma_ca_state(SpiritFunctionalState xNewState) {
- SpiritCsma(xNewState);
- }
-
- void csma_ca_init(CsmaInit* pxCsmaInit) {
- csma_ca_state(S_DISABLE); // Disabled at init
- SpiritCsmaInit(pxCsmaInit);
- SpiritCsmaSeedReloadMode(S_DISABLE); // always disable seed reload
- }
-
- /** Command Instance Methods**/
- void cmd_strobe(uint8_t cmd) {
- SpiritCmdStrobeCommand((SpiritCmd)cmd);
- }
-
- void cmd_strobe_flush_rx_fifo() {
- SpiritCmdStrobeCommand(CMD_FLUSHRXFIFO);
- }
-
- /** SPI Instance Methods **/
- StatusBytes spi_write_linear_fifo(uint8_t cNbBytes, uint8_t* pcBuffer) {
- return SdkEvalSpiWriteFifo(cNbBytes, pcBuffer);
- }
-
- StatusBytes spi_read_linear_fifo(uint8_t cNbBytes, uint8_t* pcBuffer) {
- return SdkEvalSpiReadFifo(cNbBytes, pcBuffer);
- }
-
- /** Linear FIFO Instance Methods **/
- uint8_t linear_fifo_read_num_elements_rx_fifo(void) {
- return SpiritLinearFifoReadNumElementsRxFifo();
- }
-
- uint8_t linear_fifo_read_num_elements_tx_fifo(void) {
- return SpiritLinearFifoReadNumElementsTxFifo();
- }
-
- void linear_fifo_set_almost_full_thr_rx(uint8_t cThrRxFifo) {
- SpiritLinearFifoSetAlmostFullThresholdRx(cThrRxFifo);
- }
-
- /** Calibration Instance Methods **/
- void calibration_rco(SpiritFunctionalState xNewState) {
- SpiritCalibrationRco(xNewState);
- }
-
- /** Internal Spirit Methods */
- void set_ready_state(void);
- uint8_t refresh_state(void);
-
- /** 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_spirit_irq();
- chip_select();
- cs_to_sclk_delay();
- }
-
- void chip_sync_unselect() {
- chip_unselect();
- enable_spirit_irq();
- }
-
- /** Init Instance Method **/
- void init();
-
- /** Spirit Irq Callback */
- void IrqHandler();
-
- /** Constructor **/
- SimpleSpirit1(PinName mosi, PinName miso, PinName sclk,
- PinName irq, PinName cs, PinName sdn,
- PinName led);
-
- /** Destructor **/
- ~SimpleSpirit1(void); // should never be called!
-
-public:
- enum {
- RX_DONE,
- TX_DONE,
- TX_ERR
- };
-
- 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);
- _singleton->init();
- } else {
- error("SimpleSpirit1 singleton already created!\n");
- }
-
- return *_singleton;
- }
-
- static SimpleSpirit1& Instance() {
- if(_singleton == NULL) {
- error("SimpleSpirit1 must be created before used!\n");
- }
-
- return *_singleton;
- }
-
- /** Attach a function to be called by the Spirit Irq handler when packet has arrived
- *
- * @param func A void() callback, or 0 to set as none
- *
- * @note Function 'func' will be executed in interrupt context!
- */
- void attach_irq_callback(Callback<void(int)> func) {
- _current_irq_callback = func;
- }
-
- /** Switch Radio On/Off **/
- int on(void);
- int off(void);
-
- /** Set Channel **/
- void set_channel(uint8_t channel) {
- SpiritRadioSetChannel(channel);
- }
-
- /** Send a Buffer **/
- int send(const void *payload, unsigned int payload_len);
-
- /** Read into Buffer **/
- int read(void *buf, unsigned int bufsize);
-
- /** Perform a Clear-Channel Assessment (CCA) to find out if there is
- a packet in the air or not.
- Returns 1 if packet has been seen.
- */
- int channel_clear(void);
-
- /** Check if the radio driver has just received a packet **/
- int get_pending_packet(void);
-
- /** Is radio currently receiving **/
- bool is_receiving(void) {
- return _is_receiving;
- }
-
- /** Get latest value of RSSI (in dBm) **/
- float get_last_rssi_dbm(void) {
- get_last_rssi_raw();
- return (-120.0+((float)(last_rssi-20))/2);
- }
-
- /** Get latest value of RSSI (as Spirit1 raw value) **/
- uint8_t get_last_rssi_raw(void) {
- if(last_rssi == 0) {
- last_rssi = qi_get_rssi();
- }
- return last_rssi;
- }
-
- /** Get latest value of LQI (scaled to 8-bit) **/
- uint8_t get_last_sqi(void) {
- const uint8_t max_sqi = 8 * ((SYNC_LENGTH>>1)+1);
- if(last_sqi == 0) {
- last_sqi = qi_get_sqi();
- }
- if(last_sqi > max_sqi) last_sqi = max_sqi;
-
- return (last_sqi * 255 / max_sqi);
- }
-
- /** Reset Board **/
- void reset_board() {
- init();
- }
-};
X-NUCLEO-IDS01A4 Sub-1GHz RF Expansion Board