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); }
浙公网安备 33010602011771号