赞
踩
第一次发现问题
环境:STM32H723ZGT6 UART1 PA9/PA10 空闲中断+DMA接收数据
现象:代码打印串口接收数据,串口助手每隔100ms发一次数据,,,打印结果是偶尔接收数据正确,大部分是接收到的全为0
原因:排查下来是M7核开启D-Cache缓存导致的
解决办法:
由于要用到以太网和LWIP,必须要开启缓存,按照网上的方法在MPU配置那里关掉缓存、Buff和共享也不行,
所以采用的是每次调用内核函数,清空缓存。
void UartRxIdleCallback(void) { uint16_t unLen; if((__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET)) { __HAL_UART_CLEAR_IDLEFLAG(&huart1); unLen = UART_BUF_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx) - u16UARTDMAOffset; SCB_InvalidateDCache_by_Addr(u8UARTBuff, UART_BUF_SIZE); SCB_CleanDCache(); if(unLen && unLen <= UART_BUF_SIZE) UartDataRxCallBack(&u8UARTBuff[u16UARTDMAOffset], unLen); u16UARTDMAOffset += unLen; } }
记录一下,结束。
第二次发现问题,
代码使用了FDCAN通讯,在使用中发现每次串口收到数据之后,fdcan1的一个变量值变成0了。
导致在进入CAN中断时,HAL库代码读取到了错误状态,一直进HAL_FDCAN_ErrorCallback。
一开始还怀疑是FDCAN的设置有问题,查了一圈寄存器,最后发现是hfcan1这个句柄的ttcan结构体指针的值变成0了。
指针变成0,相关的状态码和寄存器也就读成乱码了。
如下图串口收到数据时,SCB_InvalidateDCache_by_Addr 无效化缓存,直接读取数据到buff中。
最开始的时候,只是为了解决问题,以为调用了SCB_InvalidateDCache_by_Addr就万事大吉了,
后来debug走到函数里面发现,传参输入的 addr 地址 和 size 大小 都必须要是32的整数倍。
而我的buff,就是普普通通的全局变量定义,如图中编译器分配的地址是0x24000218,不是32的整数倍。
恰好,hfdcan1的地址就紧挨着这个buff,那么当我调用 SCB_InvalidateDCache_by_Addr 无效化缓存时,影响到了 hfdcan1->ttcan 的值,导致最终出现问题。
/** \brief D-Cache Invalidate by address \details Invalidates D-Cache for the given address. D-Cache is invalidated starting from a 32 byte aligned address in 32 byte granularity. D-Cache memory blocks which are part of given address + given size are invalidated. \param[in] addr address \param[in] dsize size of memory block (in number of bytes) */ __STATIC_FORCEINLINE void SCB_InvalidateDCache_by_Addr (void *addr, int32_t dsize) { #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) if ( dsize > 0 ) { int32_t op_size = dsize + (((uint32_t)addr) & (__SCB_DCACHE_LINE_SIZE - 1U)); uint32_t op_addr = (uint32_t)addr /* & ~(__SCB_DCACHE_LINE_SIZE - 1U) */; __DSB(); do { SCB->DCIMVAC = op_addr; /* register accepts only 32byte aligned values, only bits 31..5 are valid */ op_addr += __SCB_DCACHE_LINE_SIZE; op_size -= __SCB_DCACHE_LINE_SIZE; } while ( op_size > 0 ); __DSB(); __ISB(); } #endif }
最终在buff定义是,给它指定地址为32的整数倍,解决了。
attribute((at(0x24000220))) uint8_t u8UARTBuff[UART_BUF_SIZE];
volatile uint16_t u16UARTDMAOffset = 0;
总结下来就是,
一是要利用好缓存无效化函数,注意内存对齐问题
二是H7内核中,关于DMA的使用,要注意缓存刷新的问题
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。