CW32L052 DMA直接内存访问

CW32L052 DMA直接内存访问

概述

CW32L052支持DMA(Direct Memory Access),即直接内存访问,无需CPU干预,实现高速数据传输。数据的传输可以发生在:

  • 外设和内存之间:例如ADC采集数据到内存,这种传输方式常见于需要将外设采集的数据快速传输到内存进行处理的应用。
  • 内存和内存之间:例如在两个不同的数组之间传输数据,或者在不同的内存块之间进行数据拷贝。
  • 外设和外设之间:例如从一个SPI主/从机传输数据到另一个SPI从/主机。

使用DMA能够有效减轻CPU的负担,特别是在大量数据需要高效传输的情况下,可以提高系统的整体性能。

框图

DMA框图

DMA功能框图

特性

使用DMA,最核心的就是配置要传输的数据,包括数据从哪里来,要到哪里去,传输的数据的单位是什么,要传多少数据,是一次传输还是连续传输等等。

  • 4条独立DMA通道

    DMA通道

    4个DMA通道的优先级和通道号绑定,通道号越小优先级越高,通道号越大优先级越低

  • 4种传输模式:

    硬件触发BULK传输模式硬件触发BLOCK传输模式软件触发BULK传输模式软件触发BLOCK传输模式

    硬件BULK
    BLOCK
    软件BULK
    BLOCK

    BULK传输模式:

    适用于小数据块的传输,通常涉及大量的数据点,但每个数据点的大小较小

    与BLOCK模式不同,BULK模式下DMA会更频繁地启动新的传输,因为每个数据点通常被视为单独的传输单元,所以DMA控制器需要在每个数据点传输完成后需要重新配置或者启动DMA。在BULK传输模式下,传输过程不可被打断。

    BLOCK传输模式:

    适用于大数据块的高速传输,通常用于需要连续传输大量数据的情况。BLOCK模式下,DMA会将数据分成较大的块,并在传输时以这些块为单位进行操作。DMA控制器在一次配置后,连续传输多个数据块,而无需额外的干预或重新配置。 每传输完成1个数据块后就要进行一次传输优先级的仲裁,允许CPU或者更高优先级的DMA通道访问当前DMA通道所占用的外设。

    • 硬件触发和软件触发:

    要想通过DMA来传输数据,必须先给DMA控制器发送DMA请求。部分外设支持硬件触发启动DMA传输,如FLASH存储器、UART串口、TIM定时器、ADC数模转换器等被配置为DMA通道的触发源时,

    硬件DMA触发源

    可以产生DMA请求(DMA request),硬件触发启动DMA传输,

    request

    硬件触发请求

    而不支持硬件DMA的外设,只能配置为软件触发启动DMA传输

    软件DMA传输

    软件触发请求

    虽然每个通道可以接收多个外设的请求,但是同一时间只能接收一个,不能同时接收多个。

    • DMA中断

      DMA通道在传输工程中可产生2个中断标志:传输错误中断标志和传输完成中断标志

      不同 DMA 通道的中断各自独立,通过中断标志寄存器 DMA_ISR 可以获取各通道的中断标志。标志对应多个可能的产生原因,具体产生原因需查询 DMA_CSRy.STATUS 状态位,如下表所示

    • 数据宽度:

      数据位宽可以设置为8bit、16bit和32bit,DMA通道的源地址和目的地址的位宽必须完全一致

    • 数据块数量:

      传输的数据块数量可以设置为1 ~ 65535

    • 数据传输优先级

      当CPU和DMA访问不同的外设时,数据的传输可以同时进行;

      当CPU和DMA同时访问同一个外设时,CPU的优先级高于DMA。

从外设到内存

通过ADC转换完成标志触发(硬件触发)DMA方式实现外设到内存的DMA传输

核心代码:

#include "main.h"
#include "delay.h"
#include "gpio.h"
#include "cw32l052_lcd.h"
#include "cw32l052_adc.h"
#include "cw32l052_dma.h"

#define NUM0 0x070d  //段式LCD数字段码
#define NUM1 0x0600
#define NUM2 0x030e
#define NUM3 0x070a
#define NUM4 0x0603
#define NUM5 0x050b
#define NUM6 0x050f
#define NUM7 0x0700
#define NUM8 0x070f
#define NUM9 0x070b

