This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

UARTE ENDTX event latency

According to the User Guide,

After each byte has been sent over the TXD line, a TXDRDY event will be generated.


When all bytes in the TXD buffer, as specified in the TXD.MAXCNT register, have been transmitted, the
UARTE transmission will end automatically and an ENDTX event will be generated.

Are the above events generated when the stop bit of the last byte is transmitted? Or are these events generated as soon as the last byte is shifted out of internal HW shift register (6-byte internal HW FIFO)?

If we have a strict time requirement to set a IO line immediately (within 10 micro secs) after sending the last byte, is that possible? What kind of latency to be expected between the stop bit of the last byte and ENDTX event published? We plan to use 1M BAUD.

Parents
  • Hello,

    If you need to add a delay after the ENDTX event, you must use a timer. I have added this in the code below:

    #define ENDTX_GPIOTE_CH 0
    #define ENDTX_GPIOTE_CH_A 0
    #define TIMER_CAPTURE_CH 1
    #define TIMER_COMPARE_CC_NUM 0
    #define TIMER_CAPTURE_DELAY_US 2
    
    #define TIMER_RELOAD 1024
    #define TIMER_RELOAD_CC_NUM 5
    
    void timer_init(void)
    {
        NRF_TIMER3->BITMODE                 = TIMER_BITMODE_BITMODE_24Bit << TIMER_BITMODE_BITMODE_Pos;
        NRF_TIMER3->PRESCALER               = 4;
        NRF_TIMER3->SHORTS                  = TIMER_SHORTS_COMPARE0_CLEAR_Msk << TIMER_RELOAD_CC_NUM;
        NRF_TIMER3->MODE                    = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos;
        NRF_TIMER3->CC[TIMER_RELOAD_CC_NUM] = TIMER_RELOAD;
        NRF_TIMER3->CC[TIMER_COMPARE_CC_NUM]= TIMER_CAPTURE_DELAY_US;
    }
    
    void timer_start(void)
    {
        NRF_TIMER3->TASKS_START = 1;
    }
    
    void attach_ENDTX_to_pin(uint32_t pinselect)
    {
        NRF_GPIOTE->CONFIG[ENDTX_GPIOTE_CH]     = GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos |
                                                  GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos |
                                                  pinselect << GPIOTE_CONFIG_PSEL_Pos |
                                                  GPIOTE_CONFIG_OUTINIT_High << GPIOTE_CONFIG_OUTINIT_Pos;
        
        NRF_PPI->CH[ENDTX_GPIOTE_CH_A].EEP      = (uint32_t)&NRF_UARTE0->EVENTS_ENDTX;
        NRF_PPI->CH[ENDTX_GPIOTE_CH_A].TEP      = (uint32_t)&NRF_TIMER3->TASKS_CLEAR;
        NRF_PPI->FORK[ENDTX_GPIOTE_CH_A].TEP    = (uint32_t)&NRF_GPIOTE->TASKS_SET;
        NRF_PPI->CH[TIMER_CAPTURE_CH].EEP       = (uint32_t)&NRF_TIMER3->EVENTS_COMPARE[TIMER_COMPARE_CC_NUM];
        NRF_PPI->CH[TIMER_CAPTURE_CH].TEP       = (uint32_t)&NRF_GPIOTE->TASKS_CLR[ENDTX_GPIOTE_CH];
        
        
        NRF_PPI->CHENSET = (1 << ENDTX_GPIOTE_CH_A) | (1 << TIMER_CAPTURE_CH);
    }
    
    int main(void)
    {
        ...init_uart...
        timer_init();
        timer_start();
        attach_ENDTX_to_pin(22);
    }

    This will toggle the pin after TIMER_CAPTURE_DELAY_US microseconds.

    You can use the EGU (event generation unit) to do something useful instead of toggling the pin, but as you can see, the pin will go low (in this case) 2µs after the last byte is sent. 

Reply
  • Hello,

    If you need to add a delay after the ENDTX event, you must use a timer. I have added this in the code below:

    #define ENDTX_GPIOTE_CH 0
    #define ENDTX_GPIOTE_CH_A 0
    #define TIMER_CAPTURE_CH 1
    #define TIMER_COMPARE_CC_NUM 0
    #define TIMER_CAPTURE_DELAY_US 2
    
    #define TIMER_RELOAD 1024
    #define TIMER_RELOAD_CC_NUM 5
    
    void timer_init(void)
    {
        NRF_TIMER3->BITMODE                 = TIMER_BITMODE_BITMODE_24Bit << TIMER_BITMODE_BITMODE_Pos;
        NRF_TIMER3->PRESCALER               = 4;
        NRF_TIMER3->SHORTS                  = TIMER_SHORTS_COMPARE0_CLEAR_Msk << TIMER_RELOAD_CC_NUM;
        NRF_TIMER3->MODE                    = TIMER_MODE_MODE_Timer << TIMER_MODE_MODE_Pos;
        NRF_TIMER3->CC[TIMER_RELOAD_CC_NUM] = TIMER_RELOAD;
        NRF_TIMER3->CC[TIMER_COMPARE_CC_NUM]= TIMER_CAPTURE_DELAY_US;
    }
    
    void timer_start(void)
    {
        NRF_TIMER3->TASKS_START = 1;
    }
    
    void attach_ENDTX_to_pin(uint32_t pinselect)
    {
        NRF_GPIOTE->CONFIG[ENDTX_GPIOTE_CH]     = GPIOTE_CONFIG_MODE_Task << GPIOTE_CONFIG_MODE_Pos |
                                                  GPIOTE_CONFIG_POLARITY_Toggle << GPIOTE_CONFIG_POLARITY_Pos |
                                                  pinselect << GPIOTE_CONFIG_PSEL_Pos |
                                                  GPIOTE_CONFIG_OUTINIT_High << GPIOTE_CONFIG_OUTINIT_Pos;
        
        NRF_PPI->CH[ENDTX_GPIOTE_CH_A].EEP      = (uint32_t)&NRF_UARTE0->EVENTS_ENDTX;
        NRF_PPI->CH[ENDTX_GPIOTE_CH_A].TEP      = (uint32_t)&NRF_TIMER3->TASKS_CLEAR;
        NRF_PPI->FORK[ENDTX_GPIOTE_CH_A].TEP    = (uint32_t)&NRF_GPIOTE->TASKS_SET;
        NRF_PPI->CH[TIMER_CAPTURE_CH].EEP       = (uint32_t)&NRF_TIMER3->EVENTS_COMPARE[TIMER_COMPARE_CC_NUM];
        NRF_PPI->CH[TIMER_CAPTURE_CH].TEP       = (uint32_t)&NRF_GPIOTE->TASKS_CLR[ENDTX_GPIOTE_CH];
        
        
        NRF_PPI->CHENSET = (1 << ENDTX_GPIOTE_CH_A) | (1 << TIMER_CAPTURE_CH);
    }
    
    int main(void)
    {
        ...init_uart...
        timer_init();
        timer_start();
        attach_ENDTX_to_pin(22);
    }

    This will toggle the pin after TIMER_CAPTURE_DELAY_US microseconds.

    You can use the EGU (event generation unit) to do something useful instead of toggling the pin, but as you can see, the pin will go low (in this case) 2µs after the last byte is sent. 

Children
No Data
Related