Question about serial_lld.c interrupts
Posted: Sun Aug 24, 2014 3:59 pm
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:
The second one in the middle of the byte (unexpected, not seen at 57600bps) is running over the "if (b < Q_OK) {" segment:
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?).
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?).