历史上的今天

今天是:2024年10月19日(星期六)

正在发生

2021年10月19日 | stm32专题十三:DMA(三)存储器到外设

发布者:SerendipityGlow 来源: eefocus关键字:DMA  存储器  外设 手机看文章 扫描二维码
随时随地手机看文章

DMA的存储器到外设的配置,其实和存储器到存储器的配置非常类似。


只是需要注意一点,就是外设寄存器的地址如何获得?比如USART->DR数据寄存器,我们可以这样定义(基址 + 偏移)


// 外设寄存器地址

#define USART_DR_ADDRESS        (USART1_BASE + 0x04)

然后的配置就跟USART和DMA非常类似,直接上初始化过程:


bsp_dma.c


#include "bsp_dma.h"

#include

 

uint8_t SendBuff[SENDBUFF_SIZE];

 

void USART_Config(void)

{

  GPIO_InitTypeDef GPIO_InitStruct;

USART_InitTypeDef USART_InitStruct;

// 开启串口的GPIO时钟

DEBUG_UASRT_GPIO_APBxClkCmd(DEBUG_UASRT_GPIO_CLK, ENABLE);

 

  // USART的TX配置为复用推挽输出

GPIO_InitStruct.GPIO_Pin = DEBUG_UASRT_TX_GPIO_PIN;

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_Init(DEBUG_UASRT_TX_GPIO_PORT, &GPIO_InitStruct);

// USART的RX配置为浮空输入(由中文参考手册查询)

GPIO_InitStruct.GPIO_Pin = DEBUG_UASRT_RX_GPIO_PIN;

GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Init(DEBUG_UASRT_RX_GPIO_PORT, &GPIO_InitStruct);

// 开启串口时钟

DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);

// 配置串口参数(波特率、8位数据、1位停止位、无校验、发送接收模式、无硬件流控)

USART_InitStruct.USART_BaudRate = DEBUG_USART_BAUDRATE;

USART_InitStruct.USART_WordLength = USART_WordLength_8b;

USART_InitStruct.USART_StopBits = USART_StopBits_1;

USART_InitStruct.USART_Parity = USART_Parity_No;

USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;

USART_Init(DEBUG_USARTx, &USART_InitStruct);

 

// 使能串口

USART_Cmd(DEBUG_USARTx, ENABLE);

}

 

int fputc(int ch, FILE *f)

{

USART_SendData(DEBUG_USARTx, (uint8_t)ch);

while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);

 

return ch;

}

 

// Memory -> P(USART->DR)

void USARTx_DMA_Config(void)

{

DMA_InitTypeDef DMA_InitStruct;

// 开时钟,我经常会忘记这一步(DMA挂载在AHB总线

RCC_AHBPeriphClockCmd(USART_TX_DMA_CLK, ENABLE);

// 配置初始化结构体

DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)USART_DR_ADDRESS;

DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)SendBuff;

/* DMA_DIR_PeripheralSRC:外设为源,DMA_DIR_PeripheralDST:外设为目的地 */

DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralDST;

DMA_InitStruct.DMA_BufferSize = SENDBUFF_SIZE;

DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;

DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

DMA_InitStruct.DMA_Mode = DMA_Mode_Normal;

DMA_InitStruct.DMA_Priority = DMA_Priority_Medium;

DMA_InitStruct.DMA_M2M = DMA_M2M_Disable;

DMA_Init(DMA1_Channel4, &DMA_InitStruct);

DMA_Cmd(DMA1_Channel4, ENABLE);

}

bsp_dma.h头文件


#ifndef __BSP_DMA_H

#define __BSP_DMA_H

 

#include "stm32f10x.h"

 

// 串口1 USART1

#define DEBUG_USARTx    USART1

#define DEBUG_USART_BAUDRATE    115200

#define DEBUG_USART_CLK    RCC_APB2Periph_USART1

#define DEBUG_USART_APBxClkCmd    RCC_APB2PeriphClockCmd

 

// USART GPIO引脚宏定义

#define DEBUG_UASRT_GPIO_CLK RCC_APB2Periph_GPIOA

