stm32(3)DMA MtoM/MtoP

啊啊啊啊到了传输数据的环节了吼!
DMA我们理解浅显一点就是数据可以不经过CPU中断从一个地方传输到另一个地方(直接传输),这时候CPU可以干其他的事(比如点亮一个LED灯)。

1.理解概念
STM32F4xx 系列的DMA 支持外设到存储器传输、存储器到外设传输和存储器到存储器传输三种传输模式。这里的外设一般指外设的数据寄存器,比如ADC、SPI、I2C、DCMI 等等外设的数据寄存器,存储器一般是指片内SRAM、外部存储器、片内Flash 等等。
外设到存储器传输就是把外设数据寄存器内容转移到指定的内存空间。比如进行ADC采集时我们可以利用DMA 传输把AD 转换数据转移到我们定义的存储区中,这样对于多通道采集、采样频率高、连续输出数据的AD 采集是非常高效的处理方法。
存储区到外设传输就是把特定存储区内容转移至外设的数据寄存器中,这种多用于外设的发送通信。
存储器到存储器传输就是把一个指定的存储区内容拷贝到另一个存储区空间。功能类似于C 语言内存拷贝函数memcpy,利用DMA 传输可以达到更高的传输效率,特别是DMA 传输是不占用CPU 的,可以节省很多CPU 资源。
在这里插入图片描述DMA 控制器是采样AHB 主总线的,可以控制AHB 总线矩阵来启动AHB 事务。
在这里插入图片描述
上面的说法有一点不严谨,补充常识:
2^16-1 = 65535
①:1字节(byte) = 8位(bit)

②:在16位的系统中(比如8086微机) 1字 (word)= 2字节(byte)= 16(bit)

   在32位的系统中(比如win32) 1字(word)= 4字节(byte)=32(bit)

   在64位的系统中(比如win64)1字(word)= 8字节(byte)=64(bit)

   假设我是32位系统。一字 = 4B    则  65536*8/4/1024 = 128KB

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
每个外设请求都占用一个数据流通道,相同外设请求可以占用不同数据流通道。比如SPI3_RX 请求,即SPI3 数据发送请求,占用DMA1 的数据流0 的通道0,因此当我们使用该请求时,我们需要在把DMA_S0CR 寄存器的CHSEL[2:0]设置为“000”,此时相同数据流的其他通道不被选择,处于不可用状态,比如此时不能使用数据流0 的通道1 即I2C1_RX 请求等等。

可以多个数据流同时使用,但是一个数据流的通道被占用的时候这个数据流将不能再被使用。这时候要靠仲裁器分配优先级。
FIFO(first in first out)源和目标之间的一个数据中转站。

在这里插入图片描述
在这里插入图片描述FIFO模式常用于比如字节到字的转换(先存储够了再发)。4个字,16个字节。

在这里插入图片描述DMA1 的存储区端口相比DMA2 的要减少AHB2 外设的访问权,同时DMA1 外设端口是没有连接至总线矩阵的,只有连接到APB1 外设,所以DMA1 不能实现存储器到存储器传输。
DMA1: P ->M ,M->P(M:memery P:外设)
DMA2: P ->M ,M->P,M->M(M:memery P:外设)

在这里插入图片描述2.DMA初始化结构体

