Igor Stepura / kw41z-rf-driver Featured

ARM mbed Nanostack RF driver for NXP KW41Z 802.15.4 wireless MCU

This driver is used with 6LoWPAN stack.

Code far from being stable yet, but basic functionality seems to be working. Two FRDM-KW41Z boards running code build from mbed-os-example-mesh-minimal and nanostack-border-router are able to build mesh.

Main repository is at https://github.com/istepura/kw41z-rf-driver

Files at this revision

API Documentation at this revision

Comitter:
Igor Stepura
Date:
Sun Jul 23 13:49:19 2017 -0400
Parent:
2:8b42f07a0f12
Commit message:
Add energy detection and timeout support

Changed in this revision

source/NanostackRfPhyKw41z.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/source/NanostackRfPhyKw41z.cpp	Sat Jul 22 13:22:46 2017 -0400
+++ b/source/NanostackRfPhyKw41z.cpp	Sun Jul 23 13:49:19 2017 -0400
@@ -101,6 +101,12 @@
 #endif
 #define CORE_CLOCK_FREQ 47972352U
 #define gPhyMaxTxPowerLevel_d         (32)
+
+#define ZLL_IRQSTS_TMRMSK_MASK  (ZLL_IRQSTS_TMR1MSK_MASK | \
+                                      ZLL_IRQSTS_TMR2MSK_MASK | \
+                                      ZLL_IRQSTS_TMR3MSK_MASK | \
+                                      ZLL_IRQSTS_TMR4MSK_MASK )
+
 uint8_t gPhyChannelTxPowerLimits[] = { gPhyMaxTxPowerLevel_d,   /* 11 */ \
                                  gPhyMaxTxPowerLevel_d,   /* 12 */ \
                                  gPhyMaxTxPowerLevel_d,   /* 13 */ \
@@ -133,7 +139,10 @@
 MBED_UNUSED static void rf_mac64_read(uint8_t *address);
 MBED_UNUSED static void    rf_set_power_state(phyPwrMode_t newState);
 MBED_UNUSED static void rf_handle_tx_end(uint8_t);
+static void rf_set_timeout(uint32_t timeout);
+static inline uint32_t rf_get_timestamp(void);
 static void rf_set_address(uint8_t *address);
+static uint8_t rf_detect_channel_energy(void);
 
 static inline phySeqState_t rf_get_state(void)
 {
@@ -202,6 +211,56 @@
     }
 }
 
+static inline uint32_t rf_get_timestamp(void)
+{
+    uint32_t retval = ZLL->EVENT_TMR >> ZLL_EVENT_TMR_EVENT_TMR_SHIFT;
+
+    return retval;
+}
+
+static void rf_set_timeout(uint32_t timeout)
+{
+    ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_TMR3CMP_EN_MASK;
+    ZLL->T3CMP = timeout & 0x00FFFFFF;
+
+    uint32_t sts = ZLL->IRQSTS & ZLL_IRQSTS_TMRMSK_MASK;
+    sts &= ~(ZLL_IRQSTS_TMR3MSK_MASK);
+    sts |= ZLL_IRQSTS_TMR3IRQ_MASK;
+    ZLL->IRQSTS = sts;
+
+    ZLL->PHY_CTRL |= ZLL_PHY_CTRL_TMR3CMP_EN_MASK;
+    ZLL->PHY_CTRL |= ZLL_PHY_CTRL_TC3TMOUT_MASK;
+}
+
+static uint8_t rf_detect_channel_energy(void)
+{
+    if (rf_get_state() !=gIdle_c)
+    {
+        return 0;
+    }
+    rf_set_power_state(gPhyPwrRun_c);
+
+    ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_CCATYPE_MASK;
+    ZLL->PHY_CTRL |= ZLL_PHY_CTRL_CCAMSK_MASK |
+                     ZLL_PHY_CTRL_RXMSK_MASK  |
+                     ZLL_PHY_CTRL_TXMSK_MASK  |
+                     ZLL_PHY_CTRL_SEQMSK_MASK;
+
+    ZLL->PHY_CTRL |= ZLL_PHY_CTRL_CCATYPE(gCcaED_c);
+
+    ZLL->PHY_CTRL &= ~(ZLL_PHY_CTRL_XCVSEQ_MASK);
+    ZLL->PHY_CTRL |= gCCA_c;
+
+    /* Busy wait. No interrupt will be raised */
+    while (!(ZLL->IRQSTS & ZLL_IRQSTS_SEQIRQ_MASK)){}
+    ZLL->IRQSTS = ZLL->IRQSTS;
+    ZLL->PHY_CTRL &= ~(ZLL_PHY_CTRL_XCVSEQ_MASK);
+
+    int8_t caa1_ed_fnl = (ZLL->LQI_AND_RSSI & ZLL_LQI_AND_RSSI_CCA1_ED_FNL_MASK) >> ZLL_LQI_AND_RSSI_CCA1_ED_FNL_SHIFT;
+
+    return 128 + caa1_ed_fnl;
+}
+
 static void rf_init(void)
 {
     uint32_t phyReg;
@@ -278,6 +337,7 @@
     /* Install PHY ISR */
     PHY_InstallIsr();
     ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_TRCV_MSK_MASK;
+
     rf_receive();    
 }
 