#define DEBUG_UASRT_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd

 

#define DEBUG_UASRT_TX_GPIO_PORT GPIOA

#define DEBUG_UASRT_TX_GPIO_PIN GPIO_Pin_9

#define DEBUG_UASRT_RX_GPIO_PORT GPIOA

#define DEBUG_UASRT_RX_GPIO_PIN GPIO_Pin_10

 

 

#define USART_TX_DMA_CLK RCC_AHBPeriph_DMA1

// 外设寄存器地址

#define USART_DR_ADDRESS        (USART1_BASE + 0x04)

// 一次发送的数据量

#define SENDBUFF_SIZE            5000

// 串口对应的DMA请求通道

#define USART_TX_DMA_CHANNEL      DMA1_Channel4

 

extern uint8_t SendBuff[SENDBUFF_SIZE];

 

void USART_Config(void);

void USARTx_DMA_Config(void);

 

 

#endif /* __BSP_DMA_H */

然后再主函数中进行调用。注意,这里有一点与Memory to Memory不同,MtM一旦使能就会进行传输,不需要触发。而这里需要USART发送一个DMA请求,然后DMA才会开始进行数据传输,请求函数为:


/**

  * @brief  Enables or disables the USART抯 DMA interface.

  * @param  USARTx: Select the USART or the UART peripheral. 

  *   This parameter can be one of the following values:

  *   USART1, USART2, USART3, UART4 or UART5.

  * @param  USART_DMAReq: specifies the DMA request.

  *   This parameter can be any combination of the following values:

  *     @arg USART_DMAReq_Tx: USART DMA transmit request

  *     @arg USART_DMAReq_Rx: USART DMA receive request

  * @param  NewState: new state of the DMA Request sources.

  *   This parameter can be: ENABLE or DISABLE. 

  * @retval None

  */

void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState)

{

  if (NewState != DISABLE)

  {

    /* Enable the DMA transfer for selected requests by setting the DMAT and/or

       DMAR bits in the USART CR3 register */

    USARTx->CR3 |= USART_DMAReq;

  }

  else

  {

    /* Disable the DMA transfer for selected requests by clearing the DMAT and/or

       DMAR bits in the USART CR3 register */

    USARTx->CR3 &= (uint16_t)~USART_DMAReq;

  }

}

可以看到,USART-DMA请求函数,实际上配置的是UASRT_CR3寄存器,两个参数如下,分别配置的是CR3的第7位和第6位,对应发送请求使能和接受请求使能。


#define USART_DMAReq_Tx                      ((uint16_t)0x0080)

#define USART_DMAReq_Rx                      ((uint16_t)0x0040)

我们在完成初始化配置后,调用这个USART_DMACmd函数,DMA就会立刻开始传输。


在主函数中进行测试


main.c


#include "stm32f10x.h"

#include "bsp_led.h"

#include "bsp_dma.h"

 

void delay(uint32_t count);

 

int main(void)

{

uint16_t i = 0;

LED_GPIO_Config();

USART_Config();

USARTx_DMA_Config();

for (; i < SENDBUFF_SIZE; i++)

{

SendBuff[i] = 'P';

}

USART_DMACmd(DEBUG_USARTx, USART_DMAReq_Tx, ENABLE);

 

while (1)

{

LED_R_TOGGLE;

delay(0XFFFFF);

}

}

 

void delay(uint32_t count)

{

for (; count != 0; count--);

}

关键字:DMA  存储器  外设 引用地址:stm32专题十三:DMA(三)存储器到外设

上一篇:stm32专题一:GPIO输出—点亮LED
下一篇:stm32专题二:GPIO输入—按键检测

推荐阅读

        据Digital Trends报道,本周的Mate20系列伦敦发布活动期间,华为消费者业务CEO余承东在与少数几家国际媒体交流时谈到了它们的5G手机。  余承东表示“我们正在打造可折叠手机,(且是)可折叠的5G手机”。  事实上,9月份的世界经济论坛上,华为轮值主席胡厚崑就首次表示,其首款支持5G的Android智能手机也将配备可折叠显示屏,该机将...
