DMA实现数据传输流程

本文深入解析了STM32的DMA(直接内存访问)机制,包括DMA的功能、工作原理、配置和应用场合。介绍了DMA的外设通道、仲裁器、FIFO、传输模式以及中断处理。通过具体例子展示了如何使用DMA进行存储器到存储器、外设到存储器的数据传输。同时,详细阐述了DMA初始化结构体和传输过程。最后,给出了DMA在串口收发数据中的应用示例,强调了配置和使用DMA进行高效数据传输的方法。
摘要由CSDN通过智能技术生成

1.相关概念

(1)DMA直接寄存器访问

可实现外设数据寄存器到存储器、存储器到外设数据寄存器、存储器到存储器之间的高效数据传输,无需CPU操作控制。

(2)外设与存储器

外设包括ADC、SPI、I2C、USART等等
存储器包括片内SRAM、外部存储器、片内Flash等等

(3)具体应用场合举例:

ADC采集可以利用DMA将AD转换数据转移到目标存储区,适用于多通道采集、采样频率高、连续传输的ADC采集场合;
将特定存储区的数据转移到外设数据寄存器,用于外设的对外数据传输,如存储器传输数据到串口数据寄存器,串口发送数据到PC端;
存储器到存储器的数据传输利用DMA可以达到更高的传输效率,不占用CPU,从而节约CPU资源。

2.DMA功能框图

图1
在这里插入图片描述

(1)①外设通道

STM32F4系列有两个DMA控制器,每个控制器有8个数据流,每个数据流又对应8个数据通道(8个通道对应的是8个外设请求)。
DMA控制器通过DMA数据流x配置寄存器DMA_SxCR(x为0~7,对应8个DMA数据流)的CHSEL[2:0]位选择对应的通道即选择对应的外设。
DMA请求映射表如下:
在这里插入图片描述
在这里插入图片描述
每个外设请求都占用一个数据流通道,相同外设请求可以占用不同数据流通道。比如SPI3_RX请求,占用DMA1的数据流0的通道0,因此使用该请求时,需要在把DMA_S0CR寄存器的CHSEL[2:0]设置为“000”, 此时相同数据流的其他通道不被选择,处于不可用状态,比如此时不能使用数据流0的通道1即I2C1_RX请求。

(2)②仲裁器

由仲裁器判断哪个数据流优先传输
DMA_SxCR寄存器PL[1:0]位,可以设置为非常高、高、中和低四个级别;
当两个及以上数据流软件设置优先级相同时,比较数据流编号,编号小的优先级高。

(3)③FIFO

每个数据流都独立拥有四级32位FIFO(先入先出存储器缓存区,队列)。DMA传输分为FIFO模式和直接模式。
直接模式:收到外设请求会立即启动传输。
FIFO模式:在数据传输到目标地址前临时存放这些数据,通过DMA数据流xFIFO控制寄存器DMA_SxFCR的FTH[1:0]位来控制FIFO的阈值,分别为1/4、1/2、3/4和满。数据缓冲量达到阈值级别,将FIFO中的数据传输到目标地址中。
FIFO主要用于源地址和目标地址要求数据宽度不同的场合,比如源数据是源源不断的字节数据,而目标地址要求输出字宽度的数据,即在实现数据传输时同时把原来4个8位字节的数据拼凑成一个32位字数据。此时使用FIFO功能先把数据缓存起来,根据需要输出数据。
FIFO还用于突发(burst)传输。

(4)④存储器端口、⑤外设端口

DMA2(DMA控制器2)的存储器端口和外设端口都是连接到AHB总线矩阵,可以使用AHB总线矩阵功能。DMA2存储器和外设端口可以访问相关的内存地址,包括有内部Flash、内部SRAM、AHB1外设、AHB2外设、APB1、APB2外设和外部存储器空间。
DMA1的存储区端口相比DMA2的要减少AHB2外设的访问权,同时DMA1外设端口是没有连接至总线矩阵的,只有连接到APB1外设,所以DMA1不能实现存储器到存储器传输。

3.DMA传输模式

