Low level 802.15.4 transmit code

I am trying to make a simple MAC-layer transceiver using Arduino environment.  I have some code derived from this example: https://github.com/IoTS-P/nRF52-802154-Raw-Transmitter
and have discovered that it hangs after one to a few hundred transmissions.  I have gone over the datasheet for the 802.15.4 radio section and I do not see where the problem is.I am using a Zena receiver to monitor the transmissions.  I noticed that the CCA appears to take some tens-of-mS fairly often while the Zena does not show any other messages arrived during that time.  What am I doing wrong with the radio hardware?

<project files attached>

Parents
  • My uploaded files went to some bit bucket.  Here is the cleaned up code (3 files):

    //Raw802.ino
    #include <Arduino.h>
    #include <stdint.h>
    //#include <stdbool.h>
    #include "radio.h"
    #include <nrf52840.h>
    #include <Adafruit_TinyUSB.h>// Seems to need this without Serial or USB. Maybe DFU boot loader needs it?
    
    #define PIN_LEDX 22 // Red LED
    
    // channel 
    #define DEFAULT_INITIAL_CHANNEL 19
    
    // read buffer  
    uint8_t *rx_buffer;
    uint8_t u8SeqNum = 0;
    // the frame length in phy layer header 
    uint8_t pkt_len = 0;
    uint8_t u8PktBuf[100];
    
    // has data transmitting
    uint8_t bTransmitting = false;
    
    // packets
    #define MAX_PKTS_IN 12 // Maximum packets in the queue
    struct __attribute__((packed)) packets_structure
    {
      uint16_t size[MAX_PKTS_IN] = {0};
      uint8_t *pkt_buffer[MAX_PKTS_IN];
      uint8_t head = 0;
      uint8_t tail = 0;
    } packets;
    
    // channel
    uint8_t radio_channel = DEFAULT_INITIAL_CHANNEL;
    
    
    /**
     * nRF51822 RADIO handler.
     *
     * This handler is called whenever a RADIO event occurs (IRQ).
     **/
    extern "C" void RADIO_IRQHandler(void)
    {
      // if (NRF_RADIO->EVENTS_FRAMESTART)
      if (*(uint32_t *)(0x40001138)) //Events-FrameStart
      {
        *(uint32_t *)(0x40001138) = 0;
      }
    
      if (NRF_RADIO->EVENTS_READY)
      {
        NRF_RADIO->EVENTS_READY = 0;
        NRF_RADIO->TASKS_START = 1;
      }
    
      if (NRF_RADIO->EVENTS_END)
      {
        NRF_RADIO->EVENTS_END = 0;
        // NRF_RADIO->TASKS_START = 1;
        // If transmitt end
        if (bTransmitting)
        {
          bTransmitting = false;
          //Serial.write("SENDED ");
           //radio_tx_to_rx();
          //return;// maybe interrupt needs special return?
          goto exit;
        }
      }
      if (*(uint32_t *)(0x40001148))//CCA-Busy
      {
        Serial.println("CCABUSY");
        *(uint32_t *)(0x40001148) = 0;
        NRF_RADIO->TASKS_DISABLE = 1;
        while (NRF_RADIO->EVENTS_DISABLED == 0);
        //Serial.println("CCABUSY: disable the radio");
        sig_ccabusy = true;
      }
      if (*(uint32_t *)(0x4000114C))
      {
        Serial.println("CCASTOPPED");
      }
      if (*(uint32_t *)(0x40001144))//CCA-IDLE
      {
        Serial.println("CCAIDLE");
        sig_ccabusy = false;
        *(uint32_t *)(0x40001144) = 0;
        // NRF_RADIO->TASKS_CCASTART = 0
        //*(uint32_t *)(0x4000102c) = 1;
      }
      exit:
      {
      
      }
    }
    
    void setup()
    {
      pinMode(LED_BUILTIN, OUTPUT);
      pinMode(PIN_LEDX, OUTPUT); // Going for the RED Led now
      Serial.begin(115200);
      rx_buffer = (uint8_t *)malloc(IEEE802154_FRAME_LEN_MAX + 3);
    
      radio_set_sniff(radio_channel, 0); // Setup the radio
    }
    
    uint32_t ctr = 0;
    void loop()
    {
      if (NRF_RADIO->EVENTS_READY)
      {
        NRF_RADIO->EVENTS_READY = 0;
        // NRF_RADIO->TASKS_START;
      }
      delay(1);
      ctr++;
      if(ctr > 900)// Transmit every 200mS
      {
        ctr = 0;
        pkt_len = 17; 
        memcpy(u8PktBuf, "\x11\x00\x00\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff",19);
        u8PktBuf[3] = u8SeqNum++;
      }
    
    
      // memcpy pkt_buffer to tx_buffer
      if (!bTransmitting && pkt_len)
      {
        Serial.write(".");
        digitalWrite(PIN_LEDX, HIGH);
        bTransmitting = true;
        radio_send_custom(u8PktBuf, radio_channel);
        pkt_len = 0;
        digitalWrite(PIN_LEDX, LOW);
      }
    }

    //radio.cpp
    #include "radio.h"
    #include <Arduino.h>
    #include <assert.h>
    
    // signal for CCABUSY
    volatile uint8_t sig_ccabusy = false;
    
    /**
     * channel_to_freq(int channel)
     *
     * Convert a BLE channel number into the corresponding frequency offset
     * for the nRF51822.
     **/
    uint8_t channel_to_freq(int channel) {
      assert(channel > 10);
      assert(channel < 27);
      return 5 * (channel - 10);
    }
    
    /**
     * radio_disable()
     *
     * Disable the radio.
     **/
    
    void radio_disable(void) {
      if (NRF_RADIO->STATE > 0) {
        NVIC_DisableIRQ(RADIO_IRQn);
    
        NRF_RADIO->EVENTS_DISABLED = 0;
        NRF_RADIO->TASKS_DISABLE = 1;
        while (NRF_RADIO->EVENTS_DISABLED == 0);
      }
    }
    
    /**
     * @brief   Convert from dBm to the internal representation, when the
     *          radio operates as a IEEE802.15.4 transceiver.
     */
    static inline uint8_t _dbm_to_ieee802154_hwval(int8_t dbm) {
      return ((dbm - ED_RSSIOFFS) / ED_RSSISCALE);
    }
    
    static int set_cca_threshold(int8_t threshold) {
    
      if (threshold < ED_RSSIOFFS) {
        return -1;
      }
    
      uint8_t hw_val = _dbm_to_ieee802154_hwval(threshold);
    
       NRF_RADIO->CCACTRL &= ~RADIO_CCACTRL_CCAEDTHRES_Msk;
      //*(uint32_t *)(0x4000166c) &= ~RADIO_CCACTRL_CCAEDTHRES_Msk;
    
       NRF_RADIO->CCACTRL |= hw_val << RADIO_CCACTRL_CCAEDTHRES_Pos;
      //*(uint32_t *)(0x4000166c) |= hw_val << RADIO_CCACTRL_CCAEDTHRES_Pos;
      return 0;
    }
    
    /**
     * radio_set_sniff(int channel)
     *
     * Configure the nRF51822 to sniff on a specific channel.
     **/
    
    void radio_set_sniff(int channel, uint32_t access_address) {
      // Disable radio
      radio_disable();
    
      // Enable the High Frequency clock on the processor. This is a pre-requisite
      // for the RADIO module. Without this clock, no communication is possible.
      NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
      NRF_CLOCK->TASKS_HFCLKSTART = 1;
      while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
    
      // power should be one of: -30, -20, -16, -12, -8, -4, 0, 4
      NRF_RADIO->TXPOWER = RADIO_TXPOWER_TXPOWER_Neg20dBm;//Pos4dBm;
      NRF_RADIO->TXADDRESS = 0;
    
      /* Set 802154 data rate. */
      NRF_RADIO->MODE = RADIO_MODE_MODE_Ieee802154_250Kbit;
      /* Listen on channel . */
      NRF_RADIO->FREQUENCY = channel_to_freq(channel);
    
      /* set start frame delimiter */
       //NRF_RADIO->RESERVED12[4] = IEEE802154_SFD;// Gets a read-only error on ths
      *(uint32_t *)(0x40001660) = IEEE802154_SFD;
    
      /* set MHR filters */
       NRF_RADIO->MHRMATCHCONF = 0;         /* Search Pattern Configuration */
      //*(uint32_t *)(0x40001644) = 0;
    
       NRF_RADIO->MHRMATCHMAS = 0xff0007ff; /* Pattern mask */
      //*(uint32_t *)(0x40001648) = 0xff0007ff;
    
      /* and set some fitting configuration */
      NRF_RADIO->PCNF0 = ((8 << RADIO_PCNF0_LFLEN_Pos) |
                          (RADIO_PCNF0_PLEN_32bitZero << RADIO_PCNF0_PLEN_Pos) |
                          (RADIO_PCNF0_CRCINC_Include << RADIO_PCNF0_CRCINC_Pos));
    
      NRF_RADIO->PCNF1 = IEEE802154_FRAME_LEN_MAX;
    
      NRF_RADIO->MODECNF0 |=
          RADIO_MODECNF0_RU_Fast; // Enable fast mode for radio ramp up
    
      // Enable CRC
      NRF_RADIO->CRCCNF =
          ((RADIO_CRCCNF_LEN_Two << RADIO_CRCCNF_LEN_Pos) |
           (RADIO_CRCCNF_SKIPADDR_Ieee802154 << RADIO_CRCCNF_SKIPADDR_Pos));
      NRF_RADIO->CRCPOLY = 0x11021;
      NRF_RADIO->CRCINIT = 0;
    
      // DATAWHITE
      NRF_RADIO->DATAWHITEIV = 0x40;
    
      NRF_RADIO->PACKETPTR = (uint32_t)(rx_buffer);
    
      // configure CCA
      set_cca_threshold(CONFIG_IEEE802154_CCA_THRESH_DEFAULT);
    
      // Configure interrupts
      NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk | RADIO_INTENSET_FRAMESTART_Msk |
                            // RADIO_INTENSET_CCAIDLE_Msk |
                            RADIO_INTENSET_CCABUSY_Msk;
      // Enable NVIC Interrupt for Radio
      NVIC_SetPriority(RADIO_IRQn, IRQ_PRIORITY_LOW);
      NVIC_ClearPendingIRQ(RADIO_IRQn);
      NVIC_EnableIRQ(RADIO_IRQn);
    
      // Enable receiver hardware
      NRF_RADIO->EVENTS_READY = 0;
      NRF_RADIO->TASKS_RXEN = 1;
      while (NRF_RADIO->EVENTS_READY == 0);
      NRF_RADIO->EVENTS_END = 0;
      NRF_RADIO->TASKS_START = 1;
    }
    
    /**
     * Send raw data asynchronously.
     **/
    
    void radio_send_custom(uint8_t *pBuffer, uint8_t channel) {
    
      /* No shortcuts on disable. */
      NRF_RADIO->SHORTS = 0x0;
      /* Switch radio to TX. */
      radio_disable();
    
      for (size_t try_ = 0; try_ < MAX_RETRIES; try_++) 
      {
        /* Switch packet buffer to tx_buffer. */
        NRF_RADIO->PACKETPTR = (uint32_t)pBuffer;
        NRF_RADIO->INTENSET = (1 << RADIO_INTENSET_END_Pos);
        NVIC_ClearPendingIRQ(RADIO_IRQn);
        NVIC_EnableIRQ(RADIO_IRQn);
    
        NRF_RADIO->EVENTS_READY = 0;
        NRF_RADIO->TASKS_RXEN = 1;
        Serial.write("While 1 ");// NEEDS THIS DELAY
        while (!NRF_RADIO->EVENTS_READY);
    
         NRF_RADIO->EVENTS_CCAIDLE = 0;
        //*(uint32_t *)(0x40001144) = 0;
        NRF_RADIO->TASKS_CCASTART = 1;
        //*(uint32_t *)(0x4000102c) = 1;
    
         Serial.write("While 2 "); // Needs this delay
        // while(!(NRF_RADIO->EVENTS_CCAIDLE || CCABUSY));
        while(!(NRF_RADIO->EVENTS_CCAIDLE || NRF_RADIO->EVENTS_CCABUSY));
        // wait for CCAIDLE or CCABUSY
        Serial.write("While 3 ");
        while (!(*(uint32_t *)(0x40001144) || sig_ccabusy));//CCA_IDLE
        if (sig_ccabusy) 
        {
          Serial.println("WARNING: retry for CCABUSY");
          sig_ccabusy = false;
          delay(100);
          continue;
        }
    
        /* Transmit with max power. */
        NRF_RADIO->TXPOWER =
            (RADIO_TXPOWER_TXPOWER_Pos4dBm << RADIO_TXPOWER_TXPOWER_Pos);
        NRF_RADIO->FREQUENCY = channel_to_freq(channel);
    
        // enable receiver
        NRF_RADIO->EVENTS_READY = 0;
        NRF_RADIO->TASKS_TXEN = 1;
    
         Serial.write("While 4\r\n");//needs this delay
        while (!NRF_RADIO->EVENTS_READY);
        NRF_RADIO->TASKS_START = 1;
        /* From now, radio will send data and notify the result to Radio_IRQHandler */
        return;
      }
      Serial.println("ERROR: retry too many times");
    }
    
    /**
     * Change radio from TX to RX, while keeping last configuration of
     *radio_send_custom or radio_set_sniff
     **/
    void radio_tx_to_rx() {
      NRF_RADIO->PACKETPTR = (uint32_t)(rx_buffer);
      NVIC_DisableIRQ(RADIO_IRQn);
      NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk;
    
      // NRF_RADIO->INTENSET = 0;
      NVIC_ClearPendingIRQ(RADIO_IRQn);
      NVIC_EnableIRQ(RADIO_IRQn);
    
      NRF_RADIO->EVENTS_DISABLED = 0;
      NRF_RADIO->TASKS_DISABLE = 1;
    
      while (NRF_RADIO->EVENTS_DISABLED == 0);
    
      NRF_RADIO->EVENTS_READY = 0;
      NRF_RADIO->TASKS_RXEN = 1;
    }

    //radio.h
    /**
     * Radio module
     *
     * This module provides all the required functions to manage the nRF51822
     * transceiver.
     **/
    
    #pragma once
    #include <Arduino.h>
    
    extern uint8_t *rx_buffer; /* Rx buffer used by RF to store packets. */
    
    #define IRQ_PRIORITY_HIGHEST 0
    #define IRQ_PRIORITY_HIGH 1
    #define IRQ_PRIORITY_MEDIUM 2
    #define IRQ_PRIORITY_LOW 3
    
    #define RADIO_MODE_MODE_Ieee802154_250Kbit (15UL)
    
    
    #define IEEE802154_FRAME_LEN_MAX (127U)   /**< maximum 802.15.4 frame length */
    #define IEEE802154G_FRAME_LEN_MAX (2047U) /**< maximum 802.15.4g-2012 frame length */
    #define IEEE802154_ACK_FRAME_LEN (5U)     /**< ACK frame length */
    #define IEEE802154_FCS_LEN                  (2U)
    
    
    #define RADIO_PCNF0_PLEN_32bitZero (2UL) /*!< 32-bit zero preamble - used for IEEE 802.15.4 */
    #define RADIO_PCNF0_CRCINC_Include (1UL) /*!< LENGTH includes CRC */
    #define RADIO_PCNF0_CRCINC_Pos (26UL) /*!< Position of CRCINC field. */
    #define RADIO_CRCCNF_SKIPADDR_Ieee802154 (2UL) /*!< CRC calculation as per 802.15.4 standard. Starting at first byte after length field. */
    
    
    #define RADIO_INTENSET_FRAMESTART_Pos (14UL) /*!< Position of FRAMESTART field. */
    #define RADIO_INTENSET_FRAMESTART_Msk (0x1UL << RADIO_INTENSET_FRAMESTART_Pos) /*!< Bit mask of FRAMESTART field. */
    #define RADIO_INTENSET_CCAIDLE_Pos (17UL) /*!< Position of CCAIDLE field. */
    #define RADIO_INTENSET_CCAIDLE_Msk (0x1UL << RADIO_INTENSET_CCAIDLE_Pos) /*!< Bit mask of CCAIDLE field. */
    #define RADIO_INTENSET_CCABUSY_Pos (18UL) /*!< Position of CCABUSY field. */
    #define RADIO_INTENSET_CCABUSY_Msk (0x1UL << RADIO_INTENSET_CCABUSY_Pos) /*!< Bit mask of CCABUSY field. */
    
    
    #define ED_RSSISCALE        (4U)    /**< RSSI scale for internal HW value */
    #define ED_RSSIOFFS         (-92)   /**< RSSI offset for internal HW value */
    
    /**
     * @brief IEEE802.15.4 default value for CCA threshold (in dBm)
     */
    #ifndef CONFIG_IEEE802154_CCA_THRESH_DEFAULT
    #define CONFIG_IEEE802154_CCA_THRESH_DEFAULT       (-70)
    #endif
    
    /* Bits 15..8 : CCA energy busy threshold. Used in all the CCA modes except CarrierMode. */
    #define RADIO_CCACTRL_CCAEDTHRES_Pos (8UL) /*!< Position of CCAEDTHRES field. */
    #define RADIO_CCACTRL_CCAEDTHRES_Msk (0xFFUL << RADIO_CCACTRL_CCAEDTHRES_Pos) /*!< Bit mask of CCAEDTHRES field. */
    
    /**
     * @brief   Default start frame delimiter
     */
    #define IEEE802154_SFD (0xa7)
    
    // signal for CCABUSY
    extern volatile uint8_t sig_ccabusy;
    // max retries
    #define MAX_RETRIES 5
    
    // functions
    uint8_t channel_to_freq(int channel);
    void radio_disable(void);
    void radio_set_sniff(int channel, uint32_t access_address);
    void radio_send_custom(uint8_t *pBuffer, uint8_t channel);
    void radio_tx_to_rx();

