Hi,
I already read all the forum posts about this buffer order swap problem of the SAADC. Especially this one: https://devzone.nordicsemi.com/f/nordic-q-a/20291/offset-in-saadc-samples-with-easy-dma-and-ble/79053#79053
I tried to implement the PPI solution, but I am not able to bring this to work. I have still a swap in the order every second call of the callback function. Can anyone help me?
This is pretty much my firmware (without BLE stuff at the moment):
I'm using a compare event of the RTC to trigger the sample task in scan mode. Another compare event is used to enable the ppi channel again after disabling it after 10 samples per channel. The reason for that is that I want to sample at a high frequency but only 10 samples per second. The second PPI channel is used for the fix from the link above.
PPI:
void saadc_sampling_event_init(void) { ret_code_t err_code; err_code = nrf_drv_ppi_init(); APP_ERROR_CHECK(err_code); uint32_t rtc_compare_event_addr = nrf_drv_rtc_event_address_get(&rtc, NRF_RTC_EVENT_COMPARE_0);//nrf_drv_timer_compare_event_address_get(&m_timer, NRF_TIMER_CC_CHANNEL0); uint32_t saadc_sample_task_addr = nrf_drv_saadc_sample_task_get(); /* setup ppi channel so that timer compare event is triggering sample task in SAADC */ err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel_1); APP_ERROR_CHECK(err_code); err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel_2); APP_ERROR_CHECK(err_code); err_code = nrf_drv_ppi_channel_assign(m_ppi_channel_1, rtc_compare_event_addr, saadc_sample_task_addr); APP_ERROR_CHECK(err_code); err_code = nrf_drv_ppi_channel_assign(m_ppi_channel_2, nrf_saadc_event_address_get(NRF_SAADC_EVENT_END), nrf_saadc_task_address_get(NRF_SAADC_TASK_START)); APP_ERROR_CHECK(err_code); err_code = nrf_drv_ppi_channel_enable(m_ppi_channel_2); APP_ERROR_CHECK(err_code); }
SAADC:
#define SAMPLES_IN_BUFFER 10 #define ADC_CHANNEL_COUNT 3 void saadc_sampling_event_enable(void) { ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel_1); APP_ERROR_CHECK(err_code); } void saadc_sampling_event_disable(void) { ret_code_t err_code = nrf_drv_ppi_channel_disable(m_ppi_channel_1); APP_ERROR_CHECK(err_code); } void saadc_callback(nrf_drv_saadc_evt_t const * p_event) { int value = 0; int i; //Event is triggered when buffer is full! Not when one conversion is done! ////https://devzone.nordicsemi.com/f/nordic-q-a/14777/ble_app_proximity-saadc-channel-data#post-id-85497 if (p_event->type == NRF_DRV_SAADC_EVT_DONE) { ret_code_t err_code; err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER*ADC_CHANNEL_COUNT); //Set buffer so the SAADC can write to it again. This is either "buffer 1" or "buffer 2" APP_ERROR_CHECK(err_code); NRF_LOG_INFO("ADC event number: %d", (int)m_adc_evt_counter); for (i = 0; i < SAMPLES_IN_BUFFER*ADC_CHANNEL_COUNT; i++) { NRF_LOG_INFO("%d", p_event->data.done.p_buffer[i]); switch(i%3) { case 0: battery_voltage_sum = battery_voltage_sum + p_event->data.done.p_buffer[i]; break; case 1: thermistor_1_sum = thermistor_1_sum + p_event->data.done.p_buffer[i]; break; case 2: thermistor_2_sum = thermistor_2_sum + p_event->data.done.p_buffer[i]; break; } } measDone = 1; m_adc_evt_counter++; //stop sampling until Compare 1 Event of RTC saadc_sampling_event_disable(); } } void saadc_init(void) { //Source for battery measurement: //https://devzone.nordicsemi.com/nordic/nordic-blog/b/blog/posts/measuring-lithium-battery-voltage-with-nrf52 //Sampling frequeny should be 1Hz-10Hz for high saadc input resistance value! Otherwise voltage devider will be affected by the input reistance! //Total time < Sum(CH[x].tACQ+tCONV), x=0..enabled channels (Source: Datasheet) //Total time < #Channels*(40us + 2us) //3 Channels: 126us --> max sampling rate = 1/126uS = 7.94kHz --> set RTC Compare Event (PPI) to this frequency ret_code_t err_code; //Configure SAADC nrf_drv_saadc_config_t config = NRF_DRV_SAADC_DEFAULT_CONFIG; config.resolution = NRF_SAADC_RESOLUTION_12BIT; config.oversample = NRF_SAADC_OVERSAMPLE_DISABLED; //Initialize SAADC err_code = nrf_drv_saadc_init(&config, saadc_callback); APP_ERROR_CHECK(err_code); //Configure SAADC channel 0 nrf_saadc_channel_config_t channel_config = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN7); channel_config.gain = NRF_SAADC_GAIN1_4; channel_config.acq_time = SAADC_CH_CONFIG_TACQ_3us; //needed for maximum source resistance of 800kOhm (Datasheet) --> 40us. With additional C --> 3us //channel_config.burst = NRF_SAADC_BURST_ENABLED; //Initialize SAADC channel 0 err_code = nrf_drv_saadc_channel_init(0, &channel_config); APP_ERROR_CHECK(err_code); //Configure SAADC channel 1 channel_config.pin_p = NRF_SAADC_INPUT_AIN0; channel_config.reference = NRF_SAADC_REFERENCE_VDD4; channel_config.gain = NRF_SAADC_GAIN1_4; //Initialize SAADC channel 1 err_code = nrf_drv_saadc_channel_init(1, &channel_config); APP_ERROR_CHECK(err_code); //Configure SAADC channel 2 channel_config.pin_p = NRF_SAADC_INPUT_AIN1; //Initialize SAADC channel 2 err_code = nrf_drv_saadc_channel_init(2, &channel_config); APP_ERROR_CHECK(err_code); //Set SAADC buffer 1. The SAADC will start to write to this buffer err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER*ADC_CHANNEL_COUNT); APP_ERROR_CHECK(err_code); //Set SAADC buffer 2. The SAADC will write to this buffer when buffer 1 is full. This will give the applicaiton time to process data in buffer 1. err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_IN_BUFFER*ADC_CHANNEL_COUNT); APP_ERROR_CHECK(err_code); }
RTC:
static void rtc_handler(nrf_drv_rtc_int_type_t int_type) { static int i = 2; if (int_type == NRF_DRV_RTC_INT_COMPARE0) { //nrf_gpio_pin_toggle(LED); //nrf_drv_rtc_counter_clear(&rtc); //reactivate compare irq! nrf_drv_rtc_cc_set(&rtc,0,COMPARE_COUNTERTIME * i++,true); } else if (int_type == NRF_DRV_RTC_INT_COMPARE1) { nrf_gpio_pin_toggle(LED); nrf_drv_rtc_counter_clear(&rtc); //reactivate compare irq! nrf_drv_rtc_cc_set(&rtc,0,COMPARE_COUNTERTIME * 1,true); nrf_drv_rtc_cc_set(&rtc,1,COMPARE_COUNTERTIME * 1000,true); i = 2; saadc_sampling_event_enable(); } else if (int_type == NRF_DRV_RTC_INT_TICK) { rtcCounter++; } } static void lfclk_config(void) { ret_code_t err_code = nrf_drv_clock_init(); APP_ERROR_CHECK(err_code); nrf_drv_clock_lfclk_request(NULL); } static void rtc_config(void) { uint32_t err_code; //Initialize RTC instance nrf_drv_rtc_config_t config = NRF_DRV_RTC_DEFAULT_CONFIG; config.prescaler = 32; // fRTC [kHz] = 32.768 / (PRESCALER + 1 ) = 1kHz //config.prescaler = 4095; // fRTC [kHz] = 32.768 / (PRESCALER + 1 ) --> 8Hz (minimum because prescsaler is 12bit) err_code = nrf_drv_rtc_init(&rtc, &config, rtc_handler); APP_ERROR_CHECK(err_code); //Enable tick event & interrupt nrf_drv_rtc_tick_enable(&rtc,true); //Set compare channel 0 to trigger interrupt after COMPARE_COUNTERTIME seconds err_code = nrf_drv_rtc_cc_set(&rtc,0,COMPARE_COUNTERTIME * 1,true); //1kHz APP_ERROR_CHECK(err_code); //Set compare channel 1 to trigger interrupt after COMPARE_COUNTERTIME seconds err_code = nrf_drv_rtc_cc_set(&rtc,1,COMPARE_COUNTERTIME * 1000,true); //1Hz APP_ERROR_CHECK(err_code); //Power on RTC instance nrf_drv_rtc_enable(&rtc); } void timer_handler(nrf_timer_event_t event_type, void * p_context) { }
Main:
int main(void) { /* Configure board. */ bsp_board_init(BSP_INIT_LEDS); bsp_board_leds_on(); bsp_board_init(BSP_INIT_BUTTONS); APP_ERROR_CHECK(NRF_LOG_INIT(NULL)); NRF_LOG_DEFAULT_BACKENDS_INIT(); lfclk_config(); rtc_config(); saadc_init(); saadc_sampling_event_init(); saadc_sampling_event_enable(); while(1) { if(measDone == 1) { ...
Thank you all and best regards!
Manuel