ARM微控制器DMA控制器使用示例(2)

3 DMA传送延迟管理

在开发基于微控制器的固件应用程序时,用户必须确保不会出现缓冲区欠载或过载的情况,因此,准确知晓每次传输的DMA延迟是非常必要的,这有助于验证内部系统是否能够支持应用程序所需的全部数据带宽。

3.1 DMA传输时间

3.1.1 默认DMA传输时序

如第2.2.2节所述,从外设到内存的DMA传输需要两次总线访问:

  • 第一次访问:通过外设端口触发,由外设的请求引起,包括以下步骤:

    • DMA外设端口请求的仲裁过程
    • 计算外设的地址
    • 从外设读取数据到DMA的FIFO(DMA的源)
  • 第二次访问:通过内存端口触发,可以是当FIFO达到阈值时(使用FIFO模式)或在外设读取完成后立即进行(使用直接模式),包括以下步骤:

    • DMA内存端口请求的仲裁过程
    • 计算内存的地址
    • 将数据写入SRAM(DMA的目标)

当从内存传输数据到外设时,同样需要两次访问:

  • 第一次访问:DMA预测外设的访问需求,从内存中读取数据并存储到FIFO中,确保一旦触发DMA外设请求,就能立即进行数据传输。这包括:

    • DMA内存端口请求的仲裁过程
    • 计算内存的地址
    • 从内存读取数据到DMA的FIFO(DMA的源)
  • 第二次访问:当外设请求被触发时,DMA外设端口会生成一次数据传输。这包括:

    • DMA外设端口请求的仲裁过程
    • 计算外设的地址
    • 将加载的数据写入到外设的地址(DMA的目标)

通常,DMA流TS的总传输时间由以下公式确定: T_S = T_{SP}(外设访问/传输时间) +T_{SM}(内存访问/传输时间) 其中: T_{SP}是DMA外设端口访问和传输的总时长,计算公式为:

T_{SP} = t_{PA} + t_{PAC} + t_{BMA} + t_{EDT} + t_{BS}

 

表4 外设端口的访问/传输时间与所采用的DMA路径的关系

描述通过总线矩阵到AHB的DMA直接路径到APB外设
t_{PA} DMA外设端口仲裁时间1个AHB周期1个AHB周期1个AHB周期
t_{PAC}: 外设地址计算时间1个AHB周期1个AHB周期1个AHB周期
t_{BMA}: 总线矩阵仲裁时间(无并发时)^{(1)}1个AHB周期1个AHB周期不适用
t_{EDT}: 有效数据传输时间^{(2)(3)}1个AHB周期2个APB周期2个APB周期
t_{BS}: 总线同步时间不适用1个AHB周期1个AHB周期

 1. t_{BMA}的默认值设为零。

2. 对于FMC,根据所使用的外部存储器,可能会增加一个额外的周期。根据外部存储器的时序要求,可能会增加额外的AHB周期。

3. 在进行突发传输时,有效数据传输时间依赖于突发的长度(例如,INC4配置下t_{EDT}为4个AHB周期)。

TSM 是 DMA 内存端口访问和传输的总时间,它等于:

T_{SM}=t_{MA}+t_{MAC}+t_{BMA}+t_{SRAM}

其中:

  • t_{MA}是内存地址计算时间。
  • t_{MAC} 是内存端口请求仲裁时间。
  • t_{BMA}是总线矩阵仲裁时间(如果有并发访问请求)。
  • t_{SRAM} 是数据写入 SRAM(静态随机存取存储器)的时间。

表5 内存端口的访问/传输时间

描述延迟时长
t_{MA}: DMA内存端口仲裁时间1个AHB周期
t_{MAC}: 内存地址计算时间1个AHB周期
t_{BMA}: 总线矩阵仲裁时间(无并发访问时)^{(1)}1个AHB周期^{(2)}^{^{}}

 1. t_{BMA}的 默认值设为零。

2. 对于连续的SRAM访问(在没有其他主设备在此期间访问同一SRAM的情况下),T_{BMA}等于0个周期。

3.1.2 DMA传输时间与并发访问的影响

