PPI, Timers and SAADC with NRFX

Hi I am using nRF connect 2.3.0 with VS Code on Windows 11.  My board is a Custom board with nRF52832 QFAA.

I am trying to find a working example of PPI with SAADC collection.  I found this and it has A LOT of what I want but doesnt actually work.  There are several issues with it including the fact that it isnt using NRF Connect 2.x.x.

This is my sample code:

#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>
#include <errno.h>
#include <time.h>

#include <zephyr/kernel.h>
#include <zephyr/logging/log.h>
#include <nrfx_saadc.h>
#include <nrfx_ppi.h>
#include <nrfx_timer.h>
#include <drivers/nrfx_errors.h>
#include <zephyr/drivers/gpio.h>

//This is set so battery power can be down to mins and still work
#define NRF_POWER_HAS_POFCON 0

#define LOG_MODULE_NAME drone_controller_main
LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_DBG);

#if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \
	!DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels)
#error "No suitable devicetree overlay specified"
#endif

//SAADC Defines

// define the number of SAADC channels and parameters
#define SAADC_CHANNELS_IN_USE 4
#define SAADC_SAMPLE_INTERVAL_MS 100
#define SAADC_RESOLUTION NRF_SAADC_RESOLUTION_10BIT
#define SAADC_OVERSAMPLE NRF_SAADC_OVERSAMPLE_DISABLED

//define the buttons
#define SW0 DT_ALIAS(sw0)
#define SW1 DT_ALIAS(sw1)
#define SW2 DT_ALIAS(sw2)
#define SW3 DT_ALIAS(sw3)
#define SW4 DT_ALIAS(sw4)
#define SW5 DT_ALIAS(sw5)
#define SW6 DT_ALIAS(sw6)
#define SW7 DT_ALIAS(sw7)
#define SW8 DT_ALIAS(sw8)

//Devicetree node for the var resistor power
#define PWRR_NODE DT_ALIAS(pwrr)
#define PWRL_NODE DT_ALIAS(pwrl)

//Power the joysticks
#define PWRR DT_ALIAS(pwrr)
#define PWRL DT_ALIAS(pwrl)

//setup the LED's
#define LED0_R DT_ALIAS(led0)
#define LED3_G DT_ALIAS(led3)
#define LED4_B DT_ALIAS(led4)

//Timer settings
#define TIMER_INTERVAL_MS			1000
#define NRFX_SAADC_CHANNEL_COUNT 	4
#define SAADC_BUF_SIZE          	NRFX_SAADC_CHANNEL_COUNT
#define SAADC_BUF_COUNT         	2

static nrfx_timer_t timer1 = NRFX_TIMER_INSTANCE(1);				//timer instance

static nrf_saadc_value_t samples[SAADC_BUF_COUNT][SAADC_BUF_SIZE];	//sample buffer
static nrf_ppi_channel_t m_timer_saadc_ppi_channel;					//timer to ppi channel
static const uint32_t saadc_sampling_rate = 250; 					// milliseconds (ms)

static const nrf_saadc_input_t ANALOG_INPUT_MAP[NRFX_SAADC_CHANNEL_COUNT] = {NRF_SAADC_INPUT_AIN0, NRF_SAADC_INPUT_AIN1, NRF_SAADC_INPUT_AIN4, NRF_SAADC_INPUT_AIN5};

static void timer_event_handler(nrf_timer_event_t event_type, void *p_context)
{
	printk("Event");
}

// Simple function to provide an index to the next input buffer
// Will simply alernate between 0 and 1 when SAADC_BUF_COUNT is 2
static uint32_t next_free_buf_index(void)
{
    static uint32_t buffer_index = -1;
    buffer_index = (buffer_index + 1) % SAADC_BUF_COUNT;
    return buffer_index;
}

static void ppi_init(void)
{
	 nrfx_err_t err;
    // Trigger task sample from timer
    err = nrfx_ppi_channel_alloc(&m_timer_saadc_ppi_channel); 
	if(err==NRFX_SUCCESS)
		LOG_DBG("ppi alloc success");

    err = nrfx_ppi_channel_assign(m_timer_saadc_ppi_channel, 
									nrfx_timer_event_address_get(&timer1, NRF_TIMER_EVENT_COMPARE0), 
									nrf_saadc_task_address_get(NRF_SAADC,NRF_SAADC_TASK_SAMPLE));
	err = nrfx_ppi_channel_enable(m_timer_saadc_ppi_channel);
	if(err==NRFX_SUCCESS)
		LOG_DBG("PPI enable ok");
    
}

static void timer_init(void)
{
		nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG;
	timer_cfg.frequency = NRF_TIMER_FREQ_31250Hz;
	
	nrfx_timer_init(&timer1, &timer_cfg, timer_event_handler);
	nrfx_timer_extended_compare(&timer1,NRF_TIMER_CC_CHANNEL0,nrfx_timer_ms_to_ticks(&timer1, saadc_sampling_rate),NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,false);
	nrfx_timer_resume(&timer1);
}

