你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

FW_H7 V1.12.1-HAL库DMA双缓冲配置

[复制链接]
talk is cheap 提问时间:2025-8-14 19:39 / 未解决
硬件平台:H750-ART-Pi
软件平台:CubeMX+HAL库 V1.12.1版本


问题背景:需要使用定时器触发DMA-SPI向外部DAC发送数据,由于需要向外部发送的数据量较大且配置SPI总线的多通道,当前需要使用DMA双缓冲配置(从SD卡中读取BIN文件依次填充PingPong-FIFO,使用外扩SDRAM作为DMA-BUF)
遇到的问题:当前已经能够使用单缓冲+定时器触发的方式来向外发送数据,使用双缓冲时,无反应(定时器在工作,当前网络上的一些例程都是基于标准库的,参考作用有限),想求助下HAL库DMA双缓冲案例或者函数调用顺序。
详情参考gitee链接:GIt-CubeMX配置
启动定时器部分代码:HAL_DMAEx_MultiBufferStart_IT这个函数应该是DMA双缓冲的关键 但是开启后无效,即使单缓冲正常工作下也无法看到SPI_TXDR更新,很奇怪
  1. void BSP_DAC_SPI_DMA_Start()
  2. {
  3.         LookUP_BUF_INIT();
  4. //        HAL_DMAEx_MultiBufferStart(&hspi2.hdmatx, LookUP_PingPongBufer.activeBuffer, &hspi2.Instance->TXDR,LookUP_PingPongBufer.readyBuffer,BUFFER_SIZE/4);
  5.         HAL_DMAEx_MultiBufferStart_IT(&hdma_spi2_tx, LookUP_PingPongBufer.activeBuffer, &hspi2.Instance->TXDR, LookUP_PingPongBufer.readyBuffer,BUFFER_SIZE/4);

  6. //        if(HAL_SPI_Transmit_DMA(&hspi2, (uint8_t*)LookUP_PingPongBufer.activeBuffer, BUFFER_SIZE/4)!= HAL_OK)       
  7. //        {
  8. //                printf("BSP_DAC_SPI_DMA_Start  HAL_SPI_Transmit_DMA ERROR !!! \r\n");                  
  9. //        }

  10.         if(HAL_TIM_OC_Start(&htim12, TIM_CHANNEL_1) != HAL_OK)
  11.         {
  12.                 printf("BSP_DAC_SPI_DMA_Start HAL_TIM_OC_Start ERROR !!! \r\n");                  
  13.         }       
  14. }
  15. void LookUP_BUF_INIT(void)
  16. {
  17.         FRESULT result;
  18.         uint32_t bw;
  19.         char path[64];
  20.        
  21.         PingPong_Init(&LookUP_PingPongBufer,LOOKUP_BUF1_ADDR,LOOKUP_BUF2_ADDR);
  22.        

  23.         result = f_mount(&fs, DiskPath, 0);                        /* Mount a logical drive */
  24.         if (result != FR_OK)
  25.         {
  26.                 printf("mount fs failed !!\r\n", FR_Table[result]);
  27.         }

  28.         sprintf(path, "%sTable_hex.bin", DiskPath);
  29.         result = f_open(&file, path, FA_OPEN_EXISTING | FA_READ);
  30.         if (result !=  FR_OK)
  31.         {
  32.                 printf("Don't Find File : Table_hex\r\n");
  33.                 return;
  34.         }

  35.         result = f_read(&file, LookUP_PingPongBufer.activeBuffer , BUFFER_SIZE, &bw);
  36.         if (bw > 0)
  37.         {
  38.                 FsReadBuf[bw] = 0;
  39.         }
  40.        
  41.         result = f_read(&file, LookUP_PingPongBufer.readyBuffer , BUFFER_SIZE, &bw);
  42.         if (bw > 0)
  43.         {
  44.                 FsReadBuf[bw] = 0;
  45.         }


  46. //        f_close(&file);

  47. //        f_mount(NULL, DiskPath, 0);
  48. }
