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:
68:247fd6e0ab66
Parent:
65:a16f0064110a
Child:
76:f4f990741baf
--- a/source/NanostackRfPhySpirit1.cpp	Thu Jul 06 11:13:31 2017 +0200
+++ b/source/NanostackRfPhySpirit1.cpp	Thu Jul 06 14:15:57 2017 +0200
@@ -64,12 +64,12 @@
 #define FC_ACK_FRAME            0x02
 #define FC_CMD_FRAME            0x03
 
-static void rf_if_lock(void)
+static inline void rf_if_lock(void)
 {
     platform_enter_critical();
 }
 
-static void rf_if_unlock(void)
+static inline void rf_if_unlock(void)
 {
     platform_exit_critical();
 }
@@ -81,205 +81,6 @@
     return ret;
 }
 
-static int8_t rf_trigger_send(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol)
-{
-#ifndef NDEBUG
-    debug_if(!(data_length >= 3), "\n\rassert failed in: %s (%d)\n\r", __func__, __LINE__);
-#endif
-
-    /* Give 'rf_ack_sender' a better chance to run */
-    Thread::yield();
-
-    /* Get Lock */
-    rf_if_lock();
-
-    /*Check if transmitter is busy*/
-    if(rf_device->is_receiving()) { /* betzw - WAS: (rf_device->channel_clear() != 0)), do NOT use this but rather study and enable automatic CCA */
-#ifdef HEAVY_TRACING
-        tr_debug("%s (%d)", __func__, __LINE__);
-#endif
-
-        /* Release Lock */
-        rf_if_unlock();
-
-        /*Return busy*/
-        return -1;
-    } else {
-        uint16_t fcf = rf_read_16_bit(data_ptr);
-
-        /*Check if transmitted data needs to be acked*/
-        if((fcf & MAC_FCF_ACK_REQ_BIT_MASK) >> MAC_FCF_ACK_REQ_BIT_SHIFT)
-            need_ack = true;
-        else
-            need_ack = false;
-
-        /*Store the sequence number for ACK handling*/
-        tx_sequence = *(data_ptr + 2);
-
-        /*Store TX handle*/
-        mac_tx_handle = tx_handle;
-
-#ifdef HEAVY_TRACING
-        tr_info("%s (%d), len=%d, tx_handle=%x, tx_seq=%x, need_ack=%d (%x:%x, %x:%x, %x:%x, %x:%x)", __func__, __LINE__,
-                data_length, tx_handle, tx_sequence, need_ack,
-                data_ptr[3], data_ptr[4], data_ptr[5], data_ptr[6],
-                data_ptr[7], data_ptr[8], data_ptr[9], data_ptr[10]);
-#endif
-
-        /*Send the packet*/
-        rf_device->send(data_ptr, data_length);
-
-        /* Release Lock */
-        rf_if_unlock();
-    }
-
-    /*Return success*/
-    return 0;
-}
-
-static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel)
-{
-    int8_t ret_val = 0;
-    switch (new_state)
-    {
-        /*Reset PHY driver and set to idle*/
-        case PHY_INTERFACE_RESET:
-            tr_debug("%s (%d)", __func__, __LINE__);
-            rf_device->reset_board();
-            break;
-            /*Disable PHY Interface driver*/
-        case PHY_INTERFACE_DOWN:
-            tr_debug("%s (%d)", __func__, __LINE__);
-            ret_val = rf_device->off();
-            if(ret_val != 0) ret_val = -1;
-            break;
-            /*Enable PHY Interface driver*/
-        case PHY_INTERFACE_UP:
-            ret_val = rf_device->on();
-            if(ret_val != 0) {
-                tr_debug("%s (%d)", __func__, __LINE__);
-                ret_val = -1;
-                break;
-            }
-            tr_debug("%s (%d) - channel: %d", __func__, __LINE__, (int)rf_channel);
-            rf_device->set_channel(rf_channel);
-            break;
-            /*Enable wireless interface ED scan mode*/
-        case PHY_INTERFACE_RX_ENERGY_STATE:
-            tr_debug("%s (%d)", __func__, __LINE__);
-            break;
-            /*Enable Sniffer state*/
-        case PHY_INTERFACE_SNIFFER_STATE:
-            // TODO - if we really need this - WAS: rf_setup_sniffer(rf_channel);
-            tr_debug("%s (%d)", __func__, __LINE__);
-            ret_val = -1;
-            break;
-        default:
-            tr_debug("%s (%d)", __func__, __LINE__);
-            break;
-    }
-    return ret_val;
-}
-
-static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr)
-{
-    switch (extension_type)
-    {
-        /*Control MAC pending bit for Indirect data transmission*/
-        case PHY_EXTENSION_CTRL_PENDING_BIT:
-            tr_debug("%s (%d)", __func__, __LINE__);
-            break;
-
-            /*Return frame pending status*/
-        case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS:
-            tr_debug("%s (%d)", __func__, __LINE__);
-            *data_ptr = 0;
-            break;
-
-            /*Set channel, used for setting channel for energy scan*/
-        case PHY_EXTENSION_SET_CHANNEL:
-            tr_debug("%s (%d)", __func__, __LINE__);
-            break;
-
-            /*Read energy on the channel*/
-        case PHY_EXTENSION_READ_CHANNEL_ENERGY:
-            // TODO: *data_ptr = rf_get_channel_energy();
-            tr_debug("%s (%d)", __func__, __LINE__);
-            *data_ptr = (int8_t)rf_device->get_last_rssi_dbm();
-            break;
-
-            /*Read status of the link*/
-        case PHY_EXTENSION_READ_LINK_STATUS:
-            // TODO: *data_ptr = rf_get_link_status();
-            tr_debug("%s (%d)", __func__, __LINE__);
-            *data_ptr = rf_device->get_last_sqi(); // use SQI as link quality
-            break;
-
-        default:
-            tr_debug("%s (%d)", __func__, __LINE__);
-            break;
-    }
-    return 0;
-}
-
-static inline void rf_set_mac_address(uint8_t *ptr) {
-    tr_debug("%s (%d), adr0=%x, adr1=%x, adr2=%x, adr3=%x, adr4=%x, adr5=%x, adr6=%x, adr7=%x",
-             __func__, __LINE__,
-             ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]);
-    for(int i = 0; i < 8; i++) {
-        stored_mac_address[i] = ptr[i];
-    }
-}
-
-static inline void rf_get_mac_address(uint8_t *ptr) {
-    for(int i = 0; i < 8; i++) {
-        ptr[i] = stored_mac_address[i];
-    }
-    tr_debug("%s (%d), adr0=%x, adr1=%x, adr2=%x, adr3=%x, adr4=%x, adr5=%x, adr6=%x, adr7=%x",
-             __func__, __LINE__,
-             ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]);
-}
-
-static inline void rf_set_short_adr(uint8_t *ptr) {
-    stored_short_adr = (ptr[0] << 8) + ptr[1]; // big-endian
-    tr_debug("%s (%d), adr0=%x, adr1=%x, val=%d",
-             __func__, __LINE__,
-             ptr[0], ptr[1], stored_short_adr);
-}
-
-static inline void rf_set_pan_id(uint8_t *ptr) {
-    stored_pan_id = (ptr[0] << 8) + ptr[1]; // big-endian
-    tr_debug("%s (%d), adr0=%x, adr1=%x, val=%d",
-            __func__, __LINE__,
-            ptr[0], ptr[1], stored_pan_id);
-}
-
-static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr)
-{
-    switch (address_type)
-    {
-        /*Set 48-bit address*/
-        case PHY_MAC_48BIT:
-            /* Not used in this example */
-            // betzw - WAS: rf_set_mac_48bit(address_ptr);
-            break;
-            /*Set 64-bit address*/
-        case PHY_MAC_64BIT:
-            rf_set_mac_address(address_ptr);
-            break;
-            /*Set 16-bit address*/
-        case PHY_MAC_16BIT:
-            rf_set_short_adr(address_ptr);
-            break;
-            /*Set PAN Id*/
-        case PHY_MAC_PANID:
-            rf_set_pan_id(address_ptr);
-            break;
-    }
-
-    return 0;
-}
-
 /* Note: we are in IRQ context */
 static inline void rf_send_signal(int32_t signal) {
 #ifdef HEAVY_TRACING
@@ -568,12 +369,12 @@
     }
 }
 
