Question about serial_lld.c interrupts

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

Moderator: RoccoMarco

Post Reply
gicho
Posts: 16
Joined: Sun Aug 24, 2014 8:44 am

Question about serial_lld.c interrupts

Post by gicho »

I am using the serial driver on stm32f401 device. All works fine at low baud rates (57600bps). But I get strange behavior at high baudrate 921Kbps. I added a test GPIO pulse in the serve_interrupt() function to observe what is going on.
At 57600bps I see one interrupt per byte sent, at the beginning of the byte - this is expected (knowing STM "forgot" the FIFOs for uarts).
But if I just change the baudrate to 921K I see 2 interrupts per byte sent - one expected at the start and one in the middle of the byte. This second one is not expected (by me) so I made some trials.
I saw that first one (expected) is running over the "else" clause in the interrupt handler:

Code: Select all

  /* Transmission buffer empty.*/
  if ((cr1 & USART_CR1_TXEIE) && (sr & USART_SR_TXE)) {
    msg_t b;
    chSysLockFromIsr();
    b = chOQGetI(&sdp->oqueue);
    if (b < Q_OK) {
      chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
      u->CR1 = (cr1 & ~USART_CR1_TXEIE) | USART_CR1_TCIE;
    }
    else
    {
      [b]u->DR = b;[/b] //HERE
    }


The second one in the middle of the byte (unexpected, not seen at 57600bps) is running over the "if (b < Q_OK) {" segment:

Code: Select all

  /* Transmission buffer empty.*/
  if ((cr1 & USART_CR1_TXEIE) && (sr & USART_SR_TXE)) {
    msg_t b;
    chSysLockFromIsr();
    b = chOQGetI(&sdp->oqueue);
[b]    if (b < Q_OK) { //HERE
      chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY);
      u->CR1 = (cr1 & ~USART_CR1_TXEIE) | USART_CR1_TCIE;
    }[/b]
    else
    {
      u->DR = b;
    }


If I understand the code and observed behavior, the "true" case should run when driver sees that input queue is emptied, so it is the last byte of transmition; so it enables TCIE and waits it to come.
I am using sdWriteTimeout() to send data, could it be that my sending thread (task) is interrupted byte-by-byte by the transmit interrupt and my packet is sent as sequence of 1-byte packets? I have to verify if this is the case, but this would mean that filling the IO output queue takes significant time (several us per byte?).
User avatar
Giovanni
Site Admin
Posts: 14892
Joined: Wed May 27, 2009 8:48 am
Has thanked: 1202 times
Been thanked: 996 times

Re: Question about serial_lld.c interrupts

Post by Giovanni »

It looks like that the program is unable to send data fast enough so there is an end-transmission interrupt for each byte sent. This is consisten with the very high speed you are using.

You may try the UART driver, it uses DMA and gets interrupts only on when a whole buffer is sent.

The queue throughput is one of the parameters in benchmarks, see the reports, but it is not just the queue, there are also the application and the ISR itself.

Giovanni
gicho
Posts: 16
Joined: Sun Aug 24, 2014 8:44 am

Re: Question about serial_lld.c interrupts

Post by gicho »

Thank you. I seems that there is no other way but to switch to the UART driver. I will report my findings on this subject.
Post Reply