Timer in counter mode and PPI

Hi everyone,

I started playing around with the PPI interface and I'm facing some Issues. The idea is to create a hardware impuls counter. A gpio pin is set as output for the PPI and a hardware timer is set as input. The Timer is set into counter mode, so every time an impuls is registered the timer counts one up. I managed to connect a LED and a button to turn on and off when switched. The timer however doesn't seem to be increasing its counter value.

Following code has been written:

/*
 * Copyright (c) 2019 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/kernel.h>
#include "impuls_counter.h"

#include <nrfx_gpiote.h>
#include <helpers/nrfx_gppi.h>
#if defined(DPPI_PRESENT)
#include <nrfx_dppi.h>
#else
#include <nrfx_ppi.h>
#endif

#include <zephyr/logging/log.h>
#include <zephyr/irq.h>
#include <nrfx_timer.h>
#include <hal/nrf_timer.h>
#include <nrfx_timer.h>

#define INPUT_PIN DT_GPIO_PIN(DT_ALIAS(id1), gpios)
#define OUTPUT_PIN DT_GPIO_PIN(DT_ALIAS(led1), gpios)

const uint32_t rising_edge_pin = INPUT_PIN;
const uint32_t falling_edge_pin = INPUT_PIN;

LOG_MODULE_REGISTER(nrfx_sample, LOG_LEVEL_INF);

static const nrfx_timer_t timer = NRFX_TIMER_INSTANCE(0);

void timer_event_handler(nrf_timer_event_t event_type, void *p_context)
{
	printk("Called\n");
}

static void gpiote_event_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
	if (pin == falling_edge_pin)
	{
		/* Read out timer CC register and clear it */
		// uint32_t timer_cc_val = nrf_timer_cc_read(timer.p_reg, 0);
		uint32_t timer_cc_val = timer.p_reg->CC[0];
		printk("Raw timer val: %x\n", timer_cc_val);
		/* Calculate pulse length, 16M base freq */
		uint32_t pulse_len_us = (timer_cc_val >> 4) - 1;
		uint32_t pulse_len_ms = pulse_len_us / 1000;
		printk("ms: %d\n", pulse_len_ms);
		printk("us: %d\n", pulse_len_us);
		nrfx_timer_clear(&timer);
	}
	else
	{
		printk("Unknown pin. Check your button configuration\n");
	}
}

static void button_event_handler(nrfx_gpiote_pin_t pin, nrfx_gpiote_trigger_t trigger, void *context)
{
	LOG_INF("GPIO input event callback");
}

static void gpiote_init(void)
{
	nrfx_gpiote_in_config_t falling_edge = {0};
	nrfx_gpiote_in_config_t rising_edge = {0};

	falling_edge.hi_accuracy = 1;
	falling_edge.pull = NRF_GPIO_PIN_PULLUP;
	falling_edge.sense = NRF_GPIOTE_POLARITY_LOTOHI;

	rising_edge.hi_accuracy = 1;
	rising_edge.pull = NRF_GPIO_PIN_PULLUP;
	rising_edge.sense = NRF_GPIOTE_POLARITY_HITOLO;


	uint32_t err = nrfx_gpiote_in_init(rising_edge_pin, &rising_edge, NULL);
	if (err != NRFX_SUCCESS)
	{
		printk("gpiote1 err: %x", err);
		return;
	}

	err = nrfx_gpiote_in_init(falling_edge_pin, &falling_edge, gpiote_event_handler);
	if (err != NRFX_SUCCESS)
	{
		printk("gpiote2 err: %x", err);
		return;
	}

	nrfx_gpiote_in_event_enable(rising_edge_pin, 1);
	nrfx_gpiote_in_event_enable(falling_edge_pin, 1);

}

