Hello,
I'm using a modified version of the examples->peripheral->radio examples from nRF5 SDK v17.0.0 to receive packets sent on Bluetooth Low Energy channel 37 using an nRF52832. I am not using any soft device. I have a Sparkfun module, a Laird module, and my own custom hardware using this transceiver and am using a J-Link and Segger Embedded Studio to debug. Please see my code below:
void radio_set_ch(uint8_t ch)
{
if(ch<40)
{
NRF_RADIO->FREQUENCY = channel[ch];
NRF_RADIO->DATAWHITEIV = 64+ch;
NRF_LOG_INFO("Channel set to %d",ch);
} else {
NRF_LOG_ERROR("Error setting channel");
}
}
void radio_init_adv(uint8_t ch, uint8_t power)
{
//Power 0dbm, BLE 1Mbit mode
NRF_RADIO->POWER = 1;
NRF_RADIO->TXPOWER = (power << RADIO_TXPOWER_TXPOWER_Pos);
NRF_RADIO->MODE = (RADIO_MODE_MODE_Ble_1Mbit << RADIO_MODE_MODE_Pos);
//Channel
radio_set_ch(ch);
//Address configuration
NRF_RADIO->PREFIX0 = 0x8e;
NRF_RADIO->BASE0 = 0x89bed600;
NRF_RADIO->TXADDRESS = 0x00;
NRF_RADIO->RXADDRESSES = 0x01;
//Packet configuration
NRF_RADIO->PCNF0 = (
(((1UL) << RADIO_PCNF0_S0LEN_Pos) & RADIO_PCNF0_S0LEN_Msk) | //S0 length 1 byte
(((2UL) << RADIO_PCNF0_S1LEN_Pos) & RADIO_PCNF0_S1LEN_Msk) | //S1 length 2 bit
(((6UL) << RADIO_PCNF0_LFLEN_Pos) & RADIO_PCNF0_LFLEN_Msk) //Length field length 6 bit
);
NRF_RADIO->PCNF1 = (
(((50UL) << RADIO_PCNF1_MAXLEN_Pos) & RADIO_PCNF1_MAXLEN_Msk) | //Payload length max. 37 byte
(((0UL) << RADIO_PCNF1_STATLEN_Pos) & RADIO_PCNF1_STATLEN_Msk) | //Payload expansion 0 byte
(((3UL) << RADIO_PCNF1_BALEN_Pos) & RADIO_PCNF1_BALEN_Msk) | //Base address length 3 byte
(((RADIO_PCNF1_ENDIAN_Little) << RADIO_PCNF1_ENDIAN_Pos) & RADIO_PCNF1_ENDIAN_Msk) | //Endianess S0, Length, S1 and payload
(((1UL) << RADIO_PCNF1_WHITEEN_Pos) & RADIO_PCNF1_WHITEEN_Msk) //whitening enable
);
//CRC
NRF_RADIO->CRCCNF = (RADIO_CRCCNF_LEN_Three << RADIO_CRCCNF_LEN_Pos) |
(RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos); //Exclude address from CRC
NRF_RADIO->CRCINIT = 0x555555; //CRC inital value
NRF_RADIO->CRCPOLY = 0x00065B; //CRC poly
//Clear Events
NRF_RADIO->EVENTS_DISABLED = 0;
NRF_RADIO->EVENTS_END = 0;
NRF_RADIO->EVENTS_READY = 0;
NRF_RADIO->EVENTS_ADDRESS = 0;
//Interrupt on event
NRF_RADIO->INTENSET = RADIO_INTENSET_ADDRESS_Msk | RADIO_INTENSET_DISABLED_Msk;
NRF_LOG_INFO("Radio init (adv) complete");
}
void receiver(void)
{
uint8_t packet[50];
radio_init_adv(37, RADIO_TXPOWER_TXPOWER_0dBm);
NRF_RADIO->PACKETPTR = (uint32_t)&packet;
NRF_LOG_INFO("Start!");
//Radio enable & wait for ready
NRF_RADIO->EVENTS_READY = 0U;
NRF_RADIO->TASKS_RXEN = 1U;
while (NRF_RADIO->EVENTS_READY == 0U);
while(1)
{
//Listen & wait for address receive
NRF_RADIO->EVENTS_END = 0U;
NRF_RADIO->TASKS_START = 1U;
while (NRF_RADIO->EVENTS_END == 0U);
NRF_LOG_INFO("Packet was received");
NRF_LOG_INFO("S0: 0x%02X", packet[0]);
NRF_LOG_INFO("Length:%u Bytes (0x%02X)", packet[1], packet[1]);
NRF_LOG_INFO("S1: 0x%02X", packet[2]);
uint64_t adva=((uint64_t)packet[8]<<40)+((uint64_t)packet[7]<<32)+((uint64_t)packet[6]<<24)+((uint64_t)packet[5]<<16)+((uint64_t)packet[4]<<8)+(uint64_t)packet[3];
NRF_LOG_INFO("AdvA: 0x%06X%06X", (adva>>24), (adva&0xFFFFFF));
NRF_LOG_FLUSH();
}
}
receiver(); is called from my main function and for most packets such as ADV_IND and ADV_NON_CONN_IND this works fine and gives me an output like this:
<info> app: Channel set to 37 <info> app: Radio init (adv) complete <info> app: Start! <info> app: Packet was received <info> app: S0: 0x42 <info> app: Length:37 Bytes (0x25) <info> app: S1: 0x00 <info> app: AdvA: 0x16544296A738 <info> app: Packet was received <info> app: S0: 0x00 <info> app: Length:27 Bytes (0x1B) <info> app: S1: 0x00 <info> app: AdvA: 0xA4C13824E4A6
The first packet received here is sent by my phones covid app, the second is an advertisment from a simple BLE thermometer. Of course this is just an excerpt, as the device would keep listening and the list would grow.
My issue however is that this setup seems to not receive or possibly miss ADV_CONNECT_REQ packets (for example sent from my phone to the BLE thermometer). They just don't show up. I simultaneously used a TI dongle and their Packet Sniffer software, so I know for a fact that a ADV_CONNECT_REQ packet was sent on channel 37.
For further debugging I added this code:
void send_packet()
{
//Enable radio & wait for ready
NRF_RADIO->EVENTS_READY = 0U;
NRF_RADIO->TASKS_TXEN = 1;
while (NRF_RADIO->EVENTS_READY == 0U);
//Send packet
NRF_RADIO->EVENTS_END = 0U;
NRF_RADIO->TASKS_START = 1U;
while (NRF_RADIO->EVENTS_END == 0U);
//Disable radio
NRF_RADIO->EVENTS_DISABLED = 0U;
NRF_RADIO->TASKS_DISABLE = 1U;
while (NRF_RADIO->EVENTS_DISABLED == 0U);
}
void transmitter(void)
{
uint8_t packet[]={0x05,0x22,0x00,0xAA,0xAA,0xAA,0xAA,0xAA,0xAA,0xBB,0xBB,0xBB,0xBB,0xBB,0xBB,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC};
radio_init_adv(37, RADIO_TXPOWER_TXPOWER_0dBm);
NRF_RADIO->PACKETPTR = (uint32_t)&packet;
while(1)
{
send_packet();
nrf_delay_ms(200);
NRF_LOG_FLUSH();
}
}
This is used to periodically send a "dummy" ADV_CONNECT_REQ packet for test purposes. I used one nRF52832 as a transmitter, and one as a receiver, and the "dummy" ADV_CONNECT_REQ packets came through fine.
I am unable to find my mistake - why can I not receive ADV_CONNECT_REQ packets when they're being sent as a direct response to advertisements? I have tried different phones as well. The fact that I can receive the packets when they're not a direct response (above mentioned "dummy" packets) makes me think it may be a timing issue. Please advise - it must be possible somehow to receive these packets.
Best regards