stm32专题十三:DMA(三)存储器到外设

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

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

// 外设寄存器地址
#define USART_DR_ADDRESS        				(USART1_BASE + 0x04)

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

bsp_dma.c

#include "bsp_dma.h"
#include <stdio.h>

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--);
}

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值