Hi
I am working on a project that has two timers, TIMER3 and TIMER4 (TIMER3 as timer and theTIMER4 as a counter). TIMER3 resets after counting up to 4. I am using PPI to increment TIMER4 every time TIMER3 resets. TIMER4 also resets after counting up to 128. I have also a PPI event that compares the event when TIMER4 resets to trigger SAADC->TASKS_SAMPLE. I have a global variable, adc_counter, that increments every time ADC sample i ready.
I have configured my SAADC to take just one sample every time the task TASKS_SAMPLE is triggered from the PPI. I wanted to have a customized SAADC_IRQHandler that increments the global variable, the adc_counter, do the conversion, and put that in a buffer. The following is my code. I don't where I have the problem, but just noticed that the adc_counter never increments.
#include "nrf.h"
#include <stdbool.h>
#include <stdint.h>
//#include "bsp.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "math.h"
//==================================
//PPI channels
#define TIMER4_PPI_CH_A 0 // TIMER3 reloads and TIMER4 increments
#define TIMER4_PPI_CH_B 1 // TIMER4 reloads, one ADC sample is taken
//===================================
//===================================
// TIMER CC registers
#define TIMER3_RELOAD_CC_NUM 5
#define TIMER4_RELOAD_CC_NUM 5
//===================================
// TIMER3 reload value. The PWM frequency equals '16000000 / TIMER_RELOAD_VALUE'
#define TIMER3_RELOAD 4
#define TIMER4_RELOAD 128 // TIMER4 counts upto 128. Count is incremented every timer TIMER3 RELOADs
#define SAMPLES_IN_BUFFER 32 // Total number of ADC samples
static int adc_counter = 0; // counter for the ADC samples
volatile int16_t adc_value = 0;
volatile float adc_exact_value = 0;
static uint32_t adc_buffer[SAMPLES_IN_BUFFER];
//timer init
void timers_init(void)
{
NRF_TIMER3->BITMODE = TIMER_BITMODE_BITMODE_08Bit << TIMER_BITMODE_BITMODE_Pos;
NRF_TIMER3->PRESCALER = 0;
NRF_TIMER3->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk << TIMER3_RELOAD_CC_NUM;
NRF_TIMER3->MODE = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos;
NRF_TIMER3->CC[TIMER3_RELOAD_CC_NUM] = TIMER3_RELOAD;
NRF_TIMER4->BITMODE = TIMER_BITMODE_BITMODE_08Bit << TIMER_BITMODE_BITMODE_Pos;
NRF_TIMER4->PRESCALER = 0;
NRF_TIMER4->SHORTS = TIMER_SHORTS_COMPARE0_CLEAR_Msk << TIMER4_RELOAD_CC_NUM;
NRF_TIMER4->MODE = TIMER_MODE_MODE_Counter << TIMER_MODE_MODE_Pos;
NRF_TIMER4->CC[TIMER4_RELOAD_CC_NUM] = TIMER4_RELOAD;
}
void timers_start(void)
{
NRF_TIMER3->TASKS_START = 1;
NRF_TIMER4->TASKS_START = 1;
}
void SAADC_IRQHandler(void)
{
// Clear dataready event
NRF_SAADC-> EVENTS_END = 0;
adc_exact_value =(((float)adc_value/4096)*3.6f*1000)*5.545f;
adc_buffer[adc_counter] = adc_exact_value;
adc_counter++;
}
void adc_init(void)
// Enable interrupt on ADC sample ready
NRF_SAADC->INTENSET = SAADC_INTENSET_END_Msk;
NVIC_EnableIRQ(SAADC_IRQn);
// configure ADC
NRF_SAADC->CH[0].CONFIG = (SAADC_CH_CONFIG_GAIN_Gain1_6 << SAADC_CH_CONFIG_GAIN_Pos) |
(SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos) |
(SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos) |
(SAADC_CH_CONFIG_RESN_Bypass << SAADC_CH_CONFIG_RESN_Pos) |
(SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESP_Pos) |
(SAADC_CH_CONFIG_TACQ_3us << SAADC_CH_CONFIG_TACQ_Pos);
// Configure the SAADC channel with AIN2 as positive input, no negative input(single ended). // change it to AIN5 in the final version
NRF_SAADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput2 << SAADC_CH_PSELP_PSELP_Pos;
NRF_SAADC->CH[0].PSELN = SAADC_CH_PSELN_PSELN_NC << SAADC_CH_PSELN_PSELN_Pos; // Will be ignored if MODE is SE
// Configure the SAADC resolution.
NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_12bit << SAADC_RESOLUTION_VAL_Pos;
// Configure result to be put in RAM at the location of "adc_value" variable.
// Number of sample counts
NRF_SAADC->RESULT.MAXCNT = 1;
NRF_SAADC->RESULT.PTR = (uint32_t)&adc_value;
// Enable ADC
NRF_SAADC->ENABLE = SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos;
//Start the ADC
NRF_SAADC->TASKS_START = 1;
while(NRF_SAADC->EVENTS_STARTED ==0);
NRF_SAADC->EVENTS_STARTED = 0;
}
void timer4_adc_ppi(void)
{
// Create PPI event when TIMER3 reloads that triggers an increment counting task in TIMER4
NRF_PPI->CH[TIMER4_PPI_CH_A].EEP = (uint32_t)&NRF_TIMER3->EVENTS_COMPARE[TIMER3_RELOAD_CC_NUM];
NRF_PPI->CH[TIMER4_PPI_CH_A].TEP = (uint32_t)&NRF_TIMER4->TASKS_COUNT;
// Create PPI event on TIMER4 when it reaches TIMER4_RELOAD, that triggers ADC sampling task
NRF_PPI->CH[TIMER4_PPI_CH_B].EEP = (uint32_t)&NRF_TIMER4->EVENTS_COMPARE[TIMER4_RELOAD_CC_NUM];
NRF_PPI->CH[TIMER4_PPI_CH_B].TEP = (uint32_t)&NRF_SAADC->TASKS_SAMPLE;
NRF_PPI->CHENSET = ( 1 << TIMER4_PPI_CH_A) | ( 1 << TIMER4_PPI_CH_B);
}
int main(void)
{
//Empty adc_buffer
for(int n = 0; n < sizeof(adc_buffer)/sizeof(adc_buffer[0]); n++)
{
adc_buffer[n] = 0;
}
// init adc
adc_init();
// init timers
timers_init();
// start ppi
timer4_adc_ppi();
// start timers
timers_start();
while(adc_counter < SAMPLES_IN_BUFFER)
{
//do nothing until all adc samples are collected
}
// calculate the average of the samples in the buffer
float sample_sum =0;
float sample_avg=0;
for (int j = 0; j < sizeof(adc_buffer)/sizeof(adc_buffer[0]); j++)
{
sample_sum += adc_buffer[j];
}
sample_avg = sample_sum/sizeof(adc_buffer)/sizeof(adc_buffer[0]);
sample_avg = (uint16_t)sample_avg;
// UART print sample_avg (to be implemented!)
//Empty adc_buffer for next measurement
for(int n = 0; n < sizeof(adc_buffer)/sizeof(adc_buffer[0]); n++)
{
adc_buffer[n] = 0;
}
}
Is there something I am missing in my code? My goal is to take 32 samples, calculate the average and print that over UART. I didn't want to use the nrf_drv_saadc_buffer_convert() API function, as the register interface is more readable and understandable to me. Any comments, or improved code is appreciated.