我用的是正点的STM32F103来进行学习,板子和教程是野火的指南者。
之后的这个系列条记开头未标明的话,用的也是这个板子和教程。
三、DMA步伐验证
1、DMA 存储器到存储器模式实验
(1)DMA结构体解释
- typedef struct
- {
- uint32_t DMA_PeripheralBaseAddr; // 外设地址
- uint32_t DMA_MemoryBaseAddr; // 存储器地址
- uint32_t DMA_DIR; // 传输方向
- 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_M2M; // 存储器到存储器模式
- } DMA_InitTypeDef;
复制代码
- DMA_PeripheralBaseAddr:
外设地址,设定 DMA_CPAR 寄存器的值;一般设置为外设的数据寄存器地址,如果是存储器到存储器模式则设置为此中一个存储器地址。
- DMA_Memory0BaseAddr:
存储器地址,设定 DMA_CMAR 寄存器值;一般设置为我们自界说存储区的首地址。
- DMA_DIR:
传输方向选择,可选外设到存储器、存储器到外设。它设定 DMA_CCR 寄存器的DIR[1:0] 位的值。这里并没有存储器到存储器的方向选择,当利用存储器到存储器时,只必要把此中一个存储器当作外设利用即可。
- DMA_BufferSize:
设定待传输数据数目,初始化设定 DMA_CNDTR 寄存器的值。
这个DMA_BufferSize 就是要传输的次数。
这个并不是指字节巨细,而是指DMA的传输次数,传输的字节巨细由DMA_PeripheralDataSize设置。
DMA传输数据时,从DMA_MemoryBaseAddr+0地址开始放,直到DMA_MemoryBaseAddr+DMA_BufferSize-1,此时 DMA_CNDTR 变成0,传输结束。
- DMA_PeripheralInc:
如果设置为 DMA_PeripheralInc_Enable,使能外设地址自动递增功能,它设定 DMA_CCR 寄存器的 PINC 位的值;一般外设都是只有一个数据寄存器,以是一般不会使能该位。
- DMA_MemoryInc:
如果设置为 DMA_MemoryInc_Enable,使能存储器地址自动递增功能,它设定 DMA_CCR 寄存器的 MINC 位的值;我们自界说的存储区一般都是存放多个数据的,以是要使能存储器地址自动递增功能。
- DMA_PeripheralDataSize:
外设数据宽度,可选字节 (8 位)、半字 (16 位) 和字 (32 位),它设定DMA_CCR 寄存器的 PSIZE[1:0] 位的值。
- DMA_MemoryDataSize:
存储器数据宽度,可选字节 (8 位)、半字 (16 位) 和字 (32 位),它设定DMA_CCR 寄存器的 MSIZE[1:0] 位的值。当外设和存储器之间传数据时,双方的数据宽度应该设置为一致巨细。
- DMA_Mode:
DMA 传输模式选择,可选一次传输Normal或者循环传输Circular,它设定 DMA_CCR 寄存器的CIRC 位的值。例程我们的 ADC 收罗是持续循环进行的,以是利用循环传输模式。
- DMA_Priority:
软件设置通道的优先级,有 4 个可选优先级分别为非常高、高、中和低,它设定 DMA_CCR 寄存器的 PL[1:0] 位的值。DMA 通道优先级只有在多个 DMA 通道同时利用时才故意义,如果是单个通道,优先级可以任意设置。
- DMA_M2M:
存储器到存储器模式,利用存储器到存储器时用到,设定 DMA_CCR 的位 14 MEN2MEN 即可启动存储器到存储器模式。
(2)DMA结构体初始化
- DMA_InitTypeDef DMA_InitStructure;
- // 开启DMA时钟
- RCC_AHBPeriphClockCmd(DMA_CLOCK, ENABLE);
- // 源数据地址
- DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ShuZu_YouShu; //数组有32个数,每个数都是一个字,且使用const定义(存储在FLASH)
- // 目标地址
- DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ShuZu_MeiShu; //数组有32个数,每个数都是一个字
- // 方向:外设到存储器(这里的外设是内部的FLASH)
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
- // 传输大小
- DMA_InitStructure.DMA_BufferSize = 32; //因为数组有32个数,所以设32
- // 外设(内部的FLASH)地址递增
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Enable;
- // 内存地址递增
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
- // 外设数据单位
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //因为每个数大小都是一个字,所以宽度设为Word
- // 内存数据单位
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //因为每个数大小都是一个字,所以宽度设为Word
- // DMA模式,一次或者循环模式
- DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ; //一次传输模式
- //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
- // 优先级:高
- DMA_InitStructure.DMA_Priority = DMA_Priority_High;
- // 使能内存到内存的传输
- DMA_InitStructure.DMA_M2M = DMA_M2M_Enable; //因为本次是FLASH传输到SRAM,所以是存储器到存储器
- // 配置DMA通道
- DMA_Init(DMA_CHANNEL, &DMA_InitStructure);
- //清除DMA数据流传输完成标志位
- DMA_ClearFlag(DMA_FLAG_TC);
- // 使能DMA
- DMA_Cmd(DMA_CHANNEL,ENABLE);
复制代码 此中,
- // 开启DMA时钟
- RCC_AHBPeriphClockCmd(DMA_CLOCK, ENABLE);
复制代码- uint32_t ShuZu_YouShu[32]= {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 标记位后再利用DMA功能,防止不须要的干扰:
- //清除DMA数据流传输完成标志位
- DMA_ClearFlag(DMA_FLAG_TC);
复制代码 (3)步伐验证
DMA传输过后,在DEBUG界面可以看到,ShuZu_YouShu的数字传输到了ShuZu_MeiShu中
2、DMA 存储器到外设模式实验
具体实举动 将数组中的数字 传输至 串口
(1)串口初始化
代码解释均放入注释中,正文不再复述
- /**
- * @brief USART GPIO 配置,工作参数配置
- * @param 无
- * @retval 无
- */
- void USART_Config(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- USART_InitTypeDef USART_InitStructure;
- // 打开串口GPIO的时钟
- DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
-
- // 打开串口外设的时钟
- DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
- // 将USART Tx的GPIO配置为推挽复用模式
- GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
- // 将USART Rx的GPIO配置为浮空输入模式
- GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
- GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
-
- // 配置串口的工作参数
- // 配置波特率 为 115200
- USART_InitStructure.USART_BaudRate = 115200;
- // 配置 数据字长 为 8
- USART_InitStructure.USART_WordLength = USART_WordLength_8b;
- // 配置 停止位 为 1
- USART_InitStructure.USART_StopBits = USART_StopBits_1;
- // 配置 校验位 为 0
- USART_InitStructure.USART_Parity = USART_Parity_No ;
- // 配置硬件流控制
- USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
- // 配置工作模式,收发一起
- USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
- // 完成串口的初始化配置
- USART_Init(DEBUG_USARTx, &USART_InitStructure);
-
- // 使能串口
- USART_Cmd(DEBUG_USARTx, ENABLE);
- }
复制代码 (2)DMA结构体初始化
由于数据是从存储器到串口,以是设置存储器为源地址,串口的数据寄存器为目标地址。
要发送的数据有很多且都先存储在存储器中,则存储器地址指针递增;串口数据寄存器只有一个,则外设地址地址不变。
双方数据单元设置成一致,传输模式可选一次或者循环传输,只有一个 DMA 哀求,优先级任意设。
最后调用 DMA_Init 函数把这些参数写到 DMA 的寄存器中,然后使能 DMA开始传输。
- void USARTx_DMA_Config(void)
- {
- DMA_InitTypeDef DMA_InitStructure;
-
- // 开启DMA时钟
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
- // 设置DMA源地址:串口数据寄存器地址*/
- DMA_InitStructure.DMA_PeripheralBaseAddr = USART_DR_ADDRESS;
- // 内存地址(要传输的变量的指针)
- DMA_InitStructure.DMA_MemoryBaseAddr = (u32)ShuZu_YouShu;
- // 方向:从内存到外设
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
- // 传输数量
- DMA_InitStructure.DMA_BufferSize = 5000; // 传输数量 设为 5000,这个数随便设,只要不超过数组大小就可
- // 外设地址不增
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
- // 内存地址自增
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
- // 外设数据单位
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; //因为每次传输1bit,所以设为Byte
- // 内存数据单位
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //因为每次传输1bit,所以设为Byte
- // DMA模式,一次或者循环模式
- DMA_InitStructure.DMA_Mode = DMA_Mode_Normal ; //一次传输模式
- //DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
- // 优先级:中
- DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
- // 禁止内存到内存的传输
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
- // 配置DMA通道
- DMA_Init(USART_TX_DMA_CHANNEL, &DMA_InitStructure);
- // 使能DMA
- DMA_Cmd (USART_TX_DMA_CHANNEL,ENABLE);
- }
复制代码 此中,
- 外设地址DMA_PeripheralBaseAddr为串口地址(需查阅开发手册),即:
- // 外设寄存器地址
- #define PERIPH_BASE ((uint32_t)0x40000000)
- #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
- #define USART1_BASE (APB2PERIPH_BASE + 0x3800)
- #define USART_DR_ADDRESS (USART1_BASE+0x04)
复制代码
- ShuZu_YouShu数组添补为 A-Z共26个字母,再加一个回车:
- /*填充将要发送的数据*/
- for(i=0; i < 5000; i++)
- {
- ShuZu_YouShu[i] = 'A'+ i%27;
- if(ShuZu_YouShu[i] == '[')
- {
- ShuZu_YouShu[i] = '\n';
- }
- }
复制代码 (3)步伐验证
利用USART_DMACmd函数打开USART 的DMA哀求。
- /* USART1 向 DMA发出TX请求 */
- USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
复制代码 它接收三个参数:
- 第一个参数用于设置串口外设,可以是 USART1/2/3 和 UART4/5 这 5 个参数可选。
- 第二个参数设置串口的具体 DMA 哀求,有串口发送哀求 USART_DMAReq_Tx 和接收哀求 USART_DMAReq_Rx 可选。
- 第三个参数用于设置启动哀求 ENABLE 或者关闭哀求 DISABLE。
运行该函数后 USART 的DMA 发送传输就开始了,根据设置存储器的数据会发送到串口。
验证结果如下:
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |