硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1610|回复: 3
收起左侧

RP2040 DMA好像没有循环模式,只能执行1次

[复制链接]

747

主题

1049

回帖

3295

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3295
发表于 2022-3-21 22:31:54 | 显示全部楼层 |阅读模式


RP2040 DMA好像没有循环模式,只能执行1次。

回复

使用道具 举报

747

主题

1049

回帖

3295

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3295
 楼主| 发表于 2022-3-22 01:02:45 | 显示全部楼层
使用2个DMA连接在一起可以实现不间断DMA传输

https://vanhunteradams.com/Pico/ ... the-control-channel

pio-sdk中有 control-blocks 范例.
[C] 纯文本查看 复制代码
**
 * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

// Use two DMA channels to make a programmed sequence of data transfers to the
// UART (a data gather operation). One channel is responsible for transferring
// the actual data, the other repeatedly reprograms that channel.

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/dma.h"
#include "hardware/structs/uart.h"

// These buffers will be DMA'd to the UART, one after the other.

const char word0[] = "Transferring ";
const char word1[] = "one ";
const char word2[] = "word ";
const char word3[] = "at ";
const char word4[] = "a ";
const char word5[] = "time.\n";

// Note the order of the fields here: it's important that the length is before
// the read address, because the control channel is going to write to the last
// two registers in alias 3 on the data channel:
//           +0x0        +0x4          +0x8          +0xC (Trigger)
// Alias 0:  READ_ADDR   WRITE_ADDR    TRANS_COUNT   CTRL
// Alias 1:  CTRL        READ_ADDR     WRITE_ADDR    TRANS_COUNT
// Alias 2:  CTRL        TRANS_COUNT   READ_ADDR     WRITE_ADDR
// Alias 3:  CTRL        WRITE_ADDR    TRANS_COUNT   READ_ADDR
//
// This will program the transfer count and read address of the data channel,
// and trigger it. Once the data channel completes, it will restart the
// control channel (via CHAIN_TO) to load the next two words into its control
// registers.

const struct {uint32_t len; const char *data;} control_blocks[] = {
    {count_of(word0) - 1, word0}, // Skip null terminator
    {count_of(word1) - 1, word1},
    {count_of(word2) - 1, word2},
    {count_of(word3) - 1, word3},
    {count_of(word4) - 1, word4},
    {count_of(word5) - 1, word5},
    {0, NULL}                     // Null trigger to end chain.
};

int main() {
#ifndef uart_default
#warning dma/control_blocks example requires a UART
#else
    stdio_init_all();
    puts("DMA control block example:");

    // ctrl_chan loads control blocks into data_chan, which executes them.
    int ctrl_chan = dma_claim_unused_channel(true);
    int data_chan = dma_claim_unused_channel(true);

    // The control channel transfers two words into the data channel's control
    // registers, then halts. The write address wraps on a two-word
    // (eight-byte) boundary, so that the control channel writes the same two
    // registers when it is next triggered.

    dma_channel_config c = dma_channel_get_default_config(ctrl_chan);
    channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
    channel_config_set_read_increment(&c, true);
    channel_config_set_write_increment(&c, true);
    channel_config_set_ring(&c, true, 3); // 1 << 3 byte boundary on write ptr

    dma_channel_configure(
        ctrl_chan,
        &c,
        &dma_hw->ch[data_chan].al3_transfer_count, // Initial write address
        &control_blocks[0],                        // Initial read address
        2,                                         // Halt after each control block
        false                                      // Don't start yet
    );

    // The data channel is set up to write to the UART FIFO (paced by the
    // UART's TX data request signal) and then chain to the control channel
    // once it completes. The control channel programs a new read address and
    // data length, and retriggers the data channel.

    c = dma_channel_get_default_config(data_chan);
    channel_config_set_transfer_data_size(&c, DMA_SIZE_8);
    channel_config_set_dreq(&c, uart_get_dreq(uart_default, true));
    // Trigger ctrl_chan when data_chan completes
    channel_config_set_chain_to(&c, ctrl_chan);
    // Raise the IRQ flag when 0 is written to a trigger register (end of chain):
    channel_config_set_irq_quiet(&c, true);

    dma_channel_configure(
        data_chan,
        &c,
        &uart_get_hw(uart_default)->dr,
        NULL,           // Initial read address and transfer count are unimportant;
        0,              // the control channel will reprogram them each time.
        false           // Don't start yet.
    );

    // Everything is ready to go. Tell the control channel to load the first
    // control block. Everything is automatic from here.
    dma_start_channel_mask(1u << ctrl_chan);

    // The data channel will assert its IRQ flag when it gets a null trigger,
    // indicating the end of the control block list. We're just going to wait
    // for the IRQ flag instead of setting up an interrupt handler.
    while (!(dma_hw->intr & 1u << data_chan))
        tight_loop_contents();
    dma_hw->ints0 = 1u << data_chan;

    puts("DMA finished.");
#endif
}

回复

使用道具 举报

747

主题

1049

回帖

3295

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3295
 楼主| 发表于 2022-3-22 22:20:22 | 显示全部楼层
image.png
[C] 纯文本查看 复制代码
    int data_chan = dma_claim_unused_channel(true);
    int ctrl_chan = dma_claim_unused_channel(true);

    // Setup the control channel
    dma_channel_config c = dma_channel_get_default_config(ctrl_chan); // default configs
    channel_config_set_transfer_data_size(&c, DMA_SIZE_32); // 32-bit txfers
    channel_config_set_read_increment(&c, false); // no read incrementing
    channel_config_set_write_increment(&c, false); // no write incrementing

    dma_channel_configure(
        ctrl_chan,
        &c,
        &dma_hw->ch[data_chan].al1_transfer_count_trig, // txfer to transfer count trigger
        &transfer_count,
        1,
        false
    );


