历史上的今天
返回首页

历史上的今天

今天是:2024年08月29日(星期四)

正在发生

2019年08月29日 | STM32F429 >> 10. DMA_直接存储器访问

2019-08-29 来源:eefocus

本工程板级支持包文件适用于野火stm32f429 开发板。


DMA 传输实现高速数据移动过程无需任何CPU 操作控制


其支持以下三种传输方式:


外设到存储器传输;

存储器到外设传输;

存储器到存储器传输。

功能框图:


在这里插入图片描述

① 外设通道选择

外设通道选择所解决的问题是决定哪一个外设作为数据传输的源地址或目标地址。


DMA1 请求映射:

在这里插入图片描述
在这里插入图片描述

DMA2 请求映射:

在这里插入图片描述


每个外设请求都占用一个数据流通道,相同外设请求可以占用不同数据流通道。


② 仲裁器

仲裁器管理数据流方法分为两个阶段。


第一阶段属于软件阶段,我们在配置数据流时可以通过寄存器设定其优先级别,具体配置DMA_SxCR 寄存器PL[1:0] 位,可以设置为非常高、高、中和低四个级别;

第二阶段属于硬件阶段,若两个或两个以上数据流软件设置优先级一样,则他们优先取决于数据流编号,编号越低越具有优先权。

③ FIFO

每个数据流都独立拥有四级32位FIFO(先进先出存储器缓冲区)。DMA 传输具有FIFO 模式和直接模式。


直接模式在每个外设请求都立即启动对存储器传输。在直接模式下,如果 DMA配置为存储器到外设传输那 DMA会建一个数据存放在 FIFO 内,如果外设启动 DMA 传输请求就可以马上将数据传输过去。

FIFO 用于在源数据传输到目标地址之前临时存放这些数据。可以通过 DMA 数据流xFIFO 控制寄存器 DMA_SxFCR 的 FTH[1:0]位来控制 FIFO 的阈值,分别为 1/4、1/2、3/4和满。如果数据存储量达到阈值级别时,FIFO 内容将传输到目标中。

FIFO 对于要求源地址和目标地址数据宽度不同时非常有用,比如源数据是源源不断的字节数据,而目标地址要求输出字宽度的数据,即在实现数据传输时同时把原来 4 个 8位字节的数据拼凑成一个 32位字数据。此时使用 FIFO 功能先把数据缓存起来,分别根据需要输出数据。


FIFO 另外一个作用使用于突发(burst)传输。


④ 存储器端口、外设端口

DMA2(DMA 控制器 2)的存储器端口和外设端口都是连接到 AHB 总线矩阵,可以使用AHB 总线矩阵功能。DMA2 存储器和外设端口可以访问相关的内存地址,包括有内部Flash、内部 SRAM、AHB1 外设、AHB2外设、APB2 外设和外部存储器空间。


DMA1 的存储区端口相比 DMA2 的要减少 AHB2 外设的访问权,同时 DMA1外设端口是没有连接至总线矩阵的,只有连接到 APB1外设,所以 DMA1 不能实现存储器到存储器传输。


在这里插入图片描述

⑤ 编程端口

AHB 从器件编程端口是连接至 AHB2外设的。AHB2 外设在使用 DMA传输时需要相关控制信号。


DMA 数据配置


在这里插入图片描述
在这里插入图片描述

1. DMA 传输模式

DMA2 支持全部三种传输模式,而 DMA1 只有外设到存储器和存储器到外设两种模式。


直接模式要求外设和存储器数据宽度大小一样,实际上在这种模式下 DMA数据流直接使用PSIZE,MSIZE 不被使用。、


2. 源地址和目标地址

DMA数据流 x 外设地址 DMA_SxPAR(x为 0-7)寄存器用来指定外设地址,它是一个32 位数据有效寄存器。DMA数据流 x 存储器 0地址 DMA_SxM0AR(x 为 0-7) 寄存器和DMA数据流 x 存储器 1 地址 DMA_SxM1AR(x 为 0~7) 寄存器用来存放存储器地址,其中DMA_SxM1AR 只用于双缓冲模式,DMA_SxM0AR和 DMA_SxM1AR 都是 32 位数据有效的。


