This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

nRF Connect SDK - fast RSSI sampling maybe via nrfxlib

Hi,

I would like to port an existing contiki-ng code to nRF Connect SDK. Within this code, I need to sample the 2.4GHz radio RSSI value around 50000 times in a short time. My first try was by using the nrf_802154.h library from nrfxlib. Please find below the code and prj.conf.

main.c

#include <zephyr.h>
#include <stdio.h>
#include <stdbool.h>
#include <nrf_802154.h>

#define CHANNEL 26

int init_radio_to_channel(uint8_t channel)
{
	if (false == nrf_802154_receive())
	{
		printf("Failed to change radio state\n");
		return -1;
	}

	nrf_802154_channel_set(channel);

	printf("Successfully enabled the radio and changed channel to %d\n", channel);
	return 0;
}

void main(void)
{
	if (init_radio_to_channel(CHANNEL))
	{
		return;
	}

	int64_t timer_full = k_uptime_get();
	int8_t rssi = 0;
	uint32_t idx = 0;
	while (idx < 50000)
	{
		if (false == nrf_802154_rssi_measure_begin())
		{
			printf("Failed to measure rssi value\n");
			continue;
		}
		rssi = nrf_802154_rssi_last_get();
		idx++;
	}
	printf("Loop iteration count: %d -> consumed time(ms): %lld\n", idx, k_uptime_delta(&timer_full));
}

prj.con

CONFIG_NRF_802154_RADIO_DRIVER=y
CONFIG_NRF_802154_SOURCE_HAL_NORDIC=y

The code works fine, but it's to slow for my usecase.

We can observe an significant difference by comparing contiki-ng and ncs code.

I main, 735 to 9ms is something. Both codes where flashed to the same nrf52840-dk with an constant jammer next to it. The jammer simply spams the same channel constantly. So both codes were run in the same physical environment.

# Zephyr ncs
*** Booting Zephyr OS build v2.7.0-ncs1  ***
Successfully enabled the radio and changed channel to 26
Loop iteration count: 50000 -> consumed time(ms): 735

# Contiki-ng
[INFO: Main      ] Starting Contiki-NG-release
....
Loop iteration count: 50000 -> consumed time(ms): 90

Just for reference here the contiki-ng code.

PROCESS_THREAD(simple_rssi_sampler, ev, data)
{
        PROCESS_BEGIN();
        NETSTACK_MAC.off();
        NETSTACK_RADIO.on();

        if (NETSTACK_RADIO.set_value(RADIO_PARAM_CHANNEL, 26) != RADIO_RESULT_OK)
        {
                printf("ERROR: failed to change radio channel\n");
                return -1;
        }

        rtimer_clock_t timer_full = RTIMER_NOW();
        int rssi = 0;
        uint32_t idx = 0;
        while (idx < 50000)
        {
                if (NETSTACK_RADIO.get_value(RADIO_PARAM_RSSI, &rssi) != RADIO_RESULT_OK)
                {
                        printf("Failed to fetch RSSI value");
                }
                idx++;
        }
        printf("Loop iteration count: %ld -> consumed time(ms): %ld\n", idx, (RTIMER_NOW() - timer_full) * 1000 / RTIMER_SECOND);
        PROCESS_END();
}

 After some resource, it seems like contiki is build upon the nRF5 SDK.

---

Now my question. Is there a faster way to read the RSSI value?

Maybe via the hal (hardware abstraction layer) from nrfxlib, ./modules/hal/nordic/nrfx/hal/nrf_radio.h looks quite promising. At least it looks similar to the nRF5 SDK used by contiki-ng. However, I have not really an idea how to start.

Are there maybe some example codes how to use it?

Regards,

Andreas

Parents
  • Hi Andreas

    If I understand you correctly the ncs code allows you to sample the RSSI 50000 times in 735ms?

    This matches pretty well with the RSSI settling time, which is 15us as documented here.

    735ms / 50000 =  14.7us

    There is no gain in sampling the RSSI faster than the sampling time, since the RSSI value is filtered and will not change fast enough to provide any additional information. 

    I am not sure where your requirement of sampling the RSSI 50000 times comes from, but if you reduce the number of samples so that the total time is similar the end result should be the same. 

    Best regards
    Torbjørn

  • Hi Torbjørn,

    thank you very much for this hint. Just to get everything right, do we need to wait for this specific settle time before reading each RSSI value or just if the value has changed?

    If we have a look into the nrf802154 source code, I can observer the wait here nrf_802154_trx.c#L1101. However, this wait get's only executed if we have received a frame beforehand.

    This is not the case in my example code and using an constant jammer sending some garbage. Therefore, the wait is only executed ones, exactly for the first package (tested via a printf).

    So my question has changed to: Are we able to read RSSI values faster than this settle time or not?

    Regards

    Andi

