当前位置: 首页 > news >正文

【STM32】在标准库中使用DMA

1.MDA简介

DMA全称Direct Memory Access,直接存储区访问。

DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM和IO设备开辟一个直接传输数据的通道,使得CPU的效率大大提高。

STM32F4xx系列的DMA支持外设到存储器传输、存储器到外设传输和存储器到存储器传输三种传输模式。 这里的外设一般指外设的数据寄存器,比如ADC、SPI、I2C、DCMI等等外设的数据寄存器,存储器一般是指片内SRAM、外部存储器、片内Flash等等。

外设到存储器传输就是把外设数据寄存器内容转移到指定的内存空间。比如进行ADC采集时我们可以利用DMA传输把AD转换数据转移到我们定义的存储区中, 这样对于多通道采集、采样频率高、连续输出数据的AD采集是非常高效的处理方法。

存储区到外设传输就是把特定存储区内容转移至外设的数据寄存器中,这种多用于外设的发送通信。

存储器到存储器传输就是把一个指定的存储区内容拷贝到另一个存储区空间。功能类似于C语言内存拷贝函数memcpy, 利用DMA传输可以达到更高的传输效率,特别是DMA传输是不占用CPU的,可以节省很多CPU资源。

1.1外设通道选择

STM32F4xx系列资源丰富,具有两个DMA控制器,同时外设繁多,为实现正常传输,DMA需要通道选择控制。每个DMA控制器具有8个数据流, 每个数据流对应8个外设请求。在实现DMA传输之前,DMA控制器会通过DMA数据流x配置寄存器DMA_SxCR(x为0~7,对应8个DMA数据流)的CHSEL[2:0]位选择对应的通道作为该数据流的目标外设。

外设通道选择要解决的主要问题是决定哪一个外设作为该数据流的源地址或者目标地址。

DMA1各个通道的请求映像

DMA1各个通道的请求映像

DMA2各个通道的请求映像DMA2各个通道的请求映像每个外设请求都占用一个数据流通道,相同外设请求可以占用不同数据流通道。

1.2仲裁器

一个DMA控制器对应8个数据流,数据流包含要传输数据的源地址、目标地址、数据等等信息。如果我们需要同时使用同一个DMA控制器(DMA1或DMA2)多个外设请求时, 那必然需要同时使用多个数据流,那究竟哪一个数据流具有优先传输的权利呢?这就需要仲裁器来管理判断了。

仲裁器管理数据流方法分为两个阶段。第一阶段属于软件阶段,我们在配置数据流时可以通过寄存器设定它的优先级别, 具体配置DMA_SxCR寄存器PL[1:0]位,可以设置为非常高、高、中和低四个级别。第二阶段属于硬件阶段,如果两个或以上数据流软件设置优先级一样, 则他们优先级取决于数据流编号,编号越低越具有优先权,比如数据流2优先级高于数据流3。

1.3FIFO

每个数据流都独立拥有四级32位FIFO(先进先出存储器缓冲区)。DMA传输具有FIFO模式和直接模式。

直接模式在每个外设请求都立即启动对存储器传输。在直接模式下,如果DMA配置为存储器到外设传输那DMA会见一个数据存放在FIFO内, 如果外设启动DMA传输请求就可以马上将数据传输过去。

FIFO用于在源数据传输到目标地址之前临时存放这些数据。可以通过DMA数据流xFIFO控制寄存器DMA_SxFCR的FTH[1:0]位来控制FIFO的阈值, 分别为1/4、1/2、3/4和满。如果数据存储量达到阈值级别时,FIFO内容将传输到目标中。

FIFO对于要求源地址和目标地址数据宽度不同时非常有用,比如源数据是源源不断的字节数据,而目标地址要求输出字宽度的数据, 即在实现数据传输时同时把原来4个8位字节的数据拼凑成一个32位字数据。此时使用FIFO功能先把数据缓存起来,分别根据需要输出数据。

FIFO另外一个作用使用于突发(burst)传输。

2.DMA数据配置

DMA配置可能情况

2.1DMA传输模式

DMA2支持全部三种传输模式,而DMA1只有外设到存储器和存储器到外设两种模式。模式选择可以通过DMA_SxCR寄存器的DIR[1:0]位控制, 进而将DMA_SxCR寄存器的EN位置1就可以使能DMA传输。

在DMA_SxCR寄存器的PSIZE[1:0]和MSIZE[1:0]位分别指定外设和存储器数据宽度大小,可以指定为字节(8位)、半字(16位)和字(32位), 我们可以根据实际情况设置。直接模式要求外设和存储器数据宽度大小一样,实际上在这种模式下DMA数据流直接使用PSIZE,MSIZE不被使用。

2.2源地址和目标地址

DMA数据流x外设地址DMA_SxPAR(x为0~7)寄存器用来指定外设地址,它是一个32位数据有效寄存器。 DMA数据流x存储器0地址DMA_SxM0AR(x为0~7) 寄存器和DMA数据流x存储器1地址DMA_SxM1AR(x为0~7)寄存器用来存放存储器地址, 其中DMA_SxM1AR只用于双缓冲模式,DMA_SxM0AR和DMA_SxM1AR都是32位数据有效的。

