Direction finding on NRF52811

Hi!
I developed a locator and beacon pcb boards for AoA direction finding using the NRF52811 chip. The locator has 4 patch antennas and the SKY13575-639LF external antenna switch.
Software configuration for the beacon (using infocenter.nordicsemi.com/.../intro.html) :

1. Radio:

/* Enable power to RADIO */
NRF_RADIO->POWER = 1;

/* Set radio transmit power to 0dBm */
NRF_RADIO->TXPOWER = (RADIO_TXPOWER_TXPOWER_0dBm << RADIO_TXPOWER_TXPOWER_Pos);

/* Set radio mode to 1Mbit/s Bluetooth Low Energy */
NRF_RADIO->MODE = (RADIO_MODE_MODE_Ble_1Mbit << RADIO_MODE_MODE_Pos);

/* Set the requested channel */
NRF_RADIO->FREQUENCY = GetChannelFrequency(channel);

/* This value needs to correspond to the channel being used */
NRF_RADIO->DATAWHITEIV = channel;

/* Configure Access Address according to the BLE standard */
NRF_RADIO->PREFIX0 = 0x8e;
NRF_RADIO->BASE0 = 0x89bed600;

/* Use logical address 0 (prefix0 + base0) = 0x8E89BED6 when transmitting and receiving */
NRF_RADIO->TXADDRESS = 0x00;
NRF_RADIO->RXADDRESSES = 0x01;

/* PCNF-> Packet Configuration. 
* We now need to configure the sizes S0, S1 and length field to match the
* datapacket format of the advertisement packets.
*/
NRF_RADIO->PCNF0 = (
	(((1UL) << RADIO_PCNF0_S0LEN_Pos) & RADIO_PCNF0_S0LEN_Msk) |  /* Length of S0 field in bytes 0-1.    */
	(((0UL) << RADIO_PCNF0_S1LEN_Pos) & RADIO_PCNF0_S1LEN_Msk) |  /* Length of S1 field in bits 0-8.     */
	(((8UL) << RADIO_PCNF0_LFLEN_Pos) & RADIO_PCNF0_LFLEN_Msk)    /* Length of length field in bits 0-8. */
);

/* Packet configuration */
NRF_RADIO->PCNF1 = (
	(((64UL) << RADIO_PCNF1_MAXLEN_Pos) & RADIO_PCNF1_MAXLEN_Msk)   |                      /* Maximum length of payload in bytes [0-255] */
	(((0UL) << RADIO_PCNF1_STATLEN_Pos) & RADIO_PCNF1_STATLEN_Msk)   |                      /* Expand the payload with N bytes in addition to LENGTH [0-255] */
	(((3UL) << RADIO_PCNF1_BALEN_Pos) & RADIO_PCNF1_BALEN_Msk)       |                      /* Base address length in number of bytes. */
	(((RADIO_PCNF1_ENDIAN_Little) << RADIO_PCNF1_ENDIAN_Pos) & RADIO_PCNF1_ENDIAN_Msk) |  /* Endianess of the S0, LENGTH, S1 and PAYLOAD fields. */
	(((1UL) << RADIO_PCNF1_WHITEEN_Pos) & RADIO_PCNF1_WHITEEN_Msk)                         /* Enable packet whitening */
);

/* CRC config */
NRF_RADIO->CRCCNF  = (RADIO_CRCCNF_LEN_Three << RADIO_CRCCNF_LEN_Pos) |
					 (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos); /* Skip Address when computing CRC */
NRF_RADIO->CRCINIT = 0x555555;                                                  /* Initial value of CRC */
NRF_RADIO->CRCPOLY = 0x00065B;                                                  /* CRC polynomial function */

/* Clear events */
NRF_RADIO->EVENTS_DISABLED = 0;
NRF_RADIO->EVENTS_END = 0;
NRF_RADIO->EVENTS_READY = 0;
NRF_RADIO->EVENTS_ADDRESS = 0;	
//-------------------------------------
//-------------------------------------
NRF_RADIO->PACKETPTR = (uint32_t) Packet;

// Set up AoA mode
NRF_RADIO->DFEMODE = RADIO_DFEMODE_DFEOPMODE_AoA;