[C] 纯文本查看 复制代码
// 16 bit transfers. Read address increments after each transfer.
    // DREQ to Timer 0 is selected, so the DMA is throttled to audio rate
    dma_channel_config c2 = dma_channel_get_default_config(data_chan);
    // 16 bit transfers
    channel_config_set_transfer_data_size(&c2, DMA_SIZE_16);
    // increment the read adddress, don't increment write address
    channel_config_set_read_increment(&c2, true);
    channel_config_set_write_increment(&c2, false);
    // (X/Y)*sys_clk, where X is the first 16 bytes and Y is the second
    // sys_clk is 125 MHz unless changed in code
    dma_channel_set_timer0(0x0017ffff) ;
    // 0x3b means timer0 (see SDK manual)
    channel_config_set_dreq(&c2, 0x3b);
    // chain to the controller DMA channel
    channel_config_set_chain_to(&c2, ctrl_chan);
    // set wrap boundary. This is why we needed alignment!
    channel_config_set_ring(&c2, false, 9); // 1 << 9 byte boundary on read ptr


    dma_channel_configure(
        data_chan,          // Channel to be configured
        &c2,            // The configuration we just created
        &spi_get_hw(SPI_PORT)->dr, // write address
        DAC_data, // The initial read address (AT NATURAL ALIGNMENT POINT)
        sine_table_size, // Number of transfers; in this case each is 2 byte.
        false           // Don't start immediately.
    );


    // start the control channel
    dma_start_channel_mask(1u << ctrl_chan) ;

回复

使用道具 举报

747

主题

1049

回帖

3295

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
3295
 楼主| 发表于 2022-3-23 01:34:24 | 显示全部楼层
已调试成功。DMA不间断传输。

[C] 纯文本查看 复制代码
/* PIO时钟分频器,可以是浮点数 */
float g_PioClkDiv[] = 
{ 
    1.0f,       // 125M
    1.25f,      // 100M
    2.5f,       // 50M
    6.25f,      // 20M
    12.5f,      // 10M
    25.0f,      // 5M
    62.5f,      // 2M
    125.0f,     // 1M
};
    
uint16_t g_dso_rxbuf[DSO_SAMPLE_SIZE_MAX];

/*
*********************************************************************************************************
*    函 数 名: bsp_StartDso
*    功能说明: 启动示波器程序
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void bsp_StartDso(DSO_MODE_E _mode, DSO_FREQ_E _FreqId, uint32_t _SampleSize) 
{
    dma_channel_config c;
    uint offset;
    int ctrl_chan;
    int data_chan;     
    static uint32_t s_transfer_count = 0;   
    PIO pio = pio0;
    uint8_t sm = 3;    
     
    /* 设置DMA优先级为高 */
    bus_ctrl_hw->priority = BUSCTRL_BUS_PRIORITY_DMA_W_BITS | BUSCTRL_BUS_PRIORITY_DMA_R_BITS;

    if (_mode == DSO_MODE_CH1CH2)       /* 双通道 */
    {
        offset = pio_add_program(pio0, &dso_ch1ch2_program);
        pio_dso_ch1ch2_init(pio, sm, offset, g_PioClkDiv[_FreqId]);
    }
    else if (_mode == DSO_MODE_CH1)     /* 单通道交错 */
    {
        offset = pio_add_program(pio0, &dso_ch1_program);
        pio_dso_ch1_init(pio, sm, offset, g_PioClkDiv[_FreqId]);           
    }
    else
    {
        return;
    }
    
    if (_SampleSize > DSO_SAMPLE_SIZE_MAX)
    {
        return;
    }
    
    s_transfer_count = _SampleSize;
    
    /* 启用2个DMA通道,实现不间断DMA传输 */
    ctrl_chan = dma_claim_unused_channel(true);     
    data_chan = dma_claim_unused_channel(true);
    
    /* 控制通道 */
    c = dma_channel_get_default_config(ctrl_chan);
    channel_config_set_transfer_data_size(&c, DMA_SIZE_32);    /* DMA控制寄存器bit */
    channel_config_set_read_increment(&c, false);
    channel_config_set_write_increment(&c, false);

    dma_channel_configure(
        ctrl_chan,
        &c,
        &dma_hw->ch[data_chan].al1_transfer_count_trig,     /* 目标地址: 数据通道的传输个数 */
        &s_transfer_count,                                  /* 源地址: 内存变量 */
        1,                                                  /* 传送1次 */
        false                                               /* 暂时不启动DMA传输 */
    );

    /* 数据通道 */
    c = dma_channel_get_default_config(data_chan);
    channel_config_set_transfer_data_size(&c, DMA_SIZE_16);         /* 双通道8bit,合计16bit */
    channel_config_set_dreq(&c, pio_get_dreq(pio, sm, false));      /* pio状态机的fifo数据请求 */
    channel_config_set_read_increment(&c, false);                   /* 源地址不地址 FIFO */
    channel_config_set_write_increment(&c, true);                   /* 目标地址递增,内存 */
    channel_config_set_chain_to(&c, ctrl_chan);                     /* 数据通道传输完毕后,自动启动控制通道 */
    channel_config_set_ring(&c, true, 15);                          /* 1 << 15 (32K) */
    
    dma_channel_configure(
        data_chan,
        &c,
        g_dso_rxbuf,        /* 目标地址: 内存 */
        &pio->rxf[sm],      /* 源地址: pio fifo 读 */
        0,                  /* DMA控制通道将填充这个域 */
        false               /* 暂时不启动DMA传输 */
    );
    
    dma_start_channel_mask(1u << ctrl_chan);    /* 启动DMA传输 */
}
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-2 07:39 , Processed in 0.197491 second(s), 27 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表