Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[bsp][stm32][uart]:fix stm32 uart timout #10022

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

CYFS3
Copy link
Contributor

@CYFS3 CYFS3 commented Feb 22, 2025

拉取/合并请求描述:(PR description)

[

为什么提交这份PR (why to submit this PR)

fixed: #9964

你的解决方案是什么 (what is your solution)

请提供验证的bsp和config (provide the config and bsp)

  • BSP:
  • .config:
  • action:

]

当前拉取/合并请求的状态 Intent for your PR

必须选择一项 Choose one (Mandatory):

  • 本拉取/合并请求是一个草稿版本 This PR is for a code-review and is intended to get feedback
  • 本拉取/合并请求是一个成熟版本 This PR is mature, and ready to be integrated into the repo

代码质量 Code Quality:

我在这个拉取/合并请求中已经考虑了 As part of this pull request, I've considered the following:

  • 已经仔细查看过代码改动的对比 Already check the difference between PR and old code
  • 代码风格正确,包括缩进空格,命名及其他风格 Style guide is adhered to, including spacing, naming and other styles
  • 没有垃圾代码,代码尽量精简,不包含#if 0代码,不包含已经被注释了的代码 All redundant code is removed and cleaned up
  • 所有变更均有原因及合理的,并且不会影响到其他软件组件代码或BSP All modifications are justified and not affect other components or BSP
  • 对难懂代码均提供对应的注释 I've commented appropriately where code is tricky
  • 代码是高质量的 Code in this PR is of high quality
  • 已经使用formatting 等源码格式化工具确保格式符合RT-Thread代码规范 This PR complies with RT-Thread code specification
  • 如果是新增bsp, 已经添加ci检查到.github/workflows/bsp_buildings.yml 详细请参考链接BSP自查

@github-actions github-actions bot added BSP: STM32 BSP related with ST/STM32 BSP labels Feb 22, 2025
@CYFS3
Copy link
Contributor Author

CYFS3 commented Feb 22, 2025

两个ci错误好像都是rom溢出

@kaidegit
Copy link
Contributor

