打印
[应用相关]

增加 UART 接口应用时的异常分析

[复制链接]
1324|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Cube 软件包的提供,极大的降低了开发难度。 使用者在开发的过程中, 只需参考 Cube 包中提供的例
程就能快速的实现对应功能开发。 开发者为了快速开发 UART 功能,参考 Cube 包中的 UART 例程,
并根据应用情况, 扩展了另一组 UART 接口。 但是在应用过程中, 发现两路 UART 不能共存。 本文分
析了这种情况出现的原因。  

使用特权

评论回复
沙发
可怜的小弗朗士|  楼主 | 2021-11-10 10:12 | 只看该作者
背景介绍
Cube 软件包中 CDC 例程实现了虚拟串口通信功能, 数据传输链路如下图所示。  


在开发者的应用中, 需要实现下图数据传输链路。 根据应用需求, 推荐参考 Cube 软件包中的 USB
CDC 例程。

使用特权

评论回复
板凳
可怜的小弗朗士|  楼主 | 2021-11-10 10:14 | 只看该作者
问题描述
问题复现平台: STM324xG-Eval
例程路径:
STM32Cube_FW_F4_V1.15.0\Projects\STM324xG_EVAL\Applications\USB_Device\CDC_Standalone  

在对 CDC 例程了解后, 参考已有的 UART 应用, 新增了一路 UART。 对应初始化程序如下所示。 其中
USARTx 为例程原有部分,而 USARTy 为新增的一路 UART 初始化部分。
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
static DMA_HandleTypeDef hdma_tx;
GPIO_InitTypeDef GPIO_InitStruct;
if(huart->Instance == USARTx )
{
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* Enable GPIO clock */
USARTx_TX_GPIO_CLK_ENABLE();
USARTx_RX_GPIO_CLK_ENABLE();
/* Enable USARTx clock */
USARTx_CLK_ENABLE();
/* Enable DMAx clock */
DMAx_CLK_ENABLE();
/*##-2- Configure peripheral GPIO ##########################################*/
/* UART TX GPIO pin configuration */
GPIO_InitStruct.Pin = USARTx_TX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
GPIO_InitStruct.Alternate = USARTx_TX_AF;
HAL_GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStruct);
/* UART RX GPIO pin configuration */
GPIO_InitStruct.Pin = USARTx_RX_PIN;
GPIO_InitStruct.Alternate = USARTx_RX_AF;
HAL_GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStruct);
/*##-3- Configure the NVIC for UART ########################################*/
HAL_NVIC_SetPriority(USARTx_IRQn, 5, 0);
HAL_NVIC_EnableIRQ(USARTx_IRQn);
/*##-4- Configure the DMA streams ##########################################*/
/* Configure the DMA handler for Transmission process */
hdma_tx.Instance = USARTx_TX_DMA_STREAM;
hdma_tx.Init.Channel = USARTx_TX_DMA_CHANNEL;
hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_tx.Init.Mode = DMA_NORMAL;
hdma_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_tx.Init.MemBurst = DMA_MBURST_INC4;
hdma_tx.Init.PeriphBurst = DMA_PBURST_INC4;
HAL_DMA_Init(&hdma_tx);
/* Associate the initialized DMA handle to the UART handle */
__HAL_LINKDMA(huart, hdmatx, hdma_tx);
/*##-5- Configure the NVIC for DMA #########################################*/
/* NVIC configuration for DMA transfer complete interrupt (USARTx_TX) */
HAL_NVIC_SetPriority(USARTx_DMA_TX_IRQn, 6, 0);
HAL_NVIC_EnableIRQ(USARTx_DMA_TX_IRQn);
}
if(huart->Instance == USARTy )
{
/*##-1- Enable peripherals and GPIO Clocks #################################*/
/* Enable GPIO clock */
USARTy_TX_GPIO_CLK_ENABLE();
USARTy_RX_GPIO_CLK_ENABLE();
/* Enable USARTx clock */
USARTy_CLK_ENABLE();
/* Enable DMAx clock */
DMAy_CLK_ENABLE();
/*##-2- Configure peripheral GPIO ##########################################*/
/* UART TX GPIO pin configuration */
GPIO_InitStruct.Pin = USARTy_TX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FAST;
GPIO_InitStruct.Alternate = USARTy_TX_AF;
HAL_GPIO_Init(USARTy_TX_GPIO_PORT, &GPIO_InitStruct);
/* UART RX GPIO pin configuration */
GPIO_InitStruct.Pin = USARTy_RX_PIN;
GPIO_InitStruct.Alternate = USARTy_RX_AF;
HAL_GPIO_Init(USARTy_RX_GPIO_PORT, &GPIO_InitStruct);
/*##-3- Configure the NVIC for UART ########################################*/
HAL_NVIC_SetPriority(USARTy_IRQn, 7, 0);
HAL_NVIC_EnableIRQ(USARTy_IRQn);
/*##-4- Configure the DMA streams ##########################################*/
/* Configure the DMA handler for Transmission process */
hdma_tx.Instance = USARTy_TX_DMA_STREAM;
hdma_tx.Init.Channel = USARTy_TX_DMA_CHANNEL;
hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_tx.Init.Mode = DMA_NORMAL;
hdma_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_tx.Init.MemBurst = DMA_MBURST_INC4;
hdma_tx.Init.PeriphBurst = DMA_PBURST_INC4;
HAL_DMA_Init(&hdma_tx);
/* Associate the initialized DMA handle to the UART handle */
__HAL_LINKDMA(huart, hdmatx, hdma_tx);
/*##-5- Configure the NVIC for DMA #########################################*/
/* NVIC configuration for DMA transfer complete interrupt (USARTx_TX) */
HAL_NVIC_SetPriority(USARTy_DMA_TX_IRQn, 8, 0);
HAL_NVIC_EnableIRQ(USARTy_DMA_TX_IRQn);
} …
}

