Electrical – STM32 skips UART frames after framing error

dmx512stm32uart

I am currently developing a DMX512 receiver with an STM32F767ZI. DMX512 is basically a protocol transmitting a byte array via RS485. In summary it works like this:

  1. > 92us low signal (called break)
  2. > 8 us high signal (called mark after break / mab)
  3. bytes transmitted one after another with 2 stop bits

To correctly identify the beginning of the array, usually the framing error functionality of USARTs: the break signal will be seen as a framing error (missing stop bits) and then the USART starts reading bytes after the MAB.

Given this basic blueprint, I created the following interrupt handler.

USART_TypeDef *usart = this->USART();

usart->ICR |= USART_ICR_NCF;
usart->ICR |= USART_ICR_ORECF;

// new data
if (usart->ISR & USART_ISR_RXNE) {
  uint8_t data = (uint8_t) usart->RDR;
  this->last_data_timestamp_ = HAL_GetTick();
  if (this->first_ || this->next_byte_ >= 513)
    return;
  uint8_t *buffer_ptr = &this->buffer_[this->next_byte_++];
  if (*buffer_ptr != data)
    this->changed_ = true;
  *buffer_ptr = data;
}

// break condition
if (usart->ISR & USART_ISR_FE) {
  usart->ICR |= USART_ICR_FECF;
  if (!this->first_ && this->callback_ != nullptr && this->next_byte_ != 0) {
    this->callback_(this->parent_, this->buffer_, this->next_byte_,
                    this->changed_, this->callback_param_);
  }

  this->first_ = false;
  this->Clear();
}

However, after a break condition is successfully detected, 14 bytes will be skipped (and nothing will happen) until the first RXNE interrupt is called. Looking at the input signal, I noticed it is not quite to standard (stop bit is around 70us long instead of 8), I don't that this is the issue here, since it correctly identified as such after the first 14 frames. Afterwards everything executes as expected.

Further investigation has also shown, that right before data is received correctly again, the ORE bit will be set.

I have also tried attaching an oscilloscope to the input and to another pin of the STM which is toggled whenever an RXNE interrupt is called. The result looks like this:
oscilloscope view

The USART is provided with a 16MHz clock signal and its BRR register is set to 64 so that the baud rate is (with OVER8=0) – as required – 250000 kBaud/s

What could be the reason for this? Is the USART unable to identify that data transmission has started again? Why so then or how can I fix that?

EDIT: I have now also had a look at IDLE changes. Using the same method as for the RXNE interrupts, i have gotten these results:
oscilloscope view
So appareantly the USART is not able to detect a start bit in any of the previous bytes. How so? How do they differ from the 15th byte?

Best Answer

Your callback blocks the system for too long during the time it runs, and the interrupt is not made re-entrant. Normally these callbacks are used to quickly set a flag, prepare for next transmission or something similar so the interrupt is done before the next byte arrives.