NRF_RADIO->DFECTRL1 = 3 << RADIO_DFECTRL1_NUMBEROF8US_Pos | 1 << RADIO_DFECTRL1_DFEINEXTENSION_Pos;

2. Sending a packet:
NRF_RADIO->EVENTS_READY = 0U;
// Enable radio and wait for ready.
NRF_RADIO->TASKS_TXEN   = 1; 											
while (NRF_RADIO->EVENTS_READY == 0U){}

NRF_RADIO->TASKS_START = 1U;
// Start transmission.
NRF_RADIO->EVENTS_PHYEND = 0;

NRF_RADIO->EVENTS_END  = 0U;


// Wait for end of the transmission packet.	   										

while (NRF_RADIO->EVENTS_PHYEND == 0U)
{
    while (NRF_RADIO->EVENTS_END == 0U)
    {
		//counter1++;
    }
    counter2++;
} 											

NRF_RADIO->EVENTS_DISABLED = 0U;
// Disable the radio.																	
NRF_RADIO->TASKS_DISABLE   = 1U; 									
while (NRF_RADIO->EVENTS_DISABLED == 0U){} 

3. The resulting structure of the packet:

Software configuration for the locator (using infocenter.nordicsemi.com/.../intro.html):

1. Radio:

/* Enable power to RADIO */
NRF_RADIO->POWER = 1;

/* Set radio transmit power to 0dBm */
NRF_RADIO->TXPOWER = (RADIO_TXPOWER_TXPOWER_0dBm << RADIO_TXPOWER_TXPOWER_Pos);

/* Set radio mode to 1Mbit/s Bluetooth Low Energy */
NRF_RADIO->MODE = (RADIO_MODE_MODE_Ble_1Mbit << RADIO_MODE_MODE_Pos);

/* Set the requested channel */
NRF_RADIO->FREQUENCY = GetChannelFrequency(channel);

/* This value needs to correspond to the channel being used */
NRF_RADIO->DATAWHITEIV = channel;

/* Configure Access Address according to the BLE standard */
NRF_RADIO->PREFIX0 = 0x8e;
NRF_RADIO->BASE0 = 0x89bed600;

/* Use logical address 0 (prefix0 + base0) = 0x8E89BED6 when transmitting and receiving */
NRF_RADIO->TXADDRESS = 0x00;
NRF_RADIO->RXADDRESSES = 0x01;

/* PCNF-> Packet Configuration. 
* We now need to configure the sizes S0, S1 and length field to match the
* datapacket format of the advertisement packets.
*/
NRF_RADIO->PCNF0 = (
	(((1UL) << RADIO_PCNF0_S0LEN_Pos) & RADIO_PCNF0_S0LEN_Msk) |  /* Length of S0 field in bytes 0-1.    */
	(((0UL) << RADIO_PCNF0_S1LEN_Pos) & RADIO_PCNF0_S1LEN_Msk) |  /* Length of S1 field in bits 0-8.     */
	(((8UL) << RADIO_PCNF0_LFLEN_Pos) & RADIO_PCNF0_LFLEN_Msk)    /* Length of length field in bits 0-8. */
);

/* Packet configuration */
NRF_RADIO->PCNF1 = (
	(((64UL) << RADIO_PCNF1_MAXLEN_Pos) & RADIO_PCNF1_MAXLEN_Msk)   |                      /* Maximum length of payload in bytes [0-255] */
	(((0UL) << RADIO_PCNF1_STATLEN_Pos) & RADIO_PCNF1_STATLEN_Msk)   |                      /* Expand the payload with N bytes in addition to LENGTH [0-255] */
	(((3UL) << RADIO_PCNF1_BALEN_Pos) & RADIO_PCNF1_BALEN_Msk)       |                      /* Base address length in number of bytes. */
	(((RADIO_PCNF1_ENDIAN_Little) << RADIO_PCNF1_ENDIAN_Pos) & RADIO_PCNF1_ENDIAN_Msk) |  /* Endianess of the S0, LENGTH, S1 and PAYLOAD fields. */
	(((1UL) << RADIO_PCNF1_WHITEEN_Pos) & RADIO_PCNF1_WHITEEN_Msk)                         /* Enable packet whitening */
);

