STM32 H735 HAL库SPI4 DMA发送数据未更新问题求助
STM32H735 SPI4 DMA传输数据无法更新问题解决
问题核心原因
STM32H735搭载Cortex-M7内核,带有L1数据缓存(DCache)。你将DMA缓冲区放在D2区域RAM后,CPU修改数据时可能仅写入Cache而未同步到物理RAM,而DMA直接访问物理RAM,导致读取到旧数据。添加NOP延迟能偶然生效是因为Cache在这段时间内自动完成了同步,但这不是可靠的解决方案。
可靠解决方案
方案1:手动刷新数据缓存
在修改完DMA缓冲区数据后,主动将Cache中的数据同步到物理RAM,确保DMA能读取到最新值。代码示例:
// 修改DMA缓冲区数据 ToTheDac.Dac = 0x34; ToTheDac.Data[0] = (dac1 >> 8) & 0xff; ToTheDac.Data[1] = dac1 & 0xff; // 计算缓存对齐的起始地址和长度(H7的Cache行是32字节,需确保地址、长度对齐) uint32_t buf_addr = (uint32_t)&ToTheDac; uint32_t aligned_addr = buf_addr & ~(31UL); uint32_t aligned_size = ((buf_addr + sizeof(DACOUTPUT) - aligned_addr) + 31UL) & ~(31UL); // 清理数据缓存,将Cache内容同步到物理RAM SCB_CleanDCache_by_Addr((uint32_t*)aligned_addr, aligned_size); // 发起DMA传输 HAL_SPI_Transmit_DMA(&hspi4, (uint8_t*)&ToTheDac, sizeof(ToTheDac));
方案2:配置缓冲区所在内存为非缓存区
通过MPU(内存保护单元)将.spi_data所在的D2区域配置为Non-Cacheable,这样CPU读写直接操作物理RAM,无需手动刷新Cache。初始化时添加MPU配置代码:
void MPU_Config(void) { MPU_Region_InitTypeDef MPU_InitStruct = {0}; // 先禁用MPU HAL_MPU_Disable(); // 配置DMA缓冲区所在区域为非缓存 MPU_InitStruct.Enable = MPU_REGION_ENABLE; MPU_InitStruct.Number = MPU_REGION_NUMBER0; MPU_InitStruct.BaseAddress = (uint32_t)&ToTheDac; // 直接绑定缓冲区地址 MPU_InitStruct.Size = MPU_REGION_SIZE_32B; // 32字节足够覆盖你的结构体 MPU_InitStruct.SubRegionDisable = 0x00; MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0; MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS; MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_DISABLE; MPU_InitStruct.IsShareable = MPU_ACCESS_SHAREABLE; MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE; MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); // 重新启用MPU HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); }
在main()函数开头调用MPU_Config()即可,之后修改缓冲区数据无需额外刷新操作。
额外注意事项
- 确保每次发起DMA传输前,上一次传输已经完成,避免数据冲突:
if (HAL_SPI_STATE_READY == hspi4.State) { // 修改数据 + 刷新缓存(如果用方案1) // ... HAL_SPI_Transmit_DMA(&hspi4, (uint8_t*)&ToTheDac, sizeof(ToTheDac)); } - 链接脚本中
RAM_D2的定义要确保对应正确的D2区域RAM(如SRAM1/SRAM2),避免配置错误。
内容的提问来源于stack exchange,提问作者user2144480
相关产品推荐
相关产品推荐

