代码之家  ›  专栏  ›  技术社区  ›  Aleksander Alekseev

hal_ppp_transmit_dma和hal_ppp_transmit_it之间的实际区别是什么?

  •  0
  • Aleksander Alekseev  · 技术社区  · 6 年前

    这两个过程都允许我,比如,通过UART传输数据,并在完成任务后调用ISR。因此,乍一看,我觉得他们也在做同样的事情。你能解释一下区别是什么吗?即,xxx_IT程序是否在内部使用DMA(设备)?你能举一个例子,说明什么xxx-dma程序可以做xxx-it不能做的事,反之亦然(我个人只知道M2M方案)?在什么情况下我应该使用xxx_-dma而不是xxx_-it?

    2 回复  |  直到 6 年前
        1
  •  1
  •   David.O    6 年前

    在单片机中,DMA作为一个独立的单元工作。传输数据和获取数据不需要CPU时间,如本文所述。通常,在单片机中,DMA有助于从各种总线(如UART、SPI)传输数据,也有助于从其他模块(如DAC、ADC)传输数据,甚至在这些模块之间传输数据。如果您需要从RAM快速传输大型缓冲区,这非常方便,反之亦然。例如,示波器需要大量的ADC样本。每个IRQ调用可能需要几微秒,因此如果您需要1000个样本,那么它太慢,而且每个IRQ调用在处理有用数据时都会中断MCU作业流。所以DMA是解决方案。使用IRQ,您必须自己处理数据,放入缓冲区等,这也是额外的时间。如果你有TxRx,在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));

    此外,您还可以设置自己的内存缓冲区。它将通过DMA从SPI RX获取数据。

    dma eu initstructure.dma_memorybaseaddr=(uint32_t)(&spi_buffer_rx[0]);

    和你看到的Tx和Rx一样。

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

    当然,当您有更复杂的体系结构或者需要快速的数据流、读、写时,应该使用DMA。在ST32DMA中,每个外围设备都有具体的通道,所以您已经决定了哪个外围设备应该有哪个不是的DMA。尤其是当固件很复杂时。但通常不缺少DMA通道。所以,如果你的MCU中有DMA,甚至有适度的数据传输。为什么不使用它呢? 通常情况下,MCU会被各种非常方便的功能、模块所困扰。我看不到参数为什么不使用那些函数?当有许多新的宝贵方法使其发挥作用时,为什么每个人都应该只采用众所周知的老方法??

        2
  •  1
  •   0___________    6 年前

    DMA传输是在没有核心活动的情况下进行“后台”传输。

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

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