如果多个主设备尝试同时对同一从设备进行访问,可能会导致DMA服务时间在外设和内存的最坏情况访问/传输时间基础上增加额外的延迟。以下是影响DMA流服务总延迟时间的几个关键因素:

  • 当多个主设备同时对同一个AHB目标进行访问时,DMA的延迟将受到影响。如第2.1.2节所述,只有在总线矩阵仲裁器批准DMA的访问请求后,DMA传输才能启动。
  • 如果多个主设备(包括DMA和CPU)同时尝试访问同一个AHB至APB桥接,由于AHB至APB桥接的仲裁机制,DMA传输的时间将会延长,这一点在第2.3.2节中有详细说明。

在设计使用DMA传输的系统时,这些因素必须被考虑在内,以确保系统能够满足实时性能要求和数据带宽需求。了解并预测这些延迟对于优化系统的整体性能和响应速度至关重要。

3.2 示例

3.2.1 从ADC到SRAM的DMA数据传输

该示例适用于ARM内核微控制器。

模拟到数字转换器(ADC)被设置为连续三重交错模式。在此模式下,ADC以最大速率(36 MHz)持续转换单一模拟输入通道。ADC的预分频器设置为2,采样时间设定为1.5个周期,而交错模式下连续两次ADC采样间的间隔设定为5个周期。

DMA2的流0负责将ADC转换后的数值传输到SRAM的缓冲区中。DMA2通过直接路径访问ADC,但对于SRAM的访问则是通过总线矩阵来实现的。

在本示例中,从ADC的DMA触发信号(ADC EOC)到将ADC数值写入SRAM的总DMA延迟时间,若AHB/APB预分频器设为1,则为9个AHB周期;若预分频器设为2,则为11个AHB周期。

注释:在使用FIFO(先进先出队列)时,一旦FIFO达到用户所配置的阈值,就会触发DMA内存端口的访问。

表6 DMA外设端口(ADC)传输延迟

描述延迟(当AHB/APB预分频器等于1)延迟(当AHB/APB预分频器等于2)
t_{PA} DMA外设端口仲裁时间1个AHB周期1个AHB周期
t_{PAC}: 外设地址计算时间1个AHB周期1个AHB周期
t_{BMA}: 总线矩阵仲裁不适用^{(1)}不适用^{(1)}
t_{EDT}: 有效数据传输时间2个AHB周期4个AHB周期
t_{BS}: 总线同步时间1个AHB周期1个AHB周期
T_{SP}: 外设端口的DMA传输总时间5个AHB周期7个AHB周期

 1. DMA2通过直接路径访问ADC,因此不涉及总线矩阵仲裁。

以本例为参考,ADC的DMA触发信号(即ADC的EOC,即转换结束标志)至将ADC的数值写入SRAM的整个过程中的总DMA延迟时间,若AHB/APB预分频器设为1,则为9个AHB周期;若预分频器设为2,则为11个AHB周期。

注释:在使用FIFO模式时,一旦FIFO的填充水平达到用户所设定的阈值,就会激发DMA内存端口的访问操作。

3.2.2 SPI全双工DMA传输示例

示例使用的微控制器,且基于SPI1外设,配置了两个DMA请求:

  • DMA2_Stream2用于SPI1接收(SPI1_RX):此流被设定为最高优先级,目的是及时处理SPI1接收到的数据,并将这些数据从SPI1_DR寄存器传输到SRAM缓冲区。
  • DMA2_Stream3用于SPI1发送(SPI1_TX):此流负责将数据从SRAM缓冲区传输到SPI1_DR寄存器。

AHB时钟频率与APB2时钟频率相等(84 MHz),SPI1被配置为以最大速率(42 MHz)运行。DMA2_Stream2(用于SPI1接收)会在DMA2_Stream3(用于SPI1发送)之前触发,后者在两个AHB周期之后触发。

在这种配置下,CPU将无限期地轮询I2C1_DR寄存器。由于I2C1外设位于APB1总线上,而SPI1外设位于APB2总线上,系统的传输路径如下:

  • DMA2通过直接路径访问APB2(不经过总线矩阵),
  • CPU通过总线矩阵访问APB1。

这个设置旨在展示,即使CPU在APB1上进行轮询,DMA的传输时序也不会受到影响。以下图表概括了SPI全双工DMA传输的时间安排,包括发送和接收模式下的DMA时序,以及每个操作的时间调度:

