if this is RS485, it switches off the driver.
This is just RS232.
Also, don't RMW the status register.
Good point. I've been aware of this but this is someone else's code from ~2 years ago. But that RMW code comes from ST Cube MX's code generator AFAIK. So I changed it to this
__disable_irq();
if (!kde_serial_transmit_active[port])
{
// Transmitter is not already running so load the first byte and enable the TXE and TC interrupts
// First clear TC. This is done with a read of SR and a write to DR.
//kde_serial_port_handles[port]->Instance->SR &= ~(UART_FLAG_TC);
// This does a read of SR without doing RMW which the line above did
kde_serial_port_handles[port]->Instance->SR;
// This is a write of DR
kde_serial_port_handles[port]->Instance->DR = kde_serial_transmit_buffer[port][kde_serial_transmit_buffer_tx_index[port]++];
kde_serial_transmit_buffer_tx_index[port] %= KDE_SERIAL_TX_BUFFER_SIZE;
kde_serial_transmit_active[port] = true;
// Enable TX complete and TX empty interrupts. The order may matter!
__HAL_UART_ENABLE_IT(kde_serial_port_handles[port], UART_IT_TC);
__HAL_UART_ENABLE_IT(kde_serial_port_handles[port], UART_IT_TXE);
}
__enable_irq();
I hope that
kde_serial_port_handles[port]->Instance->SR;
does actually do a read of SR; I have used this elsewhere. A funny feature of C!
and in the TC ISR I now have
// Clear and disable the TC interrupt. This is supposed to be done by a read of SR and a write to DR
// but in this case we have nothing to write to DR so we clear the TC bit by writing a 0 to it but
// avoiding RMW - see http://efton.sk/STM32/gotcha/g9.html
huart->Instance->SR = ~(UART_FLAG_TC);
__HAL_UART_DISABLE_IT(huart, UART_IT_TC);
So far, no change to
existence of the 1 byte loss. It happens once every 50-100 1k packets. But, overall the reliability has improved with every change I have done here, which is kind of weird. Normally there is only
one thing causing something
Removing the SR RMW ops has significantly improved reliability, practically removing errors from shorter packets (which would be more likely cases where TX gets disabled and needs re-enabling by loading a byte into DR.
I've discovered that the loss is possibly related to whether the packets sent are smaller than a particular buffer along the data path. This is currently 512 bytes. That in turn might point to something way more complex which I can't really debug.
I am now running with the above-suggested code which doesn't need ints disabled during the copy (in both tx and rx instances) and that seems to run well
uint32_t index = serial_receive_buffer_get_index[port];
data[i] = serial_receive_buffer[port][index++];
serial_receive_buffer_get_index[port] = index % SERIAL_RX_BUFFER_SIZE;
Since the event you are looking for will be rare and complex, you may find a logic analyser with good arming/trigger/filtering is necessary to spot "if...and...then...but not..." events on the pins. That excludes anything which simply waits for a one input condition, captures everything, and relies on post-processing to filter out the 99.99999% of boring captures.
A DSO is OK. I have a LeCroy 3034. That can decode RS232, SPI, etc, but is a PITA to set up for each such thing.