用浮点导致的(

这种库就最好避免浮点吧。。

@CYFS3
Copy link
Contributor Author

CYFS3 commented Feb 22, 2025

用浮点导致的(

这种库就最好避免浮点吧。。

那就10 * HAL_RCC_GetSysClockFreq() / cfg->baud_rate / 4

@CYFS3
Copy link
Contributor Author

CYFS3 commented Feb 22, 2025

用浮点导致的(
这种库就最好避免浮点吧。。

那就10 * HAL_RCC_GetSysClockFreq() / cfg->baud_rate / 4

@

用浮点导致的(
这种库就最好避免浮点吧。。

那就10 * HAL_RCC_GetSysClockFreq() / cfg->baud_rate / 4

@wdfk-prog 大佬你觉得呢

@wdfk-prog
Copy link
Contributor

用浮点导致的(
这种库就最好避免浮点吧。。

那就10 * HAL_RCC_GetSysClockFreq() / cfg->baud_rate / 4

@

用浮点导致的(
这种库就最好避免浮点吧。。

那就10 * HAL_RCC_GetSysClockFreq() / cfg->baud_rate / 4

@wdfk-prog 大佬你觉得呢

  • 加个余量,10 * HAL_RCC_GetSysClockFreq() / cfg->baud_rate / 4 + 2000,不然万一算出来是0就不好了
  • 还有就是HAL_RCC_GetSysClockFreq不一定是串口的时钟频率
  • 一定要使用串口时钟准确计算的话参考如下实现看看
    uint32_t SPI_CLOCK = 0UL;
    /* Some series may only have APBPERIPH_BASE, but don't have HAL_RCC_GetPCLK2Freq */
    #if defined(APBPERIPH_BASE)
    SPI_CLOCK = HAL_RCC_GetPCLK1Freq();
    #elif defined(APB1PERIPH_BASE) || defined(APB2PERIPH_BASE)
    /* The SPI clock for H7 cannot be configured with a peripheral bus clock, so it needs to be written separately */
    #if defined(SOC_SERIES_STM32H7)
    /* When the configuration is generated using CUBEMX, the configuration for the SPI clock is placed in the HAL_SPI_Init function.
    Therefore, it is necessary to initialize and configure the SPI clock to automatically configure the frequency division */
    HAL_SPI_Init(spi_handle);
    SPI_CLOCK = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI123);
    #else
    if ((rt_uint32_t)spi_drv->config->Instance >= APB2PERIPH_BASE)
    {
    SPI_CLOCK = HAL_RCC_GetPCLK2Freq();
    }
    else
    {
    SPI_CLOCK = HAL_RCC_GetPCLK1Freq();
    }
    #endif /* SOC_SERIES_STM32H7) */
    #endif /* APBPERIPH_BASE */

@kaidegit
Copy link
Contributor

还有就是HAL_RCC_GetSysClockFreq不一定是串口的时钟频率

这个算cpu要等几个clk用系统时钟倒也正常?具体的式子咋推导的啊

@wdfk-prog
Copy link
Contributor

还有就是HAL_RCC_GetSysClockFreq不一定是串口的时钟频率

这个算cpu要等几个clk用系统时钟倒也正常?具体的式子咋推导的啊

  1. 系统时钟不合理,qing请看系统时钟480mhz,串口时钟只有120mhz,这样计算明显超时时间不够

image

  1. 我觉得超时时间使用两个字节的发送长度作为发送时间超时既可.因为modbus的发送完成是通过两个字符没有输入作为完成标志.我觉得可以参考

@CYFS3
Copy link
Contributor Author

CYFS3 commented Feb 23, 2025

还有就是HAL_RCC_GetSysClockFreq不一定是串口的时钟频率

这个算cpu要等几个clk用系统时钟倒也正常?具体的式子咋推导的啊

  1. 系统时钟不合理,qing请看系统时钟480mhz,串口时钟只有120mhz,这样计算明显超时时间不够

image

  1. 我觉得超时时间使用两个字节的发送长度作为发送时间超时既可.因为modbus的发送完成是通过两个字符没有输入作为完成标志.我觉得可以参考

https://github.com/RT-Thread/rt-thread/blob/master/bsp/stm32/libraries/HAL_Drivers/drivers/drv_usart.c#L344-362

@CYFS3 CYFS3 closed this Feb 23, 2025
@CYFS3 CYFS3 reopened this Feb 23, 2025
@CYFS3
Copy link
Contributor Author

CYFS3 commented Feb 23, 2025

用浮点导致的(
这种库就最好避免浮点吧。。

那就10 * HAL_RCC_GetSysClockFreq() / cfg->baud_rate / 4

@

用浮点导致的(
这种库就最好避免浮点吧。。

那就10 * HAL_RCC_GetSysClockFreq() / cfg->baud_rate / 4

@wdfk-prog 大佬你觉得呢

  • 加个余量,10 * HAL_RCC_GetSysClockFreq() / cfg->baud_rate / 4 + 2000,不然万一算出来是0就不好了
  • 还有就是HAL_RCC_GetSysClockFreq不一定是串口的时钟频率
  • 一定要使用串口时钟准确计算的话参考如下实现看看
    uint32_t SPI_CLOCK = 0UL;
    /* Some series may only have APBPERIPH_BASE, but don't have HAL_RCC_GetPCLK2Freq */
    #if defined(APBPERIPH_BASE)
    SPI_CLOCK = HAL_RCC_GetPCLK1Freq();
    #elif defined(APB1PERIPH_BASE) || defined(APB2PERIPH_BASE)
    /* The SPI clock for H7 cannot be configured with a peripheral bus clock, so it needs to be written separately */
    #if defined(SOC_SERIES_STM32H7)
    /* When the configuration is generated using CUBEMX, the configuration for the SPI clock is placed in the HAL_SPI_Init function.
    Therefore, it is necessary to initialize and configure the SPI clock to automatically configure the frequency division */
    HAL_SPI_Init(spi_handle);
    SPI_CLOCK = HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_SPI123);
    #else
    if ((rt_uint32_t)spi_drv->config->Instance >= APB2PERIPH_BASE)
    {
    SPI_CLOCK = HAL_RCC_GetPCLK2Freq();
    }
    else
    {
    SPI_CLOCK = HAL_RCC_GetPCLK1Freq();
    }
    #endif /* SOC_SERIES_STM32H7) */
    #endif /* APBPERIPH_BASE */

这边应该跟串口的时钟频率没有关系吧,--block_timeout,应该跟系统的频率有关吧

static int stm32_putc(struct rt_serial_device *serial, char c)
{
struct stm32_uart *uart;
RT_ASSERT(serial != RT_NULL);
uart = rt_container_of(serial, struct stm32_uart, serial);
rt_uint32_t block_timeout = uart->tx_block_timeout;
UART_INSTANCE_CLEAR_FUNCTION(&(uart->handle), UART_FLAG_TC);
#if defined(SOC_SERIES_STM32L4) || defined(SOC_SERIES_STM32WL) || defined(SOC_SERIES_STM32F7) || defined(SOC_SERIES_STM32F0) \
|| defined(SOC_SERIES_STM32L0) || defined(SOC_SERIES_STM32G0) || defined(SOC_SERIES_STM32H7) || defined(SOC_SERIES_STM32L5) \
|| defined(SOC_SERIES_STM32G4) || defined(SOC_SERIES_STM32MP1) || defined(SOC_SERIES_STM32WB) || defined(SOC_SERIES_STM32F3) \
|| defined(SOC_SERIES_STM32U5) || defined(SOC_SERIES_STM32H5) || defined(SOC_SERIES_STM32H7RS)
uart->handle.Instance->TDR = c;
#else
uart->handle.Instance->DR = c;
#endif
while (__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TC) == RESET && --block_timeout);
return (block_timeout != 0) ? 1 : -1;
}

@kaidegit
Copy link
Contributor

__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TC)是一个访问外设寄存器的操作,这个可能不仅仅和内核时钟有关吧?

@CYFS3
Copy link
Contributor Author

CYFS3 commented Feb 23, 2025

__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TC)是一个访问外设寄存器的操作,这个可能不仅仅和内核时钟有关吧?

但是现在的问题是block_timeout值设定的问题,那么block_timeout--,不就只是跟单片机频率有关而已吗,一开始的问题就是因为block_timeout值太小了,会导致发送没完成

@kaidegit
Copy link
Contributor

每次执行block_timeout--前会执行__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TC)

@wdfk-prog
Copy link
Contributor

__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TC)是一个访问外设寄存器的操作,这个可能不仅仅和内核时钟有关吧?

但是现在的问题是block_timeout值设定的问题,那么block_timeout--,不就只是跟单片机频率有关而已吗,一开始的问题就是因为block_timeout值太小了,会导致发送没完成

  • 说的有道理.应该是使用串口时钟计算不同波特率下的需要等待的串口超时时间.例如两个字符的发送时间.
  • 2个字符发送时间之后还在阻塞,则证明串口存在问题.
  • 由于这个时间还需要根据系统主频来执行对应代码,所以还需要系统主频计算所需运行的timeout次数

@CYFS3
Copy link
Contributor Author

CYFS3 commented Feb 24, 2025

__HAL_UART_GET_FLAG(&(uart->handle), UART_FLAG_TC)是一个访问外设寄存器的操作,这个可能不仅仅和内核时钟有关吧?

但是现在的问题是block_timeout值设定的问题,那么block_timeout--,不就只是跟单片机频率有关而已吗,一开始的问题就是因为block_timeout值太小了,会导致发送没完成

  • 说的有道理.应该是使用串口时钟计算不同波特率下的需要等待的串口超时时间.例如两个字符的发送时间.
  • 2个字符发送时间之后还在阻塞,则证明串口存在问题.
  • 由于这个时间还需要根据系统主频来执行对应代码,所以还需要系统主频计算所需运行的timeout次数

10 * HAL_RCC_GetSysClockFreq() / cfg->baud_rate / 4 ,如果是根据这个公式的话,以f1,9600波特率来计算,10*72000000/9600/4=18,750,这个值已经足够f1发送完成一个字节了。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BSP: STM32 BSP related with ST/STM32 BSP
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug][serial_v1] 主频较高时可能会导致发送不完整
3 participants