Reply
  • Hi Torbjørn,

    thank you very much for this hint. Just to get everything right, do we need to wait for this specific settle time before reading each RSSI value or just if the value has changed?

    If we have a look into the nrf802154 source code, I can observer the wait here nrf_802154_trx.c#L1101. However, this wait get's only executed if we have received a frame beforehand.

    This is not the case in my example code and using an constant jammer sending some garbage. Therefore, the wait is only executed ones, exactly for the first package (tested via a printf).

    So my question has changed to: Are we able to read RSSI values faster than this settle time or not?

    Regards

    Andi

Children
  • Hi Andi

    I discussed this with the developer, and apparently there is no way to read the RSSI faster through the library. 

    You could bypass the library altogether, and read the RSSI through the registers:

    1) Clear the RSSIEND event
    2) Trigger the RSSISTART task
    3) Wait for the RSSIEND event to be set
    4) Read the RSSI from the RSSISAMPLE register

    This is a bit of a dirty hack though. Also, I still don't see the point of oversampling a filtered signal. Essentially you are just burning through CPU cycles and power to sample a bit of extra noise. 

    Best regards
    Torbjørn

  • Hi Torbjørn,

    it's hilarious, but I am not even sure if I need such a fast sampling rate. Normally the 14.7us should be sufficient. 

    However, the exiting code does the sampling in such a way, so I have just searched for a way to port it 1:1 before optimizing it. I have exactly turned your suggestion into code, please find below the snipped. By using this function we can sample the 50000 values within 69ms.

    #include <hal/nrf_radio.h>
    #include <mdk/nrf52840.h>
    
    int8_t nrf_hal_get_rssi(void)
    {
    	nrf_radio_event_clear(NRF_RADIO, NRF_RADIO_EVENT_RSSIEND);
    	nrf_radio_task_trigger(NRF_RADIO, NRF_RADIO_TASK_RSSISTART);
    	while (!nrf_radio_event_check(NRF_RADIO, NRF_RADIO_EVENT_RSSIEND))
    	{
    	}
    
    	uint8_t rssi_sample = nrf_radio_rssi_sample_get(NRF_RADIO);
    	return -((int8_t)rssi_sample);
    }

    Sorry, but I am not so deep in this domain yet. If I checkout your proposed documentation here, I would conclude, that a new RSSI value would be ready for reading after triggering RSSI_START and waiting (0.25us) RSSIPERIOD time. Because this is what the description of RSSIPERIOD states.

    Therefore, I am still not sure what the RSSISETTLE refers to. Can we only expect changes in the read RSSI value after this amount of time (15us)? Argo, the sample code above would always read the same value until the 15us are passed?

    Please help me to understand the difference between RSSIPERIOD and RSSISETTLE .

    Thanks,

    Andi

  • Hi Andi

    Because the RSSI signal is filtered it will take 15us for any change in signal strength seen by the receiver to be fully reflected in the value you read out through the RSSISAMPLE register. 

    Put another way, what you read out of the RSSISAMPLE register is an average of all the RSSI values for the previous 15 microseconds. 

    As an example, say the RSSI level changes abruptly from -80dBm to -60dBm it will take 15us before you read -60dBm out of the RSSISAMPLE register, and if you sample many times before that you will just get a slow ramp between -80dBm and -60dBm (the filtered value). 

    If you later want to average these values then you are essentially doing double work, since the filtering is already averaging the signal, and the averaged result should be the same whether you sample at 15us or faster. 

    If you want to get an accurate estimate of how the RSSI value is changing over time (rather than an average) then sampling faster than 15us doesn't really help either, since you will only be recording the effect of the filter and not the exact RSSI value. 

    Using my example earlier you would see a smooth transition between -80 to -60 dBm over a period of ~15us, while in reality the RSSI changed immediately. 

    The reason the RSSI period is shorter is that it is useful not to be forced to wait 15us every time you sample the RSSI, but if you already did an RSSI sampling less than 15us prior then you will only be reading out a mix of the old value and the new. 

    Best regards
    Torbjørn

Related