在配置DMA 结构体的过程中,对于存储器地址我们一般都是使能递增的,而寄存器地址则不使能递增。

但是寄存器和存储器原理上都是一样的,都是存储器,为什么寄存器地址就不用递增呢?

其实为了优化封装操作,这个寄存器地址是默认递增的,所以我们不需要额外配置成递增模式。


3. 流控制器

流控制器主要涉及到一个控制 DMA传输停止问题。DMA传输在 DMA_SxCR 寄存器的 EN位被置 1 后就进入准备传输状态,如果有外设请求 DMA 传输就可以进行数据传输。

在传输之前设置 DMA_SxNDTR 寄存器为要传输数目值,DMA控制器在传输完这么多数目数据后就可以控制 DMA停止传输。


在完成一次数目传输后DMA_SxNDTR 计数值就会自减,当达到零时就说明传输完成。


如果某些情况下在传输之前我们无法确定数据的数目,那 DMA 就无法自动控制传输停止了,此时需要外设通过硬件通信向 DMA控制器发送停止传输信号。这里有一个大前提就是外设必须是可以发出这个停止传输信号,只有 SDIO 才有这个功能,其他外设不具备此功能。


4. 循环模式

循环模式相对应于一次模式。一次模式就是传输一次就停止传输,下一次传输需要手动控制,而循环模式在传输一次后会自动按照相同配置重新传输,周而复始直至被控制停止或传输发生错误。


通过 DMA_SxCR 寄存器的 CIRC 位可以使能循环模式。


5. 传输类型

DMA传输类型有单次(Single)传输和突发(Burst)传输。突发传输就是用非常短时间结合非常高数据信号率传输数据,相对正常传输速度,突发传输就是在传输阶段把速度瞬间提高,实现高速传输,在数据传输完成后恢复正常速度。

为达到这个效果突发传输过程要占用 AHB总线,保证要求每个数据项在传输过程不被分割,这样一次性把数据全部传输完才释放 AHB总线;而单次传输时必须通过 AHB 的总线仲裁多次控制才传输完成。

在这里插入图片描述

PINC 位和MINC 位是寄存器 DMA_SxCR 寄存器的第 9和第 10位,如果位被置 1则在每次数据传输后数据地址指针自动递增,其增量由 PSIZE 和 MSIZE 值决定,比如,设置 PSIZE 为半字大小,那么下一次传输地址将是前一次地址递增 2。


突发传输与 FIFO 密切相关,突发传输需要结合 FIFO 使用,具体要求 FIFO 阈值一定要是内存突发传输数据量的整数倍。FIFO 阈值选择和存储器突发大小必须配合使用。


在这里插入图片描述

6. 直接模式

默认情况下,DMA 工作在直接模式,不需配置 FIFO 阈值级别。


直接模式在每个外设请求都立即启动对存储器传输的单次传输。直接模式要求源地址和目标地址的数据宽度必须一致,所以只有 PSIZE 控制,而 MSIZE 值被忽略。突发传输是基于 FIFO 的所以直接模式不被支持。另外直接模式不能用于存储器到存储器传输。


7. 双缓冲模式

设置 DMA_SxCR 寄存器的 DBM 位为 1 可启动双缓冲传输模式,并自动激活循环模式。双缓冲不应用与存储器到存储器的传输。双缓冲模式下,两个存储器地址指针都有效,即DMA_SxM1AR 寄存器将被激活使用。开始传输使用 DMA_SxM0AR寄存器的地址指针所对应的存储区,当这个存储区数据传输完 DMA 控制器会自动切换至 DMA_SxM1AR 寄存器的地址指针所对应的另一块存储区,如果这一块也传输完成就再切换至 DMA_SxM0AR寄存器的地址指针所对应的存储区,这样循环调用。


当其中一个存储区传输完成时都会把传输完成中断标志 TCIF位置 1,如果我们使能了DMA_SxCR寄存器的传输完成中断,则可以产生中断信号。


在未使能DMA数据流传输时,可以直接写 CT位,改变开始传输的目标存储区。


8. DMA 中断

每个DMA 数据流可以在发送以下事件时产生中断:


达到半传输:DMA 数据传输达到一半时 HTIF 标志位被置 1,如果使能 HTIE 中断控制位将产生达到半传输中断;