DMA2支持全部三种传输模式;DMA1只支持外设到存储器、存储器到外设两种模式。
(1)模式选择:DMA_SxCR寄存器的DIR[1:0]位,“00”外设到存储器;“10”存储器到存储器;“01”存储器到外设。
(2)传输使能:DMA_SxCR寄存器的EN位置1
(3)数据宽度:DMA_SxCR寄存器的PSIZE[1:0]和MSIZE[1:0]位分别指定外设和存储器数据宽度大小,可以指定为字节(8位)、半字(16位)和字(32位)。直接模式要求外设和寄存器数据宽度一致,该模式下DMA数据流只使用PSIZE,MSIZE被忽略。
(4)地址设置
①外设地址:DMA_SxPAR寄存器(x为0~7)
②存储器地址:DMA_SxM0AR、DMA_SxM1AR,其中DMA_SxM1AR只用于双缓冲模式。
(5)循环模式与一次模式:一次模式时传输一次就停止传输,下一次传输需要手动控制;循环模式是传输一次后自动按照相同配置重新传输,直至被控制停止或传输错误。循环模式使能是DMA_SxCR寄存器的CIRC位。
(6)单次传输与突发传输:突发传输就是在传输阶段把速度瞬间提高,实现高速传输,在数据传输完成后恢复正常速度,有点类似达到数据块“秒传”效果。为达到这个效果突发传输过程要占用AHB总线,保证要求每个数据项在传输过程不被分割,这样一次性把数据全部传输完才释放AHB总线;而单次传输时必须通过AHB的总线仲裁多次控制才传输完成。
在这里插入图片描述
其中PBURST[1:0]和MBURST[1:0]位是位于DMA_SxCR寄存器中的, 用于分别设置外设和存储器不同节拍数的突发传输,对应为单次传输、4个节拍增量传输、8个节拍增量传输和16个节拍增量传输。
PINC位和MINC位是寄存器DMA_SxCR寄存器的第9和第10位,如果位被置1则在每次数据传输后数据地址指针自动递增, 其增量由PSIZE和MSIZE值决定,比如,设置PSIZE为半字大小,那么下一次传输地址将是前一次地址递增2。
在这里插入图片描述
突发传输与FIFO密切相关,突发传输需要结合FIFO使用,具体要求FIFO阈值一定要是内存突发传输数据量的整数倍。 FIFO阈值选择和存储器突发大小必须配合使用。
(7)直接模式与双缓冲模式
默认情况下,DMA工作在直接模式,不使能FIFO阈值级别。
①直接模式:每个外设请求都立即启动对存储器传输的单次传输。直接模式要求源地址和目标地址的数据宽度必须一致,所以只有PSIZE控制,而MSIZE值被忽略。突发传输是基于FIFO的所以直接模式不被支持。另外直接模式不能用于存储器到存储器传输。
②双缓冲模式:DMA_SxCR寄存器的DBM位置1可启动双缓冲传输模式,并自动激活循环模式。双缓冲不应用于存储器到存储器的传输。双缓冲模式下,两个存储器地址指针都有效,即DMA_SxM1AR寄存器将被激活使用。开始传输使用DMA_SxM0AR寄存器的地址指针所对应的存储区,当这个存储区数据传输完DMA控制器会自动切换至DMA_SxM1AR寄存器的地址指针所对应的另一块存储区,如果这一块也传输完成就再切换至DMA_SxM0AR寄存器的地址指针所对应的存储区,这样循环调用。
当其中一个存储区传输完成时都会把传输完成中断标志TCIF位置1,如果我们使能了DMA_SxCR寄存器的传输完成中断,则可以产生中断信号。
DMA_SxCR寄存器的CT位,当DMA控制器是在访问使用DMA_SxM0AR时CT=0,此时CPU不能访问DMA_SxM0AR,但可以向DMA_SxM1AR填充或者读取数据;当DMA控制器是在访问使用DMA_SxM1AR时CT=1,此时CPU不能访问DMA_SxM1AR,但可以向DMA_SxM0AR填充或者读取数据。另外在未使能DMA数据流传输时,可以直接写CT位,改变开始传输的目标存储区。
在这里插入图片描述
(8)流控制器
在传输之前设置DMA_SxNDTR寄存器为要传输数目值,DMA控制器在传输完这么多数目数据后就可以控制DMA停止传输。
DMA数据流x数据项数DMA_SxNDTR(x为0~7)寄存器用来记录当前仍需要传输数目,是一个16位数据有效寄存器,最大值为65535。编程时一般都会明确指定一个传输数量, 在完成一次数据传输后DMA_SxNDTR计数值就会自减,当达到零时就说明传输完成。
如果某些情况下在传输之前我们无法确定数据的数目,那DMA就无法自动控制传输停止了, 此时需要外设通过硬件通信向DMA控制器发送停止传输信号。只有SDIO可以发出停止传输信号,其他外设不具备此功能。

