Ηι
Hi everyone,
I have written a code to sample from an analog input using RTC and PPI.
The SAADC does not start on RTC compare event.
The RTC compare channel works fine. When I enable the interrupts, I capture the NRFX_RTC_INT_COMPARE0 in the rtc_handler function, however, the I cannot trigger the ADC sampling through PPI
What am I missing?
This my implementation:
/*To do
- Use the new nrfx implementation and not the legacy
- Disable the legacy definitions from sdk_config
*/
#include "app_error.h"
#include "app_timer.h"
#include "app_util_platform.h"
#include "boards.h"
#include "nrf.h"
#include "nrf_delay.h"
#include "nrf_drv_clock.h"
#include "nrf_drv_timer.h"
#include "nrf_pwr_mgmt.h"
#include "nrfx_ppi.h"
#include "nrfx_rtc.h"
#include "nrfx_saadc.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#define SAMPLES_IN_BUFFER 5 // define the number of samples to get berore generate the NRFX_SAADC_EVT_DONE event. A sample if captured for every clock tick
#define RTC_FREQUENCY 8 // tick period (frequency in Hz) - e.g RTC_FREQUENCY 8 -> period = 1/8 = 125ms
#define COMPARE_CHANNEL_0 0 // define the compare channel to set - RTC1 has 3 x compare channels while RTC1 & RTC2 have 4 x compare channels
#define COUNTER_VALUE 8 // define counter's value. Instacts the counter to produce an event after COUNTER_VALUE x period - e.g if period is 125ms and COUNTER_VALUE 8 the event will be produced after 8 x 125ms = 1s
APP_TIMER_DEF(m_notifications_timer); /**< Handler for repeated timer used send notifications. */
const nrfx_rtc_t rtc = NRFX_RTC_INSTANCE(2); // create an instance for RTC2 (RTC0 is used by the Sofd Device and RTC1 by the app timer)
static nrf_ppi_channel_t m_ppi_channel; // create an instance for PPI channels
static nrf_ppi_channel_t m_start_SAADC_ppi_channel; // create an instance for PPI channels
static nrf_saadc_value_t m_buffer_pool[2][SAMPLES_IN_BUFFER];
static uint32_t m_adc_evt_counter;
static void ppi_init(void) {
uint32_t err_code;
uint32_t rtc_compare_event_addr; // variable to hold the address of rtc event
uint32_t rtc_clear_task_addr; // variable to hold the address of rtc task
uint32_t saadc_sample_task_addr; // variable to hold the address of saadc task
rtc_compare_event_addr = nrfx_rtc_event_address_get(&rtc, NRF_RTC_EVENT_COMPARE_0); // get the address of COMPARE 0 event
rtc_clear_task_addr = nrfx_rtc_task_address_get(&rtc, NRF_RTC_TASK_CLEAR); // get the address of RTC clear task
saadc_sample_task_addr = nrfx_saadc_sample_task_get(); // getting the address of NRF_SAADC_TASK_SAMPLE. If low power is enabled it will get the address of NRF_SAADC_TASK_START
err_code = nrfx_ppi_channel_alloc(&m_ppi_channel); // allocate the channel to start SAADC task on RTC comprare event
APP_ERROR_CHECK(err_code);
err_code = nrfx_ppi_channel_alloc(&m_start_SAADC_ppi_channel); // allocate a channel to start SAADC when conversion ends
APP_ERROR_CHECK(err_code);
err_code = nrfx_ppi_channel_assign(m_ppi_channel, rtc_compare_event_addr, saadc_sample_task_addr); // Start the SAADC on RTC COMPARE event
APP_ERROR_CHECK(err_code);
err_code = nrfx_ppi_channel_assign(m_start_SAADC_ppi_channel, nrf_saadc_event_address_get(NRF_SAADC_EVENT_DONE), nrfx_saadc_sample_task_get()); // Make sure that the SAADC is always started when it ends a conversion
APP_ERROR_CHECK(err_code);
// err_code = nrfx_ppi_channel_fork_assign(m_ppi_channel, rtc_clear_task_addr); // fork the RTC clear task to RTC comprare[0] event
// APP_ERROR_CHECK(err_code);
err_code = nrfx_ppi_channel_enable(m_ppi_channel); // Enable the PPI channel
APP_ERROR_CHECK(err_code);
err_code = nrfx_ppi_channel_enable(m_start_SAADC_ppi_channel); // Enable the PPI channel
APP_ERROR_CHECK(err_code);
}
// We wll not use the rtc handler in that case since we want to trigger ADC sampling through PPI
static void rtc_handler(nrfx_rtc_int_type_t int_type) {
uint32_t err_code;
if (int_type == NRFX_RTC_INT_COMPARE0) {
NRF_LOG_INFO("Print here");
nrfx_rtc_counter_clear(&rtc);
err_code = nrfx_rtc_cc_set(&rtc, COMPARE_CHANNEL_0, COUNTER_VALUE, true);
APP_ERROR_CHECK(err_code);
}
}
// configure all RTC settings
static void rtc_config() {
uint32_t err_code; // variable to hold the error values
nrfx_rtc_config_t rtc_config = NRFX_RTC_DEFAULT_CONFIG; // set the default settings for RTC
rtc_config.prescaler = RTC_FREQ_TO_PRESCALER(RTC_FREQUENCY); // configure the prescaler: e.g 32768 / (4095 + 1) = 8Hz = 125ms (tick event every 125ms)
err_code = nrfx_rtc_init(&rtc, &rtc_config, rtc_handler); // initialize the RTC. After initialization, the instance is in power off state and it must be enabled
APP_ERROR_CHECK(err_code);
/* Setting a CC (Compare Channel). Set COMPARE_CHANNEL as compare channel. When the counter value is equal to COUNTER_VALUE the NRF_RTC_EVENT_COMPARE_0 will be generated.
Let interrupts disabled (false) since we do not use interrupt to start saadc, we use the PPI based on the NRF_RTC_EVENT_COMPARE_0 event */
err_code = nrfx_rtc_cc_set(&rtc, COMPARE_CHANNEL_0, COUNTER_VALUE, false);
APP_ERROR_CHECK(err_code);
nrfx_rtc_enable(&rtc); // enable the RTC
}
void saadc_callback(nrfx_saadc_evt_t const *p_event) {
ret_code_t err_code;
NRF_LOG_INFO("Event type: %d", p_event->type);
if (p_event->type == NRFX_SAADC_EVT_DONE) { // the NRFX_SAADC_EVT_DONE event is produced when the buffer is full. An saadc value is captured for every clock tick
NRF_LOG_INFO("Event type: NRFX_SAADC_EVT_DONE");
err_code = nrfx_ppi_channel_disable(m_start_SAADC_ppi_channel);
APP_ERROR_CHECK(err_code);
err_code = nrfx_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
int i;
NRF_LOG_INFO("ADC event number: %d", (int)m_adc_evt_counter);
for (i = 0; i < SAMPLES_IN_BUFFER; i++) {
NRF_LOG_INFO("%d", p_event->data.done.p_buffer[i]);
}
m_adc_evt_counter++;
}
nrfx_rtc_counter_clear(&rtc);
nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
// nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP);
err_code = nrfx_ppi_channel_enable(m_start_SAADC_ppi_channel); // Enable the start_SAADC PPI channel
APP_ERROR_CHECK(err_code);
}
void saadc_init(void) {
ret_code_t err_code;
static const nrfx_saadc_config_t default_config = NRFX_SAADC_DEFAULT_CONFIG; // from sdk_config file: resolution = 12bit , low power mode = true
nrf_saadc_channel_config_t channel_config = NRFX_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN6); // AIN6 is the pin P0.30 - https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Fpin.html
err_code = nrfx_saadc_init(&default_config, saadc_callback);
APP_ERROR_CHECK(err_code);
err_code = nrfx_saadc_channel_init(0, &channel_config);
APP_ERROR_CHECK(err_code);
err_code = nrfx_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
err_code = nrfx_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
}
// Initialize the low frequency clock. Do not need to initialize if using the soft device
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 log_init() {
uint32_t err_code = NRF_LOG_INIT(NULL);
APP_ERROR_CHECK(err_code);
NRF_LOG_DEFAULT_BACKENDS_INIT();
}
static void pwr_mgmt_init() {
ret_code_t ret_code = nrf_pwr_mgmt_init();
APP_ERROR_CHECK(ret_code);
}
/**
* @brief Function for main application entry.
*/
int main(void) {
log_init();
pwr_mgmt_init();
lfclk_config();
NRF_POWER->DCDCEN = 1; // Enabling the DCDC converter for lower current consumption
saadc_init();
rtc_config();
ppi_init();
NRF_LOG_INFO("SAADC HAL simple example started.");
while (1) {
nrf_pwr_mgmt_run();
NRF_LOG_FLUSH();
}
}
/** @} */
