用户工具

站点工具


icore3_arm_hal_14

差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

后一修订版
前一修订版
icore3_arm_hal_14 [2020/03/28 15:24]
zgf 创建
icore3_arm_hal_14 [2022/03/18 15:06] (当前版本)
sean
行 1: 行 1:
 +
 +|  **银杏科技有限公司旗下技术文档发布平台** ​ ||||
 +|技术支持电话|**0379-69926675-801**|||
 +|技术支持邮件|Gingko@vip.163.com|||
 +^  版本 ​ ^  日期 ​ ^  作者 ​ ^  修改内容 ​ ^
 +|  V1.0  |  2020-03-28 ​ |  gingko ​ |  初次建立 ​ | 
 +\\
 +\\
 ===== STM32CubeMX教程十四——DMA实验 ===== ===== STM32CubeMX教程十四——DMA实验 =====
  
 1. 在主界面选择File-->​New Project ​  ​或者直接点击ACCEE TO MCU SELECTOR  ​ 1. 在主界面选择File-->​New Project ​  ​或者直接点击ACCEE TO MCU SELECTOR  ​
- +{{ :​icore3:​icore3_cube_14_1.png?​direct |}}
 2. 出现芯片型号选择,搜索芯片的型号,双击型号,或者点击Start Project进入配置 2. 出现芯片型号选择,搜索芯片的型号,双击型号,或者点击Start Project进入配置
 在搜索栏的下面,提供的各种查找方式,可以选择芯片内核、型号等,可以帮助用户查找芯片。本实验选取的芯片型号为:STM32F407IGTx。 在搜索栏的下面,提供的各种查找方式,可以选择芯片内核、型号等,可以帮助用户查找芯片。本实验选取的芯片型号为:STM32F407IGTx。
- +{{ :​icore3:​icore3_cube_14_2.png?​direct |}}
 3. 配置RCC,使用外部时钟源 3. 配置RCC,使用外部时钟源
- +{{ :​icore3:​icore3_cube_14_3.png?​direct |}}
 4. 配置调试引脚 4. 配置调试引脚
- +{{ :​icore3:​icore3_cube_14_4.png?​direct |}}
 5. 将LED对应的3个引脚(PI5,PI6,PI7)设置为GPIO_Output 5. 将LED对应的3个引脚(PI5,PI6,PI7)设置为GPIO_Output
- +{{ :​icore3:​icore3_cube_14_5.png?​direct |}}
 6. 引脚模式配置 6. 引脚模式配置
- +{{ :​icore3:​icore3_cube_14_6.png?​direct |}}
 7. 配置DMA 7. 配置DMA
- +{{ :​icore3:​icore3_cube_14_7.png?​direct |}}
- +
 8. 时钟源设置,选择外部高速时钟源,配置为最大主频 8. 时钟源设置,选择外部高速时钟源,配置为最大主频
- +{{ :​icore3:​icore3_cube_14_8.png?​direct |}}
 9.  工程文件的设置,​ 这里就是工程的各种配置,​我们只用到有限几个,其他的默认即可 ​ IDE我们使用的是 MDK5 9.  工程文件的设置,​ 这里就是工程的各种配置,​我们只用到有限几个,其他的默认即可 ​ IDE我们使用的是 MDK5
- +{{ :​icore3:​icore3_cube_14_9.png?​direct |}}
- +
 10. 点击Code Generator,进行进一步配置 10. 点击Code Generator,进行进一步配置
- +{{ :​icore3:​icore3_cube_14_10.png?​direct |}}
   * **Copy all used libraries into the project folder**   * **Copy all used libraries into the project folder**
   * 将HAL库的所有.C和.H都复制到所建工程中   * 将HAL库的所有.C和.H都复制到所建工程中
行 38: 行 44:
   * 自行选择方式即可   * 自行选择方式即可
 11. 然后点击GENERATE CODE  创建工程 11. 然后点击GENERATE CODE  创建工程
- +{{ :​icore3:​icore3_cube_14_11.png?​direct |}}
 创建成功,打开工程。 创建成功,打开工程。
 \\ \\
行 55: 行 61:
 ==== 二、 实验设备及平台 ==== ==== 二、 实验设备及平台 ====
  
