RP2040 PICOSDK食用指南——DMA3下发数据之音频实验

(实际上IRQ进出中断都需要时间

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

#define sine_table_size 256

int raw_sin[sine_table_size];

//发送至DAC的数据表
unsigned short DAC_data[sine_table_size];

//到DAC数据表的地址
unsigned short * address_pointer = &DAC_data[0];

//A-channel lx,active
#define DAC_config_chan_A 0b0011000000000000

//SPI配置
#define SPI_PORT_1 spi1
#define PIN_MISO_1 12
#define PIN_CS_1   13
#define PIN_SCK_1  14
#define PIN_MOSI_1 15

void dmaIrq() {
    if (dma_channel_get_irq0_status(spi_dma_rx_chan)) {
        dma_hw->ints0 = 1u << spi_dma_rx_chan;
        dma_channel_start(spi_dma_rx_chan);
    }
}

int main()
{
    stdio_init_all();

    sleep_ms(1500);
    puts("Hello, world!");

    spi_init(SPI_PORT_1, 20000000);

    gpio_set_function(PIN_MISO_1, GPIO_FUNC_SPI);
    gpio_set_function(PIN_CS_1,   GPIO_FUNC_SPI);
    gpio_set_function(PIN_SCK_1,  GPIO_FUNC_SPI);
    gpio_set_function(PIN_MOSI_1, GPIO_FUNC_SPI);
    spi_set_format(SPI_PORT_1, 16, SPI_CPOL_0, SPI_CPHA_0, SPI_MSB_FIRST);

    //Build sine tables and dac data table
    int i;
    for ( i = 0; i < sine_table_size; i++)
    {
        raw_sin[i] = (int)(2047*sin((float)i * 6.283/(float)(sine_table_size)) + 2047); //12bit
        //将正弦波数据转换为DAC数据格式
        DAC_data[i] = (raw_sin[i] & 0x0fff) | DAC_config_chan_A;
    }
    //首先设置两个DMA通道,启动一个
    // Configure DMA for SPI
    //我们指定了初始地址为DAC数据表的起始地址
    //我们将使用两个DMA通道,一个用于控制传输,另一个用于实际
    int dataChannel = dma_claim_unused_channel(true);
    int ctrlChannel = dma_claim_unused_channel(true);

    //设置control通道
    dma_channel_config c = dma_channel_get_default_config(ctrlChannel);
    channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
    channel_config_set_read_increment(&c, false);
    channel_config_set_write_increment(&c, false);
    //c传输完成后触发dataChannel
    channel_config_set_chain_to(&c, dataChannel); // 设置链式传输到数据通道

    dma_channel_configure(
        ctrlChannel,
        &c,
        &dma_hw->ch[dataChannel].read_addr, // 目标地址: 数据通道的读取地址
        &address_pointer, // 源地址: DAC 数据表的起始地址 (指向地址的指针)
        1, // 传输数据量 (不需要传输数据)
        false // 不立即启动
    );



    //设置数据通道
    dma_channel_config c2 = dma_channel_get_default_config(dataChannel);
    channel_config_set_transfer_data_size(&c2, DMA_SIZE_16);
    //是因为我们希望数据到达DAC传输缓冲区,并且自增到达数组的下一位
    channel_config_set_read_increment(&c2, true);
    //然而目标我们不希望改变,仍然是SPI输出缓冲
    channel_config_set_write_increment(&c2, false);
    //(X/Y)*sys_clk,where X is the first 16 bytes and Y is the second 16 bytes
    //sys_clk is 125MHz, unless change in code.configured to ~44KHZ
    //我们希望调整这个DMA通道的速率以便它以音频速率将书法发送到DAC
    //每个通道都有它自己的计时器,它可以以我们想要的速率溢出,每次溢出时,我们都会执行一次新的事务
    //实际上是系统速率乘以第二个参数除以第三个参数
    dma_timer_set_fraction(0,0x0017,0xffff); //设置DMA计时器分频率为1/2
    //0x3b means timer0 (see SDK meanual)
    channel_config_set_dreq(&c2, 0x3b); // 设置 DREQ 触发源为 SPI 接收
    //配置DMA通道
    //c2传输完成后触发控制通道
    channel_config_set_chain_to(&c2, ctrlChannel); // 设置链式传输到控制通道
    dma_channel_configure{
        dataChannel,
        &c2,
        &spi_get_hw(SPI_PORT_1)->dr, // 目标地址: SPI  数据寄存器
        DAC_data, // 源地址: DAC 数据表
        sine_table_size, // 传输数据量 (sine_table_size 个字)
        false // 不立即启动
    };

    //start the control channel
    // 启动控制通道
    dma_start_channel_mask(1u << ctrlChannel);

}

 

posted @ 2025-07-07 01:30  mcwhirr  阅读(23)  评论(0)    收藏  举报