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

ADC DMA Readings shift after pausing code or breakpoint nRF52832

Hello,

I am working on a project where I am using 8 ADC channels on the nRF52832.  When I run the code the device seems to get ADC values that look correct.  But, if I pause the device or hit a break point the ADC values seem to be off.  At first when I run the code, the ADC values seem to be in correct memory region, address.  When I pause the code and restart it, it seems as if the ADC readings have move over by two bytes.  Please see the attached images.  I tested this by modifying the analog signal that would be seen on AIN2, and I can see that from the first picture, the values of AIN2 appears to be in the column 3 and changing.  After pausing and restarting the device, the readings for AIN2 appear to be in column 4.

What is going on here?  Can anyone offer any suggestions? 

I am using a nRF52832 in a module from Raytac.

Below is a listing of the code that I used for the ADC values. 

 

// saadc defines
#define SAADC_SAMPLES_IN_BUFFER 256
#define SAADC_SAMPLE_RATE 5


//setup for adc reading of pot
#if (1)

volatile uint8_t state = 1;
float pot1;
float pot2;
float pot3;
float pot4;
float inpin;
float feedpin;
bool adcsampledone = false;
int STEP_COUNT = 50;


uint32_t ADC_AIN0 = 0;
uint32_t ADC_AIN1 = 0; 
uint32_t ADC_AIN2 = 0; 
uint32_t ADC_AIN3 = 0; 
uint32_t ADC_AIN4 = 0; 
uint32_t ADC_AIN5 = 0; 
uint32_t ADC_AIN6 = 0; 
uint32_t ADC_AIN7 = 0;


static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(0);
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) 
{
    adcsampledone = true;
    //gpio024_on();
    //gpio027_on();
    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);

        ADC_AIN0 = 0;
        ADC_AIN1 = 0; 
        ADC_AIN2 = 0; 
        ADC_AIN3 = 0; 
        ADC_AIN4 = 0; 
        ADC_AIN5 = 0; 
        ADC_AIN6 = 0; 
        ADC_AIN7 = 0; 

        for (uint16_t i = 0; i < SAADC_SAMPLES_IN_BUFFER; i++) 
        {
            ADC_AIN0 += p_event->data.done.p_buffer[i++];
            ADC_AIN1 += p_event->data.done.p_buffer[i++];
            ADC_AIN2 += p_event->data.done.p_buffer[i++];
            ADC_AIN3 += p_event->data.done.p_buffer[i++];
            ADC_AIN4  += p_event->data.done.p_buffer[i++];
            ADC_AIN5 += p_event->data.done.p_buffer[i++];
            ADC_AIN6 += p_event->data.done.p_buffer[i++]; 
            ADC_AIN7 += p_event->data.done.p_buffer[i];
        }

        ADC_AIN0 = ADC_AIN0 /(SAADC_SAMPLES_IN_BUFFER/8);
        ADC_AIN1 = ADC_AIN1/(SAADC_SAMPLES_IN_BUFFER/8);
        ADC_AIN2 = ADC_AIN2/(SAADC_SAMPLES_IN_BUFFER/8);
        ADC_AIN3 = ADC_AIN3/(SAADC_SAMPLES_IN_BUFFER/8);
        ADC_AIN4 = ADC_AIN4/(SAADC_SAMPLES_IN_BUFFER/8);
        ADC_AIN5 = ADC_AIN5 /(SAADC_SAMPLES_IN_BUFFER/8);
        ADC_AIN6 = ADC_AIN6/(SAADC_SAMPLES_IN_BUFFER/8);
        ADC_AIN7 = ADC_AIN7/(SAADC_SAMPLES_IN_BUFFER/8);
        m_adc_evt_counter++;
    }
    //gpio024_off();
    //gpio027_off();
}
#endif

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;

    // AIN0 
    nrf_saadc_channel_config_t channel_0_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0);     //NRF_SAADC_INPUT_AIN4);
    channel_0_config.gain = NRF_SAADC_GAIN1_4;
    channel_0_config.reference = NRF_SAADC_REFERENCE_VDD4;

    // AIN1 
    nrf_saadc_channel_config_t channel_1_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN1);    //NRF_SAADC_INPUT_AIN5);
    channel_1_config.gain = NRF_SAADC_GAIN1_4;
    channel_1_config.reference = NRF_SAADC_REFERENCE_VDD4;

    // AIN2 
    nrf_saadc_channel_config_t channel_2_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN2);    //NRF_SAADC_INPUT_AIN6);
    channel_2_config.gain = NRF_SAADC_GAIN1_4;
    channel_2_config.reference = NRF_SAADC_REFERENCE_VDD4;

    // AIN3 
    nrf_saadc_channel_config_t channel_3_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN3);    //NRF_SAADC_INPUT_AIN7);
    channel_3_config.gain = NRF_SAADC_GAIN1_4;
    channel_3_config.reference = NRF_SAADC_REFERENCE_VDD4;

    // AIN4 
    nrf_saadc_channel_config_t channel_4_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN4);    //NRF_SAADC_INPUT_AIN0);
    channel_4_config.gain = NRF_SAADC_GAIN1_4;
    channel_4_config.reference = NRF_SAADC_REFERENCE_VDD4;
    
    // AIN5 
    nrf_saadc_channel_config_t channel_5_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN5);    //NRF_SAADC_INPUT_AIN1);
    channel_5_config.gain = NRF_SAADC_GAIN1_4;
    channel_5_config.reference = NRF_SAADC_REFERENCE_VDD4;

    // AIN6 
    nrf_saadc_channel_config_t channel_6_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN6);    //NRF_SAADC_INPUT_AIN1);
    channel_6_config.gain = NRF_SAADC_GAIN1_4;
    channel_6_config.reference = NRF_SAADC_REFERENCE_VDD4;

    // AIN7 
    nrf_saadc_channel_config_t channel_7_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7);    //NRF_SAADC_INPUT_AIN1);
    channel_7_config.gain = NRF_SAADC_GAIN1_4;
    channel_7_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_channel_init(4, &channel_4_config);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_saadc_channel_init(5, &channel_5_config);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_saadc_channel_init(6, &channel_6_config);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_saadc_channel_init(7, &channel_7_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);
}

