STM32 | 基于 HAL 库实现 DMA 驱动 GPIO 高速翻转

项目中有一款点阵式液晶驱动芯片,需要用 IO 口翻转来实现高速串转并传输,主控芯片为 STM32F103RCT6。如果直接采用库函数进行IO的翻转不仅速度上满足不了要求,还会占用大量时间影响性能,导致时序上的错误。DMA可以在没有控制器的干预下进行数据的传输,因此决定采用DMA方式来驱动IO。本文以 HAL 库实现 DMA 驱动 GPIO 高速翻转为例说明DMA的配置过程,当然也可以改变 dma_buff 数组以实现其他任意时序的输出。

一、STM32CubeMX 配置

  1. SYS Mode and Configuration

羽墨志 | STM32 SYS 配置

  1. RCC Mode and Configuration

选择外部高速时钟。
羽墨志 | STM32 RCC 配置

  1. DMA Mode and Configuration

选择 DMA1Channel 1,传输方向选择 MEMTOMEM ,使能源地址增加,传输模式这里只能选择为 Normal,如果需要使用循环模式后续可在代码中修改。PB 口共有16个管脚,数据宽度选择 Word
羽墨志 | STM32 DMA 配置

  1. GPIO Mode and Configuration

PB0管脚配置为输出管脚,后续在代码中将整个 PB 口管脚配置为输出,以便通过示波器或者逻辑分析仪观察输出。
羽墨志 | STM32 GPIO 配置

  1. Clock Configuration

羽墨志 | STM32 时钟配置

二、代码修改

  1. 修改 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();
        }
    
    }
    
  2. 修改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);
    
    }
    
  3. 定义 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 */
    
  4. 启动 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 */
    

三、下载验证

羽墨志 | STM32 DMA GPIO
通过逻辑分析仪抓取的波形可以看出,IO 的翻转频率为3.57MHz,脉宽为140ns,实验数据与程序中的设置完全吻合。
【注】完整工程以及配置过程可在此处下载

  • 1
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论
要在 STM32F4 上使用 HAL 实现 SPI1 从机接收数据,您可以按照以下步骤进行操作: 1. 配置 SPI1 接口为从机模式: ```c hspi1.Instance = SPI1; hspi1.Init.Mode = SPI_MODE_SLAVE; hspi1.Init.Direction = SPI_DIRECTION_2LINES; hspi1.Init.DataSize = SPI_DATASIZE_8BIT; hspi1.Init.CLKPolarity = SPI_POLARITY_LOW; hspi1.Init.CLKPhase = SPI_PHASE_1EDGE; hspi1.Init.NSS = SPI_NSS_SOFT; hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi1.Init.TIMode = SPI_TIMODE_DISABLE; hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE; hspi1.Init.CRCPolynomial = 10; HAL_SPI_Init(&hspi1); ``` 2. 配置 DMA 接收通道: ```c hdma_spi_rx.Instance = DMAx_STREAMy; // 根据实际情况修改 DMA 实例和通道 hdma_spi_rx.Init.Channel = DMA_CHANNEL_x; // 根据实际情况修改 DMA 通道 hdma_spi_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_spi_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_spi_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_spi_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_spi_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_spi_rx.Init.Mode = DMA_NORMAL; hdma_spi_rx.Init.Priority = DMA_PRIORITY_LOW; HAL_DMA_Init(&hdma_spi_rx); __HAL_LINKDMA(&hspi1, hdmarx, hdma_spi_rx); ``` 3. 设置接收缓冲区并启动 DMA 接收: ```c uint8_t rxBuffer[BufferSize]; // 根据实际需求设置缓冲区大小 HAL_SPI_Receive_DMA(&hspi1, rxBuffer, BufferSize); ``` 4. 在 `DMAx_STREAMy_IRQHandler()` 中处理 DMA 接收完成中断: ```c void DMAx_STREAMy_IRQHandler(void) { HAL_DMA_IRQHandler(&hdma_spi_rx); } ``` 5. 在 `HAL_SPI_RxCpltCallback()` 回调函数中处理接收完成的数据: ```c void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) { // 处理接收完成的数据 // ... } ``` 通过以上步骤,您就可以使用 HAL STM32F4 上实现 SPI1 从机接收数据了。根据您的实际需求,您可能需要进行进一步的配置和处理。请根据 HAL 的文档和您的具体硬件需求进行相应的修改和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

羽墨志

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值