@@ -323,9 +383,7 @@
     }
     rf_set_power_state(gPhyPwrRun_c);
 
-    /* Ensure that no spurious interrupts are raised, but do not change TMR1 and TMR4 IRQ status */
     irqSts = ZLL->IRQSTS;
-    irqSts &= ~(ZLL_IRQSTS_TMR1IRQ_MASK | ZLL_IRQSTS_TMR4IRQ_MASK);
     irqSts |= ZLL_IRQSTS_TMR3MSK_MASK;
     ZLL->IRQSTS = irqSts;
 
@@ -398,6 +456,8 @@
     ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_CCATYPE_MASK;
     ZLL->PHY_CTRL |= ZLL_PHY_CTRL_CCATYPE(gCcaCCA_MODE1_c);
 
+    ZLL->IRQSTS = ZLL->IRQSTS;
+
     mac_tx_handle = tx_handle;
     need_ack = (*data_ptr & 0x20) == 0x20;
 
@@ -409,24 +469,20 @@
     {
         ZLL->PHY_CTRL |= ZLL_PHY_CTRL_RXACKRQD_MASK;
         xcvseq = gTR_c;
-    
     }
     else
     {
         ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_RXACKRQD_MASK;
         xcvseq = gTX_c;        
+
+        uint32_t timeout = rf_get_timestamp();
+        timeout += ((XCVR_TSM->END_OF_SEQ & XCVR_TSM_END_OF_SEQ_END_OF_TX_WU_MASK) >> XCVR_TSM_END_OF_SEQ_END_OF_TX_WU_SHIFT) >> 4;
+        timeout += 50; /* Maigic numbers are the best!! */
+
+        rf_set_timeout(timeout);
     }    
-    uint32_t irqSts;
-    /* Ensure that no spurious interrupts are raised(do not change TMR1 and TMR4 IRQ status) */
-    irqSts = ZLL->IRQSTS;
-    irqSts &= ~(ZLL_IRQSTS_TMR1IRQ_MASK | ZLL_IRQSTS_TMR4IRQ_MASK);
-    irqSts |= ZLL_IRQSTS_TMR3MSK_MASK;
-    ZLL->IRQSTS = irqSts;
-
     ZLL->PHY_CTRL &= ~(ZLL_PHY_CTRL_XCVSEQ_MASK);
-    /* Start the TX / TRX / CCA sequence */
     ZLL->PHY_CTRL |= xcvseq;
-    /* Unmask SEQ interrupt */
     ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_SEQMSK_MASK;    
 
     return 0;
@@ -435,7 +491,6 @@
 static void rf_set_short_adr(uint8_t * short_address)
 {
     uint16_t value = ((uint16_t)short_address[0] << 8) | (uint16_t)short_address[1];
-    //memcpy(&value, short_address, sizeof(value));
     ZLL->MACSHORTADDRS0 &= ~ZLL_MACSHORTADDRS0_MACSHORTADDRS0_MASK;
     ZLL->MACSHORTADDRS0 |= ZLL_MACSHORTADDRS0_MACSHORTADDRS0(value);    
 }
@@ -499,9 +554,11 @@
         case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS:
             *data_ptr = ((ZLL->IRQSTS & ZLL_IRQSTS_RX_FRM_PEND_MASK) >> ZLL_IRQSTS_RX_FRM_PEND_SHIFT);
             break;        
-        /*Read energy on the channel*/
+        case PHY_EXTENSION_SET_CHANNEL:
+            rf_channel_set(*data_ptr);
+            break;
         case PHY_EXTENSION_READ_CHANNEL_ENERGY:
-            *data_ptr = 100;
+            *data_ptr = rf_detect_channel_energy();
             break;            
     }    
     return 0;
