硬汉嵌入式论坛

 找回密码
 立即注册
搜索
查看: 3093|回复: 22
收起左侧

[UART] H7使用BDMA+LPUART1接收的问题

[复制链接]

4

主题

27

回帖

39

积分

新手上路

积分
39
发表于 2023-12-6 09:55:08 | 显示全部楼层 |阅读模式
程序描述:  串口接收buff 使用的是  0x38000040地址 做了32位对齐处理, 开了Cache , 并且在解析数据前使用   SCB_CleanDCache_by_Addr((uint32_t *)rx_buff, rx_len);    目前在没开优化等级或者优化等级1的情况下是很正常的,  




问题:   优化等级3就会出现接收数据校验错误,调试看了  收到的数据有些不对.  然后再开优化等级3的时候,我设置了MPU    把 0x38000000 地址都禁用高速缓存后 程序又很正常了.   



想请教硬汉哥  这是什么问题  往哪方面去下手解决
回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
124425
QQ
发表于 2023-12-6 12:09:48 | 显示全部楼层
DMA接收的话,要调用无效化API, 简单省事些,直接调用这个:SCB_CleanInvalidateDCache
回复

使用道具 举报

8

主题

32

回帖

61

积分

初级会员

积分
61
发表于 2023-12-6 12:12:56 来自手机 | 显示全部楼层
mpu设置这部分为device类型
回复

使用道具 举报

4

主题

27

回帖

39

积分

新手上路

积分
39
 楼主| 发表于 2023-12-6 13:06:19 | 显示全部楼层
上面粘贴错了 是用的SCB_InvalidateDCache_by_Addr
刚刚试了下SCB_CleanInvalidateDCache 这个现在一次都校验不对了
回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
124425
QQ
发表于 2023-12-7 08:18:45 | 显示全部楼层
面包人 发表于 2023-12-6 13:06
上面粘贴错了 是用的SCB_InvalidateDCache_by_Addr
刚刚试了下SCB_CleanInvalidateDCache 这个现在一次都 ...

1、配置0x38000000地址RAM为最低性能看看正常不
https://forum.anfulai.cn/forum.php?mod=viewthread&tid=99322

2、优化问题,可以这个帖子思路锁定下

关键时候,又拿出了我的独门绝技,MDK不同优化等级导致异常的解决思路
https://forum.anfulai.cn/forum.php?mod=viewthread&tid=98479
回复

使用道具 举报

4

主题

27

回帖

39

积分

新手上路

积分
39
 楼主| 发表于 2023-12-7 09:02:11 | 显示全部楼层
配置0x38000000地址RAM为最低性能是正常的
回复

使用道具 举报

4

主题

27

回帖

39

积分

新手上路

积分
39
 楼主| 发表于 2023-12-7 09:38:49 | 显示全部楼层
找到问题了  之前把这行代码给屏蔽了  打开就没问题了  
SCB->CACR |= 1<<2;  
强制D-cache透写会影响性能吗 硬汉哥
回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
124425
QQ
发表于 2023-12-7 10:29:36 | 显示全部楼层
面包人 发表于 2023-12-7 09:38
找到问题了  之前把这行代码给屏蔽了  打开就没问题了  
SCB->CACR |= 1

这个代码SCB->CACR |= 1<<2;  删掉,不要这么操作。

建议全程MPU管理。
回复

使用道具 举报

21

主题

284

回帖

347

积分

高级会员

积分
347
发表于 2023-12-7 10:36:12 | 显示全部楼层
eric2013 发表于 2023-12-7 10:29
这个代码SCB->CACR |= 1

一直强调MPU,是不是有什么故事啊?
回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
124425
QQ
发表于 2023-12-7 10:40:28 | 显示全部楼层
yunqi 发表于 2023-12-7 10:36
一直强调MPU,是不是有什么故事啊?

因为MPU配置是这类问题的核心,这个概念必须根深蒂固的植入脑子里面,只要出数据问题,首先想到就应该是MPU配置。
回复