传输完成:DMA 数据传输完成时 TCIF 标志位被置 1,如果使能 TCIE 中断控制位将产生传输完成中断;

传输错误:DMA 访问总线发生错误或者在双缓冲模式下试图访问“受限”存储器地址寄存器时 TEIF 标志位被置 1,如果使能 TEIE 中断控制位将产生传输错误中断;

FIFO 错误:发生 FIFO 下溢或者上溢时 FEIF 标志位被置 1,如果使能 FEIE 中断控制位将产生 FIFO 错误中断;

直接模式错误:在外设到存储器的直接模式下,因为存储器总线没得到授权,使得先前数据没有完全被传输到存储器空间上,此时 DMEIF 标志位被置 1,如果使能 DMEIE中断控制位将产生直接模式错误中断。

存储器到存储器

存储器到存储器传输必须使用 DMA2,但对数据流编号以及通道选择就没有硬性要求,

可以自由选择。


编程要点:


使能DMA 时钟并复位初始化DMA 数据流;

配置DMA_InitStructure 数据流参数;

使能DMA 数据流,进行传输;

等待传输完成,并比对源数据地址与目标地址数据是否相同;

所有定义都必须在.c 文件中进行,.h 文件只负责声明


bsp_dma.c

/**

  ******************************************************************************

  * @file    bsp_dma.c

  * @author  Waao

  * @version V1.0.0

  * @date    29-Dec-2018

  * @brief   This file contains some board support package's functions for the LED.

  *            

  ******************************************************************************

  * @attention

  *

  * None

*

  ******************************************************************************

  */


#include



/* Now we created the first memory base address and the data we want to transfer */

/* Use the key word "const" to ornament the aSRC_Const_Buffer, and render this data 

   can be stored in the internal flash */

const uint32_t aSRC_Const_Buffer[BUFFER_SIZE] = {

                                    0xffffffff,0xffffffff,0x090A0B0C,0xffffffff,

                                    0x11121314,0x15161718,0x191A1B1C,0x1D1E1F20,

                                    0x21222324,0x25262728,0x292A2B2C,0xffffffff,

                                    0x31323334,0x35363738,0x393A3B3C,0x3D3E3F40,

                                    0xffffffff,0x45464748,0xffffffff,0x4D4E4F50,

                                    0x51525354,0x55565758,0x595A5B5C,0x5D5E5F60,

                                    0x61626364,0x65666768,0x696A6B6C,0x6D6E6F70,

                                    0x71727374,0xffffffff,0x797A7B7C,0xffffffff};


/* We can get the another memory base address */

uint32_t aDST_Buffer[BUFFER_SIZE];


/**

  * @brief  Initialize the DMA.

  * @param  None  

  * @retval None

  */

void DMA_Config(void)

{

DMA_InitTypeDef DMA_InitStructure;

/* DeInit the DMA */

DMA_DeInit(DMA_STREAM);

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);

/* Specifies the channel */

DMA_InitStructure.DMA_Channel = DMA_CHANNEL;

/* Specifies the base address of the peripherals */

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)aSRC_Const_Buffer;

/* Specifies the base address of the memory0 */

DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)aDST_Buffer;

/* Specifies the transmission direction */

DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToMemory;

/* Specifies the data size */

DMA_InitStructure.DMA_BufferSize = (uint32_t)BUFFER_SIZE;

/* Specifies the peripheral enable or disable */

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;

/* Specifies the memory enable or disable */

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

/* Specifies the peripheral data size */

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;

/* Specifies the mode of the DMA */

DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

/* Specifies the priority of the DMA */

DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;

/* Specifies the FIFO Mode enable or disable */

DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;

/* Specifies the FIFO Threshold */

DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;

/* Specifies the mode of the memory burst */

DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;

/* Specifies the mode of the peripheral burst */

DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;


DMA_Init(DMA_STREAM, &DMA_InitStructure);

/* Clear the transfer-compete flag */

DMA_ClearFlag(DMA_STREAM, DMA_FLAG_TCIF0);

/* Enable the DMA(set the DMA_SxCR EN pin) */

DMA_Cmd(DMA_STREAM, ENABLE);

}