图16 SPI全双工DMA传输时间图

 根据图16的描述:

  • CPU在APB1上的轮询操作不会对APB2上的DMA传输延迟产生影响。
  • 在DMA2_Stream2(SPI1_RX)传输过程中,到了第八个AHB时钟周期,不需要进行总线矩阵仲裁,因为假设最后一个访问SRAM的主设备是DMA2,所以不需要重新进行仲裁。
  • 在DMA2_Stream3(SPI1_TX)传输过程中,该DMA流会提前从SRAM中读取数据并将其写入FIFO(先进先出队列),然后一旦触发,DMA外设端口(目标是SPI1)便开始工作。
  • 对于DMA2_Stream3,在其总线同步周期内,DMA外设仲裁阶段(耗时1个AHB周期)得以执行。

4 DMA控制器编程时的技巧

4.1 关闭DMA的软件步骤

要关闭连接到DMA流的外设,必须执行以下步骤:

  • 关闭连接到该外设的DMA流。
  • 等待DMA_SxCR寄存器中的EN位被清零。 只有完成这些步骤后,才能安全地禁用外设。应将外设控制寄存器中的DMA请求使能位清零,以确保清除任何来自外设的待处理请求。 注意:在这两种情况下,传输完成中断标志(TCIF)将在DMA_LISR或DMA_HISR中设置,以指示由于流被禁用而导致传输结束。

4.2 启用新传输前清除DMA标志

在启用新传输之前,用户必须确保DMA_LISR或DMA_HISR中的传输完成中断标志(TCIF)已被清除。 作为一般建议,建议在开始新传输之前清除DMA_LIFCR和DMA_HIFCR寄存器中的所有标志。

4.3 启用DMA的软件步骤

启用DMA时,应遵循以下软件步骤:

  • 配置适当的DMA流。
  • 启用所使用的DMA流(设置DMA_SxCR寄存器中的EN位)。
  • 启用所使用的外设。应在外设控制寄存器中设置DMA请求使能位。 注意:如果用户在对应的DMA流准备好之前就启用了所使用的外设,可能会因为DMA还未能为外设提供所需的第一个数据而导致FIFO错误中断标志(FEIF)被设置。

4.4 当NDTR为0时的内存到内存传输

当配置DMA流以执行普通模式下的内存到内存传输时,一旦NDTR值降至0,传输完成标志就会被设置。此时,如果用户启用了该流的使能位,内存到内存传输将自动使用上一次NDTR的值重新触发。

4.5 外设突发传输时的PINC/MINC为0

当DMA突发特性配合外设地址递增(PINC)或内存地址递增(MINC)禁用时,可以访问支持突发传输的内部或外部(如FSMC)外设。这种模式确保在DMA流进行事务期间不会被其他DMA流中断。

4.6 双重映射的DMA请求

当用户配置两个或更多DMA流以响应同一外设请求时,软件应确保在启用新的DMA流之前,当前DMA流已完全禁用。

4.7 最佳DMA吞吐量配置

在使用STM32F4xx系列微控制器并DMA服务高速外设时,如果AHB频率降低,建议将堆栈和堆放在CCM(CPU可以通过D-bus直接寻址)中,而不是放在SRAM上,以避免CPU和DMA在访问SRAM内存时产生额外的并发冲突。

4.8 DMA传输的暂停

用户可以随时暂停DMA传输,以便稍后重新启动或在传输结束前明确禁用。 有两种情况:

  • 如果流禁用了传输,并且不打算从停止点重新启动,则除了清除DMA_SxCR寄存器中的EN位以禁用流,并等待EN位被清零之外,无需采取其他特别措施。作为结果:

        ——DMA_SxNDTR寄存器包含了流停止时剩余的数据项数量,使软件能够确定在流被中断之前传输了多少数据项。

  • 如果流暂停了传输,以便稍后通过重新启用流来恢复,则软件在禁用流(将EN位设为“0”)后必须读取DMA_SxNDTR寄存器,以了解已经收集的数据项数量。然后:

        ——必须更新外设和/或内存地址,以调整地址指针。

        ——SxNDTR寄存器必须更新为剩余要传输的数据项数量(即流被禁用时读取的值)。

        ——之后,可以重新启用流以从停止的点开始恢复传输。 注意:在这两种情况下,传输完成中断标志(TCIF)将在DMA_LISR或DMA_HISR中设置,以指示由于流中断而导致的传输结束。