当选择外设到存储器模式时,即设置DMA_SxCR寄存器的DIR[1:0] 位为“00”,DMA_SxPAR寄存器为外设地址,也是传输的源地址, DMA_SxM0AR寄存器为存储器地址,也是传输的目标地址。对于存储器到存储器传输模式,即设置DIR[1:0]位为“10”时, 采用与外设到存储器模式相同配置。而对于存储器到外设,即设置DIR[1:0]位为“01”时,DMA_SxM0AR寄存器作为为源地址,DMA_SxPAR寄存器作为目标地址。

2.3流控制器

流控制器主要涉及到一个控制DMA传输停止问题。DMA传输在DMA_SxCR寄存器的EN位被置1后就进入准备传输状态,如果有外设请求DMA传输就可以进行数据传输。 很多情况下,我们明确知道传输数据的数目,比如要传1000个或者2000个数据,这样我们就可以在传输之前设置DMA_SxNDTR寄存器为要传输数目值, DMA控制器在传输完这么多数目数据后就可以控制DMA停止传输。

DMA数据流x数据项数DMA_SxNDTR(x为0~7)寄存器用来记录当前仍需要传输数目,它是一个16位数据有效寄存器,即最大值为65535, 这个值在程序设计是非常有用也是需要注意的地方。我们在编程时一般都会明确指定一个传输数量,在完成一次数目传输后DMA_SxNDTR计数值就会自减,当达到零时就说 明传输完成。

如果某些情况下在传输之前我们无法确定数据的数目,那DMA就无法自动控制传输停止了,此时需要外设通过硬件通信向DMA控制器发送停止传输信号。 这里有一个大前提就是外设必须是可以发出这个停止传输信号,只有SDIO才有这个功能,其他外设不具备此功能。

2.4循环模式

循环模式相对应于一次模式。一次模式就是传输一次就停止传输,下一次传输需要手动控制,而循环模式在传输一次后会自动按照相同配置重新传输,周而复始直至被控制停止或传输发生错误。

通过DMA_SxCR寄存器的CIRC位可以使能循环模式。

2.5传输类型

DMA传输类型有单次(Single)传输和突发(Burst)传输。突发传输就是用非常短时间结合非常高数据信号率传输数据,相对正常传输速度, 突发传输就是在传输阶段把速度瞬间提高,实现高速传输,在数据传输完成后恢复正常速度,有点类似达到数据块“秒传”效果。为达到这个效果突发传输过程要占用AHB总线, 保证要求每个数据项在传输过程不被分割,这样一次性把数据全部传输完才释放AHB总线;而单次传输时必须通过AHB的总线仲裁多次控制才传输完成。

2.6直接模式

默认情况下,DMA工作在直接模式,不使能FIFO阈值级别。

直接模式在每个外设请求都立即启动对存储器传输的单次传输。直接模式要求源地址和目标地址的数据宽度必须一致, 所以只有PSIZE控制,而MSIZE值被忽略。突发传输是基于FIFO的所以直接模式不被支持。另外直接模式不能用于存储器到存储器传输。

在直接模式下,如果DMA配置为存储器到外设传输那DMA会见一个数据存放在FIFO内,如果外设启动DMA传输请求就可以马上将数据传输过去。

2.7双缓冲模式

设置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位,改变开始传输的目标存储区。

双缓冲模式应用在需要解码程序的地方是非常有效的。比如MP3格式音频解码播放,MP3是被压缩的文件格式, 我们需要特定的解码库程序来解码文件才能得到可以播放的PCM信号,解码需要一定的实际,按照常规方法是读取一段原始数据到缓冲区, 然后对缓冲区内容进行解码,解码后才输出到音频播放电路,这种流程对CPU运算速度要求高,很容易出现播放不流畅现象。 如果我们使用DMA双缓冲模式传输数据就可以非常好的解决这个问题,达到解码和输出音频数据到音频电路同步进行的效果。

2.8DMA中断

每个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中断控制位将产生直接模式错误中断。

3.DMA_InitTypeDef初始化结构体

