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

Reply Children
  • 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

Related