void ADC_Configuration(void);      //ADC配置函数
void DMA_Configuration(void);      //DMA配置函数
void LCD_Configuration(void);      //LCD配置函数
void LCD_Proc(uint16_t dispdata);  //LCD子程序函数

/*
**功能说明:
**ADC采集数据触发DMA,将采集到的数据(1.2V内核电压基准源)存储在内存value中,并显示在LCD屏上
*/
int main(void)
{
	LED_Init();
	LCD_Configuration();
	ADC_Configuration();
	DMA_Configuration();
	while (1)
	{
		LCD_Proc(value);  //显示采集到的ADC
		PA15_TOG();
		Delay_ms(500);
	}
}

void ADC_Configuration(void)
{
	ADC_InitTypeDef   ADC_InitStruct = {0};
	
	__RCC_ADC_CLK_ENABLE();
	__RCC_GPIOA_CLK_ENABLE();
	
	PA00_ANALOG_ENABLE(); //PA00 (AIN0)
	
	ADC_InitStruct.ADC_OpMode = ADC_SingleChOneMode; 	//单通道单次转换模式
	ADC_InitStruct.ADC_ClkDiv = ADC_Clk_Div128; 			//PCLK
	ADC_InitStruct.ADC_SampleTime = ADC_SampTime5Clk; //5个ADC时钟周期
	ADC_InitStruct.ADC_VrefSel = ADC_Vref_VDDA;       //VDDA参考电压(3.3V)
	ADC_InitStruct.ADC_InBufEn = ADC_BufEnable;       //开启跟随器
	ADC_InitStruct.ADC_TsEn = ADC_TsDisable; 					//内置温度传感器失能
	ADC_InitStruct.ADC_DMASOCEn = ADC_DMASOCEnable;   //ADC转换完成触发DMA传输
	ADC_InitStruct.ADC_Align = ADC_AlignRight; 				//ADC转换结果右对齐
	ADC_InitStruct.ADC_AccEn = ADC_AccDisable; 				//转换结果累加不使能
	ADC_Init(&ADC_InitStruct);                        //初始化ADC配置   
	CW_ADC->CR1_f.DISCARD = FALSE;                    //ADC转换结果保存策略配置:新数据覆盖未被读取的旧数据       
	CW_ADC->CR1_f.CHMUX = ADC_Vref1P2Input;           //待转换通道配置:1.2V内核电压基准源

	ADC_ClearITPendingBit(ADC_IT_EOC);
	ADC_ITConfig(ADC_IT_EOC, ENABLE);
	ADC_EnableNvic(ADC_INT_PRIORITY);

	ADC_Enable();
	ADC_SoftwareStartConvCmd(ENABLE);                  //开始转换
}

void ADC_IRQHandler(void)
{
    /* USER CODE BEGIN */
	if(ADC_GetITStatus(ADC_IT_EOC) != RESET)
	{
			ADC_ClearITPendingBit(ADC_IT_EOC);
			ADC_SoftwareStartConvCmd(ENABLE);  						//开始转换
	}
    /* USER CODE END */
}

void NVIC_Configuration(void)
{
    __disable_irq();

    NVIC_ClearPendingIRQ(DMACH1_IRQn);

    NVIC_EnableIRQ(DMACH1_IRQn);

    __enable_irq();
}

void DMA_Configuration(void)
{
	DMA_InitTypeDef DMA_InitStruct = {0};
	
	__RCC_DMA_CLK_ENABLE();
	
	DMA_StructInit(&DMA_InitStruct); 
	DMA_InitStruct.DMA_Mode = DMA_MODE_BLOCK;     //BLOCK模式
	DMA_InitStruct.DMA_TransferWidth = DMA_TRANSFER_WIDTH_32BIT; //数据宽度32bit
	DMA_InitStruct.DMA_SrcInc = DMA_SrcAddress_Fix; //源地址固定
	DMA_InitStruct.DMA_DstInc = DMA_DstAddress_Fix;  //目标地址固定
	DMA_InitStruct.DMA_TransferCnt = 1;  //数据块数量1
	DMA_InitStruct.DMA_SrcAddress = (uint32_t)&(CW_ADC->RESULT0);  //数据源地址 (外设)
	DMA_InitStruct.DMA_DstAddress = (uint32_t)&value;   //传输目标地址   (内存)
	DMA_InitStruct.TrigMode = DMA_HardTrig;  //硬件触发DMA传输
	DMA_InitStruct.HardTrigSource = DMA_HardTrig_ADC_SINGLETRANSCOM;  //硬件触发源:ADC单次转换完成标志
	DMA_Init(CW_DMACHANNEL1,&DMA_InitStruct); //DMA通道1
	DMA_ClearITPendingBit(DMA_IT_ALL);  //清除DMA中断标志位
	DMA_ITConfig(CW_DMACHANNEL1, DMA_IT_TC, ENABLE);   //使能DMA通道1中断
	NVIC_Configuration();
	DMA_Cmd(CW_DMACHANNEL1, ENABLE); //启动DMA通道1进行传输
}