/**

  * @brief  Judging whether the two figure is equal or not.

* @param  pBuffer1: The one of the figures we want to compare.

  * pBuffer2: The another figure we want to compare.

  * BufferLength: The length of the figures.

  * @retval SET or RESET;

  */

uint8_t Buffercmp(const uint32_t* pBuffer1, 

uint32_t* pBuffer2, uint16_t BufferLength)

{

while(BufferLength--)

{

if(*pBuffer1 != *pBuffer2)

{

return RESET;

}

pBuffer1++;

pBuffer2++;

}

return SET;

}



bsp_dma.h

/**

  ******************************************************************************

  * @file    bsp_dma.h

  * @author  Waao

  * @version V1.0.0

  * @date    29-Dec-2018

  * @brief   This file contains some board support package's definition for the LED.

  *            

  ******************************************************************************

  * @attention

  *

  * None

*

  ******************************************************************************

  */

#ifndef __BSP_DMA_H_

#define __BSP_DMA_H_


#include

#include "stm32f4xx_dma.h"


/* M2M */

#define DMA_CHANNEL    DMA_Channel_0

#define DMA_STREAM      DMA2_Stream0

#define DMA_STREAM_CLOCK    RCC_AHB1Periph_DMA2

#define DMA_FLAG_TCIF    DMA_Channel_0


#define BUFFER_SIZE      32

#define TIMEOUT_MAX      10000


/* M2S */

#define DMA_USART1_CHANNEL  DMA_Channel_4

#define DMA_USART1_STREAM   DMA2_Stream7

#define USART1_DR_BaseAddr  ((uint32_t)0x40011004)//(USART1_BASE+0x04)

#define SENDBUFFER_SIZE     50


#define SET 1

#define RESET 0




extern const uint32_t aSRC_Const_Buffer[BUFFER_SIZE];

extern uint32_t aDST_Buffer[BUFFER_SIZE];

extern uint8_t SendBuff[SENDBUFFER_SIZE];

void DMA_M2M_Config(void);

void DMA_M2S_Config(void);

uint8_t Buffercmp(const uint32_t* pBuffer1, uint32_t* pBuffer2, uint16_t BufferLength);

#endif



main.c

main 函数中必须在结尾处加上while 循环,否则程序会出现跑偏,出现不想要的结果


*** Using Compiler 'V5.05 update 2 (build 169)', folder: 'E:KELI_5ARMARMCCBin'

推荐阅读

史海拾趣

ELESTA GmbH公司的发展小趣事

2013年,ELESTA公司更名为ELESTA GmbH,这一品牌重塑标志着公司进入了新的发展阶段。同时,ELESTA也开始实施全球化战略,积极拓展国际市场,通过不断提升产品质量和服务水平,赢得了全球客户的信赖和认可。

Ferroperm公司的发展小趣事

在发展的过程中,Ferroperm公司不断进行技术创新和产品研发,推动产品的多样化发展。他们成功开发了一系列具有高性能和独特功能的电磁材料,如高性能铁氧体、NdFeB永磁体等。这些产品不仅满足了客户对电磁材料性能的高要求,还推动了相关行业的发展。同时,Ferroperm还不断拓展产品线,推出了变压器、电感器、滤波器等一系列电子产品,进一步巩固了其在电磁材料领域的领先地位。

DOMINANT公司的发展小趣事

随着公司业务的不断发展,统明亮开始积极拓展全球市场。它通过与国内外知名企业的合作,不断提升自身的品牌影响力和市场竞争力。同时,统明亮还积极参加各类国际展会和交流活动,与全球各地的客户建立了紧密的合作关系。这些努力使得统明亮在全球LED市场中的份额不断扩大,其品牌影响力也得到了进一步提升。

请注意,由于篇幅限制,以上仅为三个简要故事。如果需要更多关于DOMINANT公司的发展故事,建议查阅相关报道和资料。

Eby Company公司的发展小趣事

为了提供更好的物流服务,eBay推出了国际运送计划(eBay International Shipping)。该计划允许卖家将来自同一订单的多件物品合并在一个包裹中运送,从而减少了买家支付的运费。这一举措不仅提高了物流效率,也增加了买家的购买意愿。eBay还与其他物流公司合作,提供更快捷、更可靠的配送服务。

