1
\$\begingroup\$

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?

\$\endgroup\$
  • 3
    \$\begingroup\$ What do you do in the callback? Does it take several bytes worth of time to do it? \$\endgroup\$ – Justme May 10 at 17:07
  • 1
    \$\begingroup\$ After a break detection you do a this->callback_() and a this->Clear() what do these functions do? \$\endgroup\$ – brhans May 10 at 17:37
  • \$\begingroup\$ Welcome to EE.SE! If you don't stick around to respond to comments, we can't help you. \$\endgroup\$ – Dave Tweed May 10 at 23:14
  • \$\begingroup\$ thank you Justme and brhans. In the callback I sent a message via UART to my computer and appareantly I have severely underestimated the time that takes... \$\endgroup\$ – aquaatic May 11 at 8:51
  • \$\begingroup\$ That's what I thought and made an answer. \$\endgroup\$ – Justme May 11 at 13:07
2
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.