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