4.9 利用DMA2控制器及系统架构的灵活性

本节旨在展示如何利用STM32架构和DMA控制器提供的灵活性。以这种灵活性为例,我们将探讨如何反向操作DMA2的AHB外设端口和内存端口,并确保正确管理外设数据传输。为了实现这一点并接管对DMA2常规行为的控制,我们需要审视DMA2的工作模式。

由于DMA2的两个端口都连接到AHB总线矩阵,并且与AHB从设备有着对称的连接,这种架构允许根据软件配置,在外设端口和内存端口上沿一个或另一个方向传输数据。

4.9.1 在DMA2 AHB端口上反向传输的考虑

软件具有根据需求配置DMA2流传输模式的灵活性。根据配置,一个DMA2 AHB端口可能被设置为读取方向,而另一个设置为写入方向。

表8 DMA AHB端口方向与传输模式配置的对应关系

传输模式DMA2 AHB内存端口DMA2 AHB外设端口
从内存到外设读取(Read)写入(Write)
从外设到内存写入(Write)读取(Read)
内存之间传输写入(Write)读取(Read)

 正如第2.2.2节“DMA传输状态”中所讨论的,外设端口上的传输是由外设的请求来触发的,而内存端口上的传输可以由FIFO阈值(在使用FIFO模式时)触发,或者在外设读取完成后立即触发(在使用直接模式时)。

在使用DMA2内存端口来管理外设时,我们需要特别注意以下几个方面:预触发传输、缓冲区传输,以及对最后数据的管理。

预触发传输

如在第2.2.2节“DMA传输状态”中所述,当配置为内存到外设的传输模式(通过内存端口进行数据读取)时,DMA会提前读取数据,一旦DMA流被启动,就会立即进行数据读取。在直接模式下,会有一个数据被预先读取并缓冲,而在使用DMA FIFO模式时,可以预先缓冲多达4个32位宽的数据字。

在通过DMA2内存端口管理外设的读取操作时,软件必须确保在启动DMA之前先启动外设,这样可以保证首次DMA访问的有效性。

图17 展示了在外设触发的情况下,DMA在外设端口和内存端口上的访问模式。

图17 存储写入外设DMA传送模式

最后数据读取的管理

每个DMA流都有一个4×32位宽字的FIFO,用于在AHB端口间缓冲数据。在通过DMA的内存端口管理外设的读取操作时,软件必须确保额外读取4个宽字的数据,以保证最后的有效数据能够从DMA的FIFO中成功传输出去。

禁用直接模式时的缓冲传输处理: 当在外设的间接模式下(即FIFO模式被启用)通过内存端口向其写入数据时,软件需要确保对该端口的访问是由预设的FIFO阈值触发。一旦达到设定的阈值,数据便会从FIFO传送至内存端口的目标地址。

在向寄存器(例如,不具备FIFO功能的GPIO)写入数据时,DMA FIFO中的数据将会被连续不断地写入到目标地址。

最为关键的一点是,在将外设管理的职责从外设端口转移到内存端口时,软件需要重新评估传输大小和地址递增的配置。

如在第1.1.5节“传输大小”中所述,传输大小由外设端的传输宽度(字节、半字、字)以及待传输的数据项数量(即DMA_SxNTDR寄存器中编程的数值)共同决定。根据DMA的新配置,在端口角色互换后,可能需要对DMA_SxNTDR寄存器中的数值进行调整。

4.9.2 通过DMA2 AHB端口反转Quad-SPI传输的示例

在此示例中,DMA_S7M0AR被设定为指向Quad-SPI的数据寄存器地址,而DMA_S7PAR则被配置为指向数据缓冲区的地址(比如SRAM中的缓冲区)。在DMA_S7CR寄存器中,当向Quad-SPI写入数据时,应将DMA2流的方向设置为外设到内存的传输模式。反之,从Quad-SPI读取数据时,应将其设置为内存到外设的传输模式。

 写操作代码