/* CRC config */
NRF_RADIO->CRCCNF  = (RADIO_CRCCNF_LEN_Three << RADIO_CRCCNF_LEN_Pos) |
					 (RADIO_CRCCNF_SKIPADDR_Skip << RADIO_CRCCNF_SKIPADDR_Pos); /* Skip Address when computing CRC */
NRF_RADIO->CRCINIT = 0x555555;                                                  /* Initial value of CRC */
NRF_RADIO->CRCPOLY = 0x00065B;                                                  /* CRC polynomial function */

/* Clear events */
NRF_RADIO->EVENTS_DISABLED = 0;
NRF_RADIO->EVENTS_END = 0;
NRF_RADIO->EVENTS_READY = 0;
NRF_RADIO->EVENTS_ADDRESS = 0;	
//-------------------------------------
//-------------------------------------
NRF_RADIO->PACKETPTR = (uint32_t) Packet;

// Set up AoA receiver mode
NRF_RADIO->DFEMODE |= RADIO_DFEMODE_DFEOPMODE_AoA;

NRF_RADIO->DFECTRL1 = 3 << RADIO_DFECTRL1_NUMBEROF8US_Pos | 1 << RADIO_DFECTRL1_DFEINEXTENSION_Pos;

NRF_RADIO->CTEINLINECONF |= (RADIO_CTEINLINECONF_CTEINLINECTRLEN_Enabled << RADIO_CTEINLINECONF_CTEINLINECTRLEN_Pos)
						 | (RADIO_CTEINLINECONF_CTEINFOINS1_NotInS1 << RADIO_CTEINLINECONF_CTEINFOINS1_Pos)
						 | (0x07 << RADIO_CTEINLINECONF_S0CONF_Pos)
						 | (0x0F << RADIO_CTEINLINECONF_S0MASK_Pos);

2. Antenna switching:
#define ANTENNA_SWICTH_PIN0 30
#define ANTENNA_SWICTH_PIN1 28

// Configure antenna switching every 2 µs
NRF_RADIO->DFECTRL1 |= RADIO_DFECTRL1_TSWITCHSPACING_2us << RADIO_DFECTRL1_TSWITCHSPACING_Pos;

// Antenna 1 (for data)
NRF_RADIO->SWITCHPATTERN = 0b00;
// Antenna 1 (guard/reference)
NRF_RADIO->SWITCHPATTERN = 0b00;
// Antenna 2 (guard/reference)
NRF_RADIO->SWITCHPATTERN = 0b01;
// Antenna 3 (guard/reference)
NRF_RADIO->SWITCHPATTERN = 0b10;
// Antenna 4 (guard/reference)
NRF_RADIO->SWITCHPATTERN = 0b11;


// Set up the first switching pin
NRF_RADIO->PSEL.DFEGPIO[0] = ANTENNA_SWICTH_PIN0;
// Set up the second switching pin
NRF_RADIO->PSEL.DFEGPIO[0] = ANTENNA_SWICTH_PIN1;

// Set the switch offset to zero
NRF_RADIO->DFECTRL2 |= (0 << RADIO_DFECTRL2_TSWITCHOFFSET_Pos);

// Config antenna swithcing pins as output
nrf_gpio_cfg_output(ANTENNA_SWICTH_PIN0);
nrf_gpio_cfg_output(ANTENNA_SWICTH_PIN1);
nrf_gpio_pin_write(ANTENNA_SWICTH_PIN0, 0);
nrf_gpio_pin_write(ANTENNA_SWICTH_PIN0, 0);

3. IQ samples receiving:
struct IQ_Sample
{
    int16_t I;
    int16_t Q;
};

static IQ_Sample DFE_Packet[64] = {0};