4.DMA中断

(1)达到半传输:DMA数据传输达到一半时HTIF标志位被置1,如果使能HTIE中断控制位将产生达到半传输中断;
(2)传输完成:DMA数据传输完成时TCIF标志位被置1,如果使能TCIE中断控制位将产生传输完成中断;
(3)传输错误:DMA访问总线发生错误或者在双缓冲模式下试图访问“受限”存储器地址寄存器时TEIF标志位被置1,如果使能TEIE中断控制位将产生传输错误中断;
(4)FIFO错误:发生FIFO下溢或者上溢时FEIF标志位被置1,如果使能FEIE中断控制位将产生FIFO错误中断;
(5)直接模式错误:在外设到存储器的直接模式下,因为存储器总线没得到授权,使得先前数据没有完成被传输到存储器空间上,此时DMEIF标志位被置1,如果使能DMEIE中断控制位将产生直接模式错误中断。

5.DMA初始化结构体

(1)DMA_InitTypeDef初始化结构体

typedef struct {
    uint32_t Channel;              //通道选择
    uint32_t Direction;            //传输方向
    uint32_t PeriphInc;            //外设递增
    uint32_t MemInc;               //存储器递增
    uint32_t PeriphDataAlignment;  //外设数据宽度
    uint32_t MemDataAlignment;     //存储器数据宽度
    uint32_t Mode;                 //模式选择
    uint32_t Priority;             //优先级
    uint32_t FIFOMode;             //FIFO模式
    uint32_t FIFOThreshold;        //FIFO阈值
    uint32_t MemBurst;             //存储器突发传输
    uint32_t PeriphBurst;          //外设突发传输
 } DMA_InitTypeDef;

①PeriphInc:如果配置为PeriphInc_Enable,即使能外设地址自动递增(设定DMA_SxCR寄存器的PINC位的值)。一般外设只有一个数据寄存器,因此一般不会使能该位。ADC3的数据寄存器地址是固定并且只有一个所以不使能外设地址递增
②MemInc:如果配置为MemInc_Enable,使能存储器地址自动递增功能(设定DMA_SxCR寄存器的MINC位的值);我们自定义的存储区一般都是存放多个数据的,所以使能存储器地址自动递增功能。之前定义了一个包含4个元素的数组用来存放数据,使能存储区地址递增功能,自动把每个通道数据存放到对应数组元素内。
③PeriphDataAlignment:外设数据宽度,可选字节(8位)、半字(16位)和字(32位),它设定DMA_SxCR寄存器的PSIZE[1:0]位的值。ADC数据寄存器只有低16位数据有效,使用半字数据宽度。
④MemDataAlignment:存储器数据宽度,可选字节(8位)、半字(16位)和字(32位),它设定DMA_SxCR寄存器的MSIZE[1:0]位的值。保存ADC转换数据也要使用半字数据宽度,这跟我们定义的数组是相对应的。
⑤Mode:DMA传输模式选择,可选一次传输或者循环传输,它设定DMA_SxCR寄存器的CIRC位的值。我们希望ADC采集是持续循环进行的,所以使用循环传输模式。
⑥FIFOMode:FIFO模式使能,如果设置为DMA_FIFOMode_Enable表示使能FIFO模式功能(设定DMA_SxFCR寄存器的DMDIS位)。ADC采集传输使用直接传输模式即可,不需要使用FIFO模式。
⑦MemBurst:存储器突发模式选择,可选单次模式、4节拍的增量突发模式、8节拍的增量突发模式或16节拍的增量突发模式,它设定DMA_SxCR寄存器的MBURST[1:0]位的值。ADC采集传输是直接模式,要求使用单次模式。
⑧PeriphBurst:外设突发模式选择,可选单次模式、4节拍的增量突发模式、8节拍的增量突发模式或16节拍的增量突发模式,它设定DMA_SxCR寄存器的PBURST[1:0]位的值。ADC采集传输是直接模式,要求使用单次模式。

(2)DMA_HandleTypeDef初始化结构体

