When you receive 8 chars, your MCU triggers interrupt after each individual character. Your MCU UART has no input buffer, the one and only thing is 1 char sized data register (DR for unified data register or TDR/RDR if they are separate for send/receive). If you had overrun characters, then by definition, all the data that was sent, was lost forever (was never saved anywhere). Your UART is soft-locked until you remove overrun error by reading data register (the act of reading clears overrun flag and unlocks the peripheral as per F103's reference manual, check yours, I'd expect it to be similar or the same).
Basically, the problem is that you never handle overrun error, and it's not very clear from your description what you want to do about it. If you want to discard overrun data and never save it as if it was never sent to MCU, you can clear overrun flag before calling interrupt receive again:
for(int i=0; i<8; i++){
buffer2[i] = buffer1[i];
buffer1[i] = '\0';
}
volatile uint8_t temp = USART2->DR; //or RDR depending on what register you have
(void)temp;
HAL_UART_Receive_IT(&huart2, buffer1, 8);
If there was no overrun, it will do nothing at all. If there was an overrun, it will read the first overrun byte that was received while data register was empty (other data was lost), it will clear overrun flag and return the peripheral to operational condition, but if and only if there is no incoming data while calling HAL_UART_Receive_IT(&huart2, buffer1, 8);
. We could easily have timing issues - let's not forget that MCU executes this in microseconds, while physically UART could still be sending/receiving. So I would modify my solution the following way:
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
for(int i=0; i<8; i++){
buffer2[i] = buffer1[i];
buffer1[i] = '\0';
}
while(UART2_Busy());
volatile uint8_t temp = USART2->DR; //or RDR depending on what register you have
(void)temp;
HAL_UART_Receive_IT(&huart2, buffer1, 8);
}
Where Busy() checks if there is an ongoing transmission. Basically, if the line is not idle, you want to let it finish communication first, then clear overrun flag knowing that nothing new will be received while you're clearing it. You can enable IDLE interrupt for that, if you don't want to have it block anything (which makes sense if you use interrupt solution)
How about this logic:
- You call interrupt receive function.
- Immediately enable line IDLE interrupt (won't trigger immediately as per STM32F103 reference manual I'm consulting right now, needs to receive something for IDLE to trigger interrupt)
- Your interrupt receiver function will receive 8 characters and stop handling new incoming data, will copy buffer1 to buffer2 as per callback function.
- After, say, 12 characters (8 of them were processed into a buffer), IDLE interrupt occurs, where you clear overrun flag, call interrupt receive function again.
Warning: be sure to handle underrun. If only 5 characters are sent and not 8, IDLE will trigger too, make sure it won't cause a problem (it probably won't, just keep it in mind). Alternatively, you can try to enable IDLE interrupt only after receiving 8 chars.
Make sure you check reference manual on how to clear IDLE flag. STM32F103, which I have next to me, says one needs to read USART_SR and then USART_DR, and it will clear IDLE flag.