Use of nrfx_dppi with nrf5340 to control one GPIO

Dear,

I need to generate a pulse signal on one IO following this pattern:
HIGH for 12us ; LOW for 106us ;  and so on...


I tried to use TIMER0 with  NRF_TIMER_EVENT_COMPARE0 and NRF_TIMER_EVENT_COMPARE1 but the signal is often not respected (keeping one cycle the IO HIGH also during second period). So I assume I need to use dppi, but using the following code, I still not see anything happening on the io:

struct gpio_dt_spec mofset_ctrl_io = GPIO_DT_SPEC_GET(DT_NODELABEL(mofset_ctrl), gpios);

#define TIMER_INSTANCE_NUMBER 0
const nrfx_timer_t timer_instance = NRFX_TIMER_INSTANCE(TIMER_INSTANCE_NUMBER);


#define TOGGLE_INTERVAL_ON_US 12
#define TOGGLE_INTERVAL_OFF_US 106

static nrfx_gpiote_t const gpiote_inst = NRFX_GPIOTE_INSTANCE(0);
static uint8_t dppi_channel;



static void timer0_init(void)
{
    nrfx_err_t err;

    nrfx_timer_config_t timer_config = NRFX_TIMER_DEFAULT_CONFIG(16000000);
    timer_config.bit_width = NRF_TIMER_BIT_WIDTH_16;
    
    err = nrfx_timer_init(&timer_instance, &timer_config, NULL);
    if (err != NRFX_SUCCESS) {
        LOG_ERR("nrfx_timer_init error: %08x", err);
        return;
    }

    uint32_t ticks1 = nrfx_timer_us_to_ticks(&timer_instance, TOGGLE_INTERVAL_ON_US);
    uint32_t ticks2 = nrfx_timer_us_to_ticks(&timer_instance, TOGGLE_INTERVAL_ON_US + TOGGLE_INTERVAL_OFF_US);

    LOG_INF("COMPARE0: %d ticks, COMPARE1: %d ticks", ticks1, ticks2);

    nrfx_timer_extended_compare(
        &timer_instance,
        NRF_TIMER_CC_CHANNEL0,
        ticks1,
        NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK,  // Efface le compteur après COMPARE1
        true
    );

    nrfx_timer_extended_compare(
        &timer_instance,
        NRF_TIMER_CC_CHANNEL1,
        ticks2,
        NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK,  // On efface à COMPARE1
        true
    );

    // Connexion de l'IRQ
    IRQ_DIRECT_CONNECT(TIMER0_IRQn, 0, nrfx_timer_0_irq_handler, 0);
    irq_enable(TIMER0_IRQn);

    nrfx_timer_enable(&timer_instance);
    LOG_INF("Timer started");
}



static void gpiote_dppi_init(void)
{

    nrfx_err_t err;

    err = nrfx_gpiote_init(&gpiote_inst, NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY);
    if (err != NRFX_SUCCESS && err != NRFX_ERROR_ALREADY_INITIALIZED) {
        LOG_ERR("nrfx_gpiote_init error: %08x", err);
        return;
    }

    nrfx_gpiote_output_config_t gpiote_config = NRFX_GPIOTE_DEFAULT_OUTPUT_CONFIG;
    err = nrfx_gpiote_output_configure(&gpiote_inst, mofset_ctrl_io.pin, &gpiote_config, NULL);
    if (err != NRFX_SUCCESS) {
        LOG_ERR("nrfx_gpiote_output_configure error: %08x", err);
        return;
    }

    nrfx_gpiote_trigger_enable(&gpiote_inst, mofset_ctrl_io.pin, true);

    err = nrfx_dppi_channel_alloc(&dppi_channel);
    if (err != NRFX_SUCCESS) {
        LOG_ERR("nrfx_dppi_channel_alloc error: %08x", err);
        return;
    }

	nrfx_gppi_channel_endpoints_setup(dppi_channel,
	    nrfx_timer_compare_event_address_get(&timer_instance, NRF_TIMER_CC_CHANNEL0),
		nrfx_gpiote_out_task_address_get(&gpiote_inst, mofset_ctrl_io.pin));
    
    nrfx_gppi_channel_endpoints_setup(dppi_channel,
        nrfx_timer_compare_event_address_get(&timer_instance, NRF_TIMER_CC_CHANNEL1),
        nrfx_gpiote_out_task_address_get(&gpiote_inst, mofset_ctrl_io.pin));

    err = nrfx_dppi_channel_enable(dppi_channel);
    if (err != NRFX_SUCCESS) {
        LOG_ERR("Failed to enable DPPI channel, error: %08x", err);
        return;
    }

    LOG_INF("GPIOTE + DPPI initialized");

}

Do you know why ? I confess it was difficult to setup this with all the API changes on that topic (add of nrfx_gpiote_t in prototypes and other changes), and I never found one full example working for nrf5340 and NCS 2.7.0 I am using.

Thanks in advance for your piece of advice!

