Pitfalls in STM32 Standard Peripheral Library & Possible Solutions
— February 27, 2013#1 : USART DATA TRANSFER FUNCTIONS, NO CHECK ON TXE & RXNE FLAGS
Where ? in STM32f4xx_usart.c
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
{
/* Check the parameters */
assert_param(IS_USART_ALL_PERIPH(USARTx));
assert_param(IS_USART_DATA(Data));
/* Transmit Data */
USARTx->DR = (Data & (uint16_t)0x01FF);
}
In the above function USART_SendData(…. , ….) There is no check for Transmit complete flag which goes High when the content of TDR register has been transferred into the shift register. Since this check was unavailable in the code provided by ST, Whenever you try to transmit too much of data continuously over USART some of the data goes unnoticed and could not be sent as we are not waiting till the last byte got transmitted. This issues can be corrected by adding a simple line of code in the function as given below.
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
{
/* Check the parameters */
assert_param(IS_USART_ALL_PERIPH(USARTx));
assert_param(IS_USART_DATA(Data));
/* Transmit Data */
USARTx->DR = (Data & (uint16_t)0x01FF);
while((USARTx->SR & (1<<7))==0); // Wait till last byte got transmitted
}
Similar kind of Correction is required in USART_ReceiveData
If you also find some improvement ot Bug in this library or related information that can be useful for others, Do share with us. Thanks


4 Comments
Haha! I had google “stm32 peripheral library bugtracker” to publish fix for USART_SendData and found this site.
btw. I fixed my lib like this:
=============================================
unsigned long wait = 10000;
while(wait- && ((USARTx->SR & USART_SR_TXE) != USART_SR_TXE))
{}
if(wait > 0)
USARTx->DR = (Data & (uint16_t)0x01FF);
=============================================
Could you mention the specific correction to USART_ReceiveData ?
Thank you.
Oh…by the way, if we call USART_SendData within a new function in our code which does check bit 7, we are OK?
So…for USART1:
while(!(USART1->SR & 0×00000040)) {}; //do nothing yet
// now…..
USART_SendData(usart1, * );
IMHO I don’t think this is really a bug in the library. For some code you don’t want to block further execution of code waiting for the serial data to be transmitted.
For example you could have some code running that updates analog or digital outputs for time critical control based on some inputs and these outputs are not part of the system sending serial data.
If the other parts of the code require as frequent as possible updates you don’t want the processor to be sitting around waiting for serial data to be transmitted while it could be doing other more useful processing tasks.
Not having this blocking code in the library allows you to check this flag before sending more data, and if the data has not been sent it can go off and do a bit more processing before coming back and checking again. What happens if there is a rare hardware error and this flag never gets set, then your entire program would halt. If you were controlling something like a motor not blocking the code would probably be beneficial so that the user inputs are still responsive. (Assuming that it is not over the serial link, if it is there should be a timed fail-safe. Either way if you don’t block you should be able to still receive control signals)
I know for some specific applications you may want the serial data sent after each read/process block of code, and in that case you may want to block to keep the sending of data in sync with the processing.
I think not including it in the library allows you to maintain complete flexibility over how you want to handle it, and if you want to write blocking code (which actually IS a no-no) then you are free to add it if your situation warrants it.
The diagnosis and solution are correct, I just don’t think it is required in every application and therefore should not be included.