typedef struct __DMA_HandleTypeDef {
    DMA_Stream_TypeDef         *Instance;   //注册基地址
    DMA_InitTypeDef            Init;        //DMA通信参数
    HAL_LockTypeDef            Lock;        //DMA锁定对象
    __IO HAL_DMA_StateTypeDef  State;       //DMA传输状态
    void                       *Parent;     //父类指针
    void (* XferCpltCallback)( struct __DMA_HandleTypeDef * hdma);
    //DMA传输完成回调函数
    void (* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma);
    //DMA传输完成一半回调函数
    void (* XferM1CpltCallback)( struct __DMA_HandleTypeDef * hdma);
    //Memory1 DMA传输完成回调函数
    void (* XferM1HalfCpltCallback)( struct __DMA_HandleTypeDef * hdma);
    //Memory1 DMA传输完成一半回调函数
    void (* XferErrorCallback)( struct __DMA_HandleTypeDef * hdma);
    //DMA传输错误回调函数
    void (* XferAbortCallback)( struct __DMA_HandleTypeDef * hdma);
    //DMA传输中止回调函数
    __IO uint32_t               ErrorCode;             //DMA错误码
    uint32_t                    StreamBaseAddress;     //DMA数据流基地址
    uint32_t                    StreamIndex;                //DMA数据流索引
} DMA_HandleTypeDef;

①Instance: 指向DMA数据流基地址的指针,即指定使用哪个DMA数据流。可选数据流0至数据流7。 例如,我们使用模拟数字转换器ADC3规则采集4个输入通道的电压数据, 查表可知可以使用数据流0或者数据流1,这里支持两个数据流是为了避免多个通道使用时发生冲突,提供备选数据流可选。
②Init:这里包含上面介绍DMA_InitTypeDef结构体的所有参数的初始化。
③Lock:DMA锁定对象。DMA进程锁,通常都在DMA传输设置开始前锁上进程锁,设置完毕后释放进程锁
④State:DMA传输状态。它包含六种状态,
复位状态,尚未初始化或者失能;
就绪状态,已经完成初始化,随时可以传输数据;
传输忙,DMA传输进程正在进行;
传输超时状态;
传输错误状态;
传输中止状态。
⑤*Parent:父类指针。只要将该指针指向一些ADC、UART等外设的handle类,就等于完成了继承。
⑥传输过程中的回调函数:包括传输完成,传输完成一半,传输错误,传输中止回调函数。这些回调函数中可以加入用户的处理代码。
⑦ErrorCode:DMA错误码,包含
无错误:HAL_DMA_ERROR_NONE,
传输错误:HAL_DMA_ERROR_TE,
FIFO错误:HAL_DMA_ERROR_FE,
直接模式错误:HAL_DMA_ERROR_DME,
超时错误:HAL_DMA_ERROR_TIMEOUT,
参数错误:HAL_DMA_ERROR_PARAM,
没有回调函数正在执行退出请求错误:HAL_DMA_ERROR_NO_XFER,
不支持模式错误:HAL_DMA_ERROR_NOT_SUPPORTED。
⑧StreamBaseAddress:DMA数据流基地址,用来根据定义句柄计算数据流的基地址。
⑨StreamIndex:DMA数据流索引,根据数据流的序号来确定数据流的偏移地址。

6.DMA_MemToMem 存储器到存储器传输

代码实现步骤:
①使能DMA数据流时钟并复位初始化DMA数据流;
②配置DMA数据参数;
③使能DMA数据流,进行传输;
④等待传输完成,并对源数据和目标地址数据进行比较;
存储器到存储器传输必须使用DMA2,但对数据流编号以及通道选择就没有硬性要求,可以自由选择。只能使用一次传输模式不能循环传输。

typedef enum 
{
  FAILED = 0,
  PASSED = !FAILED
} TestStatus;

DMA_HandleTypeDef hdma_memtomem_dma2_stream0;

static const uint32_t SRC_Const_Buffer[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};

uint32_t DST_Buffer[32];
__IO TestStatus TransferStatus= FAILED;

