STM32F410 uart DMA and lost break/frame error interrupt

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderator: RoccoMarco

Post Reply
law
Posts: 20
Joined: Tue Jan 12, 2016 5:20 am
Has thanked: 3 times
Been thanked: 2 times

STM32F410 uart DMA and lost break/frame error interrupt

Post by law »

Hi all,

Im using STM32F410 uart 1 to transmit and receive.
I use DMA to transmit bytes. I then use TC interrupt to send a break,
then push an event to an event queue to signal that the transmitter is free.

Code: Select all

void interface_uart_tx_eot_isr(if_uart_t* p) {
    if (p->tx_last_in_chunk) {
        // Transmit break at end of tx work
        LockFromISR();
        p->uart_dev->usart->CR1 |= USART_CR1_SBK;
        UnlockFromISR();
        // register event for more tx data
        p->transmit_empty_handlerI(p->event_source);
    }
}


On the same uart I use DMA in circular mode to dump incoming bytes.
Im using framing error interrupt to wake up a worker to deal with the received data.
For the sake of this explanation, I have three stm32f410 devices connected in a ring
1Tx -> 2Rx, 2Tx -> 3Rx, 3Tx -> 1Rx.
So it is possible for, eg, device 2 to be recieving data as it is sending data.

This is working well except:
I find occasionally that I am missing a break interrupt and I'm pretty lost figuring it out.

Oscilloscpe shot uart_break_1.jpg shows 3 cycles of data.
The first is successful (5 uart interrupts).
500us later the second fails (3 uart interrupts), then 500us after that the error is detected and a breakpoint hit (yellow going high on another device - data exchange is stopped).
Note the last one is semi-successful (5 interrupts).

The oscilloscope traces are:
Green: device TX
Pink: device RX
Blue: uart interrupt (gpio toggled in interrupt)

In oscilloscope screen uart_break_2.jpg:
See data is coming in via pink. The break is also present.
At the same time, data is being sent out via green.
Blue going low indicates the uart interrupt firing, then the TC interrupt handler transmits break.


I tracked the SR register of uart 1 to see if the framing error bit is actually set:

