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.