随着集成电路的发展和数字信号处理技术的采用,数字示波器已成为集显示、测量、运算、分析、记录等各种功能于一体的智能化测量仪器。数字示波器在性能上也逐渐超越模拟示波器,并有取而代之的趋势。与模拟示波器相比,数字示波器不仅具有可存储波形、体积小、功耗低,使用方便等优点,而且还具有强大的信号实时处理分析功能。因此,数字示波器的使用越来越...
美国NIST的热磁成像与控制项目正在开发纳米级别的温度传感器 位于马里兰州的美国国家标准与技术研究所(NIST)的研究人员正在开发一种纳米级超灵敏温度传感器阵列,据悉,这种传感器可以嵌入到各种材料中。 该系统将是第一个在不透明的三维体积中对微观温度进行实时测量的系统,其中可能包括医用植入物、冰箱、电子设备,甚至是人体。 该团队介绍,热磁成像...
位带操作其实很简单,就是把位带区某寄存器的特定位,用公式给映射到位带别名区的32位地址上,该地址在编译器看来是个立即数,因此需要强制类型转换成32位地址指针,最后对指针取值操作。特别值得注意的是,在强制类型转换成地址时,一定要加volatile关键词,不然一定会被编译器level-3优化掉,导致程序出错。博主一开始是直接使用(unsigned int *),然...

史海拾趣

问答坊 | AI 解惑

我是电子人!

┍────────────────────────────────┒ │一、如何检测电解电容器?                              &n ...…

查看全部问答∨

【labview】chinese 高级 Design Pattern - Producer Consumer

【labview】Design Pattern - Producer Consumer chinese 高级 [ 本帖最后由 安_然 于 2010-5-24 15:53 编辑 ]…

查看全部问答∨

Iimage显示图像

    因为Iimage直接显示效率不高,而且不能做动态效果。所以想先draw到一块内存设备环境(与开发板显示环境一样)上,然后再bitblt到桌面dc 。这样可以省去颜色位数转换的时间(只是显示的时候省掉,始终是要转换的),于是用了以下代码 ...…

查看全部问答∨

Windows设备驱动

王老师:       经过了近20天对MSDN中设备驱动相关知识的阅读,我对Windows平台上的设备驱动有了一定的认识, 我想尝试着写一个简单的驱动,请问我应该用什么工具编写代码呢?       前些时间你说过, ...…

查看全部问答∨

【求教】一个液晶CGRAM的读写问题

我的控制器是T6963,我现在文本模式下显示汉字。下面是我的一段代码: /***************************************************************************** 函数功能:将str所指的一个字的字模(32byte)写入CGRAM 参数:     st ...…

查看全部问答∨

编译仿真出现的问题!!

document.write(overlap1); 请问这是什么原因哈!!英文是:Error launching Debug\\Enzhi Pu.axf, Failed on connect:Ee(02).Not connected to emulator    ...…

查看全部问答∨

verilog 循环要如何写才能通过综合编译?

有如下程序for(count=0;count<=254;count=count+1)  begin       while(n<16)   begin    for(j=0;j<3;j=j+1)      begin       FD[n] <= fro ...…

查看全部问答∨

ADI揭秘跟帖嘿嘿

看大家对ADI谈论的这么热闹,我也来凑凑热闹吧,网上查到的一些ADI的资料分享给大家   亚德诺半导体技术有限公司 Analog Device Inc 亚德诺半导体技术公司(Analog Devices, Inc. 纽约证券交易所代码:ADI)自从1965年创建以来到2005年 ...…

查看全部问答∨

谁有TI M4 DEMO板自带程序

谁有TI M4 DEMO板自带程序,就是那个测量加速度、温度、电流、外部通道等的程序。TI官网没有找到,哪位大侠有上传一下。…

查看全部问答∨

招聘兼职51单片机程序员

要求:      1、有3年工作经验,能熟练使用C语言编程;      2、了解C8051F350单片机,彩色液晶屏;      3、居住地点在武汉,方便联系; 具体开发项目QQ或电话联系:   &n ...…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved