Hi Team,
I've recently transitioned from using Texas Instruments modules to Nordic modules for its low energy, specifically the NRF52832 DK with the NRF Connect SDK. Therefore, I am novice in zephyr environment.
I am in the process of developing a sensor which could send 400 samples per second via Bluetooth hence the ADC must process 400 samples every second without any CPU intervention.
After days of exploring I understood that I need to use PPI and timers to enable the ADC to work autonomously. However, I struggled to find relevant documentation or examples specifically tailored for the NRF Connect SDK. Eventually I found this https://github.com/haakonsh/NCS_SAADC_example/tree/master which incorporated nrfx_saadc, nrfx_ppi and nrfx_timer to employ ADC autonomously.
When I attempted to use the provided code in my Visual Studio Code environment, I encountered numerous errors related to undefined identifiers for the nrfx_saadc and nrfx_timer headers. Additionally, several other headers required by the SAADC and timer modules themselves also resulted in undefined errors.
Below is the main.c
/*
* Copyright (c) 2019 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <nrfx_ppi.h>
#include "nrfx_saadc.h"
#include <nrfx_timer.h>
#include <hal/nrf_timer.h>
#include <helpers/nrfx_gppi.h>
#include <zephyr/logging/log.h>
#define __ZEPHYR__ 1
LOG_MODULE_REGISTER(nrfx_sample, LOG_LEVEL_INF);
#define SAADC_CHANNEL_NUM 0
#define SAMPLES_IN_BUFFER 8
#define SAMPLE_RATE 10000UL
#define TIMER1_INST_IDX 1
int16_t saadc_buf1[SAMPLES_IN_BUFFER];
int16_t saadc_buf2[SAMPLES_IN_BUFFER];
const nrfx_timer_t timer1_inst = NRFX_TIMER_INSTANCE(TIMER1_INST_IDX); //ERROR identifier "NRFX_TIMER1_INST_IDX" is undefined
void saadc_evt_handler(nrfx_saadc_evt_t const * p_event)
{
nrfx_err_t err = NRFX_SUCCESS;
static uint8_t counter = 0;
if(p_event->type == NRFX_SAADC_EVT_DONE)
{
printk("SAADC sampled: \n");
for(uint8_t i = 0; i < p_event->data.done.size; i++)
{
printk("%hi\n", p_event->data.done.p_buffer[i]);
}
}
else if(p_event->type == NRFX_SAADC_EVT_CALIBRATEDONE)
{
printk("SAADC calibrated.\n");
}
else if(p_event->type == NRFX_SAADC_EVT_BUF_REQ)
{
printk("SAADC buffer requested\n");
counter++;
if(counter%2)
{
err = nrfx_saadc_buffer_set(saadc_buf1, SAMPLES_IN_BUFFER);
if(err != NRFX_SUCCESS)
{
LOG_ERR("Error! Could not set buffer2: %d\n", err);
}
}
else
{
err = nrfx_saadc_buffer_set(saadc_buf2, SAMPLES_IN_BUFFER);
if(err != NRFX_SUCCESS)
{
LOG_ERR("Error! Could not set buffer1: %d\n", err);
}
}
}
else if(p_event->type == NRFX_SAADC_EVT_FINISHED)
{
printk("SAADC finished sampling\n\n");
}
}
void timer1_evt_handler(nrf_timer_event_t event_type, void * p_context)
{
// Nothing to do here, the timer's IRQ is not enabled
}
void timer_init(void)
{
nrfx_err_t err = NRFX_SUCCESS;
uint32_t base_frequency = NRF_TIMER_BASE_FREQUENCY_GET(timer1_inst.p_reg);
nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG(base_frequency); //ERROR identifier "NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY" is undefined
timer_cfg.bit_width = (nrf_timer_bit_width_t)NRF_TIMER_BIT_WIDTH_32;
timer_cfg.mode = NRF_TIMER_MODE_TIMER;
timer_cfg.p_context = &timer1_inst;
err = nrfx_timer_init(&timer1_inst, &timer_cfg, timer1_evt_handler);
// #if defined(__ZEPHYR__)
// IRQ_DIRECT_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_TIMER_INST_GET(TIMER1_INST_IDX)), IRQ_PRIO_LOWEST,
// NRFX_TIMER_INST_HANDLER_GET(TIMER1_INST_IDX), 0);
// #endif
if(err != NRFX_SUCCESS)
{
LOG_ERR("Error! Could not initialize TIMER1: %d\n", err);
}
nrfx_timer_extended_compare(&timer1_inst, NRF_TIMER_CC_CHANNEL0, SAMPLE_RATE, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);
}
void saadc_init(void)
{
nrfx_err_t err = NRFX_SUCCESS;
nrfx_saadc_channel_t saadc_channel = NRFX_SAADC_DEFAULT_CHANNEL_SE(NRF_SAADC_INPUT_AIN0, SAADC_CHANNEL_NUM); //ERROR identifier "NRF_SAADC_REFERENCE_INTERNAL" is undefined
nrfx_saadc_adv_config_t saadc_adv_cfg = NRFX_SAADC_DEFAULT_ADV_CONFIG;
saadc_adv_cfg.start_on_end = true;
err = nrfx_saadc_init(IRQ_PRIO_LOWEST); //ERROR identifier "IRQ_PRIO_LOWEST" is undefined
if(err != NRFX_SUCCESS)
{
LOG_ERR("Error! Could not initialize SAADC: %d\n", err);
}
err = nrfx_saadc_offset_calibrate(NULL);
if(err != NRFX_SUCCESS)
{
LOG_ERR("Error! Could not calibrate offset: %d\n", err);
}
err = nrfx_saadc_channel_config(&saadc_channel);
if(err != NRFX_SUCCESS)
{
LOG_ERR("Error! Could not configure SAADC channels: %d\n", err);
}
err = nrfx_saadc_advanced_mode_set((1 << SAADC_CHANNEL_NUM), NRF_SAADC_RESOLUTION_10BIT, &saadc_adv_cfg, saadc_evt_handler);
if(err != NRFX_SUCCESS)
{
LOG_ERR("Error! Could not set advanced SAADC mode: %d\n", err);
}
err = nrfx_saadc_buffer_set(saadc_buf1, SAMPLES_IN_BUFFER);
if(err != NRFX_SUCCESS)
{
LOG_ERR("Error! Could not set buffer1: %d\n", err);
}
err = nrfx_saadc_buffer_set(saadc_buf2, SAMPLES_IN_BUFFER);
if(err != NRFX_SUCCESS)
{
LOG_ERR("Error! Could not set buffer2: %d\n", err);
}
err = nrfx_saadc_mode_trigger();
if(err != NRFX_SUCCESS)
{
LOG_ERR("Error! Could trigger mode: %d\n", err);
}
}
int main()
{
printk("nrfx_saadc sample on %s\n", CONFIG_BOARD); //ERROR printk identifier undefined - surprisingly printk other than main() has no error
nrfx_err_t err;
/* Connect SAADC IRQ to nrfx_saadc_irq_handler */
IRQ_CONNECT(SAADC_IRQn, IRQ_PRIO_LOWEST, nrfx_isr, nrfx_saadc_irq_handler, 0); //ERROR IRQ_PRIO_LOWEST, nrfx_isr identifier undefined
timer_init();
saadc_init();
/* Allocate a PPI channel. */
nrf_ppi_channel_t channel;
err = nrfx_ppi_channel_alloc(&channel);
if (err != NRFX_SUCCESS) {
LOG_ERR("PPI channel allocation error: %08x", err);
return -1;
}
/* Configure endpoints of the channel so that the TIMER1 CAPTURE0
* event is connected with the SAADC SAMPLE task. This means that each time
* TIMER1 reaches it's set compare value, the SAADC will sample all
* enabled channel once.
*/
nrfx_gppi_channel_endpoints_setup(channel,
nrfx_timer_event_address_get(&timer1_inst, NRF_TIMER_EVENT_COMPARE0),
nrf_saadc_task_address_get(NRF_SAADC, NRF_SAADC_TASK_SAMPLE));
err = nrfx_ppi_channel_enable(channel);
if (err != NRFX_SUCCESS) {
LOG_ERR("Failed to enable PPI channel, error: %08x", err);
return -1;
}
printk("PPI configured\n");
nrfx_timer_enable(&timer1_inst);
printk("TIMER1 started\n");
while(1)
{
}
}
Below is the Kconfig
# Copyright (c) 2021 Nordic Semiconductor ASA
# SPDX-License-Identifier: Apache-2.0
config NRFX_DPPI
default HAS_HW_NRF_DPPIC
config NRFX_PPI
default HAS_HW_NRF_PPI
config NRFX_SAADC
bool "Enable SAADC driver"
depends on HAS_HW_NRF_SAADC && HAS_NRFX
config NRFX_TIMER
bool "Enable TIMER driver"
depends on HAS_HW_NRF_TIMER0 || HAS_HW_NRF_TIMER1 || \
HAS_HW_NRF_TIMER2 || HAS_HW_NRF_TIMER3 || \
HAS_HW_NRF_TIMER4
config NRFX_TIMER1
bool "Enable TIMER1 instance"
depends on HAS_HW_NRF_TIMER1
select NRFX_TIMER
source "Kconfig.zephyr"
Below is the prj.conf
CONFIG_LOG=y
CONFIG_LOG_PROCESS_THREAD_SLEEP_MS=100
CONFIG_LOG_DEFAULT_LEVEL=4
CONFIG_ASSERT=y
CONFIG_RESET_ON_FATAL_ERROR=n
CONFIG_ADC=n
CONFIG_NRFX_SAADC=y
CONFIG_NRFX_TIMER1=y
CONFIG_PICOLIBC=y
Below is the CMakeLists.txt
# SPDX-License-Identifier: Apache-2.0
cmake_minimum_required(VERSION 3.20.0)
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(adcgit)
target_sources(app PRIVATE src/main.c)
target_include_directories(app PRIVATE ../../../common)
I haven't configured the timing for 400 samples here as I couldn't figure out these errors.
I referred to almost all the Nordic forums and tried everything with no success. Kindly guide me in resolving this issue ASAP. I appreciate any help provided in this regard.