之前的 UART 发送和接收处, 同样新增了一路 UART 的发送和接收。 为了方便描述, 这里不对应用
层面进行描述。 而是直接在例程中, 时钟配置后执行下述语句, 复现问题。
#ifdef USART_X_INIT_ENABLE
UartHandle.Instance = USARTx;

if(HAL_UART_Init(&UartHandle) != HAL_OK)

if(HAL_UART_Receive_IT(&UartHandle, (uint8_t *)UserTxBuffer, 1) != HAL_OK)

#endif // USART_X_INIT_ENABLE
#ifdef USART_Y_INIT_ENABLE
UartHandley.Instance = USARTy;

if(HAL_UART_Init(&UartHandley) != HAL_OK)

if(HAL_UART_Receive_IT(&UartHandley, (uint8_t *)UserTxBuffer, 1) != HAL_OK)

#endif //USART_Y_INIT_ENABLE
while(1)
{
#ifdef USART_X_ENABLE
HAL_UART_Transmit_DMA(&UartHandle, “UARTx Test”, 11);
#endif //USART_X_ENABLE
#ifdef USART_Y_ENABLE
HAL_UART_Transmit_DMA(&UartHandley,”UARTy Test”, 11);
#endif // USART_Y_ENABLE
HAL_Delay(100);
}
结果如下表。

使用特权

评论回复
地板
可怜的小弗朗士|  楼主 | 2021-11-10 10:15 | 只看该作者
问题分析
不同 UART 接口相互独立。 UART IP 设计上, 不同 UART 同时发送不会相互影响。 初步判断应该是
UART 初始化过程中,存在冲突。
通过对结果分析, 在
UARTx UARTy 都进行初始化后, 只执行 UARTx DMA 发送时,执行异常; 只
执行
UARTy DMA 发送时,执行正常。 而在初始化中, UARTx 先于 UARTy 初始化, 进一步确认是初
始化时, 存在冲突。 并且将问题范围缩小到
HAL_UART_MspInit()函数中。
在线调试,发现在执行
UARTy 初始化时( UARTx 已经在之前初始化结束) , UARTx 发送 DMA 对应
Instant Channel 值都被改变。 其中 Instant 中保存着对应 DMA 的寄存器基地址。
仔细检查
HAL_UART_MspInit()函数,发现对于 DMA 的初试化,两个 UART 共用了例程中原有的
DMA 句柄变量, 为上述程序中的 static DMA_HandleTypeDef hdma_tx;
而在 HAL_UART_Transmit_DMA 函数中, 会对对应的 DMA 进行配置并使能, 而配置过程会依据
DMA 句柄中的参数。从而导致发送异常。
对问题的产生原因清楚后, 在新增
UART 接口的时候,初始化函数 HAL_UART_MspInit()中同样需要
新增
DMA 句柄变量, 并利用在新增 UART DMA 初始化中。 如下所示。
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
static DMA_HandleTypeDef hdma_tx;
static DMA_HandleTypeDef hdma_tx_y;

if(huart->Instance == USARTy )
{ …
hdma_tx_y.Instance = USARTy_TX_DMA_STREAM;
hdma_tx_y.Init.Channel = USARTy_TX_DMA_CHANNEL;
hdma_tx_y.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tx_y.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tx_y.Init.MemInc = DMA_MINC_ENABLE;
hdma_tx_y.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_tx_y.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_tx_y.Init.Mode = DMA_NORMAL;
hdma_tx_y.Init.Priority = DMA_PRIORITY_LOW;
hdma_tx_y.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_tx_y.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_tx_y.Init.MemBurst = DMA_MBURST_INC4;
hdma_tx_y.Init.PeriphBurst = DMA_PBURST_INC4;
HAL_DMA_Init(&hdma_tx_y);
/* Associate the initialized DMA handle to the UART handle */
__HAL_LINKDMA(huart, hdmatx, hdma_tx_y);

}


使用特权

评论回复
5
可怜的小弗朗士|  楼主 | 2021-11-10 10:16 | 只看该作者
总结
所描述的问题, 可以归结为一个开发漏洞。 而导致这个开发漏洞的原因, 更多的可能是在参考 Cube
程时, 对于各函数的了解以及变量的使用情况, 没有逐个了解。 建议在基于
Cube 例程进行开发时,能
够对各函数及变量等加以了解,在针对应用进行修改过程中, 能够减小错误率, 从而减少排错时间。
  

使用特权

评论回复
6
wowu| | 2021-12-6 14:25 | 只看该作者
是硬件本身的漏洞吗

使用特权

评论回复
7
xiaoqizi| | 2021-12-6 14:29 | 只看该作者
我非常喜欢用这个软件

使用特权

评论回复
8
木木guainv| | 2021-12-6 14:40 | 只看该作者
是的 功能很强大

使用特权

评论回复
9
磨砂| | 2021-12-6 14:41 | 只看该作者
无论用什么 都需要对其本身很了解

使用特权

评论回复
10
tpgf| | 2021-12-6 14:44 | 只看该作者
初始化代码很多啊

使用特权

评论回复
11
晓伍| | 2021-12-6 14:45 | 只看该作者
UART还有 IP吗?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

97

主题

729

帖子

0

粉丝