changeset 3:b10097c3383d

DMA test data repeatedly into PIO FIFO
author Daniel O'Connor <darius@dons.net.au>
date Mon, 29 Mar 2021 18:05:05 +1030
parents 0d653f60dec8
children b6416c4aadc8
files CMakeLists.txt modulator.c
diffstat 2 files changed, 49 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Mon Mar 29 17:39:00 2021 +1030
+++ b/CMakeLists.txt	Mon Mar 29 18:05:05 2021 +1030
@@ -22,6 +22,8 @@
 
 target_link_libraries(${NAME}
 		pico_stdlib
+		hardware_dma
+		hardware_irq
 		hardware_pio
 )
 
--- a/modulator.c	Mon Mar 29 17:39:00 2021 +1030
+++ b/modulator.c	Mon Mar 29 18:05:05 2021 +1030
@@ -19,6 +19,8 @@
 
 #include "pico/stdlib.h"
 #include "hardware/clocks.h"
+#include "hardware/dma.h"
+#include "hardware/irq.h"
 #include "hardware/pio.h"
 
 #include "dac.pio.h"
@@ -33,9 +35,21 @@
 
 uint8_t shaped_trap_dat_start[] = { 0, 1, 2, 4, 8, 16, 32, 64, 128, 0, 0, 0, 0, 0, 0, 0 };
 //uint8_t shaped_trap_dat_start[] = { 0, 1, 2, 3, 1, 2, 0, 3, 1, 1, 2, 3, 0, 1, 2, 3 };
+#define SHAPED_TRAP_DAT_BITS 4
+_Static_assert((1 << SHAPED_TRAP_DAT_BITS) == sizeof(shaped_trap_dat_start));
+
+static int dma_chan;
+
+void
+dma_handler(void) {
+    // 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, shaped_trap_dat_start, true);
+}
 
 int
-main() {
+main(void) {
     int i;
     const uint LED_PIN = PICO_DEFAULT_LED_PIN;
 
@@ -53,10 +67,42 @@
     // bits don't seem to work
     dac_program_init(pio, sm, offset, 14);
 
+// Configure a channel to write the same word (32 bits) repeatedly to PIO0
+    // SM0's TX FIFO, paced by the data request signal from that peripheral.
+    dma_chan = dma_claim_unused_channel(true);
+    dma_channel_config dmac = dma_channel_get_default_config(dma_chan);
+    channel_config_set_transfer_data_size(&dmac, DMA_SIZE_32);
+    channel_config_set_read_increment(&dmac, true);
+    channel_config_set_ring(&dmac, false, SHAPED_TRAP_DAT_BITS);
+    channel_config_set_dreq(&dmac, DREQ_PIO0_TX0);
+
+    dma_channel_configure(
+        dma_chan,
+        &dmac,
+        &pio0_hw->txf[0], // Write address (only need to set this once)
+        NULL,             // Don't provide a read address yet
+        100, 		  // Write this many times then interrupt
+        false             // Don't start yet
+    );
+
+    // Tell the DMA to raise IRQ line 0 when the channel finishes a block
+    dma_channel_set_irq0_enabled(dma_chan, true);
+
+    // Configure the processor to run dma_handler() when DMA IRQ 0 is asserted
+    irq_set_exclusive_handler(DMA_IRQ_0, dma_handler);
+    irq_set_enabled(DMA_IRQ_0, true);
+
+    // Manually call the handler once, to trigger the first transfer
+    dma_handler();
+
+    // Everything else from this point is interrupt-driven. The processor has
+    // time to sit and think about its early retirement -- maybe open a bakery?
     while (true) {
+#if 0
 	for (int i = 0; i < sizeof(shaped_trap_dat_start) / 4; i++) {
 	    pio_sm_put_blocking(pio, sm, ((uint32_t *)shaped_trap_dat_start)[i]);
 	}
+#endif
 #if 0
 	gpio_put(LED_PIN, 1);
 	sleep_ms(100);