使用道具 举报

4

主题

27

回帖

39

积分

新手上路

积分
39
 楼主| 发表于 2023-12-7 11:20:10 | 显示全部楼层
eric2013 发表于 2023-12-7 10:29
这个代码SCB->CACR |= 1

好的谢谢啦
回复

使用道具 举报

0

主题

7

回帖

7

积分

新手上路

积分
7
发表于 2026-1-19 15:07:17 | 显示全部楼层
能求一份代码吗,LPUART+BDMA,我的情况是BDMA中断接收错误
,发烧正常,不用BDMA中断接收串口中断接收可以正常收发
回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
124425
QQ
发表于 2026-1-20 00:52:27 | 显示全部楼层
waz1992 发表于 2026-1-19 15:07
能求一份代码吗,LPUART+BDMA,我的情况是BDMA中断接收错误
,发烧正常,不用BDMA中断接收串口中断接收可 ...

方便的话,可以分享下你的配置和测试看下。
回复

使用道具 举报

0

主题

7

回帖

7

积分

新手上路

积分
7
发表于 2026-1-20 09:22:08 | 显示全部楼层
#if EN_LPUART1
                UART_HandleTypeDef LPUART1_Handler; //UART1句柄
                DMA_HandleTypeDef  LPUART1DMA;   //UART1-DMA句柄  
                ALIGN_32BYTES(__attribute__((section (".RAM_D3")))) volatile u8 U1_RxBuffer;//HAL库使用的串口接收缓冲
                ALIGN_32BYTES(__attribute__((section (".RAM_D3")))) volatile uint16_t idle_time_U1 = 0;
                // 全局变量
    ALIGN_32BYTES(__attribute__((section (".RAM_D3")))) volatile FIFO_TypeDef rx_fifo_U1 = { .head = 0, .tail = 0, .count = 0 };
    ALIGN_32BYTES(__attribute__((section (".RAM_D3")))) volatile FIFO_TypeDef tx_fifo_U1 = { .head = 0, .tail = 0, .count = 0 };
    ALIGN_32BYTES(__attribute__((section (".RAM_D3")))) volatile Frame_TypeDef frame_U1 = { .length = 0, .explanation = 0 };
#endif


/****************************************************************************
函 数 名:void uart_init(u32 bound)
功    能:串口1初始化
输入参数:bound:波特率设置
返 回 值:无
说    明:无
创建时间:
作    者:
修改记录:
****************************************************************************/
void uart_init(u32 bound)
{       
        #if EN_LPUART1
          //UART 初始化设置
          LPUART1_Handler.Instance=LPUART1;                                                      //LPUART
          LPUART1_Handler.Init.BaudRate=bound;                                            //波特率
          LPUART1_Handler.Init.WordLength=UART_WORDLENGTH_8B;     //字长为8位数据格式
          LPUART1_Handler.Init.StopBits=UART_STOPBITS_1;                //一个停止位
          LPUART1_Handler.Init.Parity=UART_PARITY_NONE;                        //无奇偶校验位
          LPUART1_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE;     //无硬件流控
          LPUART1_Handler.Init.Mode=UART_MODE_TX_RX;                          //收发模式
          HAL_UART_Init(&LPUART1_Handler);                                                      //HAL_UART_Init()会使能UART1          
//          HAL_UART_Receive_IT(&LPUART1_Handler, (uint8_t*)&U1_RxBuffer, 1);//该函数会开启接收中断:标志位UART_IT_RXNE,并且设置接收缓冲以及接收缓冲接收最大数据量
    HAL_UART_Receive_DMA(&LPUART1_Handler,(uint8_t*)&rx_fifo_U1.buffer,UART_RX_FIFO_SIZE); //该函数会开启DMA接收中断
    __HAL_UART_ENABLE_IT(&LPUART1_Handler,UART_IT_IDLE);  // 使能空闲中断
  #endif
}