Code: Select all

  }, {
    sr_val = 208,
    time_us = 19787747  <--- one where error occurs. FE bit is not set. SR flags: TXE, TC, IDLE
  }, {
    sr_val = 210,       <--- FE correctly captured
    time_us = 19788109
  }, {
    sr_val = 0,
    time_us = 19788138
  }, {
    sr_val = 192,
    time_us = 19788177
  }, {
    sr_val = 210,       <--- FE correctly captured
    time_us = 19788247
  }, {
    sr_val = 192,
    time_us = 19788379  <--- Last gpio toggle


These are the last 6 SR register values captured in the interrupt.
Note in uart_break_2.jpg the uart interrupt with TC flag set fires about 200ns after RX break (pink) goes low.

I'm using Chibios and will add the usart handler.
Break is capture via FE and _uart_rx_error_isr_code and TC via _uart_tx2_isr_code.
I'm at a bit of a loss. I suspect break is not quiet set when TC interrupt happens. Maybe it is then getting cleared during servicing of TC.
Any thoughts?

(PS I've also posted this question to the ST forums)

Code: Select all

void serve_usart_irq(UARTDriver *uartp) {
  uint16_t sr;
  USART_TypeDef *u = uartp->usart;
  uint32_t cr1 = u->CR1;

  sr = u->SR;   /* SR reset step 1.*/

  // Record SR and signal
  LED_LCL_TOGGLE;
  sr_cap_t cap = {
    .sr_val = sr,
    .time_us = mod_time_util_us_get()
  };
  sr_capture_history[sr_history_idx] = cap;
  sr_history_idx++;
  if (sr_history_idx >= 16) {
    sr_history_idx = 0;
  }

  if (sr & (USART_SR_LBD | USART_SR_ORE | USART_SR_NE |
            USART_SR_FE  | USART_SR_PE)) {

    (void)u->DR;  /* SR reset step 2 - clear ORE.*/

    u->SR = ~USART_SR_LBD;
    _uart_rx_error_isr_code(uartp, translate_errors(sr));
  }

  if ((sr & USART_SR_TC) && (cr1 & USART_CR1_TCIE)) {
    /* TC interrupt cleared and disabled.*/
    u->SR = ~USART_SR_TC;
    u->CR1 = cr1 & ~USART_CR1_TCIE;

    /* End of transmission, a callback is generated.*/
    _uart_tx2_isr_code(uartp);
  }

  /* Timeout interrupt sources are only checked if enabled in CR1.*/
  if ((cr1 & USART_CR1_IDLEIE) && (sr & USART_SR_IDLE)) {
    _uart_timeout_isr_code(uartp);
  }
}
Attachments
uart_break_1.jpg
User avatar
Giovanni
Site Admin
Posts: 14820
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1188 times
Been thanked: 985 times

Re: STM32F410 uart DMA and lost break/frame error interrupt

Post by Giovanni »

Hi,

Hard to give suggestions, it is a very specific use case.

Doesn't the STM32 UART have a break detection feature? why use FE?

Giovanni
law
Posts: 20
Joined: Tue Jan 12, 2016 5:20 am
Has thanked: 3 times
Been thanked: 2 times

Re: STM32F410 uart DMA and lost break/frame error interrupt

Post by law »

Hey Giovanni,

Yeah stm32f410 does have break detection, but it seems it only really works with LIN mode enabled. It also seems the expectation then is that break would signal start of frame, rather than end of frame or data has arrived.
Also it looks like one of my oscilloscope shots didn't make it up.
This one shows the data coming in on the pink trace and data going out on the green trace. Blue trace shows the uart interrupt firing, with TC bit being set (FE not set in this one)
Attachments
uart_break_2.jpg
User avatar
Giovanni
Site Admin
Posts: 14820
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1188 times
Been thanked: 985 times

Re: STM32F410 uart DMA and lost break/frame error interrupt

Post by Giovanni »

LIN mode would not be a problem, it just enables break detection and generation. Why do you think there is an assumption for breaks? it just detects a long sequence of zeros.

I think that it is the use of FE that is not reliable, probably this is not a SW issue. Just give break detection a try and see.

Giovanni
law
Posts: 20
Joined: Tue Jan 12, 2016 5:20 am
Has thanked: 3 times
Been thanked: 2 times

Re: STM32F410 uart DMA and lost break/frame error interrupt

Post by law »

Hey,
My understanding is that LIN expects break at the start of the frame, followed by sync.
The datasheet mentions that "as soon as a framing error occurs, the receiver stops until the break detection circuit receives a 1, if the break word was not complete, or a delimiter character if a break has been detected"
I'm transmitting break at the end of my bytes.
Either way, for funsies I enabled via LINEN and LBDIE to see what I could get out of it. I just get a bunch of noise and parity errors (coming from a known working uart link).
I'd have to experiment some more.
law
Posts: 20
Joined: Tue Jan 12, 2016 5:20 am
Has thanked: 3 times
Been thanked: 2 times

Re: STM32F410 uart DMA and lost break/frame error interrupt

Post by law »

Hi Giovanni,

I did not have any success with LIN, nor did I have success with uart interrupts servicing break (or idle) flags in the conditions I previously spoke about.
I think I've found a solution - I'm not using uart TC anymore. I'm using DMA TC to send a break. Reference manual says that when setting SBK (to send break), the break character will be sent after completing the current character transmission, which appears to be underway when DMA TC is serviced.
I may have to revisit if break fires early (it definitely does on faster STM32F7).
Thanks again
User avatar
Giovanni
Site Admin
Posts: 14820
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 1188 times
Been thanked: 985 times

Re: STM32F410 uart DMA and lost break/frame error interrupt

Post by Giovanni »

Yes, when you get DMA TC, at least one frame is still outgoing, on UARTs with FIFOs potentially more than one but this is not the case on F4.

Giovanni
Post Reply