void DMACH1_IRQHandler(void)
{
    /* USER CODE BEGIN */
	if( DMA_GetITStatus(DMA_IT_TC1) )  //DMA通道1传输完成标志
    {
        DMA_ClearITPendingBit(DMA_IT_TC1);

        CW_DMACHANNEL1->CNT = 0x10001;     //REPEAT写1,传输数量为1                       
        DMA_Cmd(CW_DMACHANNEL1, ENABLE); 
    }
    /* USER CODE END */
}

演示:ADC转换结果为1580左右,换算成电压: 1580 4096 ∗ 3.3 = 1.27 V \frac{1580}{4096}*3.3=1.27V 409615803.3=1.27V
点击查看

从内存到内存

通过软件触发DMA方式实现内存(FLASH)到内存(SRAM)的DMA传输

核心代码:

//单片机头文件
#include "main.h"
#include "cw32l052_lcd.h"
#include "cw32l052_dma.h"
//硬件外设
#include "delay.h"
#include "gpio.h"
//C库
#include <string.h>

#define NUM0 0x070d  //段式LCD数字段码
#define NUM1 0x0600
#define NUM2 0x030e
#define NUM3 0x070a
#define NUM4 0x0603
#define NUM5 0x050b
#define NUM6 0x050f
#define NUM7 0x0700
#define NUM8 0x070f
#define NUM9 0x070b

#define DATASIZE 10

uint16_t const srcBuf[DATASIZE] =   //源内存(FLASH)数据
{
	9999,8888,7777,6666,5555,
	4444,3333,2222,1111,0
};

uint16_t dstBuf[DATASIZE]={0};      //目标内存(SRAM)数据

void DMA_Configuration(void);      //DMA配置函数
void LCD_Configuration(void);      //LCD配置函数
void LCD_Proc(uint16_t dispdata);  //LCD子程序函数

uint32_t value=0;  //ADC数值

/*
**功能说明:
**将srcBuf数组中的数据通过DMA传送到dstBuf数组中,
**srcBuf数组中的数据通过const关键词存储到FLASH中,
**dstBuf数组存储在SRAM程序运行过程中
**传输完成后比较两数组内容,相同则打开LED1和LED1,LCD上循环显示dstBuf数据;
**不同则进入死循环,两指示灯闪烁
*/
int main(void)
{
	LED_Init();
	LCD_Configuration();
	DMA_Configuration();
	DMA_SWTrigCmd(CW_DMACHANNEL1);   //使能通道1软件触发
	while(DMA_GetFlagStatus(CW_DMACHANNEL1)!=DMA_CHANNEL_STATUS_TRANSCOMPLETE); //等待传输完成
	if(memcmp(srcBuf,dstBuf,DATASIZE)==0)  //如果srcBuf和dstBuf相同
	{
			LED1_ON(); //指示灯
			LED2_ON();
			for(int i=0;i<10;i++)  //LCD屏显示dstBuf数据
			{
				LCD_Proc(dstBuf[i]);
				Delay_ms(500);
			}
	}
	else  //如果不相同
	{
		while(1)  //进入while死循环
		{
			PA15_TOG();  //指示灯
			PC10_TOG();
			Delay_ms(500);
		}
	}
	
	while (1)
	{
		
	}
}

