项目中有一款点阵式液晶驱动芯片,需要用 IO 口翻转来实现高速串转并传输,主控芯片为 STM32F103RCT6。如果直接采用库函数进行IO的翻转不仅速度上满足不了要求,还会占用大量时间影响性能,导致时序上的错误。DMA可以在没有控制器的干预下进行数据的传输,因此决定采用DMA方式来驱动IO。本文以 HAL 库实现 DMA 驱动 GPIO 高速翻转为例说明DMA的配置过程,当然也可以改变 dma_buff
数组以实现其他任意时序的输出。
一、STM32CubeMX 配置
选择外部高速时钟。
选择 DMA1
的 Channel 1
,传输方向选择 MEMTOMEM
,使能源地址增加,传输模式这里只能选择为 Normal
,如果需要使用循环模式后续可在代码中修改。PB
口共有16个管脚,数据宽度选择 Word
。
将PB0
管脚配置为输出管脚,后续在代码中将整个 PB
口管脚配置为输出,以便通过示波器或者逻辑分析仪观察输出。
二、代码修改
-
修改 DMA 配置
STM32CubeMX 中
DMA
只能选择Normal
模式,在void MX_DMA_Init(void)
函数中将DMA模式由DMA_NORMAL
更改为DMA_CIRCULAR
模式:/** * Enable DMA controller clock * Configure DMA for memory to memory transfers * hdma_memtomem_dma1_channel1 */ void MX_DMA_Init(void) { /* DMA controller clock enable */ __HAL_RCC_DMA1_CLK_ENABLE(); /* Configure DMA request hdma_memtomem_dma1_channel1 on DMA1_Channel1 */ hdma_memtomem_dma1_channel1.Instance = DMA1_Channel1; hdma_memtomem_dma1_channel1.Init.Direction = DMA_MEMORY_TO_MEMORY; hdma_memtomem_dma1_channel1.Init.PeriphInc = DMA_PINC_ENABLE; hdma_memtomem_dma1_channel1.Init.MemInc = DMA_MINC_DISABLE; hdma_memtomem_dma1_channel1.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; hdma_memtomem_dma1_channel1.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; hdma_memtomem_dma1_channel1.Init.Mode = DMA_CIRCULAR; hdma_memtomem_dma1_channel1.Init.Priority = DMA_PRIORITY_LOW; if(HAL_DMA_Init(&hdma_memtomem_dma1_channel1) != HAL_OK) { Error_Handler(); } }
-
修改GPIO定义
在 STM32CubeMX 中仅设置了 PB0 管脚,在 void MX_GPIO_Init(void) 中将 PB 口的十六个管脚都设置为输出,将原有的
LED_Pin
修改为GPIO_PIN_All
即可。/** Configure pins as * Analog * Input * Output * EVENT_OUT * EXTI */ void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(LED_GPIO_Port, GPIO_PIN_All, GPIO_PIN_RESET); /*Configure GPIO pin : PtPin */ GPIO_InitStruct.Pin = GPIO_PIN_All; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(LED_GPIO_Port, &GPIO_InitStruct); }
-
定义 DMA 缓冲区
/* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ uint16_t dma_buff[8] = {0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA, 0x5555, 0xAAAA}; /* USER CODE END 0 */
-
启动 DMA 传输
/* USER CODE BEGIN 2 */ HAL_DMA_Start(&hdma_memtomem_dma1_channel1, (uint32_t)(dma_buff), (uint32_t)(&GPIOB->ODR), sizeof(dma_buff)/sizeof(dma_buff[0])); /* USER CODE END 2 */
三、下载验证
通过逻辑分析仪抓取的波形可以看出,IO 的翻转频率为3.57MHz,脉宽为140ns,实验数据与程序中的设置完全吻合。
【注】完整工程以及配置过程可在此处下载。