This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
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

High Sample Rate with ADC and SoftDevice

I am trying to sample the ADC every 2ms. I notice lots of slowness with BLE advertising and typically can't connect to device over BLE when sampling. I am using PPI, configuring, and starting before the softdevice is enabled.

  1. Should nRF51822 be capable of reading ADC every 1ms to 2ms reliably?

  2. Should I move all the PPI configuration to after the softdevice is enabled and be using the sd_ppi functions?


Edit: Headline, format, added tags.

  • Why do you need to read ADC value every 1ms? Sounds overkill. It should not change between couple of minutes or more. And what tasks do you do in the ADC interrupt? The typicals SDK examples send the new battery level through ble_bas service notification. But if you are still in advertising mode, it should take a lot of time for anything.

  • Hi Chris

    I have attached an adc example which samples voltage on an input pin while the S110 softdevice is enabled. You should be aware of that you need to set the priority of the ADC interrupt explicitly to LOW. Also, PPI channels 8-15 are blocked by the softdevice, as stated in table 6 in the S110 Softdevice Specification v1.1, so using them for the application will cause conflicts with the softdevice. Use only PPI channels 0-7 for the application.

    You should also be aware of that during BLE transmission, the CPU will be blocked, therefore limiting the sampling frequency of the ADC. The ADC itself will be able to process up to 50k samples per second but the CPU will be blocked for ca 0.8 - 6.0 ms when the softdevice is enabled, depending on the amount of data you are sending over the BLE link.

    Table 12 in the S110_Softdevice_Specification_v1.1 states that throughput is up to 120kpbs for sending data from a client. However, when you send 32-40 kbps you would have to select 7.5ms connection interval and send 2 packets per connection interval. The CPU will be blocked for the whole transmission time of the 2 packets and that will block the CPU for about 1.6 ms. Sampling with 1kHz will not work because the ADC only buffers one sample and overwrites it when sampling again. The CPU is simply not available to process the ADC data every 1 millisecond.

    Table 10 in the S110_Softdevice_Specification v1.1 indicates how long the CPU is blocked in respect to what you are sending many packets in each connection interval. The thing is that the length of the blocking period also depends on several factors:

    The CPU blocking time in table 10 is therefore not very accurate because you really need to know the value of the above parameters, so the table is more of an estimate. However, when you want to obtain the shortest CPU blocking period of the softdevice you should set connection interval to 7.5ms, slave latency to zero and transfer as few packets as possible in each connection interval.

    When connection interval is 7.5ms the master and slave 32kHz clock accuracy has very little effect on the lenght of the CPU blocking period. However, it has great effect when connection interval is e.g. 4000 ms and/or when slave latency is high.

    So, to be brief, if you send or receive only one packet per connection interval, you should be able to process ADC samples with 1kHz frequency, given that you choose connection interval of 7,5ms and no slave latency. However, if you send or receive 2 packets per connection interval, you will most likely need to decrease you sampling frequency to 500 Hz.

    You can configure your PPI channels directly before initializing the softdevice or use the sd_ppi functions if you choose to initialize the PPI channels after you initialize the softdevice. Again, only use PPI channels 0-7 for the application.

  • The sample looks great. One thing I noticed is that your sample is using app_timer, is that any better/worse than using PPI?

  • Also, why do you start and stop the hfclk?

    static void adc_sampling_timeout_handler(void * p_context) { uint32_t p_is_running = 0;

    while(! p_is_running) {  							//wait for the hfclk to be available
    nrf_gpio_pin_toggle(NRF6310_LED_2);		//Toggle LED2 to indicate start of sampling
    NRF_ADC->TASKS_START = 1;							//Start ADC sampling


    void ADC_IRQHandler(void) { /* Clear dataready event */ NRF_ADC->EVENTS_END = 0;

    /* Write ADC result to port 2 */ nrf_gpio_port_write(NRF_GPIO_PORT_SELECT_PORT2, NRF_ADC->RESULT); nrf_gpio_pin_toggle(NRF6310_LED_3);

    //Use the STOP task to save current. Workaround for PAN_028 rev1.5 anomaly 1.


    //Release the external crystal


  • Hi Chris

    The application timers use the RTC1 timer in the background. When using application timers, you need to share your timing with other periodic tasks that are also using application timers. Also, the application timers are setting software interrupts that may introduce latency. For real time sampling it would be best to use TIMER1 or TIMER2 directly with PPI channels to trigger the ADC sampling. You could also use RTC1 directly if you are not enabling the application timers. RTC0 and TIMER0 are blocked by the softdevice.

    It is chosen in this example to use the external 16MHz crystal for the ADC sampling because that will guarantee that the accuracy of the ADC will be within specification. You can use the internal 16MHz RC clock but then the accuracy is no longer guaranteed. The accuracy of the internal RC is much lower than of the crystal. However, when using the external crystal, current consumption will be higher since it takes longer to start up the crystal than the RC, see tables 16 and 18 in the nRF51822 PS v1.3. In short, use the external crystal for maximum accuracy, use the internal RC for lowest current consumption.