Using PPI trace with Timer0

Hi,

I tried to implement PPI for a very timing sensitive application. The sample PPI_trace uses the RTC but it is too slow for my application so I'd want ot use timer0 but it seems its instances are in nrfx dependencies. Is there a clean way to use it ?

Best reagrds,

Charles

Parents
  • Hi,

    Sorry for the late answer. After some invastigation, it seems that my GPIOs cause the nRF52840 to go into fault. It is weird because there is already quite a few GPIOs in the application and I use the same syntax. I have no build issues, when I flash the board, I can see a led that I set up before goes on and off (it is supposed to stay on) and when I use the debug a large part of my setup works great until I try to setup this new GPIO that goes to fault and then reset the board.

    My overlay : 

    / {
        pwmleds { 
            compatible = "pwm-leds";
            pwm_led_0 {
                pwms = <&pwm0 42>;
                status = "okay";
            };
            pwm_led1: pwm_led1 {
                pwms = <&pwm0 43>;
                status = "okay";
            };
            pwm_led2: pwm_led2 {
                pwms = <&pwm0 44>;
                status = "okay";
            };
            pwm_led3: pwm_led3 {
                pwms = <&pwm0 16>;
                status = "okay";
            };
        };
    
        encoder {
    		compatible = "gpio-keys";
    		encoder_a: encoder_a {
    			gpios = < &gpio1 0x8 GPIO_ACTIVE_LOW >;
    			label = "Encodeur port A";
    		};
    		encoder_b: encoder_b {
    			gpios = < &gpio1 0x7 GPIO_ACTIVE_LOW >;
    			label = "Encodeur port B";
    		};
        };
    
        powerstage {
    		compatible = "gpio-keys";
    		filteredsynchro: filteredsynchro {
    			gpios = < &gpio1 0x0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW) >;
    			label = "Filtered Synchro";
    		};
    		unfilteredsynchro: unfilteredsynchro {
    			gpios = < &gpio1 0x1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW) >;
    			label = "Unfiltered Synchro";
    		};
            igbtplus: igbtplus {
    			gpios = < &gpio1 0x2 (GPIO_PULL_UP | GPIO_ACTIVE_LOW) >;
    			label = "Command IGBT Plus";
    		};
            igbtminus: igbtminus {
    			gpios = < &gpio1 0x3 (GPIO_PULL_UP | GPIO_ACTIVE_LOW) >;
    			label = "Command IGBT Minus";
    		};
        };
    
        buttons {
    		compatible = "gpio-keys";
    		button0: button_0 {
    			gpios = <&gpio1 14 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
    			label = "Push button switch 0";
    		};
        };
    
        aliases {
            pwm-led0 = &pwm_led0;
            pwm-led1 = &pwm_led1;
            pwm-led2 = &pwm_led2;
            pwm-led3 = &pwm_led3;
            encoder-a = &encoder_a;
            encoder-b = &encoder_b;
            filterdsynchro    = &filteredsynchro;
            unfilteredsynchro = &unfilteredsynchro;
            igbtplus          = &igbtplus;
            igbtminus         = &igbtminus;
            led0 = &led0;
    		led1 = &led1;
    		led2 = &led2;
    		led3 = &led3;
        };
    };
    
    &pwm0 {
        status = "okay";
        ch0-pin = <42>;
        ch0-inverted;
        ch1-pin = <43>;
        ch1-inverted;
        ch2-pin = <44>;
        ch2-inverted;
        ch3-pin = <16>;
        ch3-inverted;
    };
    

    Most GPIO works, the new ones are filteredsynchro, unfilteredsynchro, igbtplus, igbtminus. I use this synthax to setup the ones the work : 

    #define ENCODER_A_NODE       DT_ALIAS(encoder_a)
    static const struct gpio_dt_spec encoder_a = GPIO_DT_SPEC_GET_BY_IDX(ENCODER_A_NODE, gpios, 0);
    static struct gpio_callback encoder_a_cb_data;
    
    #define BUTTON	DT_ALIAS(sw0)
    static const struct gpio_dt_spec button = GPIO_DT_SPEC_GET_OR(BUTTON, gpios, {0});
    static struct gpio_callback button_cb_data;
    
    void setup()
    {
        ret = gpio_pin_configure_dt(&encoder_a, GPIO_INPUT | GPIO_INT_DEBOUNCE);*
        ret = gpio_pin_interrupt_configure_dt(&encoder_a, GPIO_INT_EDGE_RISING);
        gpio_init_callback(&encoder_a_cb_data, encoder_a_isr, BIT(encoder_a.pin));
    	gpio_add_callback(encoder_a.port, &encoder_a_cb_data);
    	
    	ret = gpio_pin_configure_dt(&button, GPIO_INPUT | GPIO_INT_DEBOUNCE);
    	ret = gpio_pin_interrupt_configure_dt(&button, GPIO_INT_EDGE_BOTH);
    	gpio_init_callback(&button_cb_data, button_pressed, BIT(button.pin));
    	gpio_add_callback(button.port, &button_cb_data);
    }

    Button uses a synthax I found on another sample.

    I am now trying to use the same synthax : 

    #define FILTERED_SYNCHRO_NODE	DT_ALIAS(filteredsynchro)
    #define UNFILTERED_SYNCHRO_NODE DT_ALIAS(unfilteredsynchro)
    #define IGBT_PLUS_NODE      	DT_ALIAS(igbtplus)
    #define IGBT_MINUS_NODE     	DT_ALIAS(igbtminus)
    
    static const struct gpio_dt_spec filtered_synchro   = GPIO_DT_SPEC_GET_OR(FILTERED_SYNCHRO_NODE  , gpios, {0});
    static const struct gpio_dt_spec unfiltered_synchro = GPIO_DT_SPEC_GET_OR(UNFILTERED_SYNCHRO_NODE, gpios, {0});
    static const struct gpio_dt_spec igbt_plus          = GPIO_DT_SPEC_GET_OR(IGBT_PLUS_NODE         , gpios, {0});
    static const struct gpio_dt_spec igbt_minus         = GPIO_DT_SPEC_GET_OR(IGBT_MINUS_NODE        , gpios, {0});
    
    void setup_2()
    {
        int ret;
        ret = gpio_pin_configure_dt(&filtered_synchro  , GPIO_INPUT | GPIO_INT_DEBOUNCE);
    	ret = gpio_pin_configure_dt(&unfiltered_synchro, GPIO_INPUT | GPIO_INT_DEBOUNCE);
    }

    When using debug the line 

    ret = gpio_pin_configure_dt(&filtered_synchro  , GPIO_INPUT | GPIO_INT_DEBOUNCE); 
    sends the application into hardfault.
    I don't see why this doesn't work.
    Best Regards,
    Charles
    edit : 
    My prj.conf lokks like this
    CONFIG_STDOUT_CONSOLE=y
    CONFIG_PRINTK=y
    CONFIG_PWM=y
    CONFIG_LOG=y
    CONFIG_LOG_PRINTK=y
    CONFIG_LOG_MODE_IMMEDIATE=y
    CONFIG_PWM_LOG_LEVEL_DBG=y
    CONFIG_PPI_TRACE=y
    CONFIG_SYSTEM_CLOCK_NO_WAIT=y
    edit_2 : The application also contains a sample.yaml that I am not sure how it works.
    sample:
      name: Blink LED (PWM based)
    tests:
      sample.basic.blink_led:
        # FIXME: We should remove those and just rely on depends_on
        filter: dt_alias_exists("pwm-led0") or
                dt_alias_exists("pwm-led1") or
                dt_alias_exists("pwm-led2")
        tags: drivers pwm
        depends_on: pwm
        harness: led
    
  • Hey,

    Really sorry for the late response. 

    c.tessierpiart said:
    ret = gpio_pin_configure_dt(&filtered_synchro  , GPIO_INPUT | GPIO_INT_DEBOUNCE); 
    sends the application into hardfault.

    Could you tell me what it looks like when this happens.? Also, let me know how to reproduce the issue on my side.

    Regards,

    Swathy

  • Hi,

    It has been a while and I managed to make my IOs work. I just used DT_NODELABAL instead of DT_ALIAS, dont know why it works and at this point I am too afraid to ask.

    Meanwhile, I tried your suggestion but on my main application the counter start makes it restart and on the exemple that I modified, there is no more output signal.

    Here is the modified sample : 

    /*
     * Copyright (c) 2019 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include <zephyr.h>
    #include <debug/ppi_trace.h>
    #include <drivers/counter.h>
    #include <hal/nrf_rtc.h>
    #include <hal/nrf_clock.h>
    #include <device.h>
    #include <logging/log.h>
    #include "hal/nrf_timer.h"
    
    LOG_MODULE_REGISTER(app);
    
    #define ALARM_PERIOD_US 50000
    
    #if IS_ENABLED(CONFIG_USE_TIMER2)
    #define TIMER       NRF_TIMER2
    #define TIMER_LABEL DT_LABEL(DT_NODELABEL(timer2))
    #else
    #define TIMER       NRF_TIMER3
    #define TIMER_LABEL DT_LABEL(DT_NODELABEL(timer3))
    #endif
    
    static void alarm_callback(const struct device *dev, uint8_t chan_id, uint32_t ticks,
    			   void *user_data);
    
    static struct counter_alarm_cfg alarm_cfg = {
    	.callback = alarm_callback,
    	.flags = COUNTER_ALARM_CFG_ABSOLUTE,
    };
    
    static void ppi_trace_pin_setup(uint32_t pin, uint32_t evt)
    {
    	void *handle;
    
    	handle = ppi_trace_config(pin, evt);
    	__ASSERT(handle != NULL,
    		"Failed to initialize trace pin, no PPI or GPIOTE resources?");
    
    	ppi_trace_enable(handle);
    }
    
    static void ppi_trace_setup(void)
    {
    	ppi_trace_pin_setup(3,
    		nrf_timer_event_address_get(TIMER, NRF_TIMER_EVENT_COMPARE0));
    
    	LOG_INF("PPI trace setup done.");
    }
    
    static void alarm_callback(const struct device *dev, uint8_t chan_id,
    			   uint32_t ticks, void *user_data)
    {
    	int err;
    	uint32_t alarm_cnt = (uint32_t)user_data + 1;
    
    	alarm_cfg.ticks = ticks + counter_us_to_ticks(dev, ALARM_PERIOD_US);
    	alarm_cfg.user_data = (void *)alarm_cnt;
    
    	err = counter_set_channel_alarm(dev, 0, &alarm_cfg);
    	__ASSERT_NO_MSG(err == 0);
    	(void)err;
    }
    
    static void counter_setup(void)
    {
    	int err;
    	const struct device *dev = device_get_binding(TIMER_LABEL);
    
    	__ASSERT(dev, "Sample cannot run on this board.");
    
    	alarm_cfg.ticks = counter_us_to_ticks(dev, ALARM_PERIOD_US);
    	err = counter_set_channel_alarm(dev, 0, &alarm_cfg);
    	__ASSERT_NO_MSG(err == 0);
    
    	err = counter_start(dev);
    	__ASSERT_NO_MSG(err == 0);
    }
    
    void main(void)
    {
    	ppi_trace_setup();
    	counter_setup();
    }
    

    Note that, until I replaced the RTC and rtc reference with TIMER and timer references, it worked fine.

    Best regards, Charles

Reply
  • Hi,

    It has been a while and I managed to make my IOs work. I just used DT_NODELABAL instead of DT_ALIAS, dont know why it works and at this point I am too afraid to ask.

    Meanwhile, I tried your suggestion but on my main application the counter start makes it restart and on the exemple that I modified, there is no more output signal.

    Here is the modified sample : 

    /*
     * Copyright (c) 2019 Nordic Semiconductor ASA
     *
     * SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
     */
    
    #include <zephyr.h>
    #include <debug/ppi_trace.h>
    #include <drivers/counter.h>
    #include <hal/nrf_rtc.h>
    #include <hal/nrf_clock.h>
    #include <device.h>
    #include <logging/log.h>
    #include "hal/nrf_timer.h"
    
    LOG_MODULE_REGISTER(app);
    
    #define ALARM_PERIOD_US 50000
    
    #if IS_ENABLED(CONFIG_USE_TIMER2)
    #define TIMER       NRF_TIMER2
    #define TIMER_LABEL DT_LABEL(DT_NODELABEL(timer2))
    #else
    #define TIMER       NRF_TIMER3
    #define TIMER_LABEL DT_LABEL(DT_NODELABEL(timer3))
    #endif
    
    static void alarm_callback(const struct device *dev, uint8_t chan_id, uint32_t ticks,
    			   void *user_data);
    
    static struct counter_alarm_cfg alarm_cfg = {
    	.callback = alarm_callback,
    	.flags = COUNTER_ALARM_CFG_ABSOLUTE,
    };
    
    static void ppi_trace_pin_setup(uint32_t pin, uint32_t evt)
    {
    	void *handle;
    
    	handle = ppi_trace_config(pin, evt);
    	__ASSERT(handle != NULL,
    		"Failed to initialize trace pin, no PPI or GPIOTE resources?");
    
    	ppi_trace_enable(handle);
    }
    
    static void ppi_trace_setup(void)
    {
    	ppi_trace_pin_setup(3,
    		nrf_timer_event_address_get(TIMER, NRF_TIMER_EVENT_COMPARE0));
    
    	LOG_INF("PPI trace setup done.");
    }
    
    static void alarm_callback(const struct device *dev, uint8_t chan_id,
    			   uint32_t ticks, void *user_data)
    {
    	int err;
    	uint32_t alarm_cnt = (uint32_t)user_data + 1;
    
    	alarm_cfg.ticks = ticks + counter_us_to_ticks(dev, ALARM_PERIOD_US);
    	alarm_cfg.user_data = (void *)alarm_cnt;
    
    	err = counter_set_channel_alarm(dev, 0, &alarm_cfg);
    	__ASSERT_NO_MSG(err == 0);
    	(void)err;
    }
    
    static void counter_setup(void)
    {
    	int err;
    	const struct device *dev = device_get_binding(TIMER_LABEL);
    
    	__ASSERT(dev, "Sample cannot run on this board.");
    
    	alarm_cfg.ticks = counter_us_to_ticks(dev, ALARM_PERIOD_US);
    	err = counter_set_channel_alarm(dev, 0, &alarm_cfg);
    	__ASSERT_NO_MSG(err == 0);
    
    	err = counter_start(dev);
    	__ASSERT_NO_MSG(err == 0);
    }
    
    void main(void)
    {
    	ppi_trace_setup();
    	counter_setup();
    }
    

    Note that, until I replaced the RTC and rtc reference with TIMER and timer references, it worked fine.

    Best regards, Charles

Children
No Data
Related