///////////////////////////////////////////////////////////////////////////////////////
/* Main */
///////////////////////////////////////////////////////////////////////////////////////

int main(void) {

    //initalizations
    initp_024gpio_output();
    initp_027gpio_output();
    saadc_init();
    saadc_sampling_event_init();
    saadc_sampling_event_enable();

    uint32_t err_code;

    bool epprom_error = 0;
    bsp_board_init(BSP_INIT_LEDS);
    APP_ERROR_CHECK(NRF_LOG_INIT(NULL));

    /* Initializing TWI master interface for EEPROM */
    err_code = twi_master_init();
    APP_ERROR_CHECK(err_code);

    //err_code = nrf_drv_clock_init();
    APP_ERROR_CHECK(err_code);
    nrf_drv_clock_lfclk_request(NULL);

    err_code = app_timer_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_uart_config_t uart_config = NRF_DRV_UART_DEFAULT_CONFIG;
    uart_config.pseltxd = TX_PIN_NUMBER;
    uart_config.pselrxd = RX_PIN_NUMBER;
    uart_config.hwfc = NRF_UART_HWFC_DISABLED;
    err_code = nrf_cli_init(&m_cli_uart, &uart_config, true, true, NRF_LOG_SEVERITY_INFO);
    APP_ERROR_CHECK(err_code);

    err_code = nrf_cli_start(&m_cli_uart);
    APP_ERROR_CHECK(err_code);

    lfclk_config();

    rtc_config();

    /* Main loop */
    while (1) 
    {
        UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
        nrf_cli_process(&m_cli_uart);
        if (epprom_error != eeprom_simulator_error_check()) 
        {
            epprom_error = eeprom_simulator_error_check();
            if (epprom_error != 0) 
            {
                NRF_LOG_RAW_INFO("WARNING: EEPROM transmission error detected.\n"
                "Use 'x' command to read error word.\n");
            }
        }



        if(GetDisplayControlInputValue() == true)
        {
            static uint32_t display_ControlValue_timestamp = 0;
            if ((getControlInputConfiguration() == INPUT_VOLTAGE_0_TO_5VDC)
             || (getControlInputConfiguration() == INPUT_VOLTAGE_0_TO_10VDC))
            {

                if(rtc_tick > (display_ControlValue_timestamp + 8))
                {
                    NRF_LOG_RAW_INFO("Control Voltage is " NRF_LOG_FLOAT_MARKER "\r\n", NRF_LOG_FLOAT(controlVoltage));
                    display_ControlValue_timestamp = rtc_tick;
                }
            }
        } 

        if(GetDisplayFeedbackInputValue() == true)
        {
            static uint32_t display_FeedbackValue_timestamp = 0;
            if ((getControlInputConfiguration() == INPUT_VOLTAGE_0_TO_5VDC)
             || (getControlInputConfiguration() == INPUT_VOLTAGE_0_TO_10VDC))
            {
                if(rtc_tick > (display_FeedbackValue_timestamp + 8))
                {
                    NRF_LOG_RAW_INFO("Feedback Voltage is " NRF_LOG_FLOAT_MARKER "\r\n", NRF_LOG_FLOAT(feedbackVoltage));
                    display_FeedbackValue_timestamp = rtc_tick;
                }
            }
        }
        
    }
}