/****************************************************************************
函 数 名:void HAL_UART_MspInit(UART_HandleTypeDef *huart)
功    能:串口1端口初始化
输入参数:huart:串口句柄
返 回 值:无
说    明:无
创建时间:
作    者:
修改记录:
****************************************************************************/
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
   //GPIO端口设置
        GPIO_InitTypeDef GPIO_Initure;
       
        #if EN_LPUART1
        if(huart->Instance==LPUART1)               //如果是串口1,进行串口1 MSP初始化
        {
                __HAL_RCC_GPIOA_CLK_ENABLE();                              //使能GPIOA时钟
                __HAL_RCC_LPUART1_CLK_ENABLE();                            //使能LPUART1时钟
                __HAL_RCC_BDMA_CLK_ENABLE();            //BDMA 时钟使能
       
                GPIO_Initure.Pin=GPIO_PIN_9 | GPIO_PIN_10;        //PA9/PA10
                GPIO_Initure.Mode=GPIO_MODE_AF_PP;                  //复用推挽输出
                GPIO_Initure.Pull=GPIO_PULLUP;                            //上拉
                GPIO_Initure.Speed=GPIO_SPEED_FREQ_HIGH;//高速
                GPIO_Initure.Alternate=GPIO_AF3_LPUART;        //复用为LPUART
                HAL_GPIO_Init(GPIOA,&GPIO_Initure);                   //初始化端口

                LPUART1DMA.Instance = BDMA_Channel1;                          // 根据实际硬件连接选择合适的Stream
    LPUART1DMA.Init.Request = BDMA_REQUEST_LPUART1_RX;           // 请求设置
    LPUART1DMA.Init.Direction = DMA_PERIPH_TO_MEMORY;            // 传输方向
    LPUART1DMA.Init.PeriphInc = DMA_PINC_DISABLE;                // 外设增量模式
    LPUART1DMA.Init.MemInc = DMA_MINC_ENABLE;                    // 存储增量模式
    LPUART1DMA.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;   // 外设数据大小
    LPUART1DMA.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;      // 存储数据大小
    LPUART1DMA.Init.Mode = DMA_CIRCULAR;                         // 循环控制模式
    LPUART1DMA.Init.Priority = DMA_PRIORITY_LOW;                 // 优先级
    LPUART1DMA.Init.FIFOMode = DMA_FIFOMODE_DISABLE;             // FIFO阈值选择
                LPUART1DMA.Init.MemBurst=DMA_MBURST_SINGLE;                  // 存储器突发模式
    LPUART1DMA.Init.PeriphBurst=DMA_PBURST_SINGLE;               // 外设突发模式
          
                __HAL_LINKDMA(&LPUART1_Handler,hdmarx,LPUART1DMA);
               
          /* 初始化DMA */
          if(HAL_DMA_Init(&LPUART1DMA) != HAL_OK)
          {
                  Error_Handler(__FILE__, __LINE__);     
          }
               
          HAL_NVIC_SetPriority(BDMA_Channel1_IRQn, 3, 3);
    HAL_NVIC_EnableIRQ(BDMA_Channel1_IRQn);
               
                HAL_NVIC_EnableIRQ(LPUART1_IRQn);                                //使能LPUART1中断通道
                HAL_NVIC_SetPriority(LPUART1_IRQn,3,3);        //抢占优先级3,子优先级3       
        }
        #endif
}


#if EN_LPUART1
/****************************************************************************
函 数 名:void USART1_IRQHandler(void)
功    能:串口1中断处理函数
输入参数:无
返 回 值:无
说    明:无
创建时间:
作    者:
修改记录:
****************************************************************************/
void LPUART1_IRQHandler(void)                       
{        
        HAL_UART_IRQHandler(&LPUART1_Handler);        //调用HAL库中断处理公用函数
        DMA_Data_Acquisition_U1();  
}