typedef struct {uint32_t DMA_Channel;             //通道选择uint32_t DMA_PeripheralBaseAddr;  //外设地址uint32_t DMA_Memory0BaseAddr;     //存储器0地址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_FIFOMode;            //FIFO模式uint32_t DMA_FIFOThreshold;       //FIFO阈值uint32_t DMA_MemoryBurst;         //存储器突发传输uint32_t DMA_PeripheralBurst;     //外设突发传输
} DMA_InitTypeDef;
  1. DMA_Channel:DMA请求通道选择,可选通道0至通道7,每个外设对应固定的通道, 具体设置值需要查表 DMA1各个通道的请求映像 和表 DMA2各个通道的请求映像 ; 它设定DMA_SxCR寄存器的CHSEL[2:0]位的值。例如,我们使用模拟数字转换器ADC3规则采集4个输入通道的电压数据,查表 DMA2各个通道的请求映像 可知使用通道2。

  2. DMA_PeripheralBaseAddr:外设地址,设定DMA_SxPAR寄存器的值;一般设置为外设的数据寄存器地址, 如果是存储器到存储器模式则设置为其中一个存储区地址。ADC3的数据寄存器ADC_DR地址为((uint32_t)ADC3+0x4C)。

  3. DMA_Memory0BaseAddr:存储器0地址,设定DMA_SxM0AR寄存器值;一般设置为我们自定义存储区的首地址。 我们程序先自定义一个16位无符号整形数组ADC_ConvertedValue[4]用来存放每个通道的ADC值, 所以把数组首地址(直接使用数组名即可)赋值给DMA_Memory0BaseAddr。

  4. DMA_DIR:传输方向选择,可选外设到存储器、存储器到外设以及存储器到存储器。 它设定DMA_SxCR寄存器的DIR[1:0]位的值。ADC采集显然使用外设到存储器模式。

  5. DMA_BufferSize:设定待传输数据数目,初始化设定DMA_SxNDTR寄存器的值。 这里ADC是采集4个通道数据,所以待传输数目也就是4。

  6. DMA_PeripheralInc:如果配置为DMA_PeripheralInc_Enable,使能外设地址自动递增功能,它设定DMA_SxCR寄存器的PINC位的值; 一般外设都是只有一个数据寄存器,所以一般不会使能该位。ADC3的数据寄存器地址是固定并且只有一个所以不使能外设地址递增。

  7. DMA_MemoryInc:如果配置为DMA_MemoryInc_Enable,使能存储器地址自动递增功能,它设定DMA_SxCR寄存器的MINC位的值; 我们自定义的存储区一般都是存放多个数据的,所以使能存储器地址自动递增功能。我们之前已经定义了一个包含4个元素的数字用来存放数据, 使能存储区地址递增功能,自动把每个通道数据存放到对应数组元素内。

  8. DMA_PeripheralDataSize:外设数据宽度,可选字节(8位)、半字(16位)和字(32位),它设定DMA_SxCR寄存器的PSIZE[1:0]位的值。 ADC数据寄存器只有低16位数据有效,使用半字数据宽度。

  9. DMA_MemoryDataSize:存储器数据宽度,可选字节(8位)、半字(16位)和字(32位),它设定DMA_SxCR寄存器的MSIZE[1:0]位的值。 保存ADC转换数据也要使用半字数据宽度,这跟我们定义的数组是相对应的。

  10. DMA_Mode:DMA传输模式选择,可选一次传输或者循环传输,它设定DMA_SxCR寄存器的CIRC位的值。 我们希望ADC采集是持续循环进行的,所以使用循环传输模式。

  11. DMA_Priority:软件设置数据流的优先级,有4个可选优先级分别为非常高、高、中和低,它设定DMA_SxCR寄存器的PL[1:0]位的值。 DMA优先级只有在多个DMA数据流同时使用时才有意义,这里我们设置为非常高优先级就可以了。

  12. DMA_FIFOMode:FIFO模式使能,如果设置为DMA_FIFOMode_Enable表示使能FIFO模式功能; 它设定DMA_SxFCR寄存器的DMDIS位。ADC采集传输使用直接传输模式即可,不需要使用FIFO模式。

  13. DMA_FIFOThreshold:FIFO阈值选择,可选4种状态分别为FIFO容量的1/4、1/2、3/4和满;它设定DMA_SxFCR寄存器的FTH[1:0]位; DMA_FIFOMode设置为DMA_FIFOMode_Disable,那DMA_FIFOThreshold值无效。ADC采集传输不使用FIFO模式,设置改值无效。

  14. DMA_MemoryBurst:存储器突发模式选择,可选单次模式、4节拍的增量突发模式、8节拍的增量突发模式或16节拍的增量突发模式, 它设定DMA_SxCR寄存器的MBURST[1:0]位的值。ADC采集传输是直接模式,要求使用单次模式。

  15. DMA_PeripheralBurst:外设突发模式选择,可选单次模式、4节拍的增量突发模式、8节拍的增量突发模式或16节拍的增量突发模式, 它设定DMA_SxCR寄存器的PBURST[1:0]位的值。ADC采集传输是直接模式,要求使用单次模式。

4.DMA存储器到存储器模式实验

存储器到存储器模式可以实现数据在两个内存的快速拷贝。我们先定义一个静态的源数据,然后使用DMA传输把源数据拷贝到目标地址上,最后对比源数据和目标地址的数据,看看是否传输准确。