Reply
  • My uploaded files went to some bit bucket.  Here is the cleaned up code (3 files):

    //Raw802.ino
    #include <Arduino.h>
    #include <stdint.h>
    //#include <stdbool.h>
    #include "radio.h"
    #include <nrf52840.h>
    #include <Adafruit_TinyUSB.h>// Seems to need this without Serial or USB. Maybe DFU boot loader needs it?
    
    #define PIN_LEDX 22 // Red LED
    
    // channel 
    #define DEFAULT_INITIAL_CHANNEL 19
    
    // read buffer  
    uint8_t *rx_buffer;
    uint8_t u8SeqNum = 0;
    // the frame length in phy layer header 
    uint8_t pkt_len = 0;
    uint8_t u8PktBuf[100];
    
    // has data transmitting
    uint8_t bTransmitting = false;
    
    // packets
    #define MAX_PKTS_IN 12 // Maximum packets in the queue
    struct __attribute__((packed)) packets_structure
    {
      uint16_t size[MAX_PKTS_IN] = {0};
      uint8_t *pkt_buffer[MAX_PKTS_IN];
      uint8_t head = 0;
      uint8_t tail = 0;
    } packets;
    
    // channel
    uint8_t radio_channel = DEFAULT_INITIAL_CHANNEL;
    
    
    /**
     * nRF51822 RADIO handler.
     *
     * This handler is called whenever a RADIO event occurs (IRQ).
     **/
    extern "C" void RADIO_IRQHandler(void)
    {
      // if (NRF_RADIO->EVENTS_FRAMESTART)
      if (*(uint32_t *)(0x40001138)) //Events-FrameStart
      {
        *(uint32_t *)(0x40001138) = 0;
      }
    
      if (NRF_RADIO->EVENTS_READY)
      {
        NRF_RADIO->EVENTS_READY = 0;
        NRF_RADIO->TASKS_START = 1;
      }
    
      if (NRF_RADIO->EVENTS_END)
      {
        NRF_RADIO->EVENTS_END = 0;
        // NRF_RADIO->TASKS_START = 1;
        // If transmitt end
        if (bTransmitting)
        {
          bTransmitting = false;
          //Serial.write("SENDED ");
           //radio_tx_to_rx();
          //return;// maybe interrupt needs special return?
          goto exit;
        }
      }
      if (*(uint32_t *)(0x40001148))//CCA-Busy
      {
        Serial.println("CCABUSY");
        *(uint32_t *)(0x40001148) = 0;
        NRF_RADIO->TASKS_DISABLE = 1;
        while (NRF_RADIO->EVENTS_DISABLED == 0);
        //Serial.println("CCABUSY: disable the radio");
        sig_ccabusy = true;
      }
      if (*(uint32_t *)(0x4000114C))
      {
        Serial.println("CCASTOPPED");
      }
      if (*(uint32_t *)(0x40001144))//CCA-IDLE
      {
        Serial.println("CCAIDLE");
        sig_ccabusy = false;
        *(uint32_t *)(0x40001144) = 0;
        // NRF_RADIO->TASKS_CCASTART = 0
        //*(uint32_t *)(0x4000102c) = 1;
      }
      exit:
      {
      
      }
    }
    
    void setup()
    {
      pinMode(LED_BUILTIN, OUTPUT);
      pinMode(PIN_LEDX, OUTPUT); // Going for the RED Led now
      Serial.begin(115200);
      rx_buffer = (uint8_t *)malloc(IEEE802154_FRAME_LEN_MAX + 3);
    
      radio_set_sniff(radio_channel, 0); // Setup the radio
    }
    
    uint32_t ctr = 0;
    void loop()
    {
      if (NRF_RADIO->EVENTS_READY)
      {
        NRF_RADIO->EVENTS_READY = 0;
        // NRF_RADIO->TASKS_START;
      }
      delay(1);
      ctr++;
      if(ctr > 900)// Transmit every 200mS
      {
        ctr = 0;
        pkt_len = 17; 
        memcpy(u8PktBuf, "\x11\x00\x00\x00\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff",19);
        u8PktBuf[3] = u8SeqNum++;
      }
    
    
      // memcpy pkt_buffer to tx_buffer
      if (!bTransmitting && pkt_len)
      {
        Serial.write(".");
        digitalWrite(PIN_LEDX, HIGH);
        bTransmitting = true;
        radio_send_custom(u8PktBuf, radio_channel);
        pkt_len = 0;
        digitalWrite(PIN_LEDX, LOW);
      }
    }

    //radio.cpp
    #include "radio.h"
    #include <Arduino.h>
    #include <assert.h>
    
    // signal for CCABUSY
    volatile uint8_t sig_ccabusy = false;
    
    /**
     * channel_to_freq(int channel)
     *
     * Convert a BLE channel number into the corresponding frequency offset
     * for the nRF51822.
     **/
    uint8_t channel_to_freq(int channel) {
      assert(channel > 10);
      assert(channel < 27);
      return 5 * (channel - 10);
    }
    
    /**
     * radio_disable()
     *
     * Disable the radio.
     **/
    
    void radio_disable(void) {
      if (NRF_RADIO->STATE > 0) {
        NVIC_DisableIRQ(RADIO_IRQn);
    
        NRF_RADIO->EVENTS_DISABLED = 0;
        NRF_RADIO->TASKS_DISABLE = 1;
        while (NRF_RADIO->EVENTS_DISABLED == 0);
      }
    }
    
    /**
     * @brief   Convert from dBm to the internal representation, when the
     *          radio operates as a IEEE802.15.4 transceiver.
     */
    static inline uint8_t _dbm_to_ieee802154_hwval(int8_t dbm) {
      return ((dbm - ED_RSSIOFFS) / ED_RSSISCALE);
    }
    
    static int set_cca_threshold(int8_t threshold) {
    
      if (threshold < ED_RSSIOFFS) {
        return -1;
      }
    
      uint8_t hw_val = _dbm_to_ieee802154_hwval(threshold);
    
       NRF_RADIO->CCACTRL &= ~RADIO_CCACTRL_CCAEDTHRES_Msk;
      //*(uint32_t *)(0x4000166c) &= ~RADIO_CCACTRL_CCAEDTHRES_Msk;
    
       NRF_RADIO->CCACTRL |= hw_val << RADIO_CCACTRL_CCAEDTHRES_Pos;
      //*(uint32_t *)(0x4000166c) |= hw_val << RADIO_CCACTRL_CCAEDTHRES_Pos;
      return 0;
    }
    
    /**
     * radio_set_sniff(int channel)
     *
     * Configure the nRF51822 to sniff on a specific channel.
     **/
    
    void radio_set_sniff(int channel, uint32_t access_address) {
      // Disable radio
      radio_disable();
    
      // Enable the High Frequency clock on the processor. This is a pre-requisite
      // for the RADIO module. Without this clock, no communication is possible.
      NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
      NRF_CLOCK->TASKS_HFCLKSTART = 1;
      while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0);
    
      // power should be one of: -30, -20, -16, -12, -8, -4, 0, 4
      NRF_RADIO->TXPOWER = RADIO_TXPOWER_TXPOWER_Neg20dBm;//Pos4dBm;
      NRF_RADIO->TXADDRESS = 0;
    
      /* Set 802154 data rate. */
      NRF_RADIO->MODE = RADIO_MODE_MODE_Ieee802154_250Kbit;
      /* Listen on channel . */
      NRF_RADIO->FREQUENCY = channel_to_freq(channel);
    
      /* set start frame delimiter */
       //NRF_RADIO->RESERVED12[4] = IEEE802154_SFD;// Gets a read-only error on ths
      *(uint32_t *)(0x40001660) = IEEE802154_SFD;
    
      /* set MHR filters */
       NRF_RADIO->MHRMATCHCONF = 0;         /* Search Pattern Configuration */
      //*(uint32_t *)(0x40001644) = 0;
    
       NRF_RADIO->MHRMATCHMAS = 0xff0007ff; /* Pattern mask */
      //*(uint32_t *)(0x40001648) = 0xff0007ff;
    
      /* and set some fitting configuration */
      NRF_RADIO->PCNF0 = ((8 << RADIO_PCNF0_LFLEN_Pos) |
                          (RADIO_PCNF0_PLEN_32bitZero << RADIO_PCNF0_PLEN_Pos) |
                          (RADIO_PCNF0_CRCINC_Include << RADIO_PCNF0_CRCINC_Pos));
    
      NRF_RADIO->PCNF1 = IEEE802154_FRAME_LEN_MAX;
    
      NRF_RADIO->MODECNF0 |=
          RADIO_MODECNF0_RU_Fast; // Enable fast mode for radio ramp up
    
      // Enable CRC
      NRF_RADIO->CRCCNF =
          ((RADIO_CRCCNF_LEN_Two << RADIO_CRCCNF_LEN_Pos) |
           (RADIO_CRCCNF_SKIPADDR_Ieee802154 << RADIO_CRCCNF_SKIPADDR_Pos));
      NRF_RADIO->CRCPOLY = 0x11021;
      NRF_RADIO->CRCINIT = 0;
    
      // DATAWHITE
      NRF_RADIO->DATAWHITEIV = 0x40;
    
      NRF_RADIO->PACKETPTR = (uint32_t)(rx_buffer);
    
      // configure CCA
      set_cca_threshold(CONFIG_IEEE802154_CCA_THRESH_DEFAULT);
    
      // Configure interrupts
      NRF_RADIO->INTENSET = RADIO_INTENSET_END_Msk | RADIO_INTENSET_FRAMESTART_Msk |
                            // RADIO_INTENSET_CCAIDLE_Msk |
                            RADIO_INTENSET_CCABUSY_Msk;
      // Enable NVIC Interrupt for Radio
      NVIC_SetPriority(RADIO_IRQn, IRQ_PRIORITY_LOW);
      NVIC_ClearPendingIRQ(RADIO_IRQn);
      NVIC_EnableIRQ(RADIO_IRQn);
    
      // Enable receiver hardware
      NRF_RADIO->EVENTS_READY = 0;
      NRF_RADIO->TASKS_RXEN = 1;
      while (NRF_RADIO->EVENTS_READY == 0);
      NRF_RADIO->EVENTS_END = 0;
      NRF_RADIO->TASKS_START = 1;
    }
    
    /**
     * Send raw data asynchronously.
     **/
    
    void radio_send_custom(uint8_t *pBuffer, uint8_t channel) {
    
      /* No shortcuts on disable. */
      NRF_RADIO->SHORTS = 0x0;
      /* Switch radio to TX. */
      radio_disable();
    
      for (size_t try_ = 0; try_ < MAX_RETRIES; try_++) 
      {
        /* Switch packet buffer to tx_buffer. */
        NRF_RADIO->PACKETPTR = (uint32_t)pBuffer;
        NRF_RADIO->INTENSET = (1 << RADIO_INTENSET_END_Pos);
        NVIC_ClearPendingIRQ(RADIO_IRQn);
        NVIC_EnableIRQ(RADIO_IRQn);
    
        NRF_RADIO->EVENTS_READY = 0;
        NRF_RADIO->TASKS_RXEN = 1;
        Serial.write("While 1 ");// NEEDS THIS DELAY
        while (!NRF_RADIO->EVENTS_READY);
    
         NRF_RADIO->EVENTS_CCAIDLE = 0;
        //*(uint32_t *)(0x40001144) = 0;
        NRF_RADIO->TASKS_CCASTART = 1;
        //*(uint32_t *)(0x4000102c) = 1;
    
         Serial.write("While 2 "); // Needs this delay
        // while(!(NRF_RADIO->EVENTS_CCAIDLE || CCABUSY));
        while(!(NRF_RADIO->EVENTS_CCAIDLE || NRF_RADIO->EVENTS_CCABUSY));
        // wait for CCAIDLE or CCABUSY
        Serial.write("While 3 ");
        while (!(*(uint32_t *)(0x40001144) || sig_ccabusy));//CCA_IDLE
        if (sig_ccabusy) 
        {
          Serial.println("WARNING: retry for CCABUSY");
          sig_ccabusy = false;
          delay(100);
          continue;
        }
    
        /* Transmit with max power. */
        NRF_RADIO->TXPOWER =
            (RADIO_TXPOWER_TXPOWER_Pos4dBm << RADIO_TXPOWER_TXPOWER_Pos);
        NRF_RADIO->FREQUENCY = channel_to_freq(channel);
    
        // enable receiver
        NRF_RADIO->EVENTS_READY = 0;
        NRF_RADIO->TASKS_TXEN = 1;
    
         Serial.write("While 4\r\n");//needs this delay
        while (!NRF_RADIO->EVENTS_READY);
        NRF_RADIO->TASKS_START = 1;
        /* From now, radio will send data and notify the result to Radio_IRQHandler */
        return;
      }
      Serial.println("ERROR: retry too many times");
    }
    
    /**
     * Change radio from TX to RX, while keeping last configuration of
     *radio_send_custom or radio_set_sniff
     **/
    void radio_tx_to_rx() {
      NRF_RADIO->PACKETPTR = (uint32_t)(rx_buffer);
      NVIC_DisableIRQ(RADIO_IRQn);
      NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Msk;
    
      // NRF_RADIO->INTENSET = 0;
      NVIC_ClearPendingIRQ(RADIO_IRQn);
      NVIC_EnableIRQ(RADIO_IRQn);
    
      NRF_RADIO->EVENTS_DISABLED = 0;
      NRF_RADIO->TASKS_DISABLE = 1;
    
      while (NRF_RADIO->EVENTS_DISABLED == 0);
    
      NRF_RADIO->EVENTS_READY = 0;
      NRF_RADIO->TASKS_RXEN = 1;
    }

    //radio.h
    /**
     * Radio module
     *
     * This module provides all the required functions to manage the nRF51822
     * transceiver.
     **/
    
    #pragma once
    #include <Arduino.h>
    
    extern uint8_t *rx_buffer; /* Rx buffer used by RF to store packets. */
    
    #define IRQ_PRIORITY_HIGHEST 0
    #define IRQ_PRIORITY_HIGH 1
    #define IRQ_PRIORITY_MEDIUM 2
    #define IRQ_PRIORITY_LOW 3
    
    #define RADIO_MODE_MODE_Ieee802154_250Kbit (15UL)
    
    
    #define IEEE802154_FRAME_LEN_MAX (127U)   /**< maximum 802.15.4 frame length */
    #define IEEE802154G_FRAME_LEN_MAX (2047U) /**< maximum 802.15.4g-2012 frame length */
    #define IEEE802154_ACK_FRAME_LEN (5U)     /**< ACK frame length */
    #define IEEE802154_FCS_LEN                  (2U)
    
    
    #define RADIO_PCNF0_PLEN_32bitZero (2UL) /*!< 32-bit zero preamble - used for IEEE 802.15.4 */
    #define RADIO_PCNF0_CRCINC_Include (1UL) /*!< LENGTH includes CRC */
    #define RADIO_PCNF0_CRCINC_Pos (26UL) /*!< Position of CRCINC field. */
    #define RADIO_CRCCNF_SKIPADDR_Ieee802154 (2UL) /*!< CRC calculation as per 802.15.4 standard. Starting at first byte after length field. */
    
    
    #define RADIO_INTENSET_FRAMESTART_Pos (14UL) /*!< Position of FRAMESTART field. */
    #define RADIO_INTENSET_FRAMESTART_Msk (0x1UL << RADIO_INTENSET_FRAMESTART_Pos) /*!< Bit mask of FRAMESTART field. */
    #define RADIO_INTENSET_CCAIDLE_Pos (17UL) /*!< Position of CCAIDLE field. */
    #define RADIO_INTENSET_CCAIDLE_Msk (0x1UL << RADIO_INTENSET_CCAIDLE_Pos) /*!< Bit mask of CCAIDLE field. */
    #define RADIO_INTENSET_CCABUSY_Pos (18UL) /*!< Position of CCABUSY field. */
    #define RADIO_INTENSET_CCABUSY_Msk (0x1UL << RADIO_INTENSET_CCABUSY_Pos) /*!< Bit mask of CCABUSY field. */
    
    
    #define ED_RSSISCALE        (4U)    /**< RSSI scale for internal HW value */
    #define ED_RSSIOFFS         (-92)   /**< RSSI offset for internal HW value */
    
    /**
     * @brief IEEE802.15.4 default value for CCA threshold (in dBm)
     */
    #ifndef CONFIG_IEEE802154_CCA_THRESH_DEFAULT
    #define CONFIG_IEEE802154_CCA_THRESH_DEFAULT       (-70)
    #endif
    
    /* Bits 15..8 : CCA energy busy threshold. Used in all the CCA modes except CarrierMode. */
    #define RADIO_CCACTRL_CCAEDTHRES_Pos (8UL) /*!< Position of CCAEDTHRES field. */
    #define RADIO_CCACTRL_CCAEDTHRES_Msk (0xFFUL << RADIO_CCACTRL_CCAEDTHRES_Pos) /*!< Bit mask of CCAEDTHRES field. */
    
    /**
     * @brief   Default start frame delimiter
     */
    #define IEEE802154_SFD (0xa7)
    
    // signal for CCABUSY
    extern volatile uint8_t sig_ccabusy;
    // max retries
    #define MAX_RETRIES 5
    
    // functions
    uint8_t channel_to_freq(int channel);
    void radio_disable(void);
    void radio_set_sniff(int channel, uint32_t access_address);
    void radio_send_custom(uint8_t *pBuffer, uint8_t channel);
    void radio_tx_to_rx();

Children
No Data
Related