void DMA_Configuration(void)
{
	DMA_InitTypeDef DMA_InitStruct = {0};
	
	__RCC_DMA_CLK_ENABLE();
	
	DMA_StructInit(&DMA_InitStruct); 
	DMA_InitStruct.DMA_Mode = DMA_MODE_BLOCK;     //BLOCK模式
	DMA_InitStruct.DMA_TransferWidth = DMA_TRANSFER_WIDTH_16BIT; //数据宽度16bit
	DMA_InitStruct.DMA_SrcInc = DMA_SrcAddress_Increase; //源地址固定
	DMA_InitStruct.DMA_DstInc = DMA_DstAddress_Increase;  //目标地址递增
	DMA_InitStruct.DMA_TransferCnt = DATASIZE;  //数据块数量
	DMA_InitStruct.DMA_SrcAddress = (uint32_t)&srcBuf[0];  //数据源地址 (内存)
	DMA_InitStruct.DMA_DstAddress = (uint32_t)&dstBuf[0];   //传输目标地址 (内存)
	DMA_InitStruct.TrigMode = DMA_SWTrig;  //软件触发DMA传输

	DMA_Init(CW_DMACHANNEL1,&DMA_InitStruct); //DMA通道1
	DMA_Cmd(CW_DMACHANNEL1, ENABLE); //启动DMA通道1进行传输
}

演示:LCD屏上显示通过DMA传输的dstBuf的数据
点击查看

从外设到外设

通过硬件触发DMA方式实现外设(SPI)到外设(SPI)的DMA传输

核心代码:

/*单片机头文件*/
#include "main.h"
/*硬件驱动*/
#include "delay.h"
#include "gpio.h"
#include "cw32l052_dma.h"
#include "cw32l052_spi.h"
/*C库*/
#include <string.h>

//硬件连接
//SPIY_SCK  (PA10) -- SPIX_SCK  (PB13)
//SPIY_MISO (PA11) -- SPIX_MISO (PB14)
//SPIY_MOSI (PA12) -- SPIX_MOSI (PB15)

//SPI2相关定义(Master)
#define		SPIX                     CW_SPI2               
#define 	SPIX_GPIO			    CW_GPIOB
#define  	SPIX_SCK_PIN             GPIO_PIN_13
#define 	SPIX_MISO_PIN            GPIO_PIN_14
#define  	SPIX_MOSI_PIN            GPIO_PIN_15
#define  	SPIX_AF_SCK              PB13_AFx_SPI2SCK()
#define  	SPIX_AF_MISO             PB14_AFx_SPI2MISO()
#define  	SPIX_AF_MOSI             PB15_AFx_SPI2MOSI()
#define  	SPIX_RX_DMACHANNEL       CW_DMACHANNEL1
#define  	SPIX_TX_DMACHANNEL       CW_DMACHANNEL2	
#define     SPIX_DMA_RXTRIGSOURCE    DMA_HardTrig_SPI2_RXBufferNE
#define     SPIX_DMA_TXTRIGSOURCE    DMA_HardTrig_SPI2_TXBufferE

//SPI1相关定义(Slave)
#define		SPIY                     CW_SPI1
#define 	SPIY_GPIO			    CW_GPIOA
#define  	SPIY_SCK_PIN             GPIO_PIN_10
#define  	SPIY_MISO_PIN            GPIO_PIN_11
#define  	SPIY_MOSI_PIN            GPIO_PIN_12
#define  	SPIY_AF_SCK              PA10_AFx_SPI1SCK()
#define  	SPIY_AF_MISO             PA11_AFx_SPI1MISO()
#define  	SPIY_AF_MOSI             PA12_AFx_SPI1MOSI()

//数组长度
#define   BUFFERSIZE                 ARRAY_SZ(TxBuffer1)

//发送内容1
uint8_t TxBuffer1[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
                       0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
                       0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
                       0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C,
                       0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23
                      };
//发送内容2
uint8_t TxBuffer2[] = {0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
                       0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E,
                       0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
                       0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
                       0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83
                      };
										
uint8_t RxBuffer1[BUFFERSIZE];  //接收数组1
uint8_t RxBuffer2[BUFFERSIZE];  //接收数组2
uint8_t TxCounter = 0;  //发送计数
uint8_t RxCounter = 0;  //接收计数
	
uint8_t TransferStatus1 = 1;  //DMA传输状态标志1
uint8_t TransferStatus2 = 1;  //DMA传输状态标志2
											