void Impuls_Counter_nrfx_init(void)
{
	uint8_t in_channel, out_channel;
	uint8_t ppi_channel;
	nrfx_err_t err;

	nrfx_timer_config_t timer_config = NRFX_TIMER_DEFAULT_CONFIG;
	timer_config.bit_width = 3;
	timer_config.mode = TIMER_MODE_MODE_LowPowerCounter;


	err = nrfx_timer_init(&timer, &timer_config, timer_event_handler);
	if (err != NRFX_SUCCESS)
	{
		LOG_ERR("Failed to init timer, error: 0x%08X", err);
		return;
	}

	IRQ_DIRECT_CONNECT(DT_IRQN(DT_NODELABEL(gpiote)), 0, nrfx_gpiote_irq_handler, 0);
	irq_enable(DT_IRQN(DT_NODELABEL(gpiote)));

	gpiote_init();

	err = nrfx_gpiote_channel_alloc(&in_channel);
	if (err != NRFX_SUCCESS)
	{
		LOG_ERR("Failed to allocate in_channel, error: 0x%08X", err);
		return;
	}

	err = nrfx_gpiote_channel_alloc(&out_channel);
	if (err != NRFX_SUCCESS)
	{
		LOG_ERR("Failed to allocate out_channel, error: 0x%08X", err);
		return;
	}

	// Initialize input pin to generate event on high to low transition
	// (falling edge) and call button_handler()
	static const nrfx_gpiote_input_config_t input_config = {
		.pull = NRF_GPIO_PIN_PULLUP,
	};

	const nrfx_gpiote_trigger_config_t trigger_config = {
		.trigger = NRFX_GPIOTE_TRIGGER_HITOLO,
		.p_in_channel = &in_channel,
	};

	static const nrfx_gpiote_handler_config_t handler_config = {
		.handler = button_event_handler,
	};

	err = nrfx_gpiote_input_configure(INPUT_PIN,
									  &input_config,
									  &trigger_config,
									  &handler_config);

	if (err != NRFX_SUCCESS)
	{
		LOG_ERR("nrfx_gpiote_input_configure error: 0x%08X", err);
		return;
	}

	// Initialize output pin. SET task will turn the LED on,
	// CLR will turn it off and OUT will toggle it.
	static const nrfx_gpiote_output_config_t output_config = {
		.drive = NRF_GPIO_PIN_S0S1,
		.input_connect = NRF_GPIO_PIN_INPUT_DISCONNECT,
		.pull = NRF_GPIO_PIN_NOPULL,
	};

	const nrfx_gpiote_task_config_t task_config = {
		.task_ch = out_channel,
		.polarity = NRF_GPIOTE_POLARITY_TOGGLE,
		.init_val = 1,
	};

	err = nrfx_gpiote_output_configure(OUTPUT_PIN,
									   &output_config,
									   &task_config);

	if (err != NRFX_SUCCESS)
	{
		LOG_ERR("nrfx_gpiote_output_configure error: 0x%08X", err);
		return;
	}

	nrfx_gpiote_trigger_enable(INPUT_PIN, true);
	nrfx_gpiote_out_task_enable(OUTPUT_PIN);

	LOG_INF("nrfx_gpiote initialized");

	// Allocate a (D)PPI channel.
	err = nrfx_gppi_channel_alloc(&ppi_channel);
	if (err != NRFX_SUCCESS)
	{
		LOG_ERR("nrfx_gppi_channel_alloc error: 0x%08X", err);
		return;
	}

	// Configure endpoints of the channel so that the input pin event is
	// connected with the output pin OUT task. This means that each time
	// the button is pressed, the LED pin will be toggled.
	nrfx_gppi_channel_endpoints_setup(ppi_channel,
									  nrfx_gpiote_in_event_addr_get(INPUT_PIN),
									  nrfx_gpiote_out_task_addr_get(OUTPUT_PIN));

	nrfx_gppi_channel_endpoints_setup(ppi_channel,
									  nrfx_gpiote_in_event_addr_get(INPUT_PIN),
									  nrfx_timer_task_address_get(&timer, NRF_TIMER_TASK_COUNT));

	// Enable the Channel
	nrfx_gppi_channels_enable(BIT(ppi_channel));

	while (true)
	{
		uint32_t value = nrfx_timer_capture_get(&timer, NRF_TIMER_CC_CHANNEL0);
		printk("Value %i\n", value);
		k_sleep(K_MSEC(1000));
	}
}

Prj.conf

# GPIO Configurations
CONFIG_NFCT_PINS_AS_GPIOS=y


# Configurations for timer driver
CONFIG_GPIO=y
CONFIG_SERIAL=y
CONFIG_STDOUT_CONSOLE=y
CONFIG_NRFX_GPIOTE=y
CONFIG_NRFX_TIMER0=y

# Used for timer driver
CONFIG_COMPILER_OPT="-DGPIOTE_IRQn=GPIOTE1_IRQn -DNRFX_TIMER_ENABLED=1 -DNRFX_GPIOTE_ENABLED=1 -DNRFX_TIMER0_ENABLED=1"

I know its a bit messy. Your help is highly appreciated.

Best regards

Maikel

Related