HAL_PPP_Transmit_DMA 和 HAL_PPP_Transmit_IT 之间的实际区别是什么?

What is practical difference between HAL_PPP_Transmit_DMA and HAL_PPP_Transmit_IT?

这两个过程都允许我通过 UART 传输数据并在工作完成后调用 ISR。因此,乍一看,我觉得他们在做同样的事情。你能解释一下有什么区别吗? IE。 xxx_IT 程序在内部使用 DMA(设备)吗?您能否举例说明 xxx_DMA 程序可以做什么 xxx_IT 不能做什么,反之亦然(我个人只知道 M2M 场景)?在什么情况下我应该使用 xxx_DMA 而不是 xxx_IT?

DMA传输做无核传输activity"in the background"

每次接收到或必须发送字符时都会调用中断例程。核心在每个字节传输或接收期间都很忙。

在您的情况下,您不知道 DMA 是什么,这对您来说并不重要。由于您不会从 DMA 传输中受益,因此您应该使用中断传输,因为它更容易设置。

DMA 在 MCU 中作为一个单独的单元工作。正如此处提到的 P__J__ 那样,传输数据和获取数据不需要 CPU 时间。通常在 MCU 中,dma 有助于从 UART、SPI 等各种总线传输数据,也可以从 DAC、ADC 等其他模块传输数据,甚至在这些模块之间传输数据。如果您需要从 RAM 快速传输大缓冲区,反之亦然,这将非常方便。例如,您需要大量用于示波器的 adc 样本。每个 irq 调用可能需要微秒,所以如果你需要 1000 个样本,它太慢了,而且每个 irq 调用 - 在处理有用数据时中断 MCU 作业流。所以 DMA 是解决方案。使用 IRQ,您必须自己处理数据,放入缓冲区等,这也是额外的时间。如果你有 TX RX 比它在 IRQ 上花费更多的时间。而 DMA 只是在后台写入或读取您的缓冲区。这是一个小例子:

#define BufferSize 50
uint8_t SPI_Buffer_Rx[BufferSize];
uint8_t SPI_Buffer_Tx[BufferSize];
//configuring  SPI

RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
SPI_RxFIFOThresholdConfig(SPI2, SPI_RxFIFOThreshold_HF);
SPI_InitStructure.SPI_Mode = SPI_Mode_Slave;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 0;
SPI_Init(SPI2, &SPI_InitStructure);
SPI_CalculateCRC(SPI2, DISABLE);

// RX and TX DMA configuration
/* SPI_SLAVE_Rx_DMA_Channel configuration ---------------------------------*/
RCC_AHBPeriphClockCmd(SPI_SLAVE_DMA_CLK, ENABLE);
DMA_DeInit(SPI_SLAVE_Rx_DMA_Channel);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(SPI2->DR));
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(&SPI_Buffer_Rx[0]);
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = BufferSize;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(SPI_SLAVE_Rx_DMA_Channel, &DMA_InitStructure);

/* SPI_SLAVE_Tx_DMA_Channel configuration ---------------------------------*/
DMA_DeInit(SPI_SLAVE_Tx_DMA_Channel);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(SPI2->DR));
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(&SPI_Buffer_Tx[0]);
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = BufferSize;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(SPI_SLAVE_Tx_DMA_Channel, &DMA_InitStructure);

不细说你可以看到DMA可以直接处理来自SPI数据寄存器的数据。

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(SPI2->DR));

您也可以在 RAM 中设置自己的缓冲区。它将通过DMA从SPI RX获取数据。

DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)(&SPI_Buffer_Rx[0]);

如您所见,TX 和 RX 也一样。

您还可以控制大小、类型,例如:FIFO 等。这取决于您的情况。

当你有更复杂的架构或当你需要快速的数据流、读、写时,你绝对应该使用 DMA。在 ST32 中,dma 为每个外设提供了具体的通道,因此您可以决定哪些外设应该有 DMA,哪些没有。特别是当您的固件很复杂时会发生这种情况。但通常不乏DMA通道。因此,如果您的 MCU 中有 DMA,甚至有适度的数据传输。为什么不使用它? MCU 经常卡在不同的非常方便的功能、模块中。我没有看到为什么不使用这些功能的争论?既然有很多新的宝贵方法可以使它发挥作用,为什么任何人都应该只采用旧的、众所周知的方法呢??