void DMA_Configuration(void);      //DMA配置函数
void SPI_Configuration(void);      //SPI配置函数
void SPI_GPIO_Configuration(void); //SPI相关GPIO口配置
	
/*
**功能说明:
**主机SPIY发送TxBuffer1中的数据,从机SPIX通过DMA接收数据并存储到RxBuffer1
**主机SPIY发送无效数据,启动SPI通信,同时SPIX从机通过DMA发送TxBuffer2中的数据,SIPY接收数据并存储到RxBuffer2
**单独比较TxBuffer1与RxBuffer1、TxBuffer2与RxBuffer2中的内容,比较结果通过LED灯指示
*/
int main(void)
{
	LED_Init();               //初始化LED指示灯
	SPI_GPIO_Configuration(); //配置PI相关GPIO口
	DMA_Configuration();      //配置DMA传输
	SPI_Configuration();      //配置SPI传输
	SPI_DMACmd(SPIX, SPI_DMAReq_Rx, ENABLE); //使能SPIX DMA RX
	SPI_NSSInternalSoftwareConfig(SPIX, SPI_NSSInternalSoft_Reset);//位选CS选中从机SPIX,起始信号
	while(TxCounter < BUFFERSIZE)
	{
		while(SPI_GetFlagStatus(SPIY,SPI_FLAG_TXE) == RESET);//等待发送缓冲空(为空后硬件自动置1)
		SPI_SendData(SPIY,TxBuffer1[TxCounter++]); //发送TxBuffer1中的数据,通过数据寄存器DR把数据填充到发送缓冲区中
	}
	while(DMA_GetFlagStatus(SPIX_RX_DMACHANNEL) != DMA_CHANNEL_STATUS_TRANSCOMPLETE);//等待DMA接收完成

	SPI_NSSInternalSoftwareConfig(SPIX, SPI_NSSInternalSoft_Set); //释放从机SPIX,结束信号
	TransferStatus1 = memcmp(TxBuffer1, RxBuffer1, BUFFERSIZE); //对比两数组数据
	if(TransferStatus1==0)  //如果数据相同
	{
		LED1_ON();  //LED1指示
	}
	else
	{
		LED1_OFF();
	}
	
	TxCounter = 0;
	SPI_ReceiveData(SPIY);//读DR以清除RXNE(接收非空)标志位
	SPI_DMACmd(SPIX, SPI_DMAReq_Rx, DISABLE);//失能SPIX DMA RX
	SPI_FlushSendBuff(SPIX);//清空发送缓冲区和移位寄存器
	SPI_DMACmd(SPIX, SPI_DMAReq_Tx, ENABLE);//使能SPIX DMA TX
	SPI_NSSInternalSoftwareConfig(SPIX, SPI_NSSInternalSoft_Reset);
	while(TxCounter < BUFFERSIZE)
	{			
		while(SPI_GetFlagStatus(SPIY, SPI_FLAG_TXE) == RESET){;} //主机发送数据以启动SPI通信
		SPI_SendData(SPIY, TxBuffer1[TxCounter++]);
			
		while(SPI_GetFlagStatus(SPIY, SPI_FLAG_RXNE) == RESET){;}
    	RxBuffer2[RxCounter++] = SPI_ReceiveData(SPIY);	//获取接收缓冲区中的内容	
	}
	while(SPI_GetFlagStatus(SPIY,SPI_FLAG_BUSY) == SET); //检查数据是否已经全部通过SPI发送完毕	
	SPI_NSSInternalSoftwareConfig(SPIX, SPI_NSSInternalSoft_Set); //释放
	TransferStatus2 = memcmp(TxBuffer2, RxBuffer2, BUFFERSIZE);  //检查
	if(TransferStatus2 == 0)
	{
		LED2_ON();
	}
	else
	{
		LED2_OFF();
	}
	while (1)
	{
		
	}
}

