NRF52810 SAADC buffer swap

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);

}

Parents
  • Hi!

    I had a quick look at the code.

    In saadc_init(), I see you have:

        // 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);
    

    Try this instead:

        // double buffering
        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);
    

  • Hi Sigurd
    I appreciate your prompt reply.

    I fixed the problem you pointed out.
    It now works properly.


    The cause was that this location remained as it was in the sample program.
    Incidentally, the fact that the data was stored correctly four at a time from cycles 18 to 22 onwards only seemed that way, but does that mean that there could have been a shift at some point?

Reply
  • Hi Sigurd
    I appreciate your prompt reply.

    I fixed the problem you pointed out.
    It now works properly.


    The cause was that this location remained as it was in the sample program.
    Incidentally, the fact that the data was stored correctly four at a time from cycles 18 to 22 onwards only seemed that way, but does that mean that there could have been a shift at some point?

Children
No Data
Related