// Set the sample type to IQ format
NRF_RADIO->DFECTRL1 |= (0 << RADIO_DFECTRL1_SAMPLETYPE_Pos);
// Configure the DMA pointer to RAM
NRF_RADIO->DFEPACKET.PTR = (uint32_t) DFE_Packet;
// Configure the size of the reserved buffer
NRF_RADIO->DFEPACKET.MAXCNT = 0x1C;
// Set the sample spacing to 1 µs for the reference period
NRF_RADIO->DFECTRL1 |= (RADIO_DFECTRL1_TSAMPLESPACINGREF_1us << RADIO_DFECTRL1_TSAMPLESPACINGREF_Pos);
// Set sample offset to 1
NRF_RADIO->DFECTRL2 |= (3 << RADIO_DFECTRL2_TSAMPLEOFFSET_Pos);
// Set sample spacing to 2 µs for the sample slots with Constant Tone Extension (CTE) inline mode
NRF_RADIO->CTEINLINECONF |= (RADIO_CTEINLINECONF_CTEINLINERXMODE2US_2us << RADIO_CTEINLINECONF_CTEINLINERXMODE1US_Pos);

4. Waiting for the packet:
NRF_RADIO->EVENTS_READY = 0U;
// Enable radio and wait for ready
NRF_RADIO->TASKS_RXEN = 1U;

while (NRF_RADIO->EVENTS_READY == 0U)
{
    // wait
}
NRF_RADIO->EVENTS_END = 0U;
// Start listening and wait for address received event
NRF_RADIO->TASKS_START = 1U;

// Wait for end of packet or buttons state changed
while (NRF_RADIO->EVENTS_END == 0U)
{
    // wait
}

if (NRF_RADIO->CRCSTATUS == 1U)
{
    result = 0;
}
NRF_RADIO->EVENTS_DISABLED = 0U;
// Disable radio
NRF_RADIO->TASKS_DISABLE = 1U;

while (NRF_RADIO->EVENTS_DISABLED == 0U)
{
    // wait
}
 

5. Handling the packet:
if (NRF_RADIO->EVENTS_CTEPRESENT)
{
    NRF_RADIO->EVENTS_CTEPRESENT = 0;

    for (uint8_t i = 0; i < 4; i++)
    {
        UART_Instance.Printf("I and Q;");
        UART_Instance.Printf("%d;%d;\r\n", DFE_Packet[i].I, DFE_Packet[i].Q);
    }
}

Why the resulting IQ samples look like random values?

Parents
  • Hi

    I didn't spot anything looking at your code snippets, but there are a few things to look out for. First off, using only 4 antennas are not great to get very accurate data, but I agree that it should yield better results than what you get here. Are you sure that the antenna switching and time between each IQ packet matches, so that it's getting picked up correctly. What kind of device is the advertising device, is it an nRF52833 DK for instance or a cusotm board?

    In what kind of environment are you testing this application? If you're in an office environment with a lot of BLE devices you might have some interference issues. Also, how are the boards positioned compared to one another?

    I would suggest checking out the direction finding example projects in the nRFConnect SDK for reference. Locator can be found here, and transmitter here.

    Best regards,

    Simon

Reply
  • Hi

    I didn't spot anything looking at your code snippets, but there are a few things to look out for. First off, using only 4 antennas are not great to get very accurate data, but I agree that it should yield better results than what you get here. Are you sure that the antenna switching and time between each IQ packet matches, so that it's getting picked up correctly. What kind of device is the advertising device, is it an nRF52833 DK for instance or a cusotm board?

    In what kind of environment are you testing this application? If you're in an office environment with a lot of BLE devices you might have some interference issues. Also, how are the boards positioned compared to one another?

    I would suggest checking out the direction finding example projects in the nRFConnect SDK for reference. Locator can be found here, and transmitter here.

    Best regards,

    Simon

Children
  • Thank you for reply!

    Are you sure that the antenna switching and time between each IQ packet matches, so that it's getting picked up correctly.

    How can i check it correctly?

    What kind of device is the advertising device, is it an nRF52833 DK for instance or a cusotm board?

    It is a custom board on NRF52811.

    In what kind of environment are you testing this application? If you're in an office environment with a lot of BLE devices you might have some interference issues. Also, how are the boards positioned compared to one another?

    The IQ samples given here were received with only one BLE device.

    Also, how are the boards positioned compared to one another?

    The boards were positioned as follows:

    I would suggest checking out the direction finding example projects in the nRFConnect SDK for reference. Locator can be found here, and transmitter here.

    Can I run this examples on NRF52811? I have tried to run the transmitter example by selecting ubx_bmd360eval_nrf52811 board and by using "CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y" option, but it did not work

Related