/****************************************************************************
函 数 名:void DMA1_Stream0_IRQHandler(void)
功    能:串口DMA中断
输入参数:无
返 回 值:无
说    明:无
创建时间:
作    者:
修改记录:
****************************************************************************/
void BDMA_Channel1_IRQHandler(void)
{
  HAL_DMA_IRQHandler(&LPUART1DMA);
}
/****************************************************************************
函 数 名:void DMA_Data_Acquisition_U1(void)
功    能:串口1-DMA数据从缓存中取出来
输入参数:无
返 回 值:无
说    明:无
创建时间:
作    者:
修改记录:
****************************************************************************/
void DMA_Data_Acquisition_U1(void)
{
        uint16_t remain_length;
        /* 串口是否触发空闲中断 */
  if(__HAL_UART_GET_FLAG(&LPUART1_Handler,UART_FLAG_IDLE))  
  {               
                 __HAL_UART_CLEAR_IDLEFLAG(&LPUART1_Handler);  /* 清除空闲中断 */       
                 
     rx_fifo_U1.head = rx_fifo_U1.tail; // 尾帧位置
     remain_length = __HAL_DMA_GET_COUNTER(&LPUART1DMA);  /* 获取串口数据环形针头位置 */               
     if(remain_length)
     {               
       rx_fifo_U1.tail = UART_RX_FIFO_SIZE - remain_length;
     }
      
                if(rx_fifo_U1.tail > rx_fifo_U1.head)
           {
             rx_fifo_U1.count = rx_fifo_U1.tail - rx_fifo_U1.head;
                        for (uint16_t i = 0;i<rx_fifo_U1.count;i++)
                        {
                          frame_U1.data[i] = rx_fifo_U1.buffer[rx_fifo_U1.head+i];
                        }                   
           }
           else  /* 首尾相连数据获取 */       
           {
             rx_fifo_U1.count = rx_fifo_U1.tail + UART_RX_FIFO_SIZE  - rx_fifo_U1.head;
                        for (uint16_t i = 0;i<UART_RX_FIFO_SIZE  - rx_fifo_U1.head;i++)
                        {
                          frame_U1.data[i] = rx_fifo_U1.buffer[rx_fifo_U1.head +i];
                        }
      for (uint16_t i = 0;i<rx_fifo_U1.tail;i++)
                        {
                          frame_U1.data[UART_RX_FIFO_SIZE  - rx_fifo_U1.head +i] = rx_fifo_U1.buffer[i];
                        }                        
           }
                frame_U1.length = rx_fifo_U1.count;
                frame_U1.explanation = 0;
  }       
}
麻烦帮忙看下
回复

使用道具 举报

0

主题

7

回帖

7

积分

新手上路

积分
7
发表于 2026-1-20 09:24:08 | 显示全部楼层
// 缓冲区和帧配置
#define UART_RX_FIFO_SIZE 256
#define MAX_FRAME_SIZE    256
//#define FRAME_TIMEOUT_MS  4     /* 50ms帧间隔是超大数据传输,其余数据时间都小于50   */

// 环形缓冲区结构
typedef struct {
    uint8_t buffer[UART_RX_FIFO_SIZE];
    volatile uint32_t head;   // 头入栈指针
    volatile uint32_t tail;   // 尾出栈指针
    volatile uint32_t count;  // 当前位置计数指针
} FIFO_TypeDef;

// 帧管理结构
typedef struct {
    uint8_t data[MAX_FRAME_SIZE];
    volatile uint32_t length;        // 长度指针
//    volatile uint8_t  ready;         // 帧就绪标志 0-未就绪  1-就绪
          volatile uint8_t  explanation;   // 帧就解析标志 0-未解析  1-解析
} Frame_TypeDef;