-  - iCore3 双核心板。 +  - iCore3 双核心板。[[https://​item.taobao.com/​item.htm?​id=524229438677|点击购买]] 
-  - JLINK(或相同功能)仿真器。+  - JLINK(或相同功能)仿真器。[[https://​item.taobao.com/​item.htm?​id=554869837940|点击购买]]
   - Micro USB线缆。   - Micro USB线缆。
   - Keil MDK 开发平台。   - Keil MDK 开发平台。
行 62: 行 68:
   - 装有WIN XP(及更高版本)系统的计算机。   - 装有WIN XP(及更高版本)系统的计算机。
 ==== 三、 实验原理 ==== ==== 三、 实验原理 ====
-DMA简介 +  * **DMA简介** 
-DMA,全称为"​Direct Memory Access"​,即直接存储器访问,是一种不经过CPU而直接从内存存取数据的数据交换模式。在DMA模式下,CPU只须向DMA控制器下达指令,让DMA控制器来处理数据的传送,数据传送完毕再把信息反馈给CPU,这样在很大程度上减轻了CPU资源占有率,可以极大地节省系统资源。DMA模式又可以分为Single-Word DMA(单字节DMA)和Multi-Word DMA(多字节DMA)两种。 +  ​* ​DMA,全称为"​Direct Memory Access"​,即直接存储器访问,是一种不经过CPU而直接从内存存取数据的数据交换模式。在DMA模式下,CPU只须向DMA控制器下达指令,让DMA控制器来处理数据的传送,数据传送完毕再把信息反馈给CPU,这样在很大程度上减轻了CPU资源占有率,可以极大地节省系统资源。DMA模式又可以分为Single-Word DMA(单字节DMA)和Multi-Word DMA(多字节DMA)两种。 
-DMA工作原理 +  * **DMA工作原理** 
-DMA 允许不同速度的硬件装置来沟通,而不需要依于 CPU 的大量中断负载。否则,CPU 需要从来源把每一片段的资料复制到暂存器,然后把他们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。 +    ​* ​DMA 允许不同速度的硬件装置来沟通,而不需要依于 CPU 的大量中断负载。否则,CPU 需要从来源把每一片段的资料复制到暂存器,然后把他们再次写回到新的地方。在这个时间中,CPU 对于其他的工作来说就无法使用。 
-DMA 传输主要地将一个内存区从一个装置复制到另外一个。当 CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存去。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。所以,DMA传输对于高效能嵌入式系统算法和网络是很重要的。 +    ​* ​DMA 传输主要地将一个内存区从一个装置复制到另外一个。当 CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存去。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。所以,DMA传输对于高效能嵌入式系统算法和网络是很重要的。 
-DMA类别 +  * **DMA类别** 
-按键主要有两种类型:单字节DMA、多字节DMA。 +  ​* ​按键主要有两种类型:单字节DMA、多字节DMA。 
-单字节DMA:一次传送一个字节,效率较低,但它会保证在两次DMA传送之间,CPU有机会获得总线控制权,执行一次CPU总线周期。 +    ​* ​单字节DMA:一次传送一个字节,效率较低,但它会保证在两次DMA传送之间,CPU有机会获得总线控制权,执行一次CPU总线周期。 
-多字节DMA:一次请求传送一个数据块,效率高,但在整个DMA传送期间,CPU长时间无法控制总线(无法响应其他DMA请求,无法处理其他中断等) +    ​* ​多字节DMA:一次请求传送一个数据块,效率高,但在整个DMA传送期间,CPU长时间无法控制总线(无法响应其他DMA请求,无法处理其他中断等) 
-本实验采用DMA2控制器的数据流0,选用通道0进行数据传输。通过LED的颜色来判断传输是否成功。+  ​* ​本实验采用DMA2控制器的数据流0,选用通道0进行数据传输。通过LED的颜色来判断传输是否成功。
 ==== 四、 实验程序 ==== ==== 四、 实验程序 ====
- 
 === 1. 主函数 === === 1. 主函数 ===
 +  * 初始化之后,使用HAL_DMA_Start函数开启DMA;通过HAL_DMA_GET_FLAG函数判断DMA传输是否完成,待DMA传输完成后,判断DMA传输目标数据与DMA传输源数据是否一致,即dst_buffer数组中的内容与src_buffer数组中的内容是否相等。若不相等,则测试失败,红色LED闪烁;若相等,则测试成功,蓝色LED闪烁。
 +<code c>
 +int main(void)
 +{
 +    HAL_Init();
 +    SystemClock_Config();​
 +    MX_GPIO_Init();​ //​GPIO初始化
 +    MX_DMA_Init();​ //​DMA初始化
 +    dma2.initialize();​
  
-初始化之后,使用HAL_DMA_Start函数开启DMA;通过HAL_DMA_GET_FLAG函数判断DMA传输是否完成,待DMA传输完成后,判断DMA传输目标数据与DMA传输源数据是否一致,即dst_buffer数组中的内容与src_buffer数组中的内容是否相等。若不相等,则测试失败,红色LED闪烁;若相等,则测试成功,蓝色LED闪烁。 +    ​HAL_DMA_Start(&​hdma_memtomem_dma2_stream0,​(unsigned long int)src_buffer,​(unsigned long int)dst_buffer,​(unsigned 
-  +     long int)BUFFER_SIZE);​ 
-DMA外设基地址:在此定义src_buffer数组作为DMA传输数据源,const 关键字将src_buffer数组变量定义为常量类型,表示数据存储在内部FLASH中。 +    //等待DMA传输完成 
-DMA存储器地址:在此定义dst_buffer数组作为DMA传输目标存储器,​存储在内部SDAM中。 +    while(__HAL_DMA_GET_FLAG(&​hdma_memtomem_dma2_stream0,​DMA_FLAG_TCIF0_4) == SET); 
- + 
 +    for(i = 0;i < BUFFER_SIZE;​i++){ 
 + if(dst_buffer[i] != src_buffer[i]){ 
 + while(1){ //测试失败 
 + HAL_Delay(500);​ 
 + LED_RED_ON;​ 
 + HAL_Delay(500);​ 
 + LED_RED_OFF;​ 
 +         } 
 +         } 
 +        } 
 +    while (1) //测试成功 
 +    { 
 +        HAL_Delay(500);​ 
 + LED_BLUE_ON;​ 
 + HAL_Delay(500);​ 
 + LED_BLUE_OFF;​ 
 +    } 
 +
 + 
 +</​code>​ 
 +  ​* ​DMA外设基地址:在此定义src_buffer数组作为DMA传输数据源,const 关键字将src_buffer数组变量定义为常量类型,表示数据存储在内部FLASH中。 
 +  ​* ​DMA存储器地址:在此定义dst_buffer数组作为DMA传输目标存储器,​存储在内部SDAM中。 
 +<code c> 
 +//​DMA外设基地址 
 +//​定义src_buffer数组作为DMA传输数据源 
 +//const 关键字将src_buffer数组变量定义为常量类型,表示数据存储在内部FLASH中 
 +const unsigned long int src_buffer[BUFFER_SIZE] =   
 +        0x01020304,​0x05060708,​0x090A0B0C,​0x0D0E0F10,​  
 +        0x11121314,​0x15161718,​0x191A1B1C,​0x1D1E1F20,​  
 +        0x21222324,​0x25262728,​0x292A2B2C,​0x2D2E2F30,​ 
 + ​ 0x31323334,​0x35363738,​0x393A3B3C,​0x3D3E3F40,​ 
 +  0x41424344,​0x45464748,​0x494A4B4C,​0x4D4E4F50,​ 
 +  0x51525354,​0x55565758,​0x595A5B5C,​0x5D5E5F60,​ 
 +   ​ 0x61626364,​0x65666768,​0x696A6B6C,​0x6D6E6F70,​ 
 +   ​ 0x71727374,​0x75767778,​0x797A7B7C,​0x7D7E7F80};​ 
 +//​DMA存储器地址 
 +//​定义dst_buffer数组作为DMA传输目标存储器,​存储在内部SDAM中  
 +unsigned long int dst_buffer[BUFFER_SIZE] = {0}; 
 +</​code>​
 === 2. DMA相关结构体定义 === === 2. DMA相关结构体定义 ===
 +<code c>
 +    DMA_HandleTypeDef hdma_memtomem_dma2_stream0;​
 +</​code>​
 +  * DMA的名称定义,这个结构体中存放了DMA所有用到的功能,后面的别名hdma_memtomem_dma2_stream0就是我们所用的DMA的别名,在此采用DMA2控制器的数据流0,选用通道0进行数据传输。
 +<code c>
 +typedef struct __DMA_HandleTypeDef ​
 +{  ​
 +  DMA_Stream_TypeDef ​       *Instance;
 +  //​DMA寄存器基地址  ​
 +  DMA_InitTypeDef ​           Init; //​DMA通信参数
 +  HAL_LockTypeDef ​           Lock; //​DMA锁定参数 ​   ​
 +  __IO HAL_DMA_StateTypeDef ​ State; ​         ​
 +  void        *Parent; ​                                                   ​
 +  void        (* XferCpltCallback)( struct __DMA_HandleTypeDef * hdma); ​       ​
 +  void    (* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma); ​   ​
 +  void    (* XferM1CpltCallback)( struct __DMA_HandleTypeDef * hdma); ​      
 +  void  (* XferM1HalfCpltCallback)( struct __DMA_HandleTypeDef * hdma); ​  
 +  void      (* XferErrorCallback)( struct __DMA_HandleTypeDef * hdma); ​      
 +  void      (* XferAbortCallback)( struct __DMA_HandleTypeDef * hdma); ​     ​
 +  __IO uint32_t ​   ErrorCode; ​                                                    
 +  uint32_t ​                  ​ StreamBaseAddress; ​                                               ​
 +  uint32_t ​                  ​ StreamIndex; ​                                                     ​
 +}DMA_HandleTypeDef;​
 +
 +</​code>​
 +  * 上述DMA_HandleTypeDef包含了指向寄存器的指针、互斥锁、一个描述状态的变量、一个保存错误代码的变量、指向DMA结构体的指针等。所有对DMA进行操作的函数都使用这个结构体的指针作为参数。
 +<code c>
 +typedef struct
 +{
 +    uint32_t DMA_Channel; ​                  //​选择通道
 +    uint32_t DMA_PeripheralBaseAddr; ​    //​DMA外设基地址
 +    uint32_t DMA_Memory0BaseAddr; ​        //​DMA存储器地址 ​                    
 +    uint32_t DMA_DIR; ​                      //​DMA传输方向
 +    uint32_t DMA_BufferSize; ​              //​数据传输量
 +    uint32_t DMA_PeripheralInc; ​          //​外设增量模式选择
 +    uint32_t DMA_MemoryInc; ​               //​存储器增量模式
 +    uint32_t DMA_PeripheralDataSize; ​    //​设置外设数据宽度
 +    uint32_t DMA_MemoryDataSize; ​         //​设置存储器数据宽度
 +    uint32_t DMA_Mode; ​                     //​运行模式选择
 +    uint32_t DMA_Priority; ​                //​优先级选择
 +    uint32_t DMA_FIFOMode; ​                //​FIFO模式选择
 +    uint32_t DMA_FIFOThreshold; ​          //​FIFO阀值
 +    uint32_t DMA_MemoryBurst; ​            //​存储器突发传输
 +    uint32_t DMA_PeripheralBurst; ​       //​外设突发传输 ​                       ​
 +}DMA_InitTypeDef;​
  
-  +</​code>​ 
-DMA的名称定义,这个结构体中存放了DMA所有用到的功能,后面的别名 +  DMA_Channel: DMA 请求通道选择,可选通道 0 至通道 7,每个外设对应固定的通道。 
-hdma_memtomem_dma2_stream0就是我们所用的DMA的别名,在此采用DMA2控制器的数据流0,选用通道0进行数据传输。 +  ​* ​DMA_PeripheralBaseAddr:外设地址,一般设置为外设的数据寄存器地址,如果是存储器到存储器模式,则设置为其中一个存储区地址。 
-上述DMA_HandleTypeDef包含了指向寄存器的指针、互斥锁、一个描述状态的变量、一个保存错误代码的变量、指向DMA结构体的指针等。所有对DMA进行操作的函数都使用这个结构体的指针作为参数。 +  ​* ​DMA_DIR:传输方向选择,可选外设到存储器、存储器到外设以及存储器到存储器。 
-  +  ​* ​DMA_PeripheralInc:如果配置为 DMA_PeripheralInc_Enable,使能外设地址自动递增功能。 
-DMA_Channel: DMA 请求通道选择,可选通道 0 至通道 7,每个外设对应固定的通道。 +  ​* ​DMA_MemoryInc:如果配置为 DMA_MemoryInc_Enable,使能存储器地址自动递增功能。 
-DMA_PeripheralBaseAddr:外设地址,一般设置为外设的数据寄存器地址,如果是存储器到存储器模式,则设置为其中一个存储区地址。 +  ​* ​DMA_PeripheralDataSize:外设数据宽度,可选字节(8 位)、半字(16 位)和字(32位)。 
-DMA_DIR:传输方向选择,可选外设到存储器、存储器到外设以及存储器到存储器。 +  ​* ​DMA_MemoryDataSize:存储器数据宽度,可选字节(8 位)、半字(16 位)和字(32位)。 
-DMA_PeripheralInc:如果配置为 DMA_PeripheralInc_Enable,使能外设地址自动递增功能。 +  ​* ​DMA_Priority:软件设置数据流的优先级,有 4 个可选优先级分别为非常高、高、中和低。 
-DMA_MemoryInc:如果配置为 DMA_MemoryInc_Enable,使能存储器地址自动递增功能。 +  ​* ​DMA_MemoryBurst:存储器突发模式选择,可选单次模式、 4 节拍的增量突发模式、 8 节拍的增量突发模式或 16 节拍的增量突发模式。 
-DMA_PeripheralDataSize:外设数据宽度,可选字节(8 位)、半字(16 位)和字(32位)。 +  ​* ​DMA_PeripheralBurst:外设突发模式选择,可选单次模式、 4 节拍的增量突发模式、 8 节拍的增量突发模式或 16 节拍的增量突发模式。
-DMA_MemoryDataSize:存储器数据宽度,可选字节(8 位)、半字(16 位)和字(32位)。 +
-DMA_Priority:软件设置数据流的优先级,有 4 个可选优先级分别为非常高、高、中和低。 +
-DMA_MemoryBurst:存储器突发模式选择,可选单次模式、 4 节拍的增量突发模式、 8 节拍的增量突发模式或 16 节拍的增量突发模式。 +
-DMA_PeripheralBurst:外设突发模式选择,可选单次模式、 4 节拍的增量突发模式、 8 节拍的增量突发模式或 16 节拍的增量突发模式。+
 === 3. DMA相关函数 === === 3. DMA相关函数 ===
 +  * HAL_DMA_Start();​开启DMA传输。
 +  * _HAL_DMA_GET_FLAG();​获取DMA传输标志位
 +  * _HAL_DMA_CLEAR_FLAG();​清除DMA传输完成标志
 +  * _HAL_DMA_GET_COUNTER();​得到当前还剩余多少数据
 +  * DMA开始传输
 +<code c>
 +HAL_StatusTypeDef HAL_DMA_Start(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress, uint32_t DataLength)
 +</​code>​
 +  * 参数:
 +    * DMA_HandleTypeDef *hdma为DMA的别名,​在本实验中即指DMA2的通道0
 +    * uint32_t SrcAddress DMA外设基地址
 +    * uint32_t DstAddress ​ DMA存储器地址
 +    * uint32_t DataLength 发送的数据长度
 +  * DMA获取传输标志位
  
-HAL_DMA_Start();​开启DMA传输 +<code c> 
-__HAL_DMA_GET_FLAG();​获取DMA传输标志位 +__HAL_DMA_GET_FLAG(&​hdma_memtomem_dma2_stream0,​DMA_FLAG_TCIF0_4
-__HAL_DMA_CLEAR_FLAG();​清除DMA传输完成标志 +</​code>​ 
-__HAL_DMA_GET_COUNTER();​得到当前还剩余多少数据 +  ​* ​参数: 
-DMA开始传输 +    * &​hdma_memtomem_dma2_stream0在本实验中为 DMA2的通道0 
-  +    ​* ​DMA_FLAG_TCIF0_4  ​ 对应的寄存器地址
-参数: +
-DMA_HandleTypeDef ​*hdma为DMA的别名,​在本实验中即指DMA2的通道0 +
-uint32_t SrcAddress DMA外设基地址 +
-uint32_t DstAddress ​ DMA存储器地址 +
-uint32_t DataLength 发送的数据长度 +
-DMA获取传输标志位 +
-  +
-参数: +
-&​hdma_memtomem_dma2_stream0在本实验中为 DMA2的通道0 +
-DMA_FLAG_TCIF0_4  ​ 对应的寄存器地址+
 ==== 五、 实验步骤 ==== ==== 五、 实验步骤 ====
  
icore3_arm_hal_14.1585380265.txt.gz · 最后更改: 2020/03/28 15:24 由 zgf