CMSIS Driver UART Revision: V1.02
file C:\Keil\ARM\Pack\Keil\STM32F4xx_DFP\1.0.8\RTE_Driver\UART_STM32F4xx
function UART_ReadData
static int32_t UART_ReadData (uint8_t *data, uint32_t size, UART_RESOURCES *ptr_uart) { volatile uint32_t val; osMutexWait(ptr_uart->info->mutex_read, osWaitForever); if ((size == 0) || (ptr_uart->info->rx.empty == true)) { osMutexRelease(ptr_uart->info->mutex_read); return 0; } val = (ptr_uart->info->rx.idx_in - ptr_uart->info->rx.idx_out) & (ptr_uart->rx_buffer_size - 1); if (val == 0) val = ptr_uart->rx_buffer_size; if (size > val) size = val; if ((ptr_uart->hw_flow == true) && (ptr_uart->manual_rts_cts == false)) { if (ptr_uart->flow_ctrl_threshold < val) GPIO_PinWrite(ptr_uart->pin_rts.port, ptr_uart->pin_rts.num, 0); } if (size > (ptr_uart->rx_buffer_size - ptr_uart->info->rx.idx_out)) { memcpy(data, ptr_uart->rx_buffer + ptr_uart->info->rx.idx_out, val); memcpy(data + val, ptr_uart->rx_buffer, size - val); if (ptr_uart->info->rx.idx_in == (size - val)) ptr_uart->info->rx.empty = true; ptr_uart->info->rx.idx_out = size - val; } else { memcpy(data, ptr_uart->rx_buffer + ptr_uart->info->rx.idx_out, size); val = (ptr_uart->info->rx.idx_out + size) & (ptr_uart->rx_buffer_size - 1); if (ptr_uart->info->rx.idx_in == val) ptr_uart->info->rx.empty = true; ptr_uart->info->rx.idx_out = val; }
Guess what will be if variable size is less than val?
To reproduce this issue:
As an example, UART_BAUDRATE = 921600; default ptr_uart->rx_buffer_size = 0x80 (128) HSE = 25MHz. Internall PLL is Off (system_clock is also 25MHz).
Send any bytes continuously to stm32f4 UART from outside.
On stm32f4 side:
#define BUF_SIZE 256 uint8_t buf[BUF_SIZE]; uint8_t num_read; uint8_t num = 10; while(1) { osDelay(1000); num_read = sect_uart.ReadData(buf, num); }
In this particular example, the condition
(size > (ptr_uart->rx_buffer_size - ptr_uart->info->rx.idx_out) && (size < val)
will rise in (rx_buffer_size / num) = 128/10 = 12 seconds after start of that code. This issue will happen only if ((rx_buffer_size % num) != 0). That means, hard_fault won't happen if num = 1,2,4,.. (in case rx_buffer_size = 128).
This can be fixed as you(John) suggested. But you also should check first memcpy for correctness:
memcpy(data, ptr_uart->rx_buffer + ptr_uart->info->rx.idx_out, val);
I start a separate thread for different purpose.
if statement and Branch Penalty http://www.keil.com/forum/58512/