STM32 使用 DMA 在 GPIO PIN 上生成位模式

Posted

技术标签:

【中文标题】STM32 使用 DMA 在 GPIO PIN 上生成位模式【英文标题】:STM32 Use DMA to generate bit pattern on GPIO PIN 【发布时间】:2021-09-29 05:25:30 【问题描述】:

我正在尝试在 GPIO 引脚上生成位模式。我已经设置了 DMA 引擎以从 GPIO 引脚状态数组传输到 GPIO BSRR 寄存器

这是我用来配置 DMA 的代码

hdma_tim16_ch1_up.Instance = DMA1_Channel3;
hdma_tim16_ch1_up.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_tim16_ch1_up.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tim16_ch1_up.Init.MemInc = DMA_MINC_ENABLE;
hdma_tim16_ch1_up.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
hdma_tim16_ch1_up.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
hdma_tim16_ch1_up.Init.Mode = DMA_NORMAL;
hdma_tim16_ch1_up.Init.Priority = DMA_PRIORITY_LOW;
if (HAL_DMA_Init(&hdma_tim16_ch1_up) != HAL_OK)

  Error_Handler();


/* Several peripheral DMA handle pointers point to the same DMA handle.
 Be aware that there is only one channel to perform all the requested DMAs. */
__HAL_LINKDMA(tim_baseHandle,hdma[TIM_DMA_ID_CC1],hdma_tim16_ch1_up);
__HAL_LINKDMA(tim_baseHandle,hdma[TIM_DMA_ID_UPDATE],hdma_tim16_ch1_up);

这是我用来设置传输的代码:

  uint32_t outputbuffer[] = 
  0x0000100,0x01000000,
  0x0000100,0x01000000,
  0x0000100,0x01000000,
  0x0000100,0x01000000,
  0x0000100,0x01000000,
  0x0000100,0x01000000,
  0x0000100,0x01000000
  /* ... */
  ;

  if (HAL_DMA_Start_IT(htim16.hdma[TIM_DMA_ID_UPDATE], (uint32_t)outputbuffer,  (uint32_t)&GPIOG->BSRR, 14) != HAL_OK)
  
    /* Return error status */
    return HAL_ERROR;
  
  __HAL_TIM_ENABLE_DMA(&htim16,TIM_DMA_UPDATE);
  HAL_TIM_Base_Start_IT(&htim16);

我希望看到每次计数器溢出时,DMA 从数组传输 32 位并递增到下一个数组位置,直到 DMA CNDTR 寄存器读取 0。

我设置了一个 GPIO 引脚以在每次定时器溢出时进行切换,并在数组中设置了一个交替位模式。我希望这两个 GPIO 引脚的输出形状相似,但我在连接到 DMA 的线路上得到一个更长的脉冲。任何提示将不胜感激

【问题讨论】:

【参考方案1】:

    将TIM2配置为输入捕捉直接模式(TIM2_CH1)

    配置TIM2 DMA方向“内存到外设”

    配置TIM2数据宽度半字/半字

    将 GPIO 引脚配置为 GPIO_OUTPUT,例如 16 个引脚 GPIOD0..GPIOD15

    从 HAL 库中复制并粘贴 HAL_TIM_IC_Start_DMA() 函数并为其命名 MY_TIM_IC_Start_DMA()

    在 MY_TIM_IC_Start_DMA() 中找到 HAL_DMA_Start_IT() 函数调用

    将 (uint32_t)&htim->Instance->CCR1 替换为 (uint32_t)&GPIOD->ODR

    如果 (HAL_DMA_Start_IT(htim->hdma[TIM_DMA_ID_CC1], (uint32_t)&GPIOD->ODR, (uint32_t)pData, Length) != HAL_OK)

现在您可以通过调用来启动 DMA 到 GPIO 的传输 MY_TIM_IC_Start_DMA(&htim2, TIM_CHANNEL_1,(uint32_t*)gpioBuffer,GPIO_BUFFER_SIZE); 实际传输必须通过在 TIM2_CH1 输入引脚上提供脉冲来触发(例如,通过使用来自其他定时器通道的输出比较引脚)。这些脉冲最初用于将 Timer2 CCR1 寄存器值保存到 DMA 缓冲区。调整了代码以将 DMA 缓冲区值传输到 GPIOD ODR 寄存器。

对于 GPIO 到内存的传输,将 TIM2 DMA 方向更改为“外设到内存”,将 GPIO 引脚配置为 GPIO_INPUT 并使用 GPIOD->IDR 代替修改后的 MY_TIM_IC_Start_DMA() 函数中的 HAL_DMA_Start_IT 参数中的 ODR

【讨论】:

以上是关于STM32 使用 DMA 在 GPIO PIN 上生成位模式的主要内容,如果未能解决你的问题,请参考以下文章

STM32:GPIO口的使用

STM32:GPIO口的使用

stm32读取gpio高低电平速度

STM32 MCU 上的 DMA 到 GPIO 的可靠性如何?

STM32F103(二十一)DMA(超详细的~)

stm32如何启动串口中断