Using timer capture, gpiote and ppi together to measure pulse widths

Hi,

I am trying to set up a project that continuously measures the pulse width of a signal that may or may not be present at a pin.

I want to use a Timer in capture mode that automatically starts when the edge signal changes, and generates an interrupt when the next edge is detected so it can store the value in a running array. Then after the interrupt the process starts again.

(I am using SDK 17.0.2)

Timer->GPIOTE->PPI

I am struggling a little with the config, and am wondering if this is the correct approach or not:

#include "nrfx_timer.h"
#include "nrfx_gpiote.h"
#include "nrfx_ppi.h"

#define IR_SAMPLE_SIZE  32

#define IR_GPIOTE_CHANNEL 0

static volatile uint32_t IR_PulseTimes[IR_SAMPLE_SIZE];
static volatile uint16_t IR_PulseTimesIndex;

#define TIMER_INST_IDX 4 // Or the desired timer instance index
static nrfx_timer_t timer_inst = NRFX_TIMER_INSTANCE(TIMER_INST_IDX);

static nrf_ppi_channel_t ppi_channel;

static void timer_handler(nrf_timer_event_t event_type, void *p_context) 
{
    (void)p_context; // Unused parameter

    if (event_type == NRF_TIMER_TASK_CAPTURE0) 
    {
        IR_PulseTimes[IR_PulseTimesIndex] = nrfx_timer_capture(&timer_inst, NRF_TIMER_CC_CHANNEL0);
        if (++IR_PulseTimesIndex >= IR_SAMPLE_SIZE)
        {
            IR_PulseTimesIndex = 0;
        }
    }
}

void IR_Init(void)
{
    memset((uint8_t*)IR_PulseTimes, 0x00, sizeof(IR_PulseTimes));
    IR_PulseTimesIndex = 0;

    nrfx_gpiote_in_config_t config = NRFX_GPIOTE_CONFIG_IN_SENSE_LOTOHI(false);
    config.pull = NRF_GPIO_PIN_NOPULL;
    APP_ERROR_CHECK(nrfx_gpiote_in_init(IO_IR, &config, NULL));

    nrfx_timer_config_t timer_cfg = NRFX_TIMER_DEFAULT_CONFIG;
    timer_cfg.frequency = NRF_TIMER_FREQ_16MHz; 
    timer_cfg.mode = NRF_TIMER_MODE_TIMER;
    timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
    nrfx_timer_init(&timer_inst, &timer_cfg, timer_handler);    
    
    // Find an available PPI channel
    nrfx_ppi_channel_alloc(&ppi_channel);
    
    // Configure PPI channel to connect GPIOTE event to TIMER capture task
    nrfx_ppi_channel_assign(ppi_channel,
                nrfx_gpiote_in_event_addr_get(IO_IR),
                nrfx_timer_capture_task_address_get(&timer_inst, NRF_TIMER_CC_CHANNEL0));
    
    
}

void IR_Enable(bool Enabled)
{
    if (Enabled)
    {
        memset((uint8_t*)IR_PulseTimes, 0x00, sizeof(IR_PulseTimes));
        IR_PulseTimesIndex = 0;
        nrfx_timer_compare_int_enable(&timer_inst, NRF_TIMER_CC_CHANNEL0);
        nrfx_gpiote_in_event_enable(IO_IR, true);
        nrfx_timer_enable(&timer_inst);
        nrf_ppi_channel_enable(ppi_channel);
    }
    else
    {
        nrf_ppi_channel_disable(ppi_channel);
        nrfx_timer_disable(&timer_inst);
        nrfx_gpiote_in_event_enable(IO_IR, false);
        nrfx_timer_compare_int_disable(&timer_inst, NRF_TIMER_CC_CHANNEL0);
    }
}

I would appreciate any pointers or examples to get this working, i cannot seem to get the interrupt firing.

Many thanks

Billy

Related