Kind regards,

Michael

Parents
  • Hello,

    Sorry for the late reply. 

    I believe you need to use two DPPI channels, one for setting the pin high, and one for setting it low. Try that, and if it doesn't work, can you please .zip and upload the application folder here, so that I can have a look?

    (you can drag and drop the file into where you are typing)

    Best regards,

    Edvin

  • Hello Edvin,

    Thanks for your reply and suggestion. I tried to add one DPPI channel like this :

    static void gpiote_dppi_init(void)
    {
    
        nrfx_err_t err;
    
        err = nrfx_gpiote_init(&gpiote_inst, NRFX_GPIOTE_DEFAULT_CONFIG_IRQ_PRIORITY);
        if (err != NRFX_SUCCESS && err != NRFX_ERROR_ALREADY_INITIALIZED) {
            LOG_ERR("nrfx_gpiote_init error: %08x", err);
            return;
        }
    
        nrfx_gpiote_output_config_t gpiote_config = NRFX_GPIOTE_DEFAULT_OUTPUT_CONFIG;
        err = nrfx_gpiote_output_configure(&gpiote_inst, mofset_ctrl_io.pin, &gpiote_config, NULL);
        if (err != NRFX_SUCCESS) {
            LOG_ERR("nrfx_gpiote_output_configure error: %08x", err);
            return;
        }
    
        nrfx_gpiote_trigger_enable(&gpiote_inst, mofset_ctrl_io.pin, true);
    
        err = nrfx_dppi_channel_alloc(&dppi_channel_a);
        if (err != NRFX_SUCCESS) {
            LOG_ERR("nrfx_dppi_channel_alloc error: %08x", err);
            return;
        }
    
    	err = nrfx_dppi_channel_alloc(&dppi_channel_b);
        if (err != NRFX_SUCCESS) {
            LOG_ERR("nrfx_dppi_channel_alloc error: %08x", err);
            return;
        }
    
    	nrfx_gppi_channel_endpoints_setup(dppi_channel_a,
    	    nrfx_timer_compare_event_address_get(&timer_instance, NRF_TIMER_CC_CHANNEL0),
    		nrfx_gpiote_out_task_address_get(&gpiote_inst, mofset_ctrl_io.pin));
        
        nrfx_gppi_channel_endpoints_setup(dppi_channel_b,
            nrfx_timer_compare_event_address_get(&timer_instance, NRF_TIMER_CC_CHANNEL1),
            nrfx_gpiote_out_task_address_get(&gpiote_inst, mofset_ctrl_io.pin));
    
        err = nrfx_dppi_channel_enable(dppi_channel_a);
        if (err != NRFX_SUCCESS) {
            LOG_ERR("Failed to enable DPPI channel, error: %08x", err);
            return;
        }
    
    	err = nrfx_dppi_channel_enable(dppi_channel_b);
        if (err != NRFX_SUCCESS) {
            LOG_ERR("Failed to enable DPPI channel, error: %08x", err);
            return;
        }
    
        LOG_INF("GPIOTE + DPPI initialized");
    
    }

    However, the result is still the same, IO is always at 0V. I will try to extract one minimal piece of my code so you can try and help me.

    Kind regards,

    Michael

  • Hello Edvin,

    Here is a minimalist app showing the issue. minimalist.zip

    Here is the line where I tested my timer:

            // USING timer_event_handler so to verify timer and ocompare is working. This solution is not suitable as not constant when CPU is used heavily
            // err = nrfx_timer_init(&timer_instance, &timer_config, timer_event_handler);
            // USING DPPI, but nothing happening on IO...
            err = nrfx_timer_init(&timer_instance, &timer_config, NULL);

    Using timer_event_handler, I can see IO is changing as expected, however it is not stable when CPU is used. Using DPPI, IO is always low... Thanks for your help!

    Kind regards,

    Michael

  • Dear,

    I also tried to use https://github.com/zephyrproject-rtos/hal_nordic/blob/nrfx-3.9.0/nrfx/samples/src/nrfx_gppi/fork/main.c sample but it is not working with nrf SDK 2.7.0 and nrf534 dk:
    I am facing issues on IRQ_DIRECT_CONNECT for NRF_GPIOTE:

        IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_GPIOTE_INST_GET(GPIOTE_INST_IDX)), IRQ_PRIO_LOWEST,
                    NRFX_GPIOTE_INST_HANDLER_GET(GPIOTE_INST_IDX), 0, 0);

    Will give:

    gen_isr_tables.py: error: multiple registrations at table_index 13 for irq 13 (0xd)
    Existing handler 0x7909, new handler 0xd5a5
    Has IRQ_CONNECT or IRQ_DIRECT_CONNECT accidentally been invoked on the same irq multiple times?

    If I comment that line, I have already assert error on nrfx_gpiote_init...

    I do not understand why with a clean project for nrf5340DK this is happening. Thanks in advance for your help!

    Kind regards,

    Michael

Reply Children
Related