This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Configuring ADC sampling rate and simultaneous reading from multiple channels.

Hi, guys! I'm using the nRF52 SDK 15.3 BLE_APP_UART peripheral example.

I wish to add 3 ADC channels (12-bit) to read 3 potentiometers at a sampling frequency of 6kHz.

When I tried the timer interrupt, I think I can generate a timer interrupt which is millisecond range.

Can I ask these;

0. Can I set a timer to sample analog value at 6kHz? Or due to the spec (SoftDevice, BLE, etc), is this not possible?

1. I'm using 3 channels (A0, A1, A2). Is there a way to read all 3 simultaneously? I don't want to read A0 -> A1 -> A2.

2. After reading it, I wish to send these values using NUS (Nordic UART service) to the central.

I think the TX buffer will not be empty if I send these after each ADC readings.

In the past, I used the TX complete BLE event to send multiple data. From SDK 15, how can I send these chunk of data?

3. Do you think using a different BLE service would be better instead of using NUS?

THanks for the help

  • Hi,

    0. You can set a timer to sample analog values up to the maximum sample rate of the SAADC (200 ksps). The SAADC peripheral support EasyDMA, which allows you to sample directly to RAM without CPU being involved. You will have to make sure that you have enough CPU availability to process the samples and setup new buffers.

    1. You can not read all 3 simultaneously, the nRF52 series ICs only have a single SAADC, with 8 muxed inputs. You can setup multiple channels that is sampled sequentially, by a single trigger of the SAMPLE task. This is called SCAN mode, and will sample the lowest channel first, then second lowest, and so on.

    2. Depending on the configuration of the BLE link and how often you send data, you might face issues sending the data over BLE. You will not be able to send the samples at each sample interval, but if you send larger buffers, you could be able to send all samples. With 6 kHz sample rate and 3 channels, you will need a throughput of 6000 samples * 3 channels * 16 bits = 288 kbit/s. See the softdevice specifications for more details on throughput.

    3. NUS will give you the same throughput as any other GATT service, it is just sending bytes using notifications. Just make sure that you send the samples as binary data and not convert it to strings.

    If you have not already seen it, I would recommend having a look at this examples, that basically does what you are looking for. There is also a branch for SDK 15.2.0 support, but this have not yet been fully tested.

    Best regards,
    Jørgen

  • Thanks for providing the "ble_app_uart__saadc_timer_driven__scan_mode example" example, Jørgen!

    I haven't noticed this example.

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #define SAADC_SAMPLES_IN_BUFFER 4
    #define SAADC_SAMPLE_RATE 250 /**< SAADC sample rate in ms. */
    // ...
    timer_config.frequency = NRF_TIMER_FREQ_31250Hz;
    // ...
    nrf_saadc_channel_config_t channel_0_config =
    NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4);
    // ...
    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0],SAADC_SAMPLES_IN_BUFFER);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1],SAADC_SAMPLES_IN_BUFFER);
    APP_ERROR_CHECK(err_code);
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    Then,

    0. . Is this example configuring input AIN4, AIN5, AIN6, AIN7 for reading the ADC and is the reading order 4-5-6-7?

    1.

    This is called SCAN mode, and will sample the lowest channel first, then second lowest, and so on.

    Is there a specified time interval value when sampling the next channel from the datasheet?

    (EX. After reading AIN5, the elapsed time for reading the next channel AIN6)

    I just want to see whether that interval is trivial for my case.

    2. In this example, the sampling rate is 4Hz (SAADC_SAMPLE_RATE  = 1 / 250msec)?

    Then, when increasing this up to 6kHz, do I have to modify both SAADC_SAMPLE_RATE and NRF_TIMER_FREQ_31250Hz?

    I'm curious what will be the max value of SAADC_SAMPLE_RATE.

    3. About the "m_buffer_pool[0], [1]", do I have to divide this into 2? I don't understand what this variable's job is.

    4.

    The SAADC peripheral support EasyDMA, which allows you to sample directly to RAM without CPU being involved.

    From the Github example, this doesn't use the EasyDMA, right? What should I add in order to use EasyDMA?

    5.

    You will not be able to send the samples at each sample interval, but if you send larger buffers, you could be able to send all samples.

    Can I ask the meaning of "larger buffers", please? I thought for NUS, the maximum buffer size was 20.

  • 0. Yes, that is correct. However, note that it will sample channel0 - channel1 - channel2 - channel3 regardless of which analog input the channel is configured to sample, for instance you could configure channel0 with input AIN7 and it would still be sampled first.

    1. It will sample next channel as soon as the first channel is done. The sample time will depend on the configured acquisition time.

    2. You only have to change SAADC_SAMPLE_RATE (and change nrf_drv_timer_ms_to_ticks() to nrf_drv_timer_us_to_ticks()), but increasing the timer frequency could be good to get better accuracy in the timer compare register.

    3. The SAADC peripheral support double buffering, allowing you to sample to one buffer while processing the previously filled buffer. You could just as well have used two separate variables.

    4. The SAADC always use EasyDMA to store samples directly in the buffer in RAM.

    5. The NUS example is limited by the BLE configuration. If you increase MTU size and enable DLE, NUS can support more than 20 bytes. Please have a look at this blog post to understand the different parameters.

  • Matthew,

    I am trying to read ADC A0 and trying to send these values using NUS to the central.I am working ith nRF5_SDK_16.0.0_98a08e2. Did you find a suitable example which matches your requirement.

    Thanks.

  • Jorgen,

    Do you have any "ble_app_uart__saadc_timer_driven__scan_mode example" for nRF5_SDK_16.0.0_98a08e2 sdk.

    I have modified the existing example to run with latest sdk but when I run it my program always ends up in a break point condition after log_init(). What's wrong with my code.

    Thanks for your help.

     

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    /**
    * Copyright (c) 2014 - 2019, Nordic Semiconductor ASA
    *
    * All rights reserved.
    *
    * Redistribution and use in source and binary forms, with or without modification,
    * are permitted provided that the following conditions are met:
    *
    * 1. Redistributions of source code must retain the above copyright notice, this
    * list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form, except as embedded into a Nordic
    * Semiconductor ASA integrated circuit in a product or a software update for
    * such product, must reproduce the above copyright notice, this list of
    * conditions and the following disclaimer in the documentation and/or other
    * materials provided with the distribution.
    *
    * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
    * contributors may be used to endorse or promote products derived from this
    * software without specific prior written permission.
    *
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX