Hello.
I am developing in the following environment.
・nrf52810 custom board
・nRF5 SDK v17.1.0
I am running the SAADC Scan mode to collect data from four analog channels.
SAADC is running at 10msec intervals.
When I start acquiring data, p_event->data.done.size is set to 1 when the first and second NRF_DRV_SAADC_EVT_DONE occurs.
After that, the data storage position is shifted for about 18 to 22 cycles.
If I continue to collect data beyond that, the data will be stored in the correct position.
Do you know the reason for the initial data shift?
This program also uses PPI for PWM control.
Thanks.
Part of main.c
#include <stdint.h>
#include <string.h>
#include "app_error.h"
#include "app_timer.h"
#include "flash.h"
#include "ble_ctrl.h"
#include "state.h"
#include "nordic_common.h"
#include "nrf.h"
#include "if.h"
#include "nrf_drv_gpiote.h"
#include "ad_ctrl.h"
#include "app_error.h"
#include "nrf_drv_clock.h"
#include "pwm_ctrl.h"
#include "ctrl_temp.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
static void cpu_init(void);
static void log_init(void);
static void timers_init(void);
static void gpio_init(void);
static void wdt_init(void);
static void routine_timer_start(void);
APP_TIMER_DEF(m_routine_timer_id); /**< Routine timer.(Real Time Counter) */
static unsigned char suc_routineflag;
#define WDT_RESTART() NRF_WDT->RR[0] = WDT_RR_RR_Reload /**< WDT Reload */
#define ROUTINE_TIMER_INTERVAL APP_TIMER_TICKS(10) /**< routine interval (ticks). */
int main(void)
{
bool erase_bonds;
cpu_init(); //
routine_timer_start();
for (;;)
{
WDT_RESTART();
flash_ctrl();
if(suc_routineflag == FLAG_ON){
suc_routineflag = FLAG_OFF;
state_Activity();
}
}
}
/**
***************************************************************************************************
* @brief CPU Modules initialization function
* @details Initialize CPU Modules
**************************************************************************************************/
static void cpu_init(void)
{
// 変数初期化
suc_routineflag = FLAG_ON;
// log init
log_init();
// Port init
gpio_init();
// RealTimeCounter init
timers_init();
// saadc init
saadc_init();
saadc_sampling_event_init();
flash_init();
pwm_init();
initTargetTemp();
state_init();
wdt_init();
}
static void log_init(void)
{
ret_code_t err_code = NRF_LOG_INIT(NULL);
APP_ERROR_CHECK(err_code);
//NRF_LOG_DEFAULT_BACKENDS_INIT();
}
static void routine_timeout_handler(void * p_context)
{
suc_routineflag = FLAG_ON;
}
static void timers_init(void)
{
// LFCLK start
nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART);
// Initialize timer module.
ret_code_t err_code = app_timer_init();
APP_ERROR_CHECK(err_code);
// Create timers.
err_code = app_timer_create(&m_routine_timer_id,
APP_TIMER_MODE_REPEATED,
routine_timeout_handler);
APP_ERROR_CHECK(err_code);
}
static void routine_timer_start(void)
{
ret_code_t err_code;
// Start application timers.
err_code = app_timer_start(m_routine_timer_id, ROUTINE_TIMER_INTERVAL, NULL);
APP_ERROR_CHECK(err_code);
}
static void gpio_init(void)
{
// erase
}
static void wdt_init(void)
{
NRF_WDT->CONFIG = (WDT_CONFIG_HALT_Pause << WDT_CONFIG_HALT_Pos) | (WDT_CONFIG_SLEEP_Pause << WDT_CONFIG_SLEEP_Pos);
NRF_WDT->CRV = 10 * 32768; // 10sec
NRF_WDT->RREN |= WDT_RREN_RR0_Msk; // Enable reload register 0
NRF_WDT->TASKS_START = 1;
}
Part of ad_ctrl.c
#define SAMPLES_IN_BUFFER 4 // data num
#define SAMPLING_MS 10 // sampling cycle
#define AVERAGE_NUM 10 // average count
static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(2); // used TIMER2
static nrf_saadc_value_t m_buffer_pool[2][SAMPLES_IN_BUFFER];
static nrf_ppi_channel_t m_ppi_adc_channel;
static nrf_ppi_channel_t m_ppi_adcbuf_channel;
static uint32_t m_adc_get_counter;
static uint8_t m_adc_setidx;
static uint16_t m_adc_avarage_pool[AVERAGE_NUM][SAMPLES_IN_BUFFER];
static uint16_t m_adc_data_pool[300][3];
static uint16_t m_adc_getidx;
void saadc_sampling_event_init(void)
{
ret_code_t err_code;
// PPI init
err_code = nrf_drv_ppi_init();
APP_ERROR_CHECK(err_code);
// Timer init
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);
// Timer event Setting
uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, SAMPLING_MS); // 10msをticksに変換する
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); // timerの有効化
// Timer event address get
uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer,
NRF_TIMER_CC_CHANNEL0);
// SAADC event address get
uint32_t saadc_sample_task_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_adc_channel);
APP_ERROR_CHECK(err_code);
//
err_code = nrf_drv_ppi_channel_assign(m_ppi_adc_channel,
timer_compare_event_addr,
saadc_sample_task_addr);
APP_ERROR_CHECK(err_code);
// counterplan(buffer swap)
err_code = nrf_drv_ppi_channel_alloc(&m_ppi_adcbuf_channel);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_enable(m_ppi_adcbuf_channel);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_assign(m_ppi_adcbuf_channel,
nrf_saadc_event_address_get(NRF_SAADC_EVENT_END),
nrf_saadc_task_address_get(NRF_SAADC_TASK_START));
APP_ERROR_CHECK(err_code);
}
void saadc_sampling_event_enable(void)
{
ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_adc_channel);
APP_ERROR_CHECK(err_code);
}
void saadc_sampling_event_disable(void)
{
ret_code_t err_code = nrf_drv_ppi_channel_disable(m_ppi_adc_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)
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);
int i;
NRF_LOG_INFO("ADC event number: %d ,", (int)m_adc_get_counter);
for (i = 0; i < SAMPLES_IN_BUFFER; i++)
{
NRF_LOG_INFO("%d", p_event->data.done.p_buffer[i]);
m_adc_avarage_pool[m_adc_setidx][i] = p_event->data.done.p_buffer[i];
}
if(m_adc_setidx == AVERAGE_NUM - 1){
m_adc_setidx = 0;
}
else{
m_adc_setidx++;
}
if(m_adc_get_counter < 10000){
m_adc_get_counter++;
}
}
}
void saadc_init(void)
{
// input channnel setting
ret_code_t err_code;
nrf_saadc_channel_config_t channel_config0 =
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(TH_PELTIER_SIDEA);
nrf_saadc_channel_config_t channel_config1 =
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(TH_PELTIER_SIDEB);
nrf_saadc_channel_config_t channel_config2 =
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(TH_SUBSTRATE);
nrf_saadc_channel_config_t channel_config3 =
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(INPUT_VOLTAGE);
// init
err_code = nrf_drv_saadc_init(NULL, saadc_callback);
APP_ERROR_CHECK(err_code);
// channel setting
err_code = nrf_drv_saadc_channel_init(0, &channel_config0);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_channel_init(1, &channel_config1);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_channel_init(2, &channel_config2);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_channel_init(3, &channel_config3);
APP_ERROR_CHECK(err_code);
// double buffering
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], 1);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], 1);
APP_ERROR_CHECK(err_code);
}