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

How to increase the sampling rate of the ble_app_uart__saadc_timer_driven__scan_mode example?

Hi,

in my project I have a custom board with a nRF52832 chip that reads SAADC data and transmits this data (peripheral role). This data is received by a nRF52840-DK board (central role) and written into a COM-Port of a pc. I flashed the "ble_app_uart_c" example into the nRF52840-DK and the "ble_app_uart__saadc_timer_driven__scan_mode" example into the custom board with the nRF52832 chip (nRF5_SDK_17.0.0_9d13099). This configuration works fine. The SAADC data gets transmitted by the nRF52832 custom board, received by the nRF52840-DK and written into the COM-Port of my PC.

My problem is the SAADC sampling rate (SAADC_SAMPLE_RATE) of the "ble_app_uart__saadc_timer_driven__scan_mode" example. By default the SAADC sampling rate is 250ms (4Hz). I need to increase this sampling rate to 1ms (1000Hz). But if I choose the SAADC_SAMPLE_RATE < 10ms (>100Hz) an error occured and the chip resets and tries to reconnect. I receive the following error code if I debug the ble_app_uart__saadc_timer_driven__scan_mode example:

which is produced by the ble_nus_data_send(...) function in main.c:

Unfortunaly, I am not able to find a error description for this error code.

Can you please tell me, how to increase the sampling rate of the "ble_app_uart__saadc_timer_driven__scan_mode" example to 1ms (=1000Hz)?

Parents
  • Hello,

    "ble_app_uart__saadc_timer_driven__scan_mode" example into the custom board with the nRF52832 chip (nRF5_SDK_17.0.0_9d13099).

    I am unfamiliar with this code, what example is this - where did you find this project code?
    Is this code a merge between the saadc peripheral example, modified to sample multiple channels, and the ble_app_uart example?

    My problem is the SAADC sampling rate (SAADC_SAMPLE_RATE) of the "ble_app_uart__saadc_timer_driven__scan_mode" example. By default the SAADC sampling rate is 250ms (4Hz). I need to increase this sampling rate to 1ms (1000Hz).

    Could you share with me the SAADC configuration, and how you are modifying it?
    It would also be good to see how you are using the SAADC - how the timer is set up, etc.
    Please use the "Insert -> Code" option when sharing code here on DevZone.

    I receive the following error code if I debug the ble_app_uart__saadc_timer_driven__scan_mode example:
    Unfortunaly, I am not able to find a error description for this error code.

    Could you ensure that DEBUG is defined in your preprocessor defines?
    The included image shows how you can check this, or add DEBUG if it is missing.
    Please run the program again with DEBUG defined, to see the proper error message.

    Can you please tell me, how to increase the sampling rate of the "ble_app_uart__saadc_timer_driven__scan_mode" example to 1ms (=1000Hz)?

    Yes, depending on your answer to my above question we will get started on changing the sampling rate to 1000 Hz, no problem.

    Looking forward to resolving this issue together,

    Best regards,
    Karl 

Reply
  • Hello,

    "ble_app_uart__saadc_timer_driven__scan_mode" example into the custom board with the nRF52832 chip (nRF5_SDK_17.0.0_9d13099).

    I am unfamiliar with this code, what example is this - where did you find this project code?
    Is this code a merge between the saadc peripheral example, modified to sample multiple channels, and the ble_app_uart example?

    My problem is the SAADC sampling rate (SAADC_SAMPLE_RATE) of the "ble_app_uart__saadc_timer_driven__scan_mode" example. By default the SAADC sampling rate is 250ms (4Hz). I need to increase this sampling rate to 1ms (1000Hz).

    Could you share with me the SAADC configuration, and how you are modifying it?
    It would also be good to see how you are using the SAADC - how the timer is set up, etc.
    Please use the "Insert -> Code" option when sharing code here on DevZone.

    I receive the following error code if I debug the ble_app_uart__saadc_timer_driven__scan_mode example:
    Unfortunaly, I am not able to find a error description for this error code.

    Could you ensure that DEBUG is defined in your preprocessor defines?
    The included image shows how you can check this, or add DEBUG if it is missing.
    Please run the program again with DEBUG defined, to see the proper error message.

    Can you please tell me, how to increase the sampling rate of the "ble_app_uart__saadc_timer_driven__scan_mode" example to 1ms (=1000Hz)?

    Yes, depending on your answer to my above question we will get started on changing the sampling rate to 1000 Hz, no problem.

    Looking forward to resolving this issue together,

    Best regards,
    Karl 

