I am developing a NIR (Near-Infrared) product using nRF52810.
I use 15.3 for SDK and S112 for Softdevice.
I implemented ADC (saadc) function based on ble_app_uart.
I have to read 2 ADC channels at 62.5KHz (16usec) for NIR measurement.
I made a test code and tried it out.
However, if nrf_drv_saadc_sample () is called 100 times in 62.5KHz (16usec), saadc_callback (nrf_drv_saadc_evt_t const * p_event) is rarely performed.
If nrf_drv_saadc_sample () is called 100 times in approximately 1KHz (1,000 usec) units, saadc_callback (nrf_drv_saadc_evt_t const * p_event) is performed 100 times.
As a result of my measurement test, the maximum sampling rate for ADC 2 channels is 1KHz (1,000usec).
That is, the maximum sampling rate is too slow for NIR measurement.
Looking at the nRF52810 datasheet, the SAADC Maximum sampling rate is 200KHz.
How can I read ADC 2channel in 62.5KHz (16usec) unit?
My test code is here.
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "app_util_platform.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nir_meas.h"
#define SAMPLES_IN_BUFFER 2
volatile uint8_t state = 1;
static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(1);
static nrf_saadc_value_t m_buffer_pool[2][SAMPLES_IN_BUFFER];
#define TEST_NUM 100
static uint16_t data_mv[TEST_NUM][2] = {0,};
static uint8_t count_num = 0;
static uint8_t cnt_cnt = 0;
void timer_handler(nrf_timer_event_t event_type, void * p_context)
{
if(count_num < TEST_NUM) {
APP_ERROR_CHECK(nrf_drv_saadc_sample());
count_num ++;
} else if(count_num >= TEST_NUM) {
nrf_drv_timer_disable(&m_timer);
}
}
void saadc_sampling_event_init(void)
{
ret_code_t err_code;
nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_handler);
APP_ERROR_CHECK(err_code);
/* setup m_timer for compare event every xxxms */
uint32_t ticks = nrf_drv_timer_us_to_ticks(&m_timer, 1000);
nrf_drv_timer_extended_compare(&m_timer,
NRF_TIMER_CC_CHANNEL0,
ticks,
NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
true);
nrf_drv_timer_enable(&m_timer);
}
void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
cnt_cnt++;
if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
{
ret_code_t err_code;
err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
data_mv[count_num][0] = p_event->data.done.p_buffer[0] * 3600 / 1024;
data_mv[count_num][1] = p_event->data.done.p_buffer[1] * 3600 / 1024;
printf("<%d> %d mV\r\n", count_num, data_mv[count_num][0]);
printf("<%d> %d mV\r\n", count_num, data_mv[count_num][1]);
}
printf("-<%d>- \r\n", cnt_cnt);
}
void saadc_init(void)
{
ret_code_t err_code;
nrf_saadc_channel_config_t channel_0_config =
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0);
nrf_saadc_channel_config_t channel_1_config =
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN1);
err_code = nrf_drv_saadc_init(NULL, 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_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
}
In the code above, I set TIMER to 1,000usec.
When timer_handler is called 100 times (count_num = 100), saadc_callback (cnt_cnt = 100). It is OK.
So, as a result of my testing, the maximum sampling rate is 1KHz.
Set TIMER to 1000usec or less,
If timer_handler is called 100 times (count_num = 100), saadc_callback is executed 80-90 times.
(cnt_cnt <100).
Additional comments:
Ultimately, I want to use a method to call nrf_drv_saadc_sample () through an external interrupt input pin in 62.5KHz.
So the timer routine in the current code is also using the method to call nrf_drv_saadc_sample ().
Thank you.