EPIGAP公司的发展小趣事

EPIGAP公司的创始人李先生在半导体领域拥有深厚的技术背景。在公司初创时期,他带领研发团队成功研发出一种新型的高性能芯片,该芯片在功耗和性能上均达到了行业领先水平。这一技术突破使得EPIGAP公司在激烈的市场竞争中脱颖而出,迅速获得了众多客户的青睐。凭借这一产品,EPIGAP成功打开了市场,为后续的发展奠定了坚实的基础。

汇科公司的发展小趣事

作为一家有社会责任感的企业,汇科公司始终关注环境保护和可持续发展。公司积极推广绿色生产技术和资源循环利用方案,减少生产过程中的能源消耗和废弃物排放。同时,汇科公司还积极参与社会公益活动,为社区和环境贡献自己的力量。这些举措不仅体现了公司的社会责任担当,也为其赢得了更多客户和合作伙伴的信任和支持。

问答坊 | AI 解惑

变频彩电、变频技术与逐行扫描技术

变频彩电、变频技术与逐行扫描技术 变频彩电是近几年新推出的一种无闪烁、高清晰度彩电,收视效果可与HDTV相媲美,它能够兼容数字和模拟电视标准,可以接收普通电视信号,并显示比普通电视清晰度更高、更稳定的图象;也能作为数字电视信号的显示器。因 ...…

查看全部问答>

IPTV标准化实践

本帖最后由 jameswangsynnex 于 2015-3-3 20:02 编辑 为了促进IPTV产业的发展,目前中国IPTV标准规范的制定工作正在如火如荼的进行着,参与成员涉及范围空前广泛,包含电信运营商、内容运营商、IPTV设备提供商、IPTV系统集成商、IPTV技术提供商、 ...…

查看全部问答>

取字模软件

取字模软件自己买[url=https://bbs.eeworld.com.cn/viewthread.php?tid=72780&extra=page%3D2&page=1&2]开发板[/url]时送的取字摸软件 很好用    要的快下啊…

查看全部问答>

面试最恼火的问题?

这几天忙着落实工作,头都大了.面试时最最头痛的就是一个问题! 本人22岁,工作3年,要求薪水3500,却碰到有老板说“电源说难不难,说简单也不简单,也有人拿5K,6K,8K,甚至1W.” 就是没有太多的经验和年龄不大才要求不是很高的,我一不要求管吃管住,二不要 ...…

查看全部问答>

做好医疗电子设备的电子元器件的维修

从上世纪八十年代以来,医疗行业引进了许多先进的大型电子仪器及设备, 大到0)、核磁等,小到各种彩超、监护仪等。 随着它们的所有年限增加,陆续地从保修期进入了维修期,也有一些的设备已经进入了维修高峰期。这一点和国外发达国家医疗设备服役 ...…

查看全部问答>

GPRS频繁掉线call ready(请大侠指教)

GPRS链接上服务器后,接收数据几秒或几分钟就call ready重启了,我观察了一下出现call ready的时间间隔,没规律,随机,说明服务器没问题,用万用表测电源也没感到有问题(偶看到以前几位仁兄的帖子了),CIPSTATUS查询状态,是IP INITIAL,除了电 ...…

查看全部问答>

电子制作的好帮手!

电子制作的好帮手,学习C51单片机的好工具!学习开发二者兼顾!其实你也可以开发自己喜爱的电子产品! 淘宝店里有详细功能介绍http://shop36364130.taobao.com 330658522(点击Q我)    …

查看全部问答>

SignalTapII的使用问题

请教各位大侠关于SignalTapII应用的一个小问题。 看过一些教程,应用SignalTapII的时候直接将工程和sof文件一起编译下载到FPGA中。 那要怎样去设置输入信号的数值呢。 我要做的设计是一个编码器,需要在特定的测试用例下观测输出结果。 而调入S ...…

查看全部问答>

【一起学习器件指标】电容ESR

我们在选电容的时候最关注两个指标,一个是耐压值,一个是ESR。耐压值大家都知道,要是耐压值低于工作电压,电容会爆掉。但是ESR我就搞不清楚了,ESR到底是什么意思呢?ESR越小越好么?为啥要这样子哩?…

查看全部问答>