复制代码
定时器初始化部分代码:
  1. void MX_SPI2_Init(void)
  2. {

  3.   /* USER CODE BEGIN SPI2_Init 0 */

  4.   /* USER CODE END SPI2_Init 0 */

  5.   /* USER CODE BEGIN SPI2_Init 1 */

  6.   /* USER CODE END SPI2_Init 1 */
  7.   hspi2.Instance = SPI2;
  8.   hspi2.Init.Mode = SPI_MODE_MASTER;
  9.   hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  10.   hspi2.Init.DataSize = SPI_DATASIZE_32BIT;
  11.   hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  12.   hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  13.   hspi2.Init.NSS = SPI_NSS_SOFT;
  14.   hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  15.   hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  16.   hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  17.   hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  18.   hspi2.Init.CRCPolynomial = 0x0;
  19.   hspi2.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
  20.   hspi2.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
  21.   hspi2.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
  22.   hspi2.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  23.   hspi2.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  24.   hspi2.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
  25.   hspi2.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
  26.   hspi2.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
  27.   hspi2.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
  28.   hspi2.Init.IOSwap = SPI_IO_SWAP_DISABLE;
  29.   if (HAL_SPI_Init(&hspi2) != HAL_OK)
  30.   {
  31.     Error_Handler();
  32.   }
  33.   /* USER CODE BEGIN SPI2_Init 2 */

  34.   /* USER CODE END SPI2_Init 2 */

  35. }

  36. void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
  37. {

  38.   GPIO_InitTypeDef GPIO_InitStruct = {0};
  39.   HAL_DMA_MuxSyncConfigTypeDef pSyncConfig= {0};
  40.   RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
  41.   if(spiHandle->Instance==SPI2)
  42.   {
  43.   /* USER CODE BEGIN SPI2_MspInit 0 */

  44.   /* USER CODE END SPI2_MspInit 0 */

  45.   /** Initializes the peripherals clock
  46.   */
  47.     PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI2;
  48.     PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_CLKP;
  49.     if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
  50.     {
  51.       Error_Handler();
  52.     }

  53.     /* SPI2 clock enable */
  54.     __HAL_RCC_SPI2_CLK_ENABLE();

  55.     __HAL_RCC_GPIOI_CLK_ENABLE();
  56.     /**SPI2 GPIO Configuration
  57.     PI1     ------> SPI2_SCK
  58.     PI2     ------> SPI2_MISO
  59.     PI3     ------> SPI2_MOSI
  60.     */
  61.     GPIO_InitStruct.Pin = GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
  62.     GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  63.     GPIO_InitStruct.Pull = GPIO_NOPULL;
  64.     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  65.     GPIO_InitStruct.Alternate = GPIO_AF5_SPI2;
  66.     HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);

  67.     /* SPI2 DMA Init */
  68.     /* SPI2_TX Init */
  69.     hdma_spi2_tx.Instance = DMA1_Stream0;
  70.     hdma_spi2_tx.Init.Request = DMA_REQUEST_SPI2_TX;
  71.     hdma_spi2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
  72.     hdma_spi2_tx.Init.PeriphInc = DMA_PINC_DISABLE;
  73.     hdma_spi2_tx.Init.MemInc = DMA_MINC_ENABLE;
  74.     hdma_spi2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
  75.     hdma_spi2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
  76.     hdma_spi2_tx.Init.Mode = DMA_CIRCULAR;
  77.     hdma_spi2_tx.Init.Priority = DMA_PRIORITY_LOW;
  78.     hdma_spi2_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
  79.     hdma_spi2_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
  80.     hdma_spi2_tx.Init.MemBurst = DMA_MBURST_SINGLE;
  81.     hdma_spi2_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
  82.     if (HAL_DMA_Init(&hdma_spi2_tx) != HAL_OK)
  83.     {
  84.       Error_Handler();
  85.     }

  86.     pSyncConfig.SyncSignalID = HAL_DMAMUX1_SYNC_TIM12_TRGO;
  87.     pSyncConfig.SyncPolarity = HAL_DMAMUX_SYNC_RISING;
  88.     pSyncConfig.SyncEnable = ENABLE;
  89.     pSyncConfig.EventEnable = ENABLE;
  90.     pSyncConfig.RequestNumber = 1;
  91.     if (HAL_DMAEx_ConfigMuxSync(&hdma_spi2_tx, &pSyncConfig) != HAL_OK)
  92.     {
  93.       Error_Handler();
  94.     }

  95.     __HAL_LINKDMA(spiHandle,hdmatx,hdma_spi2_tx);

  96.     /* SPI2 interrupt Init */
  97.     HAL_NVIC_SetPriority(SPI2_IRQn, 0, 0);
  98.     HAL_NVIC_EnableIRQ(SPI2_IRQn);
  99.   /* USER CODE BEGIN SPI2_MspInit 1 */

  100. //                HAL_DMAEx_MultiBufferStart_IT(&hdma_spi2_tx, (uint8_t*)LookUP_PingPongBufer.activeBuffer, (uint32_t)hspi2.Instance->TXDR, (uint8_t*)LookUP_PingPongBufer.readyBuffer,1000);
  101.                
  102.   /* USER CODE END SPI2_MspInit 1 */
  103.   }
  104. }