int main(void)
{
 
  HAL_StatusTypeDef har_status;
  
  /* 复位所有外设,初始化Flash接口和系统滴答定时器 */
  HAL_Init();
  /* 配置系统时钟 */
  SystemClock_Config();
  
  /* 板载LED初始化 */
  LED_GPIO_Init();
  
  /* DMA初始化 */ 
  MX_DMA_Init();
  
  //开始DMA传输
  har_status=HAL_DMA_Start(&hdma_memtomem_dma2_stream0,(uint32_t)&SRC_Const_Buffer,(uint32_t)&DST_Buffer,32);
  
  if(har_status==HAL_OK)
  {
    /* 检查发送和接收的数据是否相等 */
    TransferStatus = Buffercmp(SRC_Const_Buffer, DST_Buffer, 32);
    
    /* 如果接收和发送的数据都是相同的,则通过 */
    if(TransferStatus == 1)
    {
      LED1_ON;
    }
    /* 如果接收和发送的数据不同,则传输出错 */
    else
    {
      LED2_ON;
    }
  }
  else
  {
    LED3_ON;
  }  
  /* 无限循环 */
  while (1)
  {

  }
}
/**
  * 函数功能: 判断指定长度的两个数据源是否完全相等
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明: 如果完全相等返回1,只要其中一对数据不相等返回0
  */
 uint8_t Buffercmp(const uint32_t* pBuffer,
                 uint32_t* pBuffer1, uint16_t BufferLength)
 {
     /* 数据长度递减 */
     while (BufferLength--) {
         /* 判断两个数据源是否对应相等 */
         if (*pBuffer != *pBuffer1) {
             /* 对应数据源不相等马上退出函数,并返回0 */
             return 0;
         }
         /* 递增两个数据源的地址指针 */
         pBuffer++;
         pBuffer1++;
     }
     /* 完成判断并且对应数据相对 */
     return 1;
 }
/**
  * 函数功能: DMA配置
  * 输入参数: 无
  * 返 回 值: 无
  * 说    明: 无
  */
void MX_DMA_Init(void) 
{
  /* 使能DMA控制器时钟 */
  __HAL_RCC_DMA2_CLK_ENABLE();
  
  /* 配置DMA通道工作方式 */
  hdma_memtomem_dma2_stream0.Instance = DMA2_Stream0;//数据流0
  hdma_memtomem_dma2_stream0.Init.Channel = DMA_CHANNEL_0;//通道0
  hdma_memtomem_dma2_stream0.Init.Direction = DMA_MEMORY_TO_MEMORY;//数据传输方向:存储器->存储器
  hdma_memtomem_dma2_stream0.Init.PeriphInc = DMA_PINC_ENABLE;//外设地址不变    
  hdma_memtomem_dma2_stream0.Init.MemInc = DMA_MINC_ENABLE;//内存地址自增
  hdma_memtomem_dma2_stream0.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;//传输数据半字16位    
  hdma_memtomem_dma2_stream0.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;//接收数据半字16位
  hdma_memtomem_dma2_stream0.Init.Mode = DMA_NORMAL;//发一次开启一次
  hdma_memtomem_dma2_stream0.Init.Priority = DMA_PRIORITY_HIGH;//优先级(设置为最高优先级)
  hdma_memtomem_dma2_stream0.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
  hdma_memtomem_dma2_stream0.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
  hdma_memtomem_dma2_stream0.Init.MemBurst = DMA_MBURST_SINGLE;
  hdma_memtomem_dma2_stream0.Init.PeriphBurst = DMA_PBURST_SINGLE;
  HAL_DMA_Init(&hdma_memtomem_dma2_stream0);

}

7.DMA串口收发数据

//main.c  
#define SEND_BUF_SIZE (8800)	//发送数据长度,最好等于sizeof(TEXT_TO_SEND)+2的整数倍.