Children
  • Hi,

    thank you so much for your reply.

    1. I found this project code here: 

    https://github.com/NordicPlayground/nRF52-ADC-examples/tree/master/ble_app_uart__saadc_timer_driven__scan_mode

    You are right, this code is a merge between the saadc peripheral example, modified to sample four channels, and the ble_app_uart example.

    2. Here you can see the SAADC configuration in the "ble_app_uart__saadc_timer_driven__scan_mode" example:

    #define SAADC_SAMPLES_IN_BUFFER         4
    #define SAADC_SAMPLE_RATE               250                                         /**< SAADC sample rate in ms. */               
    
    volatile uint8_t state = 1;
    
    static const nrf_drv_timer_t   m_timer = NRF_DRV_TIMER_INSTANCE(3);
    static nrf_saadc_value_t       m_buffer_pool[2][SAADC_SAMPLES_IN_BUFFER];
    static nrf_ppi_channel_t       m_ppi_channel;
    static uint32_t                m_adc_evt_counter;
    
    void timer_handler(nrf_timer_event_t event_type, void* p_context)
    {
    
    }
    
    
    void saadc_sampling_event_init(void)
    {
        ret_code_t err_code;
        err_code = nrf_drv_ppi_init();
        APP_ERROR_CHECK(err_code);
        
        nrf_drv_timer_config_t timer_config = NRF_DRV_TIMER_DEFAULT_CONFIG;
        timer_config.frequency = NRF_TIMER_FREQ_31250Hz;
        err_code = nrf_drv_timer_init(&m_timer, &timer_config, timer_handler);
        APP_ERROR_CHECK(err_code);
    
        /* setup m_timer for compare event */
        uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer,SAADC_SAMPLE_RATE);
        nrf_drv_timer_extended_compare(&m_timer, NRF_TIMER_CC_CHANNEL0, ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);
        nrf_drv_timer_enable(&m_timer);
    
        uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer, NRF_TIMER_CC_CHANNEL0);
        uint32_t saadc_sample_event_addr = nrf_drv_saadc_sample_task_get();
    
        /* setup ppi channel so that timer compare event is triggering sample task in SAADC */
        err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
        APP_ERROR_CHECK(err_code);
        
        err_code = nrf_drv_ppi_channel_assign(m_ppi_channel, timer_compare_event_addr, saadc_sample_event_addr);
        APP_ERROR_CHECK(err_code);
    }
    
    
    void saadc_sampling_event_enable(void)
    {
        ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);
        APP_ERROR_CHECK(err_code);
    }
    
    
    void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
    {
        if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
        {
            ret_code_t err_code;
            uint16_t adc_value;
            uint8_t value[SAADC_SAMPLES_IN_BUFFER*2];
            uint16_t bytes_to_send;
         
            // set buffers
            err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAADC_SAMPLES_IN_BUFFER);
            APP_ERROR_CHECK(err_code);
    						
            // print samples on hardware UART and parse data for BLE transmission
            printf("ADC event number: %d\r\n",(int)m_adc_evt_counter);
            for (int i = 0; i < SAADC_SAMPLES_IN_BUFFER; i++)
            {
                printf("%d\r\n", p_event->data.done.p_buffer[i]);
    
                adc_value = p_event->data.done.p_buffer[i];
                value[i*2] = adc_value;
                value[(i*2)+1] = adc_value >> 8;
            }
    
             // Send data over BLE via NUS service. Create string from samples and send string with correct length.
            uint8_t nus_string[50];
            bytes_to_send = sprintf(nus_string, 
                                    "CH0: %d\r\nCH1: %d\r\nCH2: %d\r\nCH3: %d",
                                    p_event->data.done.p_buffer[0],
                                    p_event->data.done.p_buffer[1],
                                    p_event->data.done.p_buffer[2],
                                    p_event->data.done.p_buffer[3]);
    
            err_code = ble_nus_data_send(&m_nus, nus_string, &bytes_to_send, m_conn_handle);
            if ((err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_ERROR_NOT_FOUND))
            {
                APP_ERROR_CHECK(err_code);
            }
    	
            m_adc_evt_counter++;
        }
    }
    
    
    void saadc_init(void)
    {
        ret_code_t err_code;
    	
        nrf_drv_saadc_config_t saadc_config = NRF_DRV_SAADC_DEFAULT_CONFIG;
        saadc_config.resolution = NRF_SAADC_RESOLUTION_12BIT;
    	
        nrf_saadc_channel_config_t channel_0_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4);
        channel_0_config.gain = NRF_SAADC_GAIN1_4;
        channel_0_config.reference = NRF_SAADC_REFERENCE_VDD4;
    	
        nrf_saadc_channel_config_t channel_1_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN5);
        channel_1_config.gain = NRF_SAADC_GAIN1_4;
        channel_1_config.reference = NRF_SAADC_REFERENCE_VDD4;
    	
        nrf_saadc_channel_config_t channel_2_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN6);
        channel_2_config.gain = NRF_SAADC_GAIN1_4;
        channel_2_config.reference = NRF_SAADC_REFERENCE_VDD4;
    	
        nrf_saadc_channel_config_t channel_3_config =
            NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7);
        channel_3_config.gain = NRF_SAADC_GAIN1_4;
        channel_3_config.reference = NRF_SAADC_REFERENCE_VDD4;				
    	
        err_code = nrf_drv_saadc_init(&saadc_config, saadc_callback);
        APP_ERROR_CHECK(err_code);
    
        err_code = nrf_drv_saadc_channel_init(0, &channel_0_config);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_channel_init(1, &channel_1_config);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_channel_init(2, &channel_2_config);
        APP_ERROR_CHECK(err_code);
        err_code = nrf_drv_saadc_channel_init(3, &channel_3_config);
        APP_ERROR_CHECK(err_code);	
    
        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);
    }
    
    /**@brief Application main function.
     */
    int main(void)
    {
        bool erase_bonds;
    
        // Initialize.
        uart_init();
        log_init();
        timers_init();
        buttons_leds_init(&erase_bonds);
        power_management_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        services_init();
        advertising_init();
        conn_params_init();
    
        saadc_sampling_event_init();
        saadc_init();
        saadc_sampling_event_enable();
    
        // Start execution.
        printf("\r\nUART started.\r\n");
        NRF_LOG_INFO("Debug logging for UART over RTT started.");
        advertising_start();
    
        // Enter main loop.
        for (;;)
        {
            idle_state_handle();
        }
    }

    I tried to modify the SAADC_SAMPLE_RATE to 1. If I set the SAADC_SAMPLE_RATE to 1, I receive the error which I already mentioned.

    3. Where can I find your included image for checking or adding DEBUG? How can I ensure that DEBUG is defined in my preprocessor defines?

    Thank you in advance.

  • Michael01101 said:
    thank you so much for your reply.

    No problem at all, I am happy to help!

    Michael01101 said:

    1. I found this project code here: 

    https://github.com/NordicPlayground/nRF52-ADC-examples/tree/master/ble_app_uart__saadc_timer_driven__scan_mode

    You are right, this code is a merge between the saadc peripheral example, modified to sample four channels, and the ble_app_uart example.



    Thank you for confirming this and for sharing your configuration. 

    Michael01101 said:
    3. Where can I find your included image for checking or adding DEBUG? How can I ensure that DEBUG is defined in my preprocessor defines?

    My apologies, it seems like my upload in the previous comment failed. I have updated my previous comment to contain the picture now.
    With DEBUG enabled the generated error will be output to the logging module. It will be very helpful to see this error code and where it is generated, to resolve your issue.

    Best regards,
    Karl

  • Hi,

    thank you for your fast reply.

    I ran the program with the modified SAADC_SAMPLING_RATE (set to 1ms) again. This time with DEBUG defined. I receive the following error in the debug terminal:

    <info> app: Debug logging for UART over RTT started.
    <info> app: Connected
    <info> app: Data len is set to 0xF4(244)
    <error> app: ERROR 19 [NRF_ERROR_RESOURCES] at C:\SDK\SDKv17\nRF5_SDK_17.0.0_9d13099\examples\ble_peripheral\ble_app_uart__saadc_timer_driven__scan_mode_second\main.c:784
    PC at: 0x0002A417
    <error> app: End of error report
    It looks like that error gets produced by the ble_nus_data_send(...) function. Line 784 equals the line with the APP_ERROR_CHECK(...) in main.c:

            err_code = ble_nus_data_send(&m_nus, nus_string, &bytes_to_send, m_conn_handle);
            if ((err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_ERROR_NOT_FOUND))
            {
                APP_ERROR_CHECK(err_code);
            }

    Can you please explain to me, why the ble_nus_data_send(...) function, for sending data over BLE via NUS service, can´t handle the increased data rate?

    Do you have any suggestions how to solve this issue?

    Thank you in advance.

  • Michael01101 said:
    I ran the program with the modified SAADC_SAMPLING_RATE (set to 1ms) again. This time with DEBUG defined. I receive the following error in the debug terminal:

    Fantastic, this makes the issue a lot easier to resolve.

    Michael01101 said:
    It looks like that error gets produced by the ble_nus_data_send(...) function. Line 784 equals the line with the APP_ERROR_CHECK(...) in main.c:
    Michael01101 said:
    Can you please explain to me, why the ble_nus_data_send(...) function, for sending data over BLE via NUS service, can´t handle the increased data rate?

    Looking into the ble_nus_data_send function from the SDK/components/ble/ble_services/ble_nus/ble_nus.c file, we see that it returns the error code from sd_ble_gatts_hvx.
    Looking at the API Reference documentation for sd_ble_gatts_hvx we see that the NRF_ERROR_RESOURCES is generated when too many notifications are queued - i.e the frequency of calls to sd_ble_gatts_hvx is too high.
    This makes sense if you are trying to push a new notification every 1 ms, with the connection interval specified in the unmodified example ( 20 - 75 ms ).
    So, to resolve this issue, I would suggest either lowering your connection intreval to 7.5 ms ( if it is important that the SAADC readings are sent as fast as possible ), and averaging the measurements over >= 8 readings, to make sure that a new accurate reading is sent to the central every connection interval.

    Could you make these changes, and see if it resolves your issue?

    Best regards,
    Karl

  • Hi,

    thank you for your response.

    I made your recommended changes and it works.

    Unfortunaly, averaging the SAADC values is no option for my project. For my project all four channels must be sampled with 1ms (1000Hz) and transmitted without averaging of the measurements.

    It looks like that the maximum string length of the ble_nus_data_send() function is 20bytes. This data rate is to low for my project.

    1. Is there a way to increase the maximum string length of the ble_nus_data_send() function to increase the data rate for sending data over BLE via NUS service?

    2. Do you have any suggestions how to solve this issue?

    Thank you so much in advance.

Related