Hi, radio experts here. Due to some limited conditions I have to implement one custom radio communication pattern in MCUBoot, not the BLE stack which is a bit too heavy for a bootloader. I am using PCA-10040 DK for my experiment. The strange thing is that if I choose crystal clock as LF clock source, the radio communication is working well and what confused me most is the radio works even when there is no crystal clock on my custom board. After I changed the LF clock source to RC, the radio seems out of sync which the receiver(my custom board using NRF24L01+ chip) hardly receives any packet. I should emphsis that my NRF24L01+ board receives packets smoothly from crystal clock.
I have attached the source code related to radio tx/rx.
static volatile uint8_t end_isr, disabled_isr, recv_ok; static volatile uint8_t radio_mode = RADIO_RX_MODE; ISR_DIRECT_DECLARE(radio_nrf5_isr) { if (NRF_RADIO->EVENTS_READY) { NRF_RADIO->EVENTS_READY = 0; } if (NRF_RADIO->EVENTS_ADDRESS) { NRF_RADIO->EVENTS_ADDRESS = 0; } if (NRF_RADIO->EVENTS_PAYLOAD) { NRF_RADIO->EVENTS_PAYLOAD = 0; } if (NRF_RADIO->EVENTS_END) { NRF_RADIO->EVENTS_END = 0; end_isr = 1; if (NRF_RADIO->CRCSTATUS) { recv_ok = 1; } } if (NRF_RADIO->EVENTS_DISABLED) { NRF_RADIO->EVENTS_DISABLED = 0; disabled_isr = 1; } ISR_DIRECT_PM(); return 1; } static uint32_t swap_bits(uint32_t inp); static uint32_t bytewise_bitswap(uint32_t inp); static uint32_t swap_bits(uint32_t inp) { uint32_t i; uint32_t retval = 0; inp = (inp & 0x000000FFUL); for (i = 0; i < 8; i++) { retval |= ((inp >> i) & 0x01) << (7 - i); } return retval; } static uint32_t bytewise_bitswap(uint32_t inp) { return (swap_bits(inp >> 24) << 24) | (swap_bits(inp >> 16) << 16) | (swap_bits(inp >> 8) << 8) | (swap_bits(inp)); } static int apply_address_workarounds() { // Set up radio parameters. NRF_RADIO->MODECNF0 = (NRF_RADIO->MODECNF0 & ~RADIO_MODECNF0_RU_Msk) | RADIO_MODECNF0_RU_Default << RADIO_MODECNF0_RU_Pos; // Workaround for nRF52832 Rev 1 Errata 102 and nRF52832 Rev 1 Errata 106. This will reduce sensitivity by 3dB. *((volatile uint32_t *)0x40001774) = (*((volatile uint32_t *)0x40001774) & 0xFFFFFFFE) | 0x01000000; return 0; } uint32_t dev_addr(void) { #if defined(TEST_SENDER) return TEST_ADDRESS_10086; #else return TEST_ADDRESS_10010; #endif } /** * @brief Function for configuring the radio to operate in ShockBurst compatible mode. * * To configure the application running on nRF24L series devices: * * @verbatim * uint8_t tx_address[5] = { 0xC0, 0x01, 0x23, 0x45, 0x67 }; * hal_nrf_set_rf_channel(7); * hal_nrf_set_address_width(HAL_NRF_AW_5BYTES); * hal_nrf_set_address(HAL_NRF_TX, tx_address); * hal_nrf_set_address(HAL_NRF_PIPE0, tx_address); * hal_nrf_open_pipe(0, false); * hal_nrf_set_datarate(HAL_NRF_1MBPS); * hal_nrf_set_crc_mode(HAL_NRF_CRC_16BIT); * hal_nrf_setup_dynamic_payload(0xFF); * hal_nrf_enable_dynamic_payload(false); * @endverbatim * * When transmitting packets with hal_nrf_write_tx_payload(const uint8_t *tx_pload, uint8_t length), * match the length with PACKET_STATIC_LENGTH. * hal_nrf_write_tx_payload(payload, PACKET_STATIC_LENGTH); * */ void update_base1_address(const uint8_t *addr); void hal_radio_configure(void) { uint32_t address; NVIC_DisableIRQ(RADIO_IRQn); NRF_RADIO->POWER = RADIO_POWER_POWER_Disabled << RADIO_POWER_POWER_Pos; NRF_RADIO->POWER = RADIO_POWER_POWER_Enabled << RADIO_POWER_POWER_Pos; NRF_RADIO->SHORTS = RADIO_SHORTS_READY_START_Enabled << RADIO_SHORTS_READY_START_Pos; // Radio config NRF_RADIO->TXPOWER = (RADIO_TXPOWER_TXPOWER_0dBm << RADIO_TXPOWER_TXPOWER_Pos); NRF_RADIO->MODE = (RADIO_MODE_MODE_Nrf_2Mbit << RADIO_MODE_MODE_Pos); set_radio_channel(57); // Radio address config NRF_RADIO->PREFIX0 = ((uint32_t)swap_bits(0x2) << 24) // Prefix byte of address 3 converted to nRF24L series format | ((uint32_t)swap_bits(0x1) << 16) // Prefix byte of address 2 converted to nRF24L series format | ((uint32_t)swap_bits(0x0) << 8) // Prefix byte of address 1 converted to nRF24L series format | ((uint32_t)swap_bits(0xE6) << 0); // Prefix byte of address 0 converted to nRF24L series format NRF_RADIO->PREFIX1 = ((uint32_t)swap_bits(0xC7) << 24) // Prefix byte of address 7 converted to nRF24L series format | ((uint32_t)swap_bits(0xC6) << 16) // Prefix byte of address 6 converted to nRF24L series format | ((uint32_t)swap_bits(0x3) << 0); // Prefix byte of address 4 converted to nRF24L series format NRF_RADIO->BASE0 = bytewise_bitswap(0x7FE67FE6UL); // Base address for prefix 0 converted to nRF24L series format address = dev_addr(); update_base1_address((uint8_t *)&address); NRF_RADIO->TXADDRESS = 0x00UL; // Set device address 0 to use when transmitting NRF_RADIO->RXADDRESSES = 0x1fUL; // Enable device address 0 to use to select which addresses to receive // Packet configuration NRF_RADIO->PCNF0 = (PACKET_S1_FIELD_SIZE << RADIO_PCNF0_S1LEN_Pos) | (PACKET_S0_FIELD_SIZE << RADIO_PCNF0_S0LEN_Pos) | (PACKET_LENGTH_FIELD_SIZE << RADIO_PCNF0_LFLEN_Pos); //lint !e845 "The right argument to operator '|' is certain to be 0" // Packet configuration NRF_RADIO->PCNF1 = (RADIO_PCNF1_WHITEEN_Disabled << RADIO_PCNF1_WHITEEN_Pos) | (RADIO_PCNF1_ENDIAN_Big << RADIO_PCNF1_ENDIAN_Pos) | (PACKET_BASE_ADDRESS_LENGTH << RADIO_PCNF1_BALEN_Pos) | (PACKET_STATIC_LENGTH << RADIO_PCNF1_STATLEN_Pos) | (PACKET_PAYLOAD_MAXSIZE << RADIO_PCNF1_MAXLEN_Pos); //lint !e845 "The right argument to operator '|' is certain to be 0" // CRC Config NRF_RADIO->CRCCNF = (RADIO_CRCCNF_LEN_Two << RADIO_CRCCNF_LEN_Pos); // Number of checksum bits if ((NRF_RADIO->CRCCNF & RADIO_CRCCNF_LEN_Msk) == (RADIO_CRCCNF_LEN_Two << RADIO_CRCCNF_LEN_Pos)) { NRF_RADIO->CRCINIT = 0xFFFFUL; // Initial value NRF_RADIO->CRCPOLY = 0x11021UL; // CRC poly: x^16 + x^12^x^5 + 1 } else if ((NRF_RADIO->CRCCNF & RADIO_CRCCNF_LEN_Msk) == (RADIO_CRCCNF_LEN_One << RADIO_CRCCNF_LEN_Pos)) { NRF_RADIO->CRCINIT = 0xFFUL; // Initial value NRF_RADIO->CRCPOLY = 0x107UL; // CRC poly: x^8 + x^2^x^1 + 1 } NRF_RADIO->INTENSET = (RADIO_INTENSET_DISABLED_Enabled << RADIO_INTENSET_DISABLED_Pos) | (RADIO_INTENSET_END_Enabled << RADIO_INTENSET_END_Pos); IRQ_DIRECT_CONNECT(RADIO_IRQn, 0, radio_nrf5_isr, 0); NVIC_ClearPendingIRQ(RADIO_IRQn); NVIC_EnableIRQ(RADIO_IRQn); } void wait_end(void) { end_isr = 0; while ( end_isr == 0 ); end_isr = 0; } void radio_disable(void) { if (NRF_RADIO->STATE == RADIO_STATE_STATE_Disabled) { return; } disabled_isr = 0; NRF_RADIO->TASKS_DISABLE = 1; while ( disabled_isr == 0 ); disabled_isr = 0; } void send_enable(uint8_t *p_data) { NRF_RADIO->PACKETPTR = (uint32_t)&(p_data[0]); NRF_RADIO->EVENTS_END = 0; NRF_RADIO->EVENTS_DISABLED = 0; NRF_RADIO->TASKS_TXEN = 1; } void set_radio_channel(uint8_t ch) { NRF_RADIO->FREQUENCY = ch; } void select_tx_pipe(uint8_t pipe) { NRF_RADIO->TXADDRESS = pipe; } void get_rx_pipe(uint8_t *flags) { *flags = NRF_RADIO->RXMATCH; } void update_base1_address(const uint8_t *addr) { uint8_t base_addr[4]; base_addr[0] = 0xC3; base_addr[1] = addr[0]; base_addr[2] = addr[1]; base_addr[3] = addr[2]; NRF_RADIO->BASE1 = bytewise_bitswap(*(uint32_t *)(base_addr)); // Base address for prefix 1-7 converted to nRF24L series format apply_address_workarounds(); } void set_tx_address(const uint8_t *addr, uint8_t flags) { update_base1_address(addr); select_tx_pipe((flags & (RFFLAG_DATA | RFFLAG_ACK)) + 1); } void recv_start(void) { NRF_RADIO->EVENTS_END = 0; NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->EVENTS_DISABLED = 0; NRF_RADIO->TASKS_START = 1; } void recv_enable(uint8_t *p_data) { NRF_RADIO->PACKETPTR = (uint32_t)&(p_data[0]); NRF_RADIO->EVENTS_END = 0; NRF_RADIO->EVENTS_READY = 0; NRF_RADIO->EVENTS_DISABLED = 0; NRF_RADIO->TASKS_RXEN = 1; } /* Sends an advertising PDU on the given channel index. */ int hal_radio_send_packet(const uint8_t *addr, uint8_t flags, uint8_t *p_data, uint8_t data_len) { if (data_len > PACKET_PAYLOAD_MAXSIZE) return -1; if (radio_mode == RADIO_RX_MODE) { radio_disable(); radio_mode = RADIO_TX_MODE; } #if defined(ENABLE_RADIO_PA) PA_CTRL_TX_ACTIVE; #endif if (data_len < PACKET_PAYLOAD_MAXSIZE) { memset(p_data + data_len, 0, PACKET_PAYLOAD_MAXSIZE - data_len); } if (flags & RFFLAG_BROADCAST) { select_tx_pipe(0); } else { set_tx_address(addr, flags); } send_enable(p_data); wait_end(); radio_disable(); // disable for rx mode return 0; } int hal_radio_recv_packet(uint8_t * flags, uint8_t *p_data) { uint32_t address; uint8_t ret = -1, pipe; static uint8_t buf[PACKET_PAYLOAD_MAXSIZE]; #if defined(ENABLE_RADIO_PA) PA_CTRL_RX_ACTIVE; #endif if (radio_mode == RADIO_TX_MODE) { radio_disable(); address = dev_addr(); update_base1_address((uint8_t *)&address); recv_enable(buf); radio_mode = RADIO_RX_MODE; } else if (NRF_RADIO->STATE == RADIO_STATE_STATE_Disabled) { recv_enable(buf); } else if (end_isr) { end_isr = 0; if (recv_ok) { recv_ok = 0; get_rx_pipe(&pipe); if (pipe == 0) { *flags = RFFLAG_BROADCAST; } else { *flags = (pipe - 1) & (RFFLAG_DATA | RFFLAG_ACK); } memcpy(p_data, buf, PACKET_PAYLOAD_MAXSIZE); ret = 0; } recv_start(); disabled_isr = 0; } return ret; } void hal_clock_hfclk_enable(void) { NRF_CLOCK->EVENTS_HFCLKSTARTED = 0; NRF_CLOCK->TASKS_HFCLKSTART = 1; while( NRF_CLOCK->EVENTS_HFCLKSTARTED == 0 ); } void radio_init(void) { hal_clock_hfclk_enable(); hal_radio_configure(); }