硬汉嵌入式论坛

 找回密码
 立即注册
查看: 484|回复: 6
收起左侧

[有问必答] 求助:STM32G030的USART不定长DMA发送有问题

[复制链接]

3

主题

124

回帖

133

积分

初级会员

积分
133
发表于 2024-1-22 13:56:43 | 显示全部楼层 |阅读模式
求助:STM32G030的USART不定长DMA发送有问题,可能因为这个影响接收。

发送用dma,接收用的中断,dma设置字节到字节传输,normal模式。后来发现大概平均5000多次会出现一次接收超时,调试发现是出了ORE错误,RDR寄存器本来应该是1字节,显示了2字节数据,多出来的高字节应该是接收数据的第一个字节。继续排查发现第一次dma发送没有问题,TDR寄存器是1字节,之后几次发送TDR寄存器有时就是显示2字节,多出来的高字节应该是发送数据的第一个字节。代码是用LL库仿照hal库写的,用原版HAL库也是一样的问题。Uartsend是在TC中断标志清掉之后使用的,预留的发送间隔时间远远大于发送耗时,现在用的中断只有systick和uart和dma,dma中断实际没用到,也排除人为关中断导致没有及时处理接收中断的可能性。uart发送改成阻塞发送或者中断发送都没有出现过这种问题,不知道dma发送是哪里配置有问题。
int UARTSend(uint8_t * buffer,uint16_t len)
{
    LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
    LL_DMA_ClearFlag_TC1(DMA1);
    LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, len);
    LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t)sendbuffer);
    LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_1, (uint32_t) &(USART1->TDR));
    while(len>0)
    {
        len--;
        sendbuffer[len] = buffer[len];
    }
    LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);

    LL_USART_ClearFlag_TC(USART1);
    LL_USART_EnableDMAReq_TX(USART1);
    return 0;
}
static void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */

  /* USER CODE END USART1_Init 0 */

  LL_USART_InitTypeDef USART_InitStruct = {0};

  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

  LL_RCC_SetUSARTClockSource(LL_RCC_USART1_CLKSOURCE_PCLK1);

  /* Peripheral clock enable */
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);

  LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
  /**USART1 GPIO Configuration
  PA9   ------> USART1_TX
  PA10   ------> USART1_RX
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_9;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = LL_GPIO_PIN_10;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USART1 DMA Init */

  /* USART1_TX Init */
  LL_DMA_SetPeriphRequest(DMA1, LL_DMA_CHANNEL_1, LL_DMAMUX_REQ_USART1_TX);

  LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_MEMORY_TO_PERIPH);

  LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_LOW);

  LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_NORMAL);

  LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);

  LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);

  LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_BYTE);

  LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_BYTE);

  /* USART1 interrupt Init */
  NVIC_SetPriority(USART1_IRQn, 0);
  NVIC_EnableIRQ(USART1_IRQn);

  /* USER CODE BEGIN USART1_Init 1 */
  LL_DMA_ConfigAddresses(DMA1, LL_DMA_CHANNEL_1,
                         (uint32_t)Uart1Def.RCVBuffer,
                         LL_USART_DMA_GetRegAddr(USART1, LL_USART_DMA_REG_DATA_TRANSMIT),
                         LL_DMA_GetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1));
  LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 0);
  /* USER CODE END USART1_Init 1 */
  USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
  USART_InitStruct.BaudRate = 19200;
  USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_9B;
  USART_InitStruct.StopBits = LL_USART_STOPBITS_1;
  USART_InitStruct.Parity = LL_USART_PARITY_EVEN;
  USART_InitStruct.TransferDirection = LL_USART_DIRECTION_TX_RX;
  USART_InitStruct.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
  USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
  LL_USART_Init(USART1, &USART_InitStruct);
  LL_USART_SetTXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_8);
  LL_USART_SetRXFIFOThreshold(USART1, LL_USART_FIFOTHRESHOLD_1_8);
  LL_USART_DisableFIFO(USART1);
  LL_USART_ConfigAsyncMode(USART1);

  /* USER CODE BEGIN WKUPType USART1 */

  /* USER CODE END WKUPType USART1 */

  LL_USART_Enable(USART1);

  /* Polling USART1 initialisation */
  while((!(LL_USART_IsActiveFlag_TEACK(USART1))) || (!(LL_USART_IsActiveFlag_REACK(USART1))))
  {
  }
  /* USER CODE BEGIN USART1_Init 2 */
  LL_USART_EnableIT_PE(USART1);
  LL_USART_EnableIT_ERROR(USART1);
  LL_USART_EnableIT_RXNE(USART1);
  LL_USART_EnableIT_TC(USART1);
  LL_DMA_EnableIT_TE(DMA1,LL_DMA_CHANNEL_1);
  /* USER CODE END USART1_Init 2 */

}


回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106846
QQ
发表于 2024-1-22 16:04:09 | 显示全部楼层
串口DMA发送主要就是这个问题,你仅发送,不接收试试



回复

使用道具 举报

3

主题

124

回帖

133

积分

初级会员

积分
133
 楼主| 发表于 2024-1-22 16:30:47 | 显示全部楼层
改成只dma发送,现在全速运行TDR寄存器是清零状态,能正常发送,之前按道理应该也看不到TDR寄存器,实际上能看到TDR保留了最后一个字节。
回复

使用道具 举报

3

主题

124

回帖

133

积分

初级会员

积分
133
 楼主| 发表于 2024-1-22 17:26:46 | 显示全部楼层
skyshine 发表于 2024-1-22 16:30
改成只dma发送,现在全速运行TDR寄存器是清零状态,能正常发送,之前按道理应该也看不到TDR寄存器,实际上 ...

可能是调试器的问题,只发送:dma、中断、阻塞都看不到TDR寄存器;加入接收:dma发送的TDR寄存器有时会显示两个字节,中断和阻塞一直显示1个字节,没有出现过两个字节的情况。
回复

使用道具 举报

3

主题

124

回帖

133

积分

初级会员

积分
133
 楼主| 发表于 2024-1-23 10:05:52 | 显示全部楼层
乌龙了,没注意看手册,bit8这里是奇偶校验位,发送的时候bit8有时就是1,这个是硬件自动填充的,这样看的话TDR和RDR都是没有问题的。收发平均5000多次就会出现ORE错误这个问题后面要重新排查一下原因
回复

使用道具 举报

3

主题

124

回帖

133

积分

初级会员

积分
133
 楼主| 发表于 2024-1-23 10:56:07 | 显示全部楼层
我现在修改了串口中断的优先级,问题解决了。之前systick和串口中断优先级都是3,systick这里有串口超时判断,应该是在接收过程中systick超时判断条件没有及时更新,导致程序以为接收完毕,提前处理接收数据,导致RDR寄存器没有及时读取,最后触发ORE错误。没想到错误这么低级,前后调试了好几天
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106846
QQ
发表于 2024-1-24 08:59:54 | 显示全部楼层
skyshine 发表于 2024-1-23 10:56
我现在修改了串口中断的优先级,问题解决了。之前systick和串口中断优先级都是3,systick这里有串口超时判 ...

谢谢告知最终原因。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-7 10:50 , Processed in 0.308532 second(s), 26 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表