/*
*	Function: saadc_handler
*	Description: 	This handler is called when there is SAADC data available
*					when the data is processed, saadc is re-enabled for more data.
*					Data is sent to the calibrate routine until the drone is ready
*					then the data is formatted for the joystick.
*/
static void saadc_handler(nrfx_saadc_evt_t const * p_event)
{
	uint16_t samples_number;
	uint16_t flydata[4];
	nrfx_err_t err;

	switch (p_event->type)
	{
		case NRFX_SAADC_EVT_DONE:			
			samples_number = p_event->data.done.size;
			for (uint16_t i = 0; i < samples_number; i++)
			{
				LOG_DBG("SAADC_Value: Channel[%d] - %d",i,p_event->data.done.p_buffer[i]);
				//flydata[i]=p_event->data.done.p_buffer[i];
			}

			break;
		case NRFX_SAADC_EVT_BUF_REQ:
			err = nrfx_saadc_buffer_set(&samples[next_free_buf_index()][0], SAADC_BUF_SIZE);
			break;

		default:
			LOG_DBG("SAADC evt %d", p_event->type);
			break;
	}
}

static void saadc_configure(void)
{
	nrfx_err_t err;
	uint8_t channel_mask = 0;
	static nrfx_saadc_channel_t channel_configs[NRFX_SAADC_CHANNEL_COUNT];
	nrfx_saadc_adv_config_t saadc_adv_config = NRFX_SAADC_DEFAULT_ADV_CONFIG;

	//Update the timer and start for the adv config
    saadc_adv_config.internal_timer_cc = 0;
    saadc_adv_config.start_on_end = true;

	err = nrfx_saadc_init(NRFX_SAADC_DEFAULT_CONFIG_IRQ_PRIORITY);
    if(err!=NRFX_SUCCESS)
		LOG_INF("Error: SAADC init failed");
	
	for(int i=0;i<NRFX_SAADC_CHANNEL_COUNT;i++)
	{
		nrf_saadc_input_t pin = ANALOG_INPUT_MAP[i];
		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_INTERNAL;          
        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 = nrfx_saadc_channels_config(channel_configs, NRFX_SAADC_CHANNEL_COUNT);
	err = nrfx_saadc_advanced_mode_set(channel_mask, NRF_SAADC_RESOLUTION_10BIT, &saadc_adv_config, saadc_handler);

	// Configure two buffers to ensure double buffering of samples, to avoid data loss when the sampling frequency is high
    err = nrfx_saadc_buffer_set(&samples[next_free_buf_index()][0], SAADC_BUF_SIZE);
	err = nrfx_saadc_mode_trigger();
}

void main(void)
{
	printk("Hello World! %s\n", CONFIG_BOARD);
	LOG_DBG("LOG DBG test");

	timer_init();
	ppi_init();
	saadc_configure();
		
	while(1)
	{
		__WFE();
	}
}

This is the conf file:

#required for the custom board
CONFIG_CLOCK_CONTROL_NRF_K32SRC_XTAL=n
CONFIG_CLOCK_CONTROL_NRF_K32SRC_RC=y

#memory settings
CONFIG_HEAP_MEM_POOL_SIZE=16384
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2304
CONFIG_MAIN_STACK_SIZE=2048

#Thread settings
CONFIG_THREAD_NAME=y
CONFIG_THREAD_MONITOR=y

#GPIO and ADC settings
CONFIG_GPIO=y
CONFIG_NRFX_SAADC=y
CONFIG_NRFX_PPI=y
CONFIG_NRFX_TIMER1=y

#Enable statistics (MCU ADDED)
CONFIG_STATS=y
CONFIG_STATS_NAMES=y

#MCU Manager
CONFIG_MCUMGR=y
CONFIG_MCUMGR_CMD_IMG_MGMT=y
CONFIG_MCUMGR_CMD_OS_MGMT=y
CONFIG_BOOTLOADER_MCUBOOT=y

# Support for taskstat command
CONFIG_OS_MGMT_TASKSTAT=y


#Logging
CONFIG_CONSOLE=y
CONFIG_LOG_BACKEND_RTT=y
CONFIG_LOG_DEFAULT_LEVEL=4
CONFIG_USE_SEGGER_RTT=y
CONFIG_RTT_CONSOLE=y
CONFIG_PRINTK=y
CONFIG_LOG_PRINTK=y
CONFIG_CBPRINTF_FP_SUPPORT=y
CONFIG_LOG=y
CONFIG_LOG_MODE_IMMEDIATE=y

My problem is that NO sample is ever printed in the event handler and it is not even called.  What happens when I run it without stepping through is a fault:

[00:00:00.002,532] <err> os: >>> ZEPHYR FATAL ERROR 1: Unhandled interrupt on CPU 0
[00:00:00.003,112] <err> os: Current thread: 0x20000368 (main)
[00:00:00.008,575] <err> fatal_error: Resetting system

I am very new to this and am trying to get samples first.  Please let me know if you see anything I missed or more likely didn't configure correctly.  If there is a PPI SAADC example somewhere I could look at that would help.  I have looked at the PPI Trace example and it doesn't seem to apply.

Thanks

Parents Reply Children
No Data
Related