-/* Note: we are in IRQ context */
-static inline void rf_handle_tx_err(void) {
+/* Note: we might be in IRQ context */
+static inline void rf_handle_tx_err(phy_link_tx_status_e phy_val = PHY_LINK_TX_FAIL) {
     /*Call PHY TX Done API*/
     if(device_driver.phy_tx_done_cb){
         need_ack = false;
-        phy_status = PHY_LINK_TX_FAIL;
+        phy_status = phy_val;
         rf_send_signal(RF_SIG_CB_TX_DONE);
     }
 }
@@ -596,6 +397,208 @@
     }
 }
 
+static int8_t rf_trigger_send(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol)
+{
+#ifndef NDEBUG
+    debug_if(!(data_length >= 3), "\r\nassert failed in: %s (%d)\r\n", __func__, __LINE__);
+#endif
+
+    /* Give 'rf_ack_sender' a better chance to run */
+    Thread::yield();
+
+    /* Get Lock */
+    rf_if_lock();
+
+    /*Check if transmitter is busy*/
+    if(rf_device->is_receiving()) { /* betzw - WAS: (rf_device->channel_clear() != 0)), do NOT use this but rather study and enable automatic CCA */
+#ifdef HEAVY_TRACING
+        tr_debug("%s (%d)", __func__, __LINE__);
+#endif
+
+        /* Release Lock */
+        rf_if_unlock();
+
+        /*Return busy*/
+        return -1;
+    } else {
+        uint16_t fcf = rf_read_16_bit(data_ptr);
+
+        /*Check if transmitted data needs to be acked*/
+        if((fcf & MAC_FCF_ACK_REQ_BIT_MASK) >> MAC_FCF_ACK_REQ_BIT_SHIFT)
+            need_ack = true;
+        else
+            need_ack = false;
+
+        /*Store the sequence number for ACK handling*/
+        tx_sequence = *(data_ptr + 2);
+
+        /*Store TX handle*/
+        mac_tx_handle = tx_handle;
+
+#ifdef HEAVY_TRACING
+        tr_info("%s (%d), len=%d, tx_handle=%x, tx_seq=%x, need_ack=%d (%x:%x, %x:%x, %x:%x, %x:%x)", __func__, __LINE__,
+                data_length, tx_handle, tx_sequence, need_ack,
+                data_ptr[3], data_ptr[4], data_ptr[5], data_ptr[6],
+                data_ptr[7], data_ptr[8], data_ptr[9], data_ptr[10]);
+#endif
+
+        /*Send the packet*/
+        int ret = rf_device->send(data_ptr, data_length);
+        if(ret != RADIO_TX_OK) {
+            rf_handle_tx_err(PHY_LINK_CCA_FAIL);
+        }
+
+        /* Release Lock */
+        rf_if_unlock();
+    }
+
+    /*Return success*/
+    return 0;
+}
+
+static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel)
+{
+    int8_t ret_val = 0;
+    switch (new_state)
+    {
+        /*Reset PHY driver and set to idle*/
+        case PHY_INTERFACE_RESET:
+            tr_debug("%s (%d)", __func__, __LINE__);
+            rf_device->reset_board();
+            break;
+            /*Disable PHY Interface driver*/
+        case PHY_INTERFACE_DOWN:
+            tr_debug("%s (%d)", __func__, __LINE__);
+            ret_val = rf_device->off();
+            if(ret_val != 0) ret_val = -1;
+            break;
+            /*Enable PHY Interface driver*/
+        case PHY_INTERFACE_UP:
+            ret_val = rf_device->on();
+            if(ret_val != 0) {
+                tr_debug("%s (%d)", __func__, __LINE__);
+                ret_val = -1;
+                break;
+            }
+            tr_debug("%s (%d) - channel: %d", __func__, __LINE__, (int)rf_channel);
+            rf_device->set_channel(rf_channel);
+            break;
+            /*Enable wireless interface ED scan mode*/
+        case PHY_INTERFACE_RX_ENERGY_STATE:
+            tr_debug("%s (%d)", __func__, __LINE__);
+            break;
+            /*Enable Sniffer state*/
+        case PHY_INTERFACE_SNIFFER_STATE:
+            // TODO - if we really need this - WAS: rf_setup_sniffer(rf_channel);
+            tr_debug("%s (%d)", __func__, __LINE__);
+            ret_val = -1;
+            break;
+        default:
+            tr_debug("%s (%d)", __func__, __LINE__);
+            break;
+    }
+    return ret_val;
+}
+
+static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr)
+{
+    switch (extension_type)
+    {
+        /*Control MAC pending bit for Indirect data transmission*/
+        case PHY_EXTENSION_CTRL_PENDING_BIT:
+            tr_debug("%s (%d)", __func__, __LINE__);
+            break;
+
+            /*Return frame pending status*/
+        case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS:
+            tr_debug("%s (%d)", __func__, __LINE__);
+            *data_ptr = 0;
+            break;
+
+            /*Set channel, used for setting channel for energy scan*/
+        case PHY_EXTENSION_SET_CHANNEL:
+            tr_debug("%s (%d)", __func__, __LINE__);
+            break;
+
+            /*Read energy on the channel*/
+        case PHY_EXTENSION_READ_CHANNEL_ENERGY:
+            // TODO: *data_ptr = rf_get_channel_energy();
+            tr_debug("%s (%d)", __func__, __LINE__);
+            *data_ptr = (int8_t)rf_device->get_last_rssi_dbm();
+            break;
+
+            /*Read status of the link*/
+        case PHY_EXTENSION_READ_LINK_STATUS:
+            // TODO: *data_ptr = rf_get_link_status();
+            tr_debug("%s (%d)", __func__, __LINE__);
+            *data_ptr = rf_device->get_last_sqi(); // use SQI as link quality
+            break;
+
+        default:
+            tr_debug("%s (%d)", __func__, __LINE__);
+            break;
+    }
+    return 0;
+}
+
+static inline void rf_set_mac_address(uint8_t *ptr) {
+    tr_debug("%s (%d), adr0=%x, adr1=%x, adr2=%x, adr3=%x, adr4=%x, adr5=%x, adr6=%x, adr7=%x",
+             __func__, __LINE__,
+             ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]);
+    for(int i = 0; i < 8; i++) {
+        stored_mac_address[i] = ptr[i];
+    }
+}
+
+static inline void rf_get_mac_address(uint8_t *ptr) {
+    for(int i = 0; i < 8; i++) {
+        ptr[i] = stored_mac_address[i];
+    }
+    tr_debug("%s (%d), adr0=%x, adr1=%x, adr2=%x, adr3=%x, adr4=%x, adr5=%x, adr6=%x, adr7=%x",
+             __func__, __LINE__,
+             ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]);
+}
+
+static inline void rf_set_short_adr(uint8_t *ptr) {
+    stored_short_adr = (ptr[0] << 8) + ptr[1]; // big-endian
+    tr_debug("%s (%d), adr0=%x, adr1=%x, val=%d",
+             __func__, __LINE__,
+             ptr[0], ptr[1], stored_short_adr);
+}
+
+static inline void rf_set_pan_id(uint8_t *ptr) {
+    stored_pan_id = (ptr[0] << 8) + ptr[1]; // big-endian
+    tr_debug("%s (%d), adr0=%x, adr1=%x, val=%d",
+            __func__, __LINE__,
+            ptr[0], ptr[1], stored_pan_id);
+}
+
+static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr)
+{
+    switch (address_type)
+    {
+        /*Set 48-bit address*/
+        case PHY_MAC_48BIT:
+            /* Not used in this example */
+            // betzw - WAS: rf_set_mac_48bit(address_ptr);
+            break;
+            /*Set 64-bit address*/
+        case PHY_MAC_64BIT:
+            rf_set_mac_address(address_ptr);
+            break;
+            /*Set 16-bit address*/
+        case PHY_MAC_16BIT:
+            rf_set_short_adr(address_ptr);
+            break;
+            /*Set PAN Id*/
+        case PHY_MAC_PANID:
+            rf_set_pan_id(address_ptr);
+            break;
+    }
+
+    return 0;
+}
+
 static void rf_ack_loop(void) {
     static uint16_t buffer[2] = {
             (FC_ACK_FRAME << MAC_FCF_FRAME_TYPE_SHIFT),
@@ -657,7 +660,8 @@
         }
 
         if(signals & RF_SIG_CB_TX_DONE) {
-            device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, phy_status, 0, 0);
+            device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, phy_status,
+                                         (phy_status == PHY_LINK_CCA_FAIL) ? 0xFF : 0, 0);
 #ifdef HEAVY_TRACING
             tr_debug("%s (%d)", __func__, __LINE__);
 #endif
@@ -694,7 +698,7 @@
                 rf_ack_sender.start(rf_ack_loop);
 
 #ifndef NDEBUG
-        debug_if(!(ret == osOK), "\n\rassert failed in: %s (%d)\n\r", __func__, __LINE__);
+        debug_if(!(ret == osOK), "\r\nassert failed in: %s (%d)\r\n", __func__, __LINE__);
 #endif
     }
 }