#ifndef __BSP_DMA_H
#define __BSP_DMA_H#ifdef __cplusplus
extern "C"{#endif#include "stm32f4xx.h"/* 相关宏定义,使用存储器到存储器传输必须使用DMA2 */
#define DMA_STREAM               DMA2_Stream0
#define DMA_CHANNEL              DMA_Channel_0
#define DMA_STREAM_CLOCK         RCC_AHB1Periph_DMA2
#define DMA_IT_TCIF              DMA_IT_TCIF0
#define DMA_IT_HTIF              DMA_IT_HTIF0
#define DMA_FLAG_TCIF            DMA_FLAG_TCIF0
#define DMA_FLAG_HTIF            DMA_FLAG_HTIF0
#define DMA_STREAM_IRQn          DMA2_Stream0_IRQn
#define DMA_STREAM_IRQHandler    DMA2_Stream0_IRQHandler#define BUFFER_SIZE              32void Init_M2M_DMA(void);
#ifdef __cplusplus
}
#endif#endif
#include "bsp_dma.h"
#include "stdio.h"
#include "string.h"/* 定义aSRC_Const_Buffer数组作为DMA传输数据源
const关键字将aSRC_Const_Buffer数组变量定义为常量类型 */
const uint32_t aSRC_Const_Buffer[BUFFER_SIZE]= {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传输目标存储器 */
uint32_t aDST_Buffer[BUFFER_SIZE];void Init_M2M_DMA(void)
{/* 使能DMA时钟 */RCC_AHB1PeriphClockCmd(DMA_STREAM_CLOCK, ENABLE);/* 复位初始化DMA数据流 */DMA_DeInit(DMA_STREAM);/* 确保DMA数据流复位完成 */while (DMA_GetCmdStatus(DMA_STREAM) != DISABLE) {}DMA_InitTypeDef  DMA_InitStructure;DMA_InitStructure.DMA_BufferSize=BUFFER_SIZE;//一次DMA事务传输的数据个数DMA_InitStructure.DMA_Channel=DMA_CHANNEL;DMA_InitStructure.DMA_DIR=DMA_DIR_MemoryToMemory;DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOThreshold_Full;DMA_InitStructure.DMA_Memory0BaseAddr= (uint32_t)aDST_Buffer;DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Word;DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)aSRC_Const_Buffer;DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Word;DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Enable;DMA_InitStructure.DMA_Priority=DMA_Priority_Low;DMA_Init(DMA_STREAM,&DMA_InitStructure);//配置中断控制器并使能中断NVIC_InitTypeDef NVIC_InitStruct;NVIC_InitStruct.NVIC_IRQChannel=DMA_STREAM_IRQn;NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;NVIC_Init(&NVIC_InitStruct);DMA_ITConfig(DMA_STREAM,DMA_IT_TCIF|DMA_IT_HTIF,ENABLE);DMA_ClearITPendingBit(DMA_STREAM,DMA_IT_TCIF|DMA_IT_HTIF);DMA_Cmd(DMA_STREAM,ENABLE);
}void DMA_STREAM_IRQHandler(void)
{if(SET== DMA_GetFlagStatus(DMA_STREAM,DMA_FLAG_HTIF)){printf("half transfer\r\n");DMA_ClearFlag(DMA_STREAM,DMA_FLAG_HTIF);}else if(SET== DMA_GetFlagStatus(DMA_STREAM,DMA_FLAG_TCIF)){printf("transfer complete\r\n");DMA_ClearFlag(DMA_STREAM,DMA_FLAG_TCIF);}//	if(SET==DMA_GetITStatus(DMA_STREAM,DMA_IT_HTIF))
//	{
//		//half transfer complete
//		printf("half transfer\r\n");
//		DMA_ClearITPendingBit(DMA_STREAM,DMA_IT_HTIF);
//		
//	}
//	else if(SET==DMA_GetITStatus(DMA_STREAM,DMA_IT_TCIF))
//	{
//		//transfer complete
//		
//		if(0== memcmp(aSRC_Const_Buffer,aDST_Buffer,BUFFER_SIZE))
//		{
//			printf("transfer complete\r\n");
//		}
//		DMA_ClearITPendingBit(DMA_STREAM,DMA_IT_TCIF);
//	}
}

编程注意事项:

  1. 对于存储器到存储器传输模式,源地址和目标地址的设置, 采用与外设到存储器模式相同配置。也就是源存储器地址当作外设地址。
  2. 我们在中断服务函数中检查ITStatus时发现,没有检测到half transfer的IT标志位,但是可以检测到transfer complete的IT标志位。但是FlagStatus都可以获取到,也不知道是啥问题。
  3. 如果我换为其他的DMA2_STREAM,比如DMA2_Stream1。甚至transfer complete的IT标志位都没有检测到。也不知道是啥原因。
  4. 对于存储器到存储器传输模式,只能选择DMA2。

2024/7/5更新
上文,我们提到在没有中断服务函数中没有检测到ITStatus,原来是因为那个DMA_ITConfig函数传参错误导致的。我们查看原函数注释发现:

/*** @brief  Enables or disables the specified DMAy Streamx interrupts.* @param  DMAy_Streamx: where y can be 1 or 2 to select the DMA and x can be 0*          to 7 to select the DMA Stream.* @param DMA_IT: specifies the DMA interrupt sources to be enabled or disabled. *          This parameter can be any combination of the following values:*            @arg DMA_IT_TC:  Transfer complete interrupt mask*            @arg DMA_IT_HT:  Half transfer complete interrupt mask*            @arg DMA_IT_TE:  Transfer error interrupt mask*            @arg DMA_IT_FE:  FIFO error interrupt mask* @param  NewState: new state of the specified DMA interrupts.*          This parameter can be: ENABLE or DISABLE.* @retval None*/

使能中断函数中没有明确是哪个明确到是哪一个dma stream,但是在get或者clear函数中的参数又明确到了是哪一个dma stream。

/*** @brief  Checks whether the specified DMAy Streamx interrupt has occurred or not.* @param  DMAy_Streamx: where y can be 1 or 2 to select the DMA and x can be 0*          to 7 to select the DMA Stream.* @param  DMA_IT: specifies the DMA interrupt source to check.*          This parameter can be one of the following values:*            @arg DMA_IT_TCIFx:  Streamx transfer complete interrupt*            @arg DMA_IT_HTIFx:  Streamx half transfer complete interrupt*            @arg DMA_IT_TEIFx:  Streamx transfer error interrupt*            @arg DMA_IT_DMEIFx: Streamx direct mode error interrupt*            @arg DMA_IT_FEIFx:  Streamx FIFO error interrupt*         Where x can be 0 to 7 to select the DMA Stream.* @retval The new state of DMA_IT (SET or RESET).*/

这里需要特别注意一下。。。。所以,我们更新一下代码

DMA_ITConfig(DMA_STREAM,DMA_IT_TC|DMA_IT_HT,ENABLE);void DMA_STREAM_IRQHandler(void)
{if(SET==DMA_GetITStatus(DMA_STREAM,DMA_IT_HTIF)){//half transfer completeprintf("half transfer\r\n");DMA_ClearITPendingBit(DMA_STREAM,DMA_IT_HTIF);}else if(SET==DMA_GetITStatus(DMA_STREAM,DMA_IT_TCIF)){//transfer completeif(0== memcmp(aSRC_Const_Buffer,aDST_Buffer,BUFFER_SIZE)){printf("transfer complete\r\n");}DMA_ClearITPendingBit(DMA_STREAM,DMA_IT_TCIF);}
}

相关文章:

【STM32】在标准库中使用DMA

1.MDA简介 DMA全称Direct Memory Access,直接存储区访问。 DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和…...

多线程详解

文章目录 多线程创建方式p3一些教程 狂神说 多线程创建方式p3 代码: package com.demo1;//创建线程方式一:继承Thread类,重写run()方法,调用start开启线程/*** 总结:注意,线程开启不一定立即执行,dCPU调度执行*/public class TestThread1 extends Thre…...

软件工程需求之:业务需求与用户需求

在软件开发项目中,"业务需求"和"用户需求"是两个核心概念,它们分别从不同的角度描述了软件应该具备的功能和特性。理解这两个概念的区别对于成功地规划和开发软件至关重要。 业务需求 业务需求主要关注于软件项目如何帮助实现企业…...

Nettyの源码分析

本篇为Netty系列的最后一篇,按照惯例会简单介绍一些Netty相关核心源码。 1、Netty启动源码分析 代码就使用最初的Netty服务器案例,在bind这一行打上断点,观察启动的全过程: 由于某些方法的调用链过深,节约篇幅&#xf…...

MySQL远程登录

root是超级管理员,默认情况下,root不能作为远程登录的用户名,远程登录前,需要将登录的数据库在本地登录,修改权限,输入: update user set host % where user root ; 回车键,再输…...

html的作业

目录 作业题目 1.用户注册 A图 B代码 2.工商银行电子汇款单 A图 B代码 3.李白诗词 A图 B代码 4.豆瓣电影 A图 B代码 学习产出&#xff1a; 作业题目 1.用户注册 A图 B代码 <!DOCTYPE html> <html lang"zh"> <head><meta charset&qu…...

【TORCH】查看dataloader里的数据,通过dataloader.dataset或enumerate

文章目录 dataloader.dataset示例代码使用自定义数据集使用 MNIST 数据集 说明 enumerate示例代码说明使用 MNIST 数据集的例子 dataloader.dataset 是的&#xff0c;您可以直接访问 train_loader 的数据集来查看数据&#xff0c;而不必通过 enumerate 遍历数据加载器。可以通…...

KDTree 简单原理与实现

介绍 K-D树是一种二叉树的数据结构&#xff0c;其中每个节点代表一个k维点&#xff0c;可用于组织K维空间中的点&#xff0c;其中K通常是一个非常大的数字。二叉树结构允许对多维空间中的点进行非常有效的搜索&#xff0c;包括最近邻搜索和范围搜索&#xff0c;树中的每个非叶…...

[c++] 可变参数模版

前言 可变参数模板是C11及之后才开始使用,学校的老古董编译器不一定能用 相信大家在刚入门c/c时都接触过printf函数 int printf ( const char * format, ... ); printf用于将数据格式化输出到屏幕上,它的参数非常有意思,可以支持任意数量,任意类型的多参数.而如果我们想实现类…...

QWidget窗口抗锯齿圆角的一个实现方案(支持子控件)2

QWidget窗口抗锯齿圆角的一个实现方案&#xff08;支持子控件&#xff09;2 本方案使用了QGraphicsEffect&#xff0c;由于QGraphicsEffect对一些控件会有渲染问题&#xff0c;比如列表、表格等&#xff0c;所以暂时仅作为研究&#xff0c;优先其他方案 在之前的文章中&#…...

数据结构之“队列”(全方位认识)

&#x1f339;个人主页&#x1f339;&#xff1a;喜欢草莓熊的bear &#x1f339;专栏&#x1f339;&#xff1a;数据结构 前言 上期博客介绍了” 栈 “这个数据结构&#xff0c;他具有先进后出的特点。本期介绍“ 队列 ”这个数据结构&#xff0c;他具有先进先出的特点。 目录…...

密码学复习

目录 基础 欧拉函数 欧拉函数φ(n)定义 计算方法的技巧 当a=a_1*a_2*……*a_n时 欧拉定理 剩余系 一些超简单密码 维吉尼亚 密钥fox 凯撒(直接偏移) 凯特巴氏(颠倒字母表) 摩斯密码(字母对应电荷线) 希尔(hill)密码 一些攻击 RSA 求uf+vg=1 快速幂模m^…...

【文献解析】一种像素级的激光雷达相机配准方法

大家好呀&#xff0c;我是一个SLAM方向的在读博士&#xff0c;深知SLAM学习过程一路走来的坎坷&#xff0c;也十分感谢各位大佬的优质文章和源码。随着知识的越来越多&#xff0c;越来越细&#xff0c;我准备整理一个自己的激光SLAM学习笔记专栏&#xff0c;从0带大家快速上手激…...

Http 实现请求body体和响应body体的双向压缩方案

目录 一、前言 二、方案一(和http header不进行关联) 二、方案二(和http header进行关联) 三、 客户端支持Accept-Encoding压缩方式,服务器就一定会进行压缩吗? 四、参考 一、前言 有时请求和响应的body体比较大,需要进行压缩,以减少传输的带宽。 二、方案一(和…...

C++(Qt)-GIS开发-简易瓦片地图下载器

Qt-GIS开发-简易瓦片地图下载器 文章目录 Qt-GIS开发-简易瓦片地图下载器1、概述2、安装openssl3、实现效果4、主要代码4.1 算法函数4.2 瓦片地图下载url拼接4.3 多线程下载 5、源码地址6、参考 更多精彩内容&#x1f449;个人内容分类汇总 &#x1f448;&#x1f449;GIS开发 …...

誉天教育7月开班计划:为梦想插上腾飞的翅膀!

随着夏日的脚步渐近&#xff0c;誉天教育也迎来了新一轮的学习热潮。在这个充满活力和希望的季节里&#xff0c;我们精心策划了7月的开班计划&#xff0c;旨在为广大学子提供一个优质、高效的学习平台&#xff0c;助力他们追逐梦想&#xff0c;实现自我价值。 本月 Linux云计算…...

STM32基础篇:GPIO

GPIO简介 GPIO&#xff1a;即General Purpose Input/Output&#xff0c;通用目的输入/输出。就是一种片上外设&#xff08;内部模块&#xff09;。 对于STM32的芯片来说&#xff0c;周围有一圈引脚&#xff0c;有时需要对引脚进行读写&#xff08;读&#xff1a;从外部输入一…...

HTTPS 发送请求出现TLS握手失败

最近在工作中&#xff0c;调外部接口&#xff0c;发现在clientHello步骤报错&#xff0c;服务端没有返回serverHello。 从网上找了写方法&#xff0c;都没有解决&#xff1b; 在idea的vm options加上参数&#xff1a; -Djavax.net.debugSSL,handshake 把SSL和handshake的日…...

数字化精益生产系统--IFS财务管理系统

IFS财务管理系统是一款功能丰富、高效且灵活的企业财务管理软件&#xff0c;广泛应用于多个行业和不同规模的企业中。以下是对IFS财务管理系统的功能设计&#xff1a;...

基于SpringBoot的校园台球厅人员与设备管理系统

本系统是要设计一个校园台球厅人员与设备管理系统&#xff0c;这个系统能够满足校园台球厅人员与设备的管理及用户的校园台球厅人员与设备管理功能。系统的主要功能包括首页、个人中心、用户管理、会员账号管理、会员充值管理、球桌信息管理、会员预约管理、普通预约管理、留言…...

免杀笔记 ---> Session0--DLL注入

刚更新完上一篇&#xff0c;于是我们就马不停蹄的去跟新下一篇&#xff01;&#xff01; Session0注入 &#xff1a;&#xff1a; 各位看官如果觉得还不错的可以给博主点个赞&#x1f495;&#x1f495; 这次&#xff0c;我把这个脚本直接传到Github上了 喜欢的师傅点个Star噢…...

如何做好IT类的技术面试?

我们在找工作时&#xff0c;需要结合自己的现状&#xff0c;针对意向企业做好充分准备。作为程序员&#xff0c;你有哪些面试IT技术岗的技巧&#xff1f; 方向一&#xff1a;分享你面试IT公司的小技巧 我分享一些基于广泛观察和用户反馈的面试IT公司的小技巧&#xff1a; 技术准…...

A7 配置方式Master SPI如何更改位宽

在 FPGA 完成自初始化后&#xff0c;INIT 释放&#xff0c;FPGA 对模式引脚 (M[2:0]) 进行采样&#xff0c;以确定使用哪种配置模式。当模式引脚 M[2:0] 001 时&#xff0c;FPGA 开始以大约 3 MHz 的频率在 CCLK 上输出时钟。随后&#xff0c;FCS_B 驱动为低电平&#xff0c;紧…...

linux kthread任务管理

目录 一、linux 创建内核线程1.1 kthread_create1.2 kthread_create_worker kthread_queue_work 二、设置线程优先级和调度策略2.1 sched_setscheduler2.2 调度策略 一、linux 创建内核线程 1.1 kthread_create 在 linux 中&#xff0c;可以使用 kthread_create 接口创建内核…...

第一节 网络安全概述

一.网络空间安全 网络空间&#xff1a;一个由信息基础设施组成相互依赖的网络。 ---- 海陆空天&#xff08;大海、陆 地、天空、航天&#xff09; 通信保密阶段 ---- 计算机安全 ----- 信息系统安全 ----- 网络空间安全 计算机安全&#xff1a;开始秉持着“严于律己&#x…...

星光云VR全景系统源码

星光云VR全景系统源码 体验地址请查看...

spdlog一个非常好用的C++日志库(七): 源码分析之异常类spdlog_ex

目录 1.自定义异常类spdlog_ex 1.1.通用异常 1.2.系统调用异常 1.3.what()函数 2.异常的使用 2.1.抛出异常 2.2.控制异常使用 1.自定义异常类spdlog_ex 标准库异常类&#xff08;std::exception&#xff09;系列&#xff0c;能满足大多数使用异常的场景&#xff0c;但对…...

从一次 SQL 查询的全过程了解 DolphinDB 线程模型

1. 前言 DolphinDB 的线程模型较为复杂&#xff0c;写入与查询分布式表都可能需要多个类型的线程。通过了解 SQL 查询的全过程&#xff0c;可以帮助我们了解 DolphinDB 的线程模型&#xff0c;掌握 DolpinDB 的配置&#xff0c;以及优化系统性能的方法。 本教程以一个分布式 …...

Vue3.js“非原始值”响应式实现基本原理笔记(二)

如果您觉得这篇文章有帮助的话&#xff01;给个点赞和评论支持下吧&#xff0c;感谢~ 作者&#xff1a;前端小王hs 阿里云社区博客专家/清华大学出版社签约作者/csdn百万访问前端博主/B站千粉前端up主 此篇文章是博主于2022年学习《Vue.js设计与实现》时的笔记整理而来 书籍&a…...

论文 | PRCA: 通过可插拔奖励驱动的上下文适配器拟合用于检索问答的黑盒大语言模型

论文全称&#xff1a;PRCA: Fitting Black-Box Large Language Models for Retrieval Question Answering via Pluggable Reward-Driven Contextual Adapter 核心问题&#xff1a;如何在检索增强式问答&#xff08;ReQA&#xff09;任务中&#xff0c;利用大型语言模型&#xf…...

网络状态的智能感知:WebKit 支持 Network Information API 深度解析

网络状态的智能感知&#xff1a;WebKit 支持 Network Information API 深度解析 在现代 Web 应用中&#xff0c;理解用户的网络连接状态对于提供适应性体验至关重要。Network Information API&#xff0c;一个新兴的 Web API&#xff0c;允许 Web 应用访问设备的网络信息&…...

Vue3基础知识:组合式API中的provide和inject,他们作用是什么?如何使用?以及案例演示

1.provide和inject相较于父子传递的不同在于provide,inject可以用于跨层级通信&#xff08;通俗易懂的讲就是可以实现爷孙之间的直接信息传递&#xff09;。 1.跨层级传递数据 1.在顶层组件通过provide函数提供数据 2.底层组件通过inject函数获取数据 演示一&#xff1a;跨…...

Transformer自注意力机制(Self-Attention)模型

​ 上一篇我们介绍了transform专题一&#xff1a;Seq2seq model&#xff0c;也知道了transfrom属于seq2seq模型&#xff0c;这一排篇咱们接着介绍另外几种seq2seq架构的模型。&#xff09;RNN&#xff08;循环神经网络&#xff09;CNN&#xff08;卷积神经网络&#xff09;&…...

【计算机体系结构】缓存的false sharing

在介绍缓存的false sharing之前&#xff0c;本文先介绍一下多核系统中缓存一致性是如何维护的。 目前主流的多核系统中的缓存一致性协议是MESI协议及其衍生协议。 MESI协议 MESI协议的4种状态 MESI协议有4种状态。MESI是4种状态的首字母缩写&#xff0c;缓存行的4种状态分别…...

Ubuntu24.04 Isaacgym的安装

官方论坛 rl-接口 教程1 教程2 教程3 1.下载压缩包 link 2. 解压 tar -xvf IsaacGym_Preview_4_Package.tar.gz核心教程在 isaacgym/docs/install.html下 3. 从源码安装 Ubuntu24.04还需首先进入虚拟环境 python -m venv myenv # 创建虚拟环境&#xff0c;已有可跳过…...

docker 设置代理,通过代理服务器拉取镜像

docker 拉取目标镜像需要通过代理服务器进行时&#xff0c;可以通过为 docker 配置全局代理来实现。 注&#xff1a;Linux 上通过临时命令 export HTTP_PROXY 设置的代理&#xff0c;对 curl 这些有用&#xff0c;但是对 docker pull 不起作用。 示例 假设您的代理服务器地址是…...

OpenCV教程02:图像处理系统1.0(翻转+形态学+滤波+缩放+旋转)

-------------OpenCV教程集合------------- Python教程99&#xff1a;一起来初识OpenCV&#xff08;一个跨平台的计算机视觉库&#xff09; OpenCV教程01&#xff1a;图像的操作&#xff08;读取显示保存属性获取和修改像素值&#xff09; OpenCV教程02&#xff1a;图像处理…...

人工智能在招投标领域的运用---监控视频连续性检测

作者&#xff1a;舒城县公共交易中心 zhu_min726126.com 原创&#xff0c;转载请注明出处。 摘要 随着人工智能&#xff08;AI&#xff09;技术的飞速发展&#xff0c;其在各个领域的应用日益广泛。本文旨在探讨人工智能在招投标领域的运营&#xff0c;重点介绍AI对视频完整…...

加装德国进口高精度主轴 智能手机壳「高质量高效率」钻孔铣槽

在当前高度智能化的社会背景下&#xff0c;智能手机早已成为人们生活、工作的必备品&#xff0c;智能手机壳作市场需求量巨大。智能手机壳的加工过程涉及多个环节&#xff0c;包括钻孔和铣槽等。钻孔要求精度高、孔位准确&#xff0c;而铣槽则需要保证槽位规整、深度适宜。这些…...

Java Stream API 常用操作技巧

Java 8 引入的 Stream API 为集合操作提供了一种声明式编程模型&#xff0c;极大地简化了数据处理的复杂性。本文将介绍 Java Stream API 的几种常用操作方式&#xff0c;帮助开发者更高效地处理集合数据。 1. 过滤&#xff08;Filtering&#xff09; 过滤是选择集合中满足特…...

SwiftData 模型对象的多个实例在 SwiftUI 中不能及时同步的解决

概览 我们已经知道,用 CoreData 在背后默默支持的 SwiftUI 视图在使用 @FetchRequest 来查询托管对象集合时,若查询结果中的托管对象在别处被改变将不会在 FetchedResults 中得到及时的刷新。 那么这一“囧境”在 SwiftData 里是否也会“卷土重来”呢?空说无益,就让我们在…...

Android 系统网络、时间服务器配置修改

1.修改wifi 是否可用的检测地址&#xff1a; 由于编译的源码用的是谷歌的检测url,国内访问不了&#xff0c;系统会认为wifi网络受限&#xff0c;所以改成国内的地址 adb shell settings delete global captive_portal_https_urladb shell settings delete global captive_por…...

类和对象深入理解

目录 static成员概念静态成员变量面试题补充代码1代码2代码3如何访问private中的成员变量 静态成员函数静态成员函数没有this指针 特性 友元友元函数友元类 内部类特性1特性2 匿名对象拷贝对象时的一些编译器优化 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接…...

在postgres数据库中的几个简单用法

1、例如表中coord_str的字段数据是121.12334 31.3435这样的字符串&#xff0c;如何将对应的数据转换成geometry数据&#xff0c;实现如下 UPDATE coordinates SET geom ST_GeomFromText(POINT( || split_part(coord_str, , 1) || || split_part(coord_str, , 2) || ), 43…...

SQLServer Manager Studio扩展开发从入门到弃坑

Visualstudio的已经开发好了&#xff0c;可这个就是不行&#xff0c;直接运行点这些按钮加载失败&#xff0c;而我直接不调试模式&#xff0c;则直接什么都没有&#xff0c;调试 发现是根本没触发逻辑的。 文档资料太少&#xff0c; 我换了几个ssms.exe都不行&#xff0c;18-20…...

ComfyUI预处理器ControlNet简单介绍与使用(附件工作流)

简介 ControlNet 是一个很强的插件&#xff0c;提供了很多种图片的控制方式&#xff0c;有的可以控制画面的结构&#xff0c;有的可以控制人物的姿势&#xff0c;还有的可以控制图片的画风&#xff0c;这对于提高AI绘画的质量特别有用。接下来就演示几种热门常用的控制方式 1…...

【篇三】在vue3上实现阿里云oss文件直传

之前写了两篇关于文件上传的文章 【篇一】使用springbootvue实现阿里云oss上传 【篇二】使用springbootvue实现阿里云oss文件直传&#xff0c;解决大文件分片上传问题 今天介绍一下在vue3中实现阿里云oss文件直传&#xff0c;主要是基于篇二中的源码进行修改&#xff0c;看具体…...

OceanBase v4.2 特性解析:对Json与Xml的扩展支持

1. 背景 OceanBase的Oracle模式当前已实现对XMLType类型的支持&#xff0c;不仅包含了基本的构造、查询、更新以及格式转换功能&#xff0c;还支持使用Xpath查询从XML数据中提取特定值。在V 4.2.2 版本中&#xff0c;我们进一步扩展了Oracle模式下对XMLType的支持&#xff0c;…...

《框架封装 · 统一异常处理和返回值包装》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…...

深入WebKit:揭秘复杂文档的高效渲染之道

深入WebKit&#xff1a;揭秘复杂文档的高效渲染之道 在当今信息爆炸的时代&#xff0c;网页不再仅仅是简单的文本和图片的集合&#xff0c;而是充满了复杂布局和丰富媒体内容的交互式平台。WebKit 作为众多流行浏览器的心脏&#xff0c;其布局引擎承担着将 HTML、CSS 代码转换…...