Thanks.

  • Good day,

    So when the saadc_callback occurs, I was not stopping the timer.  I have added a disable of the timer at the start of the saadc_callback and then re-enable it when completing the callback.  This seems to have fixed the issue.

    The callback now looks like this.

    void saadc_callback(nrf_drv_saadc_evt_t const *p_event) 
    {
        adcsampledone = true;
        //gpio024_on();
        //gpio027_on();
        if (p_event->type == NRF_DRV_SAADC_EVT_DONE) 
        {
            nrf_drv_timer_disable(&m_timer);
            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);
    
            ADC_AIN0 = 0;
            ADC_AIN1 = 0; 
            ADC_AIN2 = 0; 
            ADC_AIN3 = 0; 
            ADC_AIN4 = 0; 
            ADC_AIN5 = 0; 
            ADC_AIN6 = 0; 
            ADC_AIN7 = 0; 
    
            for (uint16_t i = 0; i < SAADC_SAMPLES_IN_BUFFER; i++) 
            {
                ADC_AIN0 += p_event->data.done.p_buffer[i++];
                ADC_AIN1 += p_event->data.done.p_buffer[i++];
                ADC_AIN2 += p_event->data.done.p_buffer[i++];
                ADC_AIN3 += p_event->data.done.p_buffer[i++];
                ADC_AIN4  += p_event->data.done.p_buffer[i++];
                ADC_AIN5 += p_event->data.done.p_buffer[i++];
                ADC_AIN6 += p_event->data.done.p_buffer[i++]; 
                ADC_AIN7 += p_event->data.done.p_buffer[i];
            }
    
            ADC_AIN0 = ADC_AIN0 /(SAADC_SAMPLES_IN_BUFFER/8);
            ADC_AIN1 = ADC_AIN1/(SAADC_SAMPLES_IN_BUFFER/8);
            ADC_AIN2 = ADC_AIN2/(SAADC_SAMPLES_IN_BUFFER/8);
            ADC_AIN3 = ADC_AIN3/(SAADC_SAMPLES_IN_BUFFER/8);
            ADC_AIN4 = ADC_AIN4/(SAADC_SAMPLES_IN_BUFFER/8);
            ADC_AIN5 = ADC_AIN5 /(SAADC_SAMPLES_IN_BUFFER/8);
            ADC_AIN6 = ADC_AIN6/(SAADC_SAMPLES_IN_BUFFER/8);
            ADC_AIN7 = ADC_AIN7/(SAADC_SAMPLES_IN_BUFFER/8);
            m_adc_evt_counter++;
            nrf_drv_timer_enable(&m_timer);
        }
        //gpio024_off();
        //gpio027_off();
    }

  • Hi 

    The problem is that the debugger only stops the CPU core when you enter a breakpoint, but timers and other peripherals will keep running in the background. 

    Most likely the SAADC peripheral will fill up the RAM buffer, and set the interrupt, but since the MCU is not running the next RAM buffer will not be configured. Then when the CPU wakes up and finally configures the buffer the SAADC has been triggered in the background, meaning it is out of sync with the code. 

    I don't think there is a good solution to this problem, other than to stop the timer that is triggering the ADC before breakpoint location, and start it again afterwards. 

    Best regards
    Torbjørn

  • Hi 

    That was a different solution than I expected, but good to hear you found the issue Slight smile

    Best regards
    Torbjørn

Related