Delay UART initialization in Zephyr

For my application I need the UART TX/RX pins pulled low until I am ready to turn on the UART.  Is there a method in Zephyr to do this?  
Currently when Zephyr starts it reads the device tree configuration and initializes the UART driver before main, which then places pull up on the TX/RX pin.  How can I manually control when the UART initialization occurs in my code? 

Parents
  • Hi,

    You could always use gpio_pin_configure_dt() to configure GPIOs during runtime when the time is right, or any other uart-specific functions from the UART API that suits your applications needs.

    Is this sufficient for you or do you want to do the full initialization when you see fit?

    Kind regards,
    Andreas

  • That will not work as that on power up the TX pin goes high which is not allowed.   The TX pin must stay low (or tristated) until we are ready, for personnel safety reasons.    

    If we try to turn pin over to GPIO in main() then what happens is on power up TX goes high, main then drives low.  Additionally in the datasheet it says the UART must be disabled before you change pins to GPIO. 

    I did try using the pinctrl and power manager to disable the UART and then set a pinctrl state for sleep with TX/RX pulled low.  When I put the peripheral in the sleep mode the RX pin does go low, but the TX remains high.  I did not go and debug the UARTE driver to figure out what is wrong, but it did not work as expected.  Also this still has issue of the TX pin going high before main() where we would sleep peripheral.  

    I have posted on the Zephyr forum and this delayed initialization with devicetrees is a feature in the bleeding edge of Zephyr but not in the version we have. 
    Other suggestions I have received is to add hardware to make sure pins are disconnected.  This would work but adding hardware to work around Zephyr is a bit insane and costly.  

    I have been trying to figure out if the driver can be setup and initialized outside of the devicetree.  I personally do not like devicetrees as they are too complex and rigid and the macro foo is insane.  Thus I would greatly prefer a solution which removes device trees and gives the developers back control over the initialization process.   Yes I do know that devicetrees is part of the koolaid that you drink when you join the Zephyr cult, and I will have to adapt or change careers. 

  • trampas said:
    That will not work as that on power up the TX pin goes high which is not allowed.   The TX pin must stay low (or tristated) until we are ready, for personnel safety reasons.    

    Ah, if this is not an option then the suggestion I made is not too helpful.

    trampas said:
    I have posted on the Zephyr forum and this delayed initialization with devicetrees is a feature in the bleeding edge of Zephyr but not in the version we have. 
    Other suggestions I have received is to add hardware to make sure pins are disconnected.  This would work but adding hardware to work around Zephyr is a bit insane and costly.  

    If you don't mind, could you share that discussion here for reference? The suggestion is interesting, but as you mention it's costly for something that should be possible to do in software.

    trampas said:
    I have been trying to figure out if the driver can be setup and initialized outside of the devicetree.  I personally do not like devicetrees as they are too complex and rigid and the macro foo is insane.  Thus I would greatly prefer a solution which removes device trees and gives the developers back control over the initialization process.   Yes I do know that devicetrees is part of the koolaid that you drink when you join the Zephyr cult, and I will have to adapt or change careers. 

    I see where you're coming from w.r.t this. There are both upsides and downsides to the Macro based Zephyr cult environment, but hey atleast the coolaid is tasty when it works. The feedback is something we're aware of, specially w.r.t relatively basic applications using more classical peripherals rather than controlling 2-3 wireless stacks/standards with more.  Hopefully you will find the frustration less and less present with time

    I'll bring the question to the Nordic developers and raise a feature request for this and if it's not already started from the Zephyr side I will share a PR if it gets picked up by them.

    Kind regards,
    Andreas

  • Here is the thread on discord. https://discordapp.com/channels/720317445772017664/733037557218279515/1245049020242595922

    As far as the Macro foo.  A trick that Devicetrees could use is to define structures in macros.  For example on bare metal system (ATSAM) I use macros for pins. 

    typedef struct {

    uint32_t pinNum; //this is a pin number, upper 16bits is port, lower is pin number

    void *ptrPerherial; //if using a peripheral, set this pointer to peripheral

    pinMuxType_t type; //which pin mux is needed for peripheral

    uint32_t id; //pad, pin, waveform, adc channel, etc

    pinMuxType_t sleepType; //what to do with pin when you sleep

    }pin_t;

    Then I define a pin like:

    #define DAIG_LED_PIN (const pin_t){PIN_PA15, nullptr, PERPIHERAL_GPIO_OUTPUT_LOW, 0, PERPIHERAL_GPIO_OUTPUT_LOW}


    Now a function like setting pin low is:

    static inline void PinLow (const pin_t pin) __attribute__((always_inline));

    static inline void PinLow (const pin_t pin)

    {

    PORT->Group[PIN_GET_PORT(pin.pinNum)].OUTCLR.reg=(1<<PIN_GET_PIN(pin.pinNum));

    }

    so in the code if you have

    PinLow(DAIG_LED_PIN);

    The function parameter is a constant, the function is inline

    so the preprocessor/compiler can optimize it. Now the whole
    function call is optimized at compile time to the fewest assembly instructions as possible.

    This #define of a const struct trick works great as the structure is

    not put in flash or RAM and can be optimized by compiler for no memory

    or run time performance hits.

    So I think much of the devicetree system could use a similar method to
    make the macros more readable. Then if the initialization of drivers
    was done with a static inline function before main, us mortals could read

    The code and understand. Maybe even work around issues (if we can disable

    regen of the devicetree macros).



     

  • Zephyr might be tasty when it work, however what are the recovery options when it fails?

    I have thought about this UART issue, an went through several ideas discussing with anyone who will listen, not many by the way.  The best solution I can come up with at the moment is making an out of tree driver by copying nordic's uarte driver from zephyr and then renaming to something like 'myuarte'.  Then in this custom driver make it work the way I need it to and add to my project. 

    This is not the best option but might be good enough to move forward, while we wait for  Zephyr to grow up and mature.

  • trampas said:
    The best solution I can come up with at the moment is making an out of tree driver by copying nordic's uarte driver from zephyr and then renaming to something like 'myuarte'

    This is within what I have thought as well. I were playing around with trying to use an overlay to modify the existing UART device binding, i.e setting it up but not initializing before I call the initialization of the device but I can't quite get it to do this. Maybe the missing ingredient is to do what you say, i.e copy the existing device and creating your own custom variant of the UART that allows for this.

    Even though it's a bit clunky it is also one of the good features with Zephyr i.e allowing for relatively standardized customization of devices and nodes.

    I won't be able to look further into creating a sample for this for a while, but I am fairly confident that your suggestion will work

    Kind regards,
    Andreas

Reply
  • trampas said:
    The best solution I can come up with at the moment is making an out of tree driver by copying nordic's uarte driver from zephyr and then renaming to something like 'myuarte'

    This is within what I have thought as well. I were playing around with trying to use an overlay to modify the existing UART device binding, i.e setting it up but not initializing before I call the initialization of the device but I can't quite get it to do this. Maybe the missing ingredient is to do what you say, i.e copy the existing device and creating your own custom variant of the UART that allows for this.

    Even though it's a bit clunky it is also one of the good features with Zephyr i.e allowing for relatively standardized customization of devices and nodes.

    I won't be able to look further into creating a sample for this for a while, but I am fairly confident that your suggestion will work

    Kind regards,
    Andreas

Children
Related