RP2040 DMA好像没有循环模式,只能执行1次
RP2040 DMA好像没有循环模式,只能执行1次。
使用2个DMA连接在一起可以实现不间断DMA传输
https://vanhunteradams.com/Pico/DAC/DMA_DAC.html#Start-the-control-channel
pio-sdk中有 control-blocks 范例.
**
* 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.al3_transfer_count, // Initial write address
&control_blocks, // 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
}
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.al1_transfer_count_trig, // txfer to transfer count trigger
&transfer_count,
1,
false
);
// 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) ;
已调试成功。DMA不间断传输。
/* 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;
/*
*********************************************************************************************************
* 函 数 名: 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);
}
else if (_mode == DSO_MODE_CH1) /* 单通道交错 */
{
offset = pio_add_program(pio0, &dso_ch1_program);
pio_dso_ch1_init(pio, sm, offset, g_PioClkDiv);
}
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.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, /* 源地址: pio fifo 读 */
0, /* DMA控制通道将填充这个域 */
false /* 暂时不启动DMA传输 */
);
dma_start_channel_mask(1u << ctrl_chan); /* 启动DMA传输 */
}
页:
[1]