/* Program M0AR with QUADSPI data register address */
DMA2_Stream7->M0AR = (uint32_t)&QUADSPI->DR;
/* Program PAR with Buffer address */
DMA2_Stream7->PAR = (uint32_t)&u32Buffer[0];
/* Write number of data items to transfer */
DMA2_Stream7->NDTR = 0x100;
/* Configure DMA : MSIZE=PSIZE=0x02 (Word), CHSEL=0x03 
(QUADSPI), PINC=1, DIR=0x00 */
DMA2_Stream7->CR = DMA_SxCR_PSIZE_1 | 
DMA_SxCR_MSIZE_1 | 3ul<<25 | DMA_SxCR_PINC;
/* Enable DMA request generation */
QUADSPI->CR |= QUADSPI_CR_DMAEN;
/* Write the DLR Register */
QUADSPI->DLR = (0x100* 4)-1;
/* Write to QUADSPI DCR */
QUADSPI->CCR = QUADSPI_CCR_IMODE_0| 
QUADSPI_CCR_ADMODE_0| QUADSPI_CCR_DMODE| 
QUADSPI_CCR_ADSIZE| QUAD_IN_FAST_PROG_CMD;
/* Write the AR Register */
QUADSPI->AR = 0x00ul;
/* Enable the selected DMA2_Stream7 by setting EN bit */
DMA2_Stream7->CR |= (uint32_t)DMA_SxCR_EN;
/* Wait for the end of Transfer */
while((QUADSPI->SR & QUADSPI_SR_TCF) != 
QUADSPI_SR_TCF);

 

读操作代码

/* Program M0AR with QUADSPI data register address */
DMA2_Stream7->M0AR = (uint32_t)&QUADSPI->DR;
/* Program PAR with Buffer address */
DMA2_Stream7->PAR = (uint32_t)&u32Buffer[0];
/* Write number of data items to transfer */
DMA2_Stream7->NDTR = 0x100;
/* Configure DMA : MSIZE=PSIZE=0x02 (Word), CHSEL=0x03 
(QUADSPI), PINC=1, DIR=0x01 */
DMA2_Stream7->CR = DMA_SxCR_PSIZE_1 | 
DMA_SxCR_MSIZE_1 | 3ul<<25 | DMA_SxCR_PINC| 
DMA_SxCR_DIR_0;
/* Enable DMA request generation */
QUADSPI->CR |= QUADSPI_CR_DMAEN;
/* Write the DLR Register */
QUADSPI->DLR = ((0x100+4)* 4)-1;
/* Write to QUADSPI DCR */
QUADSPI->CCR = QUADSPI_CCR_IMODE_0| 
QUADSPI_CCR_ADMODE_0| QUADSPI_CCR_DMODE| 
QUADSPI_CCR_ADSIZE| 
QUADSPI_CCR_FMODE_0|QUAD_OUT_FAST_READ_CMD;
/* Write the AR Register */
QUADSPI->AR = 0x00ul;
/* Enable the selected DMA2_Stream7 by setting EN bit */
DMA2_Stream7->CR |= (uint32_t)DMA_SxCR_EN;
/* Wait for the end of Transfer */
while((DMA2_Stream7->CR & DMA_SxCR_EN) == 
DMA_SxCR_EN);

4.10 微控制器DMA传输与缓存维护以防止数据不一致性

当软件使用可缓存的内存区域作为DMA的源或目的缓冲区时,必须在启动DMA操作前执行缓存清洗操作,以确保所有数据都被确实写入到子系统内存中。在DMA传输完成之后,如果需要从外设读取数据,软件必须在读取更新的内存区域之前执行缓存失效操作。

为了提高数据传输的可靠性,建议为DMA缓冲区使用不可缓存的内存区域。软件可以通过内存保护单元(MPU)配置一个不可缓存的内存块,作为CPU和DMA之间的共享内存使用。

5 总结

DMA控制器旨在满足多种嵌入式应用场景的需求,主要通过以下特点实现:

  • 为固件提供选择灵活性,可以在16个流和16个通道(每个DMA控制器8个通道)之间选择最合适的组合,
  • 利用双AHB端口架构减少了DMA传输的总体延迟时间,并通过直接路径连接到APB桥,避免了DMA在服务低速APB外设时CPU在AHB1访问上的停滞,
  • DMA中FIFO的实现增加了固件配置源和目标之间不同数据尺寸的灵活性,并在使用增量突发传输模式时加快了数据传输速度。

通过这些设计,DMA控制器能够提高数据传输的效率和性能,同时减少CPU的负载,使得系统能够更加高效地运行,尤其是在需要处理大量数据或高速数据流的场合。

  • 10
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MUKAMO

你的鼓励是我们创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值