@@ -618,19 +675,10 @@
     ZLL->PHY_CTRL &= ~(ZLL_PHY_CTRL_TMR2CMP_EN_MASK |
             ZLL_PHY_CTRL_TMR3CMP_EN_MASK |
             ZLL_PHY_CTRL_TC3TMOUT_MASK );
-    /* clear all PP IRQ bits to avoid unexpected interrupts( do not change TMR1 and TMR4 IRQ status ) */
     ZLL->IRQSTS &= ~(ZLL_IRQSTS_TMR1IRQ_MASK | ZLL_IRQSTS_TMR4IRQ_MASK);
 }
 
 
-
-/*
- * \brief Function is a RF interrupt vector. End of frame in RX and TX are handled here as well as CCA process interrupt.
- *
- * \param none
- *
- * \return none
- */
 static volatile uint32_t gIrqStatus = 0;
 static void PHY_InterruptHandler(void)
 {
@@ -673,9 +721,7 @@
     while( ZLL->SEQ_STATE & ZLL_SEQ_STATE_SEQ_STATE_MASK ) {}
 
     irqStatus = ZLL->IRQSTS;
-    /* Mask TMR3 interrupt */
     irqStatus |= ZLL_IRQSTS_TMR3MSK_MASK;
-    /* Clear transceiver interrupts except TMRxIRQ */
     irqStatus &= ~( ZLL_IRQSTS_TMR1IRQ_MASK |
                     ZLL_IRQSTS_TMR2IRQ_MASK |
                     ZLL_IRQSTS_TMR3IRQ_MASK |
@@ -683,31 +729,6 @@
     ZLL->IRQSTS = irqStatus;
 }
 
-static inline void rf_clean_timeout_isr(void)
-{
-    uint32_t irqStatus;
-
-    /* Set the PHY sequencer back to IDLE and disable TMR3 comparator and timeout */
-    ZLL->PHY_CTRL &= ~(ZLL_PHY_CTRL_TMR3CMP_EN_MASK | 
-                       ZLL_PHY_CTRL_TC3TMOUT_MASK   | 
-                       ZLL_PHY_CTRL_XCVSEQ_MASK);
-    /* Mask SEQ, RX, TX and CCA interrupts */
-    ZLL->PHY_CTRL |= ZLL_PHY_CTRL_CCAMSK_MASK |
-                     ZLL_PHY_CTRL_RXMSK_MASK  |
-                     ZLL_PHY_CTRL_TXMSK_MASK  |
-                     ZLL_PHY_CTRL_SEQMSK_MASK;
-
-    while( ZLL->SEQ_STATE & ZLL_SEQ_STATE_SEQ_STATE_MASK ) {}
-
-    irqStatus = ZLL->IRQSTS;
-    /* Mask TMR3 interrupt */
-    irqStatus |= ZLL_IRQSTS_TMR3MSK_MASK;
-    /* Clear transceiver interrupts except TMR1IRQ and TMR4IRQ. */
-    irqStatus &= ~( ZLL_IRQSTS_TMR1IRQ_MASK |
-                    ZLL_IRQSTS_TMR4IRQ_MASK );
-    ZLL->IRQSTS = irqStatus;
-}
-
 static inline uint8_t rf_convert_lqi(uint8_t rssi)
 {
     if (rssi >= 220)
@@ -722,6 +743,14 @@
     return rssi;
 }
 
+static inline int8_t rf_lqi_to_rssi(uint8_t lqi)
+{
+    /* As per NXP's PHY implemenation */
+    int32_t rssi = (36 * lqi - 9836) / 109;
+
+    return (int8_t)rssi;
+}
+
 static void rf_handle_rx_end(void)
 {
     uint32_t irqSts;
@@ -731,17 +760,16 @@
     /* disable autosequence stop by TC3 match */
     ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_TC3TMOUT_MASK;
     /* mask TMR3 interrupt (do not change other IRQ status) */
-    irqSts  = ZLL->IRQSTS & (ZLL_IRQSTS_TMR1MSK_MASK |
-            ZLL_IRQSTS_TMR2MSK_MASK |
-            ZLL_IRQSTS_TMR3MSK_MASK |
-            ZLL_IRQSTS_TMR4MSK_MASK );
+    irqSts  = ZLL->IRQSTS & ZLL_IRQSTS_TMR3MSK_MASK;
     irqSts |= ZLL_IRQSTS_TMR3MSK_MASK;
     /* aknowledge TMR3 IRQ */
     irqSts |= ZLL_IRQSTS_TMR3IRQ_MASK;
     ZLL->IRQSTS = irqSts;
 
-    uint8_t rssi = (ZLL->LQI_AND_RSSI & ZLL_LQI_AND_RSSI_LQI_VALUE_MASK) >> ZLL_LQI_AND_RSSI_LQI_VALUE_SHIFT;
-    uint8_t lqi = rf_convert_lqi(rssi);
+    uint8_t phyRssi = (ZLL->LQI_AND_RSSI & ZLL_LQI_AND_RSSI_LQI_VALUE_MASK) >> ZLL_LQI_AND_RSSI_LQI_VALUE_SHIFT;
+    uint8_t lqi = rf_convert_lqi(phyRssi);
+    int8_t  rssi = rf_lqi_to_rssi(lqi);
+
     uint8_t psduLength = (ZLL->IRQSTS & ZLL_IRQSTS_RX_FRAME_LENGTH_MASK) >> ZLL_IRQSTS_RX_FRAME_LENGTH_SHIFT; /* Including FCS (2 bytes) */
     uint8_t len = psduLength - 2;
 
@@ -792,7 +820,9 @@
             (!(irqStatus & ZLL_IRQSTS_RXIRQ_MASK)) &&
             (gTX_c != xcvseqCopy) )
         {
-            rf_clean_timeout_isr();
+            ZLL->IRQSTS = irqStatus | ZLL_IRQSTS_TMR3MSK_MASK;
+            ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_TMR3CMP_EN_MASK;
+
             device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_FAIL, 1, 1);
         }
         else