typedef struct
{
  uint32_t DMA_Channel;            /*!< Specifies the channel used for the specified stream. 
                                        This parameter can be a value of @ref DMA_channel */
 
  uint32_t DMA_PeripheralBaseAddr; /*!< 外设地址 P->M Specifies the peripheral base address for DMAy Streamx. */

  uint32_t DMA_Memory0BaseAddr;    /*!< 存储器0地址Specifies the memory 0 base address for DMAy Streamx. 
                                        This memory is the default memory used when double buffer mode is
                                        not enabled. */

  uint32_t DMA_DIR;                /*!<传输方向 Specifies if the data will be transferred from memory to peripheral, 
                                        from memory to memory or from peripheral to memory.
                                        This parameter can be a value of @ref DMA_data_transfer_direction */

  uint32_t DMA_BufferSize;         /*!< 数据数目Specifies the buffer size, in data unit, of the specified Stream. 
                                        The data unit is equal to the configuration set in DMA_PeripheralDataSize
                                        or DMA_MemoryDataSize members depending in the transfer direction. */

  uint32_t DMA_PeripheralInc;      /*!<外设递增 Specifies whether the Peripheral address register should be incremented or not.
                                        This parameter can be a value of @ref DMA_peripheral_incremented_mode */

  uint32_t DMA_MemoryInc;          /*!< Specifies whether the memory address register should be incremented or not.
                                        This parameter can be a value of @ref DMA_memory_incremented_mode */

  uint32_t DMA_PeripheralDataSize; /*!< Specifies the Peripheral data width.
                                        This parameter can be a value of @ref DMA_peripheral_data_size */

  uint32_t DMA_MemoryDataSize;     /*!< Specifies the Memory data width.
                                        This parameter can be a value of @ref DMA_memory_data_size */

  uint32_t DMA_Mode;               /*!< Specifies the operation mode of the DMAy Streamx.
                                        This parameter can be a value of @ref DMA_circular_normal_mode
                                        @note The circular buffer mode cannot be used if the memory-to-memory
                                              data transfer is configured on the selected Stream */

  uint32_t DMA_Priority;           /*!< Specifies the software priority for the DMAy Streamx.
                                        This parameter can be a value of @ref DMA_priority_level */

  uint32_t DMA_FIFOMode;          /*!< Specifies if the FIFO mode or Direct mode will be used for the specified Stream.
                                        This parameter can be a value of @ref DMA_fifo_direct_mode
                                        @note The Direct mode (FIFO mode disabled) cannot be used if the 
                                               memory-to-memory data transfer is configured on the selected Stream */

  uint32_t DMA_FIFOThreshold;      /*!< Specifies the FIFO threshold level.
                                        This parameter can be a value of @ref DMA_fifo_threshold_level */

  uint32_t DMA_MemoryBurst;        /*!< Specifies the Burst transfer configuration for the memory transfers. 
                                        It specifies the amount of data to be transferred in a single non interruptable 
                                        transaction. This parameter can be a value of @ref DMA_memory_burst 
                                        @note The burst mode is possible only if the address Increment mode is enabled. */

  uint32_t DMA_PeripheralBurst;    /*!< Specifies the Burst transfer configuration for the peripheral transfers. 
                                        It specifies the amount of data to be transferred in a single non interruptable 
                                        transaction. This parameter can be a value of @ref DMA_peripheral_burst
                                        @note The burst mode is possible only if the address Increment mode is enabled. */  
}DMA_InitTypeDef;
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200418171604493.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2F2YWxvdmVm,size_16,color_FFFFFF,t_70)

**DMA 运行高效,使用方便,在很多测试实验都会用到,这里先详解存储器到存储器和存储器到外设这两种模式,其他功能模式在其他章节会有很多使用到的情况,也会有相关的分析。存储器到存储器模式可以实现数据在两个内存的快速拷贝。我们先定义一个静态的源数据,然后使用DMA 传输把源数据拷贝到目标地址上,最后对比源数据和目标地址的数据,看看是否传输准确。**暂时用RGB指示程序状态,关于RGB彩色灯电路可以参考GPIO章节。
编程思路:
1) 使能DMA 数据流时钟并复位初始化DMA 数据流;
2) 配置DMA 数据流参数;
3) 使能DMA 数据流,进行传输;
4) 等待传输完成,并对源数据和目标地址数据进行比较。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200418201302144.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2F2YWxvdmVm,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200418201324848.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2F2YWxvdmVm,size_16,color_FFFFFF,t_70)

**2.MtoM一个存储区到另一个存储区**
1.配置代码
2.比较源数据和接收数据是否相同函数
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200418205905595.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2F2YWxvdmVm,size_16,color_FFFFFF,t_70)
主函数
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200418205958344.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2F2YWxvdmVm,size_16,color_FFFFFF,t_70)
用调试的方法验证DMA MtoM是可行的:
首先我先选择想看看的接收到的数据aDST_Buffer,以及我比较两个缓冲区数据是否相同的标志位TransferStatus;右键都添加到第一个wach窗口里。再单步调试,发现数据的确是设想的那样,证明中间没有出错。

![在这里插入图片描述](https://img-blog.csdnimg.cn/20200418203500916.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2F2YWxvdmVm,size_16,color_FFFFFF,t_70)
关于调试的一点补充:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200418204050260.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2F2YWxvdmVm,size_16,color_FFFFFF,t_70)
这里要重点区分一下单步调试和逐步调试:**单步调试(逐跳且到一个函数时会跳进去)逐步调试(逐跳且到一个函数时不会跳进去)**
而且在VIEW里面还可以看到外设相关的寄存器变量。
![在这里插入图片描述](https://img-blog.csdnimg.cn/2020041820491527.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2F2YWxvdmVm,size_16,color_FFFFFF,t_70)

**3.MtoP一个存储区到一个外设**
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200418214544981.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2F2YWxvdmVm,size_16,color_FFFFFF,t_70)
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值