• 【STM32】DMA数据转运(存储器到外设)


    本篇博客重点在于标准库函数的理解与使用,搭建一个框架便于快速开发

    目录

    前言

    外设DMA请求使能

    DMA1

    DMA2 

    常用的外设DMA使能库函数 

    配置串口发送的DMA请求

    驱动代码

    MyDMA.h

    MyDMA.c

    main.c 


    前言

    【STM32】DMA数据转运(存储器到存储器)_stm32dma往ccr搬运-CSDN博客

    【STM32】ADC模拟数字转换(规则组多通道)+ DMA数据转运(外设到存储器)-CSDN博客

    本博客学习DMA将数据从存储器转运到外设的代码,其实就是外设到存储器反过来

    外设DMA请求使能

    DMA请求同时只能有一个请求有效 !!!

    DMA1

    DMA2 

    注意: DMA2控制器及相关请求仅存在于大容量产品和互联型产品中

    常用的外设DMA使能库函数 

    1. void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq,FunctionalState NewState);
    2. void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);
    3. void DAC_DMACmd(uint32_t DAC_Channel, FunctionalState NewState);
    4. void I2C_DMACmd(I2C_TypeDef* I2Cx, FunctionalState NewState);
    5. void SDIO_DMACmd(FunctionalState NewState);
    6. void SPI_I2S_DMACmd(SPI_TypeDef* SPIx, uint16_t SPI_I2S_DMAReq, FunctionalState NewState);
    7. void TIM_DMAConfig(TIM_TypeDef* TIMx, uint16_t TIM_DMABase, uint16_t TIM_DMABurstLength)
    8. void TIM_DMACmd(TIM_TypeDef* TIMx, uint16_t TIM_DMASource,FunctionalState NewState);

    配置串口发送的DMA请求

    DMA请求同时只能有一个请求有效 

    1. DMA_InitTypeDef DMA_InitStructure;
    2. DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;
    3. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//USART1->DR寄存器为8位
    4. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址指针不自增,固定为&USART1->DR
    5. DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;
    6. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    7. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器地址指针自增
    8. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设为转运的目的地
    9. DMA_InitStructure.DMA_BufferSize = Size;
    10. DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//单次转运
    11. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//失能,存储器到存储器才使能
    12. DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
    13. DMA_Init(DMA1_Channel4, &DMA_InitStructure);//USART1的Tx引脚位于DMA1的通道4

    串口利用DMA发送

    使用DMA进行发送,可以通过设置USART_CR3寄存器上的DMAT位激活。当TXE位被置为’1’ 时,DMA就从指定的SRAM区传送数据到USART_DR寄存器。为USART的发送分配一个DMA 通道的步骤如下(x表示通道号):

    1. 在DMA控制寄存器上将USART_DR寄存器地址配置成DMA传输的目的地址。在每个TXE 事件后,数据将被传送到这个地址。

    2. 在DMA控制寄存器上将存储器地址配置成DMA传输的源地址。在每个TXE事件后,将从 此存储器区读出数据并传送到USART_DR寄存器。

    3. 在DMA控制寄存器中配置要传输的总的字节数。

    4. 在DMA寄存器上配置通道优先级。

    5. 根据应用程序的要求,配置在传输完成一半还是全部完成时产生DMA中断。

    6. 在DMA寄存器上激活该通道。

    当传输完成DMA控制器指定的数据量时,DMA控制器在该DMA通道的中断向量上产生一中断。 在发送模式下,当DMA传输完所有要发送的数据时,DMA控制器设置DMA_ISR寄存器的TCIF 标志;监视USART_SR寄存器的TC标志可以确认USART通信是否结束,这样可以在关闭 USART或进入停机模式之前避免破坏最后一次传输的数据;软件需要先等待TXE=1,再等待 TC=1。

    USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);//使能USART1的Tx发送请求

    驱动代码

    配置串口发送的代码这里不再赘述,如有需要可以阅读下方博客。

    【STM32】USART通用同步/异步收发器(串口数据的接收与发送)_stm32 usart同步时钟-CSDN博客

    MyDMA.h

    1. #ifndef __MYDMA_H
    2. #define __MYDMA_H
    3. void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint16_t Size);
    4. void MyDMA_Transfer(void);
    5. #endif

    MyDMA.c

    1. #include "stm32f10x.h" // Device header
    2. #include "MyDMA.h"
    3. uint16_t MyDMA_Size;
    4. void MyDMA_Init(uint32_t AddrA, uint32_t AddrB, uint16_t Size)
    5. {
    6. MyDMA_Size = Size;
    7. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    8. DMA_InitTypeDef DMA_InitStructure;
    9. DMA_InitStructure.DMA_PeripheralBaseAddr = AddrA;
    10. DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//USART1->DR寄存器为8位
    11. DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址指针不自增,固定为&USART1->DR
    12. DMA_InitStructure.DMA_MemoryBaseAddr = AddrB;
    13. DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    14. DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器地址指针自增
    15. DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;//外设为转运的目的地
    16. DMA_InitStructure.DMA_BufferSize = Size;
    17. DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//单次转运
    18. DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;//失能,存储器到存储器才使能
    19. DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
    20. DMA_Init(DMA1_Channel4, &DMA_InitStructure);//USART1的Tx引脚位于DMA1的通道4
    21. DMA_Cmd(DMA1_Channel4, DISABLE);//先不开始转运
    22. }
    23. void MyDMA_Transfer(void)
    24. {
    25. USART_DMACmd(USART1, USART_DMAReq_Tx, DISABLE);
    26. DMA_Cmd(DMA1_Channel4, DISABLE);
    27. DMA_SetCurrDataCounter(DMA1_Channel4, MyDMA_Size);//设置数据转运的大小
    28. DMA_Cmd(DMA1_Channel4, ENABLE);
    29. USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);//使能USART1的Tx发送请求
    30. while (DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET);
    31. DMA_ClearFlag(DMA1_FLAG_TC4);
    32. }

    main.c 

    1. #include "stm32f10x.h" // Device header
    2. #include "Delay.h"
    3. #include "MyDMA.h"
    4. #include "Serial.h"
    5. #include "Key.h"
    6. uint8_t Buff_Send[200] = {0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D};
    7. uint16_t Conuter, Percent;
    8. uint8_t KeyNum;
    9. int main(void)
    10. {
    11. Serial_Init();
    12. Key_Init();
    13. MyDMA_Init((uint32_t)&USART1->DR, (uint32_t)Buff_Send, 200);
    14. while (1)
    15. {
    16. KeyNum = Key_GetNum();
    17. if(KeyNum)
    18. {
    19. printf("\r\nData:\r\n");
    20. MyDMA_Transfer();
    21. Conuter = DMA_GetCurrDataCounter(DMA1_Channel4);
    22. Percent = 100 - (float)Conuter * 100 / 200;
    23. printf("\r\nSend%d%%", Percent);//显示传输百分比
    24. if(Percent == 100)
    25. {
    26. printf("\r\n*************Send Finish!******************\r\n");
    27. }
    28. }
    29. }
    30. }
  • 相关阅读:
    在字节跳动,一个更好的企业级SparkSQL Server这么做
    分布式存储 vs. 全闪集中式存储:金融数据仓库场景下的性能对比
    我用python分析买房数据
    初学UE5,UE4的教程适用UE5吗?
    [Python进阶] Pyinstaller打包程序时为程序添加图标
    Spring Boot中 CommandLineRunner 与 ApplicationRunner作用、区别
    找到 K 个最接近的元素
    数据结构<7> 图
    校招秋招,性格和职业有关系吗?
    C#应用程序界面开发基础——窗体控制(1)——Form窗体(删除事件部分,没看懂)
  • 原文地址:https://blog.csdn.net/m0_75090944/article/details/142262049