void SPI_GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};
		
    //打开GPIO时钟
    __RCC_GPIOA_CLK_ENABLE();
    __RCC_GPIOB_CLK_ENABLE();

    //SPI SCK MOSI MISO 复用
    SPIY_AF_SCK;
    SPIY_AF_MISO;
    SPIY_AF_MOSI;
    SPIX_AF_SCK;
    SPIX_AF_MISO;
    SPIX_AF_MOSI;

    //推挽输出
    GPIO_InitStructure.Pins = SPIY_SCK_PIN | SPIY_MOSI_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Init(SPIY_GPIO, &GPIO_InitStructure);

    GPIO_InitStructure.Pins = SPIX_MISO_PIN;
    GPIO_Init(SPIX_GPIO, &GPIO_InitStructure);

    //浮空输入
    GPIO_InitStructure.Pins = SPIX_SCK_PIN | SPIX_MOSI_PIN;
    GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
    GPIO_Init(SPIX_GPIO, &GPIO_InitStructure);

    GPIO_InitStructure.Pins = SPIY_MISO_PIN;
    GPIO_Init(SPIY_GPIO, &GPIO_InitStructure);
}

void SPI_Configuration(void)
{
	SPI_InitTypeDef SPI_InitStructure = {0};
	
	__RCC_SPI1_CLK_ENABLE();
	__RCC_SPI2_CLK_ENABLE();
	
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //双线全双工模式
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主机模式
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //数据位宽8bit
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;  //时钟极性
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//时钟相位,奇数边缘采样
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //配置NSS引脚(片选信号线)的使用模式,软件控制
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8; //波特率:PCLK8分频
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //MSB先行模式
	SPI_InitStructure.SPI_Speed = SPI_Speed_Low; //低速
	SPI_Init(SPIY,&SPI_InitStructure);
	
	SPI_InitStructure.SPI_Mode = SPI_Mode_Slave; //从机模式
	SPI_Init(SPIX,&SPI_InitStructure);
	
	SPI_Cmd(SPIX,ENABLE);
	SPI_Cmd(SPIY,ENABLE);
}

void DMA_Configuration(void)
{
	DMA_InitTypeDef DMA_InitStructure = {0};
	
	__RCC_DMA_CLK_ENABLE();
	
	//DMA TX
	DMA_InitStructure.DMA_Mode = DMA_MODE_BLOCK; //BLOCK模式
	DMA_InitStructure.DMA_TransferWidth = DMA_TRANSFER_WIDTH_8BIT;
	DMA_InitStructure.DMA_SrcInc = DMA_SrcAddress_Increase;
	DMA_InitStructure.DMA_DstInc = DMA_DstAddress_Fix;
	DMA_InitStructure.TrigMode = DMA_HardTrig;
	DMA_InitStructure.HardTrigSource = SPIX_DMA_TXTRIGSOURCE;
	DMA_InitStructure.DMA_TransferCnt = BUFFERSIZE;
	DMA_InitStructure.DMA_SrcAddress = (uint32_t)&TxBuffer2[0];
	DMA_InitStructure.DMA_DstAddress = (uint32_t)&SPIX->DR; //数据寄存器
	DMA_Init(SPIX_TX_DMACHANNEL,&DMA_InitStructure);
	DMA_Cmd(SPIX_TX_DMACHANNEL,ENABLE);
	
	//DMA RX
	DMA_InitStructure.DMA_Mode = DMA_MODE_BLOCK;
	DMA_InitStructure.DMA_TransferWidth = DMA_TRANSFER_WIDTH_8BIT;
	DMA_InitStructure.DMA_SrcInc = DMA_SrcAddress_Fix;
	DMA_InitStructure.DMA_DstInc = DMA_DstAddress_Increase;
	DMA_InitStructure.TrigMode = DMA_HardTrig;
	DMA_InitStructure.HardTrigSource = SPIX_DMA_RXTRIGSOURCE;
	DMA_InitStructure.DMA_TransferCnt = BUFFERSIZE;
	DMA_InitStructure.DMA_SrcAddress = (uint32_t)&SPIX->DR;
	DMA_InitStructure.DMA_DstAddress = (uint32_t)&RxBuffer1[0];
	DMA_Init(SPIX_RX_DMACHANNEL,&DMA_InitStructure);
	DMA_Cmd(SPIX_RX_DMACHANNEL,ENABLE);
}

提供资源

思维导图: DMA直接内存访问.emmx

讲解视频: 所有完整讲解视频均由CW32生态社区发布,敬请关注。

微信公众号

关注博主微信公众号:灵萧宝殿
分享更多有趣有料内容
点此扫码

  • 16
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值