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

How to use nrfx SAADC driver on Zephyr RTOS

Hello guys.

We use NCS v1.4.2 and Zephyr RTOS to develop the application code for our nRF52840 SoC.

Thanks to your support, we were able to use Zephyr ADC APIs and take the readings from some ADC channels (thread).

However, we would like to benefit from some nRF ADC features like taking periodic samples in the background (timer + PPI + ADC) or calling an interrupt function when ADC values are above/below pre-defined limits (e.g. to use nrfx_saadc_limits_set() function to set the limits). For that features, it is needed to use nrfx drivers directly. 

There is one example that shows how, in general, nrfx drivers are used - link. By following the analogy from that example, I tried to disable native Zephyr ADC driver and enable nrfx saadc driver with the following two lines in my prj.config file:

CONFIG_ADC=n
CONFIG_ADC_NRFX_SAADC=y

I also included nrfx_saadc header file  line in my main.cpp file:

#include <nrfx_saadc.h>

When I compile the code that contains some saadc related functions (init, config...), the compiler complaints about the undefined reference to nrfx_saadc_xxx() functions that are all declared in included nrfx_saadc.h file:

build/../src/main.cpp:187: undefined reference to `nrfx_saadc_channels_config'
build/../src/main.cpp:190: undefined reference to `nrfx_saadc_advanced_mode_set'
build/../src/main.cpp:197: undefined reference to `nrfx_saadc_buffer_set'
build/../src/main.cpp:200: undefined reference to `nrfx_saadc_buffer_set'
build/../src/main.cpp:203: undefined reference to `nrfx_saadc_mode_trigger'

Do you have any idea what I am missing here? Do I need to include something more in my prj.config file that will disable the usage of Zephyr ADC APIs and encourage the usage of NRFX SAADC driver?

Thanks in advance for your time and efforts.

Sincerely,

Bojan.

Parents
  • Just figured out that I needed to include:

    CONFIG_ADC=n
    CONFIG_NRFX_SAADC=y

    Instead of:

    CONFIG_ADC=n
    CONFIG_ADC_NRFX_SAADC=y

    The code now compiles but when I try to debug it I get stuck:

    *** Booting Zephyr OS build v2.4.0-ncs2  ***
    [00:00:00.345,001] <err> os: >>> ZEPHYR FATAL ERROR 1: Unhandled interrupt on CPU 0
    [00:00:00.353,698] <err> os: Current thread: 0x20002708 (unknown)
    [00:00:00.365,783] <err> fatal_error: Resetting system

    The only thing I have in my main() function is adc_configure() with the following content:

    static void adc_configure(void)
    {
        int err_code;
    
        nrfx_saadc_adv_config_t saadc_adv_config = NRFX_SAADC_DEFAULT_ADV_CONFIG;
        saadc_adv_config.internal_timer_cc = 0;
        saadc_adv_config.start_on_end = true;
    
        err_code = nrfx_saadc_init(NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY);
        //APP_ERROR_CHECK(err_code);
    
        static nrfx_saadc_channel_t channel_configs[ADC_CHANNELS_IN_USE];
    
        uint8_t channel_mask = 0;
        for(int i = 0; i < ADC_CHANNELS_IN_USE; i++) {
            nrf_saadc_input_t pin = ANALOG_INPUT_MAP[i];
            // Apply default config to each channel
            nrfx_saadc_channel_t config = NRFX_SAADC_DEFAULT_CHANNEL_SE(pin, i);
    
            // Replace some parameters in default config
            config.channel_config.reference = NRF_SAADC_REFERENCE_VDD4;          
            config.channel_config.gain = NRF_SAADC_GAIN1_4;
    
            // Copy to list of channel configs
            memcpy(&channel_configs[i], &config, sizeof(config));
    
            // Update channel mask
            channel_mask |= 1 << i;
        }
    
        err_code = nrfx_saadc_channels_config(channel_configs, ADC_CHANNELS_IN_USE);
        //APP_ERROR_CHECK(err_code);
    
        err_code = nrfx_saadc_advanced_mode_set(channel_mask,
                                                NRF_SAADC_RESOLUTION_14BIT,
                                                &saadc_adv_config,
                                                event_handler);
        //APP_ERROR_CHECK(err_code);
                                                
        // Configure two buffers to ensure double buffering of samples, to avoid data loss when the sampling frequency is high
        err_code = nrfx_saadc_buffer_set(&samples[next_free_buf_index()][0], SAADC_BUF_SIZE);
        //APP_ERROR_CHECK(err_code);
    
        err_code = nrfx_saadc_buffer_set(&samples[next_free_buf_index()][0], SAADC_BUF_SIZE);
        //APP_ERROR_CHECK(err_code);
    
        err_code = nrfx_saadc_mode_trigger();
        //APP_ERROR_CHECK(err_code);
    }

    Please help.

  • I wanted to give it a try with nrfx timer, by including only timer_init() function in main.c:

    static void timer_init(void)
    {
        nrfx_err_t err_code;
    
        nrfx_timer_config_t timer_config = NRFX_TIMER_DEFAULT_CONFIG;
        timer_config.frequency = NRF_TIMER_FREQ_31250Hz;
        err_code = nrfx_timer_init(&m_sample_timer, &timer_config, timer_handler);
        printk("nrfx_timer_init: %u\n", err_code);
        //APP_ERROR_CHECK(err_code);
        nrfx_timer_extended_compare(&m_sample_timer,
                                    NRF_TIMER_CC_CHANNEL0,
                                    nrfx_timer_ms_to_ticks(&m_sample_timer, saadc_sampling_rate),
                                    NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                    false);
    
        nrfx_timer_resume(&m_sample_timer);
    }

    Now the code runs but nrfx_timer_init() function returns 0xBAD0000.

    For the nrfx timers, I included the following in prj.config file:

    CONFIG_NRFX_TIMER=y
    CONFIG_NRFX_TIMER1=y

    and 

    #include <nrfx_timer.h>

    in main.c.

    I also tried to connect Zephyr's and nrfx timer IRQ handlers with:

    IRQ_CONNECT(TIMER1_IRQn, NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY,
                nrfx_timer_1_irq_handler, NULL, 0);

    but to no avail. What I am missing in the case of nrfx timers?

    My impressions are that some deeper explanation is needed (e.g. in the form of tutorials) on how we can benefit from nrfx drivers in Zephyr environment. One example we currently have (link) is not enough.

    Cheers,

    Bojan.

Reply
  • I wanted to give it a try with nrfx timer, by including only timer_init() function in main.c:

    static void timer_init(void)
    {
        nrfx_err_t err_code;
    
        nrfx_timer_config_t timer_config = NRFX_TIMER_DEFAULT_CONFIG;
        timer_config.frequency = NRF_TIMER_FREQ_31250Hz;
        err_code = nrfx_timer_init(&m_sample_timer, &timer_config, timer_handler);
        printk("nrfx_timer_init: %u\n", err_code);
        //APP_ERROR_CHECK(err_code);
        nrfx_timer_extended_compare(&m_sample_timer,
                                    NRF_TIMER_CC_CHANNEL0,
                                    nrfx_timer_ms_to_ticks(&m_sample_timer, saadc_sampling_rate),
                                    NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
                                    false);
    
        nrfx_timer_resume(&m_sample_timer);
    }

    Now the code runs but nrfx_timer_init() function returns 0xBAD0000.

    For the nrfx timers, I included the following in prj.config file:

    CONFIG_NRFX_TIMER=y
    CONFIG_NRFX_TIMER1=y

    and 

    #include <nrfx_timer.h>

    in main.c.

    I also tried to connect Zephyr's and nrfx timer IRQ handlers with:

    IRQ_CONNECT(TIMER1_IRQn, NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY,
                nrfx_timer_1_irq_handler, NULL, 0);

    but to no avail. What I am missing in the case of nrfx timers?

    My impressions are that some deeper explanation is needed (e.g. in the form of tutorials) on how we can benefit from nrfx drivers in Zephyr environment. One example we currently have (link) is not enough.

    Cheers,

    Bojan.

Children
No Data
Related