Hello,
I'm trying to port the radio synchronization to a nRF5340. For this i need to use a DPPI group that clear a timer and disable itself for doing the task only 1 time. Unfortunately when i try to do it, the timer is not cleared.
I have try to isolate the problem with a simpler code that use a timer and DPPI group for making some shorter period. The code is not clearing the timer when using the DPPI group:
/* Includes ------------------------------------------------------------------*/
#include <nrfx_dppi.h>
#include <nrfx_gpiote.h>
#include <nrfx_timer.h>
#include <drivers/clock_control/nrf_clock_control.h>
/* Private define ------------------------------------------------------------*/
#define OUTPUT_PIN NRF_GPIO_PIN_MAP(1,7)
#define PERIOD (40*16000)
#define SHORT_PERIOD (20*16000)
#define OFFSET 1
#define PULSE_WIDTH 16000
/* Private variables ---------------------------------------------------------*/
// Timer need 4 CC
// CC0: overflow
// CC1: short period
// CC2: for generating the raise of the output signal
// CC3: for generating the fall of the output signal
static const nrfx_timer_t timer = NRFX_TIMER_INSTANCE(0);
static nrf_dppi_channel_group_t group;
static uint32_t counter = 0;
/* Private functions declaration ---------------------------------------------*/
static void timer_init(void);
static void configure_one_time_clear(void);
static void timer_handler(nrf_timer_event_t event_type, void *p_context);
static void output_init(void);
/* Public functions ----------------------------------------------------------*/
void main(void)
{
z_nrf_clock_bt_ctlr_hf_request();
timer_init();
output_init();
while(1) {
k_sleep(K_MSEC(1000));
}
}
/* Private functions implementation ------------------------------------------*/
static void timer_init(void)
{
nrfx_timer_config_t timer_config = NRFX_TIMER_DEFAULT_CONFIG;
timer_config.bit_width = NRF_TIMER_BIT_WIDTH_32;
nrfx_timer_init(&timer, &timer_config, timer_handler);
nrfx_timer_compare(&timer, NRF_TIMER_CC_CHANNEL0, PERIOD, true);
nrf_timer_shorts_enable(timer.p_reg, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK);
nrfx_timer_compare(&timer, NRF_TIMER_CC_CHANNEL1, SHORT_PERIOD, false);
nrfx_timer_compare(&timer, NRF_TIMER_CC_CHANNEL2, OFFSET, false);
nrfx_timer_compare(&timer, NRF_TIMER_CC_CHANNEL3, OFFSET + PULSE_WIDTH, false);
IRQ_CONNECT(TIMER0_IRQn, NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY - 1,
nrfx_timer_0_irq_handler, NULL, 0);
nrfx_timer_enable(&timer);
configure_one_time_clear();
}
static void configure_one_time_clear(void)
{
uint8_t channel;
nrfx_dppi_group_alloc(&group);
nrfx_dppi_channel_alloc(&channel);
nrf_timer_publish_set(timer.p_reg, NRF_TIMER_EVENT_COMPARE1, channel);
nrf_timer_subscribe_set(timer.p_reg, NRF_TIMER_TASK_CLEAR, channel);
nrf_dppi_subscribe_set(NRF_DPPIC, nrf_dppi_group_disable_task_get(group), channel);
nrfx_dppi_channel_include_in_group(channel, group);
}
static void timer_handler(nrf_timer_event_t event_type, void *p_context)
{
if (event_type == NRF_TIMER_EVENT_COMPARE0) {
counter++;
if (counter == 2) {
counter = 0;
nrfx_dppi_group_enable(group);
}
}
}
static void output_init(void)
{
if (!nrfx_gpiote_is_init()) {
nrfx_gpiote_init(0);
}
nrfx_gpiote_out_config_t const out_config = {
.init_state = NRF_GPIOTE_INITIAL_VALUE_LOW,
.action = NRF_GPIOTE_POLARITY_TOGGLE,
.task_pin = true,
};
nrfx_gpiote_out_init(OUTPUT_PIN, &out_config);
nrfx_gpiote_out_task_enable(OUTPUT_PIN);
uint8_t channel;
nrfx_dppi_channel_alloc(&channel);
nrf_timer_publish_set(timer.p_reg, NRF_TIMER_EVENT_COMPARE2, channel);
nrf_gpiote_subscribe_set(
NRF_GPIOTE,
nrfx_gpiote_set_task_get(OUTPUT_PIN),
channel);
nrfx_dppi_channel_enable(channel);
nrfx_dppi_channel_alloc(&channel);
nrf_timer_publish_set(timer.p_reg, NRF_TIMER_EVENT_COMPARE3, channel);
nrf_gpiote_subscribe_set(
NRF_GPIOTE,
nrfx_gpiote_clr_task_get(OUTPUT_PIN),
channel);
nrfx_dppi_channel_enable(channel);
}
The equivalent code that use PPI instead of DPPI work correctly on a nRF52840:
/* Includes ------------------------------------------------------------------*/
#include <nrfx_ppi.h>
#include <nrfx_gpiote.h>
#include <nrfx_timer.h>
#include <drivers/clock_control/nrf_clock_control.h>
/* Private define ------------------------------------------------------------*/
#define OUTPUT_PIN NRF_GPIO_PIN_MAP(1,7)
#define PERIOD (40*16000)
#define SHORT_PERIOD (20*16000)
#define OFFSET 1
#define PULSE_WIDTH 16000
/* Private variables ---------------------------------------------------------*/
// Timer need 4 CC
// CC0: overflow
// CC1: short period
// CC2: for generating the raise of the output signal
// CC3: for generating the fall of the output signal
static const nrfx_timer_t timer = NRFX_TIMER_INSTANCE(0);
static nrf_ppi_channel_group_t group;
static uint32_t counter = 0;
/* Private functions declaration ---------------------------------------------*/
static void timer_init(void);
static void configure_one_time_clear(void);
static void timer_handler(nrf_timer_event_t event_type, void *p_context);
static void output_init(void);
/* Public functions ----------------------------------------------------------*/
void main(void)
{
z_nrf_clock_bt_ctlr_hf_request();
timer_init();
output_init();
while(1) {
k_sleep(K_MSEC(1000));
}
}
/* Private functions implementation ------------------------------------------*/
static void timer_init(void)
{
nrfx_timer_config_t timer_config = NRFX_TIMER_DEFAULT_CONFIG;
timer_config.bit_width = NRF_TIMER_BIT_WIDTH_32;
nrfx_timer_init(&timer, &timer_config, timer_handler);
nrfx_timer_compare(&timer, NRF_TIMER_CC_CHANNEL0, PERIOD, true);
nrf_timer_shorts_enable(timer.p_reg, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK);
nrfx_timer_compare(&timer, NRF_TIMER_CC_CHANNEL1, SHORT_PERIOD, false);
nrfx_timer_compare(&timer, NRF_TIMER_CC_CHANNEL2, OFFSET, false);
nrfx_timer_compare(&timer, NRF_TIMER_CC_CHANNEL3, OFFSET + PULSE_WIDTH, false);
IRQ_CONNECT(TIMER0_IRQn, NRFX_TIMER_DEFAULT_CONFIG_IRQ_PRIORITY - 1,
nrfx_timer_0_irq_handler, NULL, 0);
nrfx_timer_enable(&timer);
configure_one_time_clear();
}
static void configure_one_time_clear(void)
{
nrf_ppi_channel_t channel;
nrfx_ppi_group_alloc(&group);
nrfx_ppi_channel_alloc(&channel);
nrfx_ppi_channel_assign(channel,
nrfx_timer_event_address_get(&timer, NRF_TIMER_EVENT_COMPARE1),
nrfx_timer_task_address_get(&timer, NRF_TIMER_TASK_CLEAR));
nrfx_ppi_channel_include_in_group(channel, group);
nrfx_ppi_channel_alloc(&channel);
nrfx_ppi_channel_assign(channel,
nrfx_timer_event_address_get(&timer, NRF_TIMER_EVENT_COMPARE1),
nrfx_ppi_task_addr_group_disable_get(group));
nrfx_ppi_channel_include_in_group(channel, group);
}
static void timer_handler(nrf_timer_event_t event_type, void *p_context)
{
if (event_type == NRF_TIMER_EVENT_COMPARE0) {
counter++;
if (counter == 2) {
counter = 0;
nrfx_ppi_group_enable(group);
}
}
}
static void output_init(void)
{
if (!nrfx_gpiote_is_init()) {
nrfx_gpiote_init(0);
}
nrfx_gpiote_out_config_t const out_config = {
.init_state = NRF_GPIOTE_INITIAL_VALUE_LOW,
.action = NRF_GPIOTE_POLARITY_TOGGLE,
.task_pin = true,
};
nrfx_gpiote_out_init(OUTPUT_PIN, &out_config);
nrfx_gpiote_out_task_enable(OUTPUT_PIN);
nrf_ppi_channel_t channel;
nrfx_ppi_channel_alloc(&channel);
nrf_ppi_event_endpoint_setup(NRF_PPI, channel, nrf_timer_event_address_get(timer.p_reg, NRF_TIMER_EVENT_COMPARE2));
nrf_ppi_task_endpoint_setup(NRF_PPI, channel, nrfx_gpiote_set_task_addr_get(OUTPUT_PIN));
nrfx_ppi_channel_enable(channel);
nrfx_ppi_channel_alloc(&channel);
nrf_ppi_event_endpoint_setup(NRF_PPI, channel, nrf_timer_event_address_get(timer.p_reg, NRF_TIMER_EVENT_COMPARE3));
nrf_ppi_task_endpoint_setup(NRF_PPI, channel, nrfx_gpiote_clr_task_addr_get(OUTPUT_PIN));
nrfx_ppi_channel_enable(channel);
}
Is there something wrong in my DPPI code or is there a bug or limitation in the nRF5340 ?