I would like to use GPIOTE, PPI, and TIMER to do the following.
I'm using three GPIO pins. Each pin will get square-wave like signals of varying frequency. On each pin I need to get the interval between rising edges. My thought is to use GPIOTE to detect the rising edge on each pin and use PPI to connect that GPIOTE event to a TIMER capture task. Since I'm using NRFX_TIMER1 there are four channels available so I can assign each pin's GPIOTE interrupt to its own CC channel. After two interrupts from a pin, I'll be able to calculate the interval between rising edges for that pin. I would need to get the CC[x] value at the time of the capture task for each GPIOTE interrupt. Then do something like current - previous to get the number of timer ticks between rising edges.
I can put together code that gets me to the capture task for each pin but I can't figure out how to generate an interrupt so that I can retrieve the timer's tick count at the time of the capture task. I think I need three separate interrupts, one for each pin and the interrupt would have to be generated at the time of the capture task. Can you tell me how to do this?
I have thought about using EVENTS_COMPARE but doesn't that require the CC[x] register to hold a compare to value plus I wouldn't know in advance how to set the compare value.
I've looked into the EGU peripheral but I can't figure out how to assign a separate EGU to a given capture task. Any ideas or clarification would be greatly appreciated.
#include <stdbool.h> #include "nrf.h" #include "nrfx_gpiote.h" #include "nrfx_ppi.h" #include "nrfx_timer.h" #include "nrf_delay.h" #include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" #define PWM_ONE_PIN NRF_GPIO_PIN_MAP(0, 29) #define PWM_TWO_PIN NRF_GPIO_PIN_MAP(0, 30) #define PWM_THR_PIN NRF_GPIO_PIN_MAP(0, 31) static const nrfx_timer_t m_timer1 = NRFX_TIMER_INSTANCE(0); static uint32_t m_rpm1_count = 0; nrf_ppi_channel_t ppi_channel_1, ppi_channel_2, ppi_channel_3; void in_pin_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) { } void timer_handler_count(nrf_timer_event_t event_type, void * p_context) { } void timer_handler_read_counts(nrf_timer_event_t event_type, void * p_context) { uint32_t count1 = 0, count2 = 0, count3 = 0; count1 = nrfx_timer_capture_get(&m_timer1, NRF_TIMER_CC_CHANNEL0); count2 = nrfx_timer_capture_get(&m_timer1, NRF_TIMER_CC_CHANNEL1); count3 = nrfx_timer_capture_get(&m_timer1, NRF_TIMER_CC_CHANNEL2); NRF_LOG_INFO("C1: %d C2: %d C3: %d", count1, count2, count3); } /** * @brief Function for configuring: PWM_ONE_PIN pin for input sensing */ static void gpiote_init(void) { ret_code_t err_code; err_code = nrfx_gpiote_init(); APP_ERROR_CHECK(err_code); nrfx_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_LOTOHI(true); in_config.pull = NRF_GPIO_PIN_PULLDOWN; err_code = nrfx_gpiote_in_init(PWM_ONE_PIN, &in_config, in_pin_handler); APP_ERROR_CHECK(err_code); nrfx_gpiote_in_event_enable(PWM_ONE_PIN, false); err_code = nrfx_gpiote_in_init(PWM_TWO_PIN, &in_config, in_pin_handler); APP_ERROR_CHECK(err_code); nrfx_gpiote_in_event_enable(PWM_TWO_PIN, false); err_code = nrfx_gpiote_in_init(PWM_THR_PIN, &in_config, in_pin_handler); APP_ERROR_CHECK(err_code); nrfx_gpiote_in_event_enable(PWM_THR_PIN, false); } void timer_init() { ret_code_t err_code; nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG; timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32; err_code = nrfx_timer_init(&m_timer1, &timer_cfg, timer_handler_read_counts); APP_ERROR_CHECK(err_code); nrfx_timer_enable(&m_timer1); } void ppi_init() { ret_code_t err_code; err_code = nrfx_ppi_channel_alloc(&ppi_channel_1); APP_ERROR_CHECK(err_code); err_code = nrfx_ppi_channel_alloc(&ppi_channel_2); APP_ERROR_CHECK(err_code); err_code = nrfx_ppi_channel_alloc(&ppi_channel_3); APP_ERROR_CHECK(err_code); uint32_t gpiote_evt_addr_1 = nrfx_gpiote_in_event_addr_get(PWM_ONE_PIN); uint32_t gpiote_evt_addr_2 = nrfx_gpiote_in_event_addr_get(PWM_TWO_PIN); uint32_t gpiote_evt_addr_3 = nrfx_gpiote_in_event_addr_get(PWM_THR_PIN); uint32_t timer1_capture1_task_addr = nrfx_timer_task_address_get(&m_timer1, NRF_TIMER_TASK_CAPTURE0); uint32_t timer1_capture2_task_addr = nrfx_timer_task_address_get(&m_timer1, NRF_TIMER_TASK_CAPTURE1); uint32_t timer1_capture3_task_addr = nrfx_timer_task_address_get(&m_timer1, NRF_TIMER_TASK_CAPTURE2); uint32_t timer1_clear_task_addr = nrfx_timer_task_address_get(&m_timer1, NRF_TIMER_TASK_CLEAR); err_code = nrfx_ppi_channel_assign(ppi_channel_1, gpiote_evt_addr_1, timer1_capture1_task_addr); APP_ERROR_CHECK(err_code); // err_code = nrfx_ppi_channel_fork_assign(ppi_channel_1, // <generate an interrupt so I can get and use the value in cc[0]>); // APP_ERROR_CHECK(err_code); err_code = nrfx_ppi_channel_assign(ppi_channel_2, gpiote_evt_addr_2, timer1_capture2_task_addr); APP_ERROR_CHECK(err_code); // err_code = nrfx_ppi_channel_fork_assign(ppi_channel_2, // <generate an interrupt so I can get and use the value in cc[1]>); // APP_ERROR_CHECK(err_code); err_code = nrfx_ppi_channel_assign(ppi_channel_3, gpiote_evt_addr_3, timer1_capture3_task_addr); APP_ERROR_CHECK(err_code); // err_code = nrfx_ppi_channel_fork_assign(ppi_channel_3, // <generate an interrupt so I can get and use the value in cc{2]>); // APP_ERROR_CHECK(err_code); err_code = nrfx_ppi_channel_enable(ppi_channel_1); APP_ERROR_CHECK(err_code); err_code = nrfx_ppi_channel_enable(ppi_channel_2); APP_ERROR_CHECK(err_code); err_code = nrfx_ppi_channel_enable(ppi_channel_3); APP_ERROR_CHECK(err_code); } /** * @brief Function for application main entry. */ int main(void) { uint32_t err_code = NRF_LOG_INIT(NULL); APP_ERROR_CHECK(err_code); NRF_LOG_DEFAULT_BACKENDS_INIT(); gpiote_init(); timer_init(); ppi_init(); NRF_LOG_INFO("Example start\r\n"); while (true) { while(NRF_LOG_PROCESS() == true); } }