复制代码

SPI初始化部分代码:

  1. /* TIM12 init function */
  2. void MX_TIM12_Init(void)
  3. {

  4.   /* USER CODE BEGIN TIM12_Init 0 */

  5.   /* USER CODE END TIM12_Init 0 */

  6.   TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  7.   TIM_MasterConfigTypeDef sMasterConfig = {0};
  8.   TIM_OC_InitTypeDef sConfigOC = {0};

  9.   /* USER CODE BEGIN TIM12_Init 1 */

  10.   /* USER CODE END TIM12_Init 1 */
  11.   htim12.Instance = TIM12;
  12.   htim12.Init.Prescaler = 240-1;
  13.   htim12.Init.CounterMode = TIM_COUNTERMODE_UP;
  14.   htim12.Init.Period = 1000-1;
  15.   htim12.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  16.   htim12.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  17.   if (HAL_TIM_Base_Init(&htim12) != HAL_OK)
  18.   {
  19.     Error_Handler();
  20.   }
  21.   sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  22.   if (HAL_TIM_ConfigClockSource(&htim12, &sClockSourceConfig) != HAL_OK)
  23.   {
  24.     Error_Handler();
  25.   }
  26.   if (HAL_TIM_PWM_Init(&htim12) != HAL_OK)
  27.   {
  28.     Error_Handler();
  29.   }
  30.   sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC1REF;
  31.   sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  32.   if (HAL_TIMEx_MasterConfigSynchronization(&htim12, &sMasterConfig) != HAL_OK)
  33.   {
  34.     Error_Handler();
  35.   }
  36.   sConfigOC.OCMode = TIM_OCMODE_PWM1;
  37.   sConfigOC.Pulse = (1000)/2-1;
  38.   sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
  39.   sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  40.   if (HAL_TIM_PWM_ConfigChannel(&htim12, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  41.   {
  42.     Error_Handler();
  43.   }
  44.   /* USER CODE BEGIN TIM12_Init 2 */

  45.   /* USER CODE END TIM12_Init 2 */

  46. }

  47. void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
  48. {

  49.   if(tim_baseHandle->Instance==TIM12)
  50.   {
  51.   /* USER CODE BEGIN TIM12_MspInit 0 */

  52.   /* USER CODE END TIM12_MspInit 0 */
  53.     /* TIM12 clock enable */
  54.     __HAL_RCC_TIM12_CLK_ENABLE();

  55.     /* TIM12 interrupt Init */
  56.     HAL_NVIC_SetPriority(TIM8_BRK_TIM12_IRQn, 0, 0);
  57.     HAL_NVIC_EnableIRQ(TIM8_BRK_TIM12_IRQn);
  58.   /* USER CODE BEGIN TIM12_MspInit 1 */

  59.   /* USER CODE END TIM12_MspInit 1 */
  60.   }
  61. }
复制代码

图为使用逻辑分析仪抓取单缓冲数据时刻,SPI总线数据
image.png
收藏 评论2 发布时间:2025-8-14 19:39

举报

2个回答
xmshao 回答时间:5 天前
talk is cheap 回答时间:昨天 16:32

xmshao 发表于 2025-8-17 08:00
你可以参考下这篇文章。</p>
<p>[基于STM32H7 DMA 双缓冲实现SPI逐个数据输出](<a href="https://mp.weixin.qq.com/s/u">https://mp.weixin.qq.com/s/u</a> ...

[md]您好 我仔细看了下 微信公众号文章和参考手册 似乎没有区别 1.我测试了HAL_DMAEx_EnableMuxRequestGenerator(&hdma_dma_generator0);函数对当前双缓冲无法启动的问题也没有改善 2.为避免变量RAM所属区域的影响,我还变更了变量存储区域到SRAM4(D3区域),也是没有作用 我还是无法理解为什么我的代码在单缓冲的情况下是能正常工作,双缓冲下异常😕 双缓冲情况下我只修改这个函数

image.png

image.png

所属标签

相似问题

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版