@@ -808,7 +838,6 @@
                     else
                     {
                         ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_XCVSEQ_MASK;
-                        /* wait for Sequence Idle (if not already) */
                         ZLL->PHY_CTRL |= (ZLL_PHY_CTRL_CCAMSK_MASK |
                                 ZLL_PHY_CTRL_RXMSK_MASK |
                                 ZLL_PHY_CTRL_TXMSK_MASK |
@@ -833,54 +862,11 @@
                 case gRX_c:
                     rf_handle_rx_end();
                     break;
-
-                case gCCA_c:
-                    if( gCcaED_c == ((ZLL->PHY_CTRL & ZLL_PHY_CTRL_CCATYPE_MASK) >> ZLL_PHY_CTRL_CCATYPE_SHIFT) )
-                    {
-                        //Radio_Phy_PlmeEdConfirm( (ZLL->LQI_AND_RSSI & ZLL_LQI_AND_RSSI_CCA1_ED_FNL_MASK) >> ZLL_LQI_AND_RSSI_CCA1_ED_FNL_SHIFT, mPhyInstance );
-                    }
-                    else /* CCA */
-                    {
-                        if( irqStatus & ZLL_IRQSTS_CCA_MASK )
-                        {
-                            device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 1, 1);
-                        }
-                        else
-                        {
-                        }
-                    }
-                    break;
                 default:
                     break;
             }
         }
     }
-    /* Timers interrupt */
-    else
-    {
-        /* Timer 3 Compare Match */
-        if( (irqStatus & ZLL_IRQSTS_TMR3IRQ_MASK) && (!(irqStatus & ZLL_IRQSTS_TMR3MSK_MASK)) )
-        {
-
-            if( gIdle_c == xcvseqCopy )
-            {
-                device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_FAIL, 1, 1);
-            }
-        }
-
-        /* Timer 4 Compare Match */
-        if( (irqStatus & ZLL_IRQSTS_TMR4IRQ_MASK) && (!(irqStatus & ZLL_IRQSTS_TMR4MSK_MASK)) )
-        {
-            /* Disable TMR4 comparator */
-            ZLL->PHY_CTRL &= ~ZLL_PHY_CTRL_TMR4CMP_EN_MASK;
-            /* Mask and clear TMR4 interrupt (do not change other IRQ status) */
-            irqStatus &= ~( ZLL_IRQSTS_TMR1MSK_MASK |
-                            ZLL_IRQSTS_TMR2MSK_MASK |
-                            ZLL_IRQSTS_TMR3MSK_MASK );
-            irqStatus |= ZLL_IRQSTS_TMR4IRQ_MASK | ZLL_IRQSTS_TMR4MSK_MASK;
-            ZLL->IRQSTS = irqStatus;
-        }
-    }
 }
 
 static void rf_handle_tx_end(uint8_t rx_frame_pending)