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

nrfx_saadc.c Fills Buffer in Indefinite Order and Skips Samples

Hardware/Software
Device: nRF5340 PDK
Software versions:
NordicSemiconductor/nrfx v2.0.0
zephyrproject-rtos/zephyr v2.1.0


Description
I'm currently sampling 4 channels using `nrfx_saadc_simple_mode_set(...)` in blocking mode, and calling `nrfx_saadc_mode_trigger()` after calibrating the saadc in blocking mode.

The first time sampling the buffer looks like {CH0, CH1, CH3, CH2} (which is an issue of its own) and each time it is sampled afterwards it looks like {~2473, CH0, CH1, CH3}

ch0 = 247, ch1 = 328, ch2 = 525, ch3 = 427
ch0 = 2474, ch1 = 247, ch2 = 328, ch3 = 524
ch0 = 2483, ch1 = 248, ch2 = 328, ch3 = 524
ch0 = 2473, ch1 = 247, ch2 = 328, ch3 = 524


Code

#include <zephyr.h>
#include <sys/printk.h>
#include <power/power.h>
#include <soc.h>
#include <nrfx_saadc.h>

#define DEFAULT_CHANNEL_CONFIG = {                  \
    .channel_config =                               \
    {                                               \
        .resistor_p = NRF_SAADC_RESISTOR_DISABLED,  \
        .resistor_n = NRF_SAADC_RESISTOR_DISABLED,  \
        .gain       = NRF_SAADC_GAIN1_6,            \
        .reference  = NRF_SAADC_REFERENCE_INTERNAL, \
        .acq_time   = NRF_SAADC_ACQTIME_40US,       \
        .mode       = NRF_SAADC_MODE_SINGLE_ENDED,  \
        .burst      = NRF_SAADC_BURST_ENABLED,      \
    },                                              \
    .pin_p          = NRF_SAADC_INPUT_AIN0,         \
    .pin_n          = NRF_SAADC_INPUT_DISABLED,     \
    .channel_index  = 0                             \
};

K_TIMER_DEFINE(wake_timer, NULL, NULL);

ISR_DIRECT_DECLARE(saadc_isr){
    if (NRF_SAADC_S->EVENTS_STARTED){
      NRF_SAADC_S->EVENTS_STARTED = 0;
    }

    if (NRF_SAADC_S->EVENTS_END){
      NRF_SAADC_S->EVENTS_END = 0;
    }
    
    if (NRF_SAADC_S->EVENTS_DONE){
      NRF_SAADC_S->EVENTS_DONE = 0;
    }

    if (NRF_SAADC_S->EVENTS_RESULTDONE){
      NRF_SAADC_S->EVENTS_RESULTDONE = 0;
    }
    
    if (NRF_SAADC_S->EVENTS_CALIBRATEDONE){
      NRF_SAADC_S->EVENTS_CALIBRATEDONE = 0;
    }
    
    if (NRF_SAADC_S->EVENTS_STOPPED){
      NRF_SAADC_S->EVENTS_STOPPED = 0;
    }

    ISR_DIRECT_PM();
    
    return 1;
}

int main(void){
    nrfx_err_t err_code;
    nrfx_saadc_channel_t ch0 = DEFAULT_CHANNEL_CONFIG;
    nrfx_saadc_channel_t ch1 = DEFAULT_CHANNEL_CONFIG;
    nrfx_saadc_channel_t ch2 = DEFAULT_CHANNEL_CONFIG;
    nrfx_saadc_channel_t ch3 = DEFAULT_CHANNEL_CONFIG;
    
    ch1.pin_p = NRF_SAADC_INPUT_AIN6;
    ch1.channel_index = 1;
    ch1.pin_p = NRF_SAADC_INPUT_AIN7;
    ch1.channel_index = 2;
    ch1.pin_p = NRF_SAADC_INPUT_AIN2;
    ch1.channel_index = 3;

            while (true){
                // Connect IRQ
                IRQ_DIRECT_CONNECT(SAADC_IRQn, 6, saadc_isr, 0);

                err_code = nrfx_saadc_init(0);
                if (err_code != NRFX_SUCCESS)
                  return err_code;

                nrfx_saadc_channel_t channels[4] = {ch0, ch1, ch2, ch3};
                err_code = nrfx_saadc_channels_config(channels, 4);
                if (err_code != NRFX_SUCCESS)
                  return err_code;

                // Calibrate SAADC
                err_code = nrfx_saadc_offset_calibrate(NULL);
                if (err_code != NRFX_SUCCESS)
                  return err_code;
                
                u8_t channel_mask = (1U << 0) | ( 1U << 1) | (1U << 2) | (1U << 3);
                err_code = nrfx_saadc_simple_mode_set(channel_mask,
                                              NRF_SAADC_RESOLUTION_10BIT,
                                              NRF_SAADC_OVERSAMPLE_16X,
                                              NULL);
                if (err_code != NRFX_SUCCESS)
                    return err_code;
                
                // Give buffer and trigger sample
                nrf_saadc_value_t buffer[4] = {0};
                err_code = nrfx_saadc_buffer_set(buffer, 4);
                if (err_code != NRFX_SUCCESS)
                    return err_code;
                err_code = nrfx_saadc_mode_trigger();
                if (err_code != NRFX_SUCCESS)
                    return err_code;
                // Note: channel order is off in buffer
                nrf_saadc_value_t ch0_counts = buffer[0]; // Forced to ~250cnts
                nrf_saadc_value_t ch1_counts = buffer[1]; // Forced to ~350cnts
                nrf_saadc_value_t ch2_counts = buffer[2]; // Forced to ~450cnts
                nrf_saadc_value_t ch3_coutns = buffer[3]; // Forced to ~550cnts

                printk("ch0 = %d, ch1 = %d, ch2 = %d, ch3 = %d\n",
                       ch0_counts, ch1_counts, ch2_counts, ch3_counts);
                
                // Sleep for 100ms
                nrfx_saadc_uninit();
                k_timer_start(&wake_timer, K_MSEC(100), 0);
                k_cpu_idle();
            }
}

Parents Reply
  • Thank you for your reply. My current implementation performs each operation, including calibration, in blocking mode according to the documentation. If I include an event handler, whose implementation is not yet supported on an RTOS, I have to do event handling manually with the ISR I provided above.

    This is a problem because the nrfx_saadc driver has an internal structure which relies on information passed to the nrfx_saadc_handler_t and I can not replicate those updates with my ISR. This makes the driver think that resources are still busy when they in fact are not. I can't update this internal struct with my ISR because it is declared as static.

Children
No Data
Related