差别

这里会显示出您选择的修订版和当前版本之间的差别。

到此差别页面的链接

两侧同时换到之前的修订记录 前一修订版
后一修订版
前一修订版
mp_rp2040_dma [2021/10/16 13:22]
gongyusu
mp_rp2040_dma [2021/10/16 14:04] (当前版本)
gongyusu [2. 寄存器列表]
行 1: 行 1:
 ## RP2040的DMA数据传输 ## RP2040的DMA数据传输
 +### 1. Rp2040的DMA介绍
 {{ ::​rp2040_dma.png |}} {{ ::​rp2040_dma.png |}}
 {{ ::​rp2040_csr_alias.png |}} {{ ::​rp2040_csr_alias.png |}}
行 8: 行 9:
   * 单个外围设备的带宽需求可能很高,例如>​在短时间内的50%总线注入率   * 单个外围设备的带宽需求可能很高,例如>​在短时间内的50%总线注入率
   * 总线延迟很低,但多个主机可能会竞争总线访问   * 总线延迟很低,但多个主机可能会竞争总线访问
 +
 +此外,DMA的传输fifo和双主结构允许对同一外设同时进行多个访问,以提高总吞吐量。因此,DREQ机制的选择至关重要:​
 +  * 如果在TDF中备份了多个写操作,传统的“打开水龙头”方法可能会导致溢出。一些系统通过过度配置外围fifo和将DREQ阈值设置到完全水平以下来解决这个问题,但这浪费了宝贵的面积和功率
 +  * Arm风格的单次和突发握手不允许在当前请求被服务时注册额外的请求。当fifo非常浅时,这限制了性能。
 +RP2040 DMA使用基于信用的DREQ机制。对于每个外设,DMA尝试保持外设容量所能容纳的传输量。这使得在没有fabric延迟或争用的情况下,通过8深外围FIFO实现全总线吞吐量(每个时钟1个字),而不存在溢出或下流的可能性。
 +
 +对于每个通道,DMA维护一个计数器。dreq信号上的每个1时钟脉冲将增加计数器(饱和)。当非0时,通道请求从DMA的内部仲裁器进行传输,当将传输发送到地址fifo时,计数器将减少。此时转移正在进行中,但还没有完成。
 +{{ :​dreq_counting.png |}}
 +其效果是根据外围FIFO中可用的空间或数据的数量上限。在稳定状态下,这提供了最大的流量,但不能底流或底流。
 +需要注意的是,用户不能访问当前由DMA服务的FIFO。这将导致通道和外围设备变得不同步,并可能导致数据损坏或丢失。
 +另一个警告是,多个通道不应该连接到同一个DREQ。
 +
 +
 +### 2. 寄存器列表
 +{{ :​dma_reg1.png |}}
 +
 +  * Busy:bit24,标记DMA是否正在进行中,当通道开始一个新的传输序列时,该标志升高,当该序列的最后一次传输完成时,该标志降低。在BUSY为高值时清除EN将暂停通道,并且在暂停时BUSY将保持高值。
 +  * IRQ_QUIET:bit21,在QUIET模式下,通道不会在每个传输块的末尾生成irq。相反,当将NULL写入触发器寄存器时将引发IRQ,这表明控制区块链的结束。这减少了在传输由许多小控制块组成的DMA链时由CPU提供服务的中断数量。
 +  * TREQ_SEL:bit20-15, 选择一个转移请求信号。信道使用传输请求信号来调整其数据传输速率。TREQ信号的来源是内部(TIMERS)或外部(DREQ,来自系统的数据请求)。
 +    * 0x0到0x3a→选择DREQ n为TREQ
 +    * 0x3b→选择定时器0作为TREQ
 +    * 0x3c→选择定时器1作为TREQ
 +    * 0x3d→选择定时器2作为TREQ(可选)
 +    * 0x3e→选择定时器3作为TREQ(可选)
 +    * 0x3f→永久请求,用于非节奏传输。
 +  * CHAIN_TO:bit14-11, 当该通道完成时,它将触发CHAIN_TO指示的通道。通过设置CHAIN_TO =(此通道)禁用。重置值等于通道号(因此CHAIN_TO默认禁用)。
 +  * INCR_WRITE:bit5, 如果是1,写地址随着每次传输而增加。如果为0,则每次写入都指向相同的初始地址。对于内存到外设的传输,通常应该禁用此功能。
 +  * INCR_READ:bit4, 如果是1,读地址随着每次传输而增加。如果为0,则每次读都指向相同的初始地址。对于外设到内存的传输,通常应该禁用此功能。
 +  * DATA_SIZE:bit3-2, 设置每个总线传输的大小(字节/​半字/​字)。READ_ADDR和WRITE_ADDR每次传输都增加这个量(1/​2/​3字节)。
 +    * 0x0→SIZE_BYTE
 +    * 0x1→SIZE_HALFWORD
 +    * 0x2→SIZE_WORD
 +  * HIGH_PRIORITY:bit1,HIGH_PRIORITY在问题调度中给予通道优先处理:​在每次调度中,优先考虑所有高优先级通道,然后只考虑一个低优先级通道,然后返回到高优先级通道。这只影响DMA调度通道的顺序。DMA的总线优先级没有改变。如果DMA未饱和,那么低优先级通道将不会出现吞吐量损失。
 +  * EN:bit0, DMA通道启用。当值为1时,通道将响应触发事件,这将导致通道变为BUSY并开始传输数据。当0时,通道将忽略触发器,停止发送传输,并暂停当前的传输序列(例如,如果BUSY已经处于高电平,那么将继续保持高电平)
 +
 +### 3. 示例
 +
 +<code c>
 +void dma_handler() {
 +    static int pwm_level = 0;
 +    static uint32_t wavetable[N_PWM_LEVELS];​
 +    static bool first_run = true;
 +    // Entry number `i` has `i` one bits and `(32 - i)` zero bits. 
 +    if (first_run) {
 +        first_run = false;
 +        for (int i = 0; i < N_PWM_LEVELS;​ ++i)
 +            wavetable[i] = ~(~0u << i); 
 +     }
 +     // Clear the interrupt request.
 +     
 +     ​dma_hw->​ints0 = 1u << dma_chan;
 +     // Give the channel a new wave table entry to read from, and re-trigger it
 +     ​dma_channel_set_read_addr(dma_chan,​ &​wavetable[pwm_level],​ true);
 +
 +     ​pwm_level = (pwm_level + 1) % N_PWM_LEVELS;​
 +}     
 +</​code>​
 +