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 上生成位模式的主要内容,如果未能解决你的问题,请参考以下文章