#if EN_LPUART1
                extern volatile u8 U1_RxBuffer;//HAL库USART接收Buffer
    extern volatile uint16_t idle_time_U1;       
                // 全局变量
    extern volatile FIFO_TypeDef rx_fifo_U1;
    extern volatile FIFO_TypeDef tx_fifo_U1;
    extern volatile Frame_TypeDef frame_U1;
extern void DataTransSerialPort1(uint8_t *data,uint16_t len);
extern void DMA_Data_Acquisition_U1(void);

#endif
H文件关键参数定义
回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
124425
QQ
发表于 2026-1-20 11:02:18 | 显示全部楼层
waz1992 发表于 2026-1-20 09:22
#if EN_LPUART1
                UART_HandleTypeDef LPUART1_Handler; //UART1句柄
                DMA_HandleTypeDef  LPUART1DMA;  ...

看下map文件,确定没有分配到TCM RAM空间吧

U1_RxBuffer
回复

使用道具 举报

0

主题

7

回帖

7

积分

新手上路

积分
7
发表于 2026-1-20 11:18:09 | 显示全部楼层
myUsbRxData                              0x2400a7c0   Data        1024  usbd_cdc_if.o(.RAM_D1)
    myUsbRxNum                               0x2400abc0   Data           2  usbd_cdc_if.o(.RAM_D1)
    U1_RxBuffer                              0x2400abe0   Data           1  usart.o(.RAM_D3)
    idle_time_U1                             0x2400ac00   Data           2  usart.o(.RAM_D3)
    rx_fifo_U1                               0x2400ac20   Data         268  usart.o(.RAM_D3)
    tx_fifo_U1                               0x2400ad40   Data         268  usart.o(.RAM_D3)
空间位置应该是对的
回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
124425
QQ
发表于 2026-1-20 16:41:30 | 显示全部楼层
waz1992 发表于 2026-1-20 11:18
myUsbRxData                              0x2400a7c0   Data        1024  usbd_cdc_if.o(.RAM_D1)
     ...

最后一个地方看下,看下BDMA的NDTR寄存器动了没。

然后你这个函数DMA_Data_Acquisition_U1最好在回调函数里面处理,不要直接这样加入到中断,防止前面的代码已经把标志清除了
回复

使用道具 举报

0

主题

7

回帖

7

积分

新手上路

积分
7
发表于 2026-1-20 16:59:36 | 显示全部楼层
然后你这个函数DMA_Data_Acquisition_U1最好在回调函数里面处理,不要直接这样加入到中断,防止前面的代码已经把标志清除了

好的,谢谢
20fa2f10-69e5-4e4d-89b8-35c87c07008a.png
回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
124425
QQ
发表于 2026-1-20 19:47:04 | 显示全部楼层

这个完全没动,你的DMA完全没工作

你的RAM地址空间应该没有正确分配到SRAM4,这个BDMA仅支持SRAM4,你都分配到AXI SRAM 0x2400 0000地址了

1234.png



回复

使用道具 举报

0

主题

7

回帖

7

积分

新手上路

积分
7
发表于 2026-1-21 10:51:02 | 显示全部楼层
你的RAM地址空间应该没有正确分配到SRAM4,这个BDMA仅支持SRAM4,你都分配到AXI SRAM 0x2400 0000地址了

是的,问题基本解决了,谢谢
回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
124425
QQ
发表于 2026-1-22 00:57:49 | 显示全部楼层
waz1992 发表于 2026-1-21 10:51
是的,问题基本解决了,谢谢

我也是看到你17楼的回复地址,才反应过来这个问题。
回复

使用道具 举报

0

主题

7

回帖

7

积分

新手上路

积分
7
发表于 2026-1-22 11:54:38 | 显示全部楼层
eric2013 发表于 2026-1-22 00:57
我也是看到你17楼的回复地址,才反应过来这个问题。

之前几乎没有用到过地址分配,所以不知道自己是否分配成功,只看到后面变成D3,以为分配成功,谢谢帮忙解决问题,谢谢
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2026-10-24 08:43 , Processed in 0.471399 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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