This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

CMSIS Driver v1.10 UART_STM32F4xx.c Bug

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?

Parents
  • 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);
    

Reply
  • 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);
    

Children