为什么 HAL 会减慢 UART 传输速度。?

Why HAL slow down the UART transmission.?

提问人:vishnu m c 提问时间:10/19/2023 最后编辑:Issylinvishnu m c 更新时间:10/23/2023 访问量:77

问:

我正在使用 Nucleo 板 STML073Rz 对频率为 1khz 的正弦波进行采样。我的STMCubeIDE配置如下。

系统频率 : HSE 8Mhz

蒂默尔2

预标量:8-1, 比分 : 100-1, 定时器过流频率:10000Hz, 触发事件选择:更新事件

模数转换器

预标量:同步时钟模式除以 2, ADC分辨率:8bit分辨率, 数据对齐方式:右, 外部触发转换源:Timer2触发输出事件

串口2

时钟:sysclock 8Mhz, 波特率 : 115200, 字长:8bit, 溢出:禁用

我的要求是对正弦波进行采样,该正弦波以 10000Hz 的采样频率输入 ADC6 通道。我使用以下逻辑将示例发送到网关。

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    endOfConversion = 1;
    HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
}

HAL_TIM_Base_Start(&htim2);
HAL_ADC_Start_IT(&hadc);

numsamples=4500;
txcount = 0;
endOfConversion=0;
do
{
    if(endOfConversion==1)
    {
        adc_value = HAL_ADC_GetValue(&hadc);
        HAL_UART_Transmit(&huart1, &adc_value, 1, 10);
        endOfConversion=0;
        txcount+=1;
    }
}while(txcount<=numsamples);
HAL_ADC_Stop_IT(&hadc);

这里只显示逻辑,而不是整个代码。在网关上,我绘制了样本的 FFT,它显示峰值为 2000Hz,而不是 1000Hz。

经过一番调试,我发现 HAL 延迟了 1 字节的传输,因此只有备用样本被发送到网关。

为什么 HAL UART 会延迟传输?

嵌入式 STM32 Nucleo

评论

2赞 the busybee 10/19/2023
您是否考虑了串行通信的传输时间?
0赞 the busybee 10/19/2023
您可以将源简化为最小的可重现示例,该示例由计时器和传输部分组成。如果您希望我们真正帮助您,请这样做并将其添加到您的问题中。

答:

2赞 GandhiGandhi 10/19/2023 #1

假设这是标记 10000Hz (100us) 间隔的事件时间线。|

Timer2 和 ADC 的配置方式是,每次转换时都会触发 TIM2 和 ADC。从数据手册中可以看出,ADC转换相对于100us间隔非常快(0.4uz),因此我们可以假设ADC转换回调与图中的触发同时发生。

|------|------|-----|-----|------|
^Tim2 IRQ / ADC trigger / HAL_ADC_ConvCpltCallback

就像@the-busybee的评论所提到的,UART速度是相关的。UART配置为轮询模式,因此这也很重要。 在 115200Hz 波特率线上发送 10 位(不是 ~bytes~,感谢 @pmacfarlane),这将需要大约 ~100us(这是来自 10/115200 的粗略幅度猜测)。HAL_UART_Transmit(&huart1, &adc_value, 1, 10);

上一个带有定时器和ADC事件的时间线发生在后台的硬件中。同时,在主循环中运行的代码同时在前台的软件中发生。如果 UART 传输时间超过 100 微秒,那么以下是正在发生的事情的可能时间表:do {} while

|------|------|-----|-----|------|
^Tim2 IRQ / ADC trigger / HAL_ADC_ConvCpltCallback

|......Auuuuuuur....Auuuuuur......A
  |    | |     ^ The main loop resets the conversion flag with `endOfConversion=0`
  |    | ^ Time spent transmitting the read value over the UART
  |    ^ main loop reads ADC value HAL_ADC_GetValue(&hadc);
  ^ The main while loop is waiting for `if(endOfConversion==1)` to be true

当下一个 irq 发生时,UART 传输仍在进行中,但由于 UART 完成后被重置,因此环路必须等待另一个 TIM2 IRQ 读取和传输另一个样本。endOfConversion

我认为您可以通过在 UART 传输之前重置来解决这个问题,以在上面的软件时间线中取出所有这些“.”状态,如下所示:endOfConversion

    if(endOfConversion==1)
    {
        adc_value = HAL_ADC_GetValue(&hadc);
        endOfConversion=0;       
        HAL_UART_Transmit(&huart1, &adc_value, 1, 10);
        txcount+=1;
    }

如果此解决方案导致有趣的采样率问题,那么您需要做一些更高级的事情,例如缓存数据以供以后传输,或者使用更高的波特率 UART(如果可能)。


这就是我所说的缓存数据,以便在您有足够的内存时稍后传输的意思。

numsamples=4500;
txcount = 0;
endOfConversion=0;
uint16_t samples[4500];
// Measure all of the samples
do
{
    if(endOfConversion==1)
    {
        adc_value = HAL_ADC_GetValue(&hadc);
        samples[txcount] = adc_value;
        endOfConversion=0;
        txcount+=1;
    }
}while(txcount<=numsamples);
HAL_ADC_Stop_IT(&hadc);

// Transmit the samples
for(int i = 0; i < numsamples; i++){
    adc_value = samples[i]
    HAL_UART_Transmit(&huart1, &adc_value, 1, 10);
}

评论

0赞 vishnu m c 10/20/2023
我已经按照您的建议进行了检查,但是我仍然有问题,损失有所减少。现在,随机样本会丢失,而不是备用请求。我也尝试过使用传输中断方法。即使在中断方法中,我也发现了样本损失。我在 uart complete 回调中切换了一个引脚并扰乱了频率。它显示 2.51Khz。也就是说,数据以 5.02Khz 的速度发送
0赞 GandhiGandhi 10/20/2023
UART花费的时间比我想象的要多,我不知道为什么。确保 UART 配置为异步模式,禁用硬件流控制,并且没有奇偶校验位。同样,只是为了进行实验,尝试将 UART 字长配置为“9 位,包括奇偶校验”,并尝试仅发送 8 位 adc 读数,而不是使用 .也许这足以加快速度。HAL_UART_Transmit(&huart1, &adc_value, 1, 8)
0赞 GandhiGandhi 10/20/2023
如果这仍然不起作用,我在最后添加了一个片段来尝试。
0赞 pmacfarlane 10/26/2023
我建议不要将 HAL 用于 UART。使用LL驱动接口,或手动戳数据寄存器。HAL 有如此多的开销,尤其是在调用每个字节时。