u8 SendBuff[SEND_BUF_SIZE]; //发送数据缓冲区
const u8 TEXT_TO_SEND[] = {"ALIENTEK Pandora STM32L4 IOT DMA 串口实验"};//显示出来是42 汉字1Byte,空格2Byte,字母数字1Byte 再加上\n\r 共44个Bytes
//使用了const关键字修饰,即常量类型,使得变量存储在内部flash空间上。
int main(void)
{
    u8 t = 0, j, mask;
    u16 i;
    float pro = 0;                  //进度

    HAL_Init();
    SystemClock_Config();		//初始化系统时钟为80M
    delay_init(80); 			//初始化延时函数    80M系统时钟
    uart_init(115200);			//初始化串口,波特率为115200

    LED_Init();					//初始化LED
    KEY_Init();					//初始化按键
    LCD_Init();					//初始化LCD

    MYDMA_Config(DMA1_Channel4, DMA_REQUEST_2); //初始化DMA


    j = sizeof(TEXT_TO_SEND);
    for(i = 0; i < SEND_BUF_SIZE; i++) //填充ASCII字符集数据 一共8800Bytes
    {
        if(t >= j) //加入换行符
        {
            if(mask)
            {
                SendBuff[i] = 0x0a;
                t = 0;
            }
            else
            {
                SendBuff[i] = 0x0d;
                mask++;
            }
        }
        else //复制TEXT_TO_SEND语句
        {
            mask = 0;
            SendBuff[i] = TEXT_TO_SEND[t];
            t++;
        }
    }

    while(1)
    {
        t = KEY_Scan(0);

        if(t == KEY0_PRES) //KEY0按下
        {
			HAL_UART_Transmit_DMA(&UART1_Handler, (u8*)SendBuff, SEND_BUF_SIZE); //启动传输

            //使能串口1的DMA发送 //等待DMA传输完成,此时我们来做另外一些事,点灯
            //实际应用中,传输数据期间,可以执行另外的任务
            while(1)
            {	//DMA_HandleTypeDef  UART1TxDMA_Handler;      //DMA句柄
                if(__HAL_DMA_GET_FLAG(&UART1TxDMA_Handler, DMA_FLAG_TC4)) //等待DMA2_Steam7传输完成
                {
                    __HAL_DMA_CLEAR_FLAG(&UART1TxDMA_Handler, DMA_FLAG_TC4); //清除DMA2_Steam7传输完成标志
                    HAL_UART_DMAStop(&UART1_Handler);      //传输完成以后关闭串口DMA
                    break;
                }

                pro = __HAL_DMA_GET_COUNTER(&UART1TxDMA_Handler); //返回当前DMA通道传输中剩余数据单元的数量
                pro = 1 - pro / SEND_BUF_SIZE; //得到百分比
                pro *= 100;      			  //扩大100倍
            }
        }
        delay_ms(10);
    }
}
//dma.c
/**
 * @brief	DMAx的各通道配置,这里的传输形式是固定的,这点要根据不同的情况来修改
 *			从存储器->外设模式/8位数据宽度/存储器增量模式
 *
 * @param   DMA_Streamx		DMA通道选择,DMA1_Channel0~7/DMA2_Channel0~7
 * @param   chx				DMA请求选择,@ref DMA_REQUEST_0~DMA_REQUEST_7
 *
 * @return  void
 */
void MYDMA_Config(DMA_Channel_TypeDef *DMA_Channel, u32 seq)
{
    if((u32)DMA_Channel > (u32)DMA2) //得到当前stream是属于DMA2还是DMA1
    {
        __HAL_RCC_DMA2_CLK_ENABLE();//DMA2时钟使能
    }

    else
    {
        __HAL_RCC_DMA1_CLK_ENABLE();//DMA1时钟使能
    }

    __HAL_LINKDMA(&UART1_Handler, hdmatx, UART1TxDMA_Handler);  //将DMA与USART1联系起来(发送DMA)

    //Tx DMA配置
    UART1TxDMA_Handler.Instance = DMA_Channel;                          //通道选择
    UART1TxDMA_Handler.Init.Request = seq;                              //请求选择
    UART1TxDMA_Handler.Init.Direction = DMA_MEMORY_TO_PERIPH;           //存储器到外设
    UART1TxDMA_Handler.Init.PeriphInc = DMA_PINC_DISABLE;               //外设非增量模式
    UART1TxDMA_Handler.Init.MemInc = DMA_MINC_ENABLE;                   //存储器增量模式
    UART1TxDMA_Handler.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;  //外设数据长度:8位
    UART1TxDMA_Handler.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;     //存储器数据长度:8位
    UART1TxDMA_Handler.Init.Mode = DMA_NORMAL;                          //外设普通模式
    UART1TxDMA_Handler.Init.Priority = DMA_PRIORITY_HIGH;             	//中等优先级

    HAL_DMA_DeInit(&UART1TxDMA_Handler);
    HAL_DMA_Init(&UART1TxDMA_Handler);
}

未完待续。。。。。。。。。。。。。。。。。。。。。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值