changeset 28:600a394629e6

Use 8 bit auto pull otherwise the PIOs jitter (due to DMA contention I guess?) Don't need to unroll the PIO loops. Create PIo function to reset each PIO. Check the DMA IRQ is for us - we get unknown IRQs which need to be ignored or things break.
author Daniel O'Connor <darius@dons.net.au>
date Thu, 27 Feb 2025 13:58:37 +1030
parents e1d8fe3e418a
children babdb5376356
files ctrl.pio dac.pio modulator.c
diffstat 3 files changed, 90 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/ctrl.pio	Wed Feb 26 11:03:59 2025 +1030
+++ b/ctrl.pio	Thu Feb 27 13:58:37 2025 +1030
@@ -2,22 +2,18 @@
 ; Copyright (c) 2025 Daniel O'Connor
 ;
 
+.program ctrl
 .define TRIGGER_IRQ 0
 
-.program ctrl
+PUBLIC init:
 ; Assert all 0s
     mov pins, null
+    nop
 ; Wait for start trigger and clear IRQ
     wait 1 irq TRIGGER_IRQ
 .wrap_target
     out pins 8 [1]
     nop        [1]
-    out pins 8 [1]
-    nop        [1]
-    out pins 8 [1]
-    nop        [1]
-    out pins 8 [1]
-    nop        [1]
 .wrap
 
 % c-sdk {
@@ -38,7 +34,7 @@
         &c,
         true,  // Shift-to-right
         true,  // Autopull enabled
-        32     // Autopull threshold (bits!)
+        8      // Autopull threshold (bits!)
     );
 
     // We only send, so disable the RX FIFO to make the TX FIFO deeper.
@@ -46,7 +42,12 @@
 
     sm_config_set_clkdiv(&c, clkdiv);
 
-    // Load our configuration
+    // Load our configuration (but don't start)
     pio_sm_init(pio, sm, offset, &c);
 }
+
+static inline uint ctrl_reset_instr (uint offset) {
+    // encode a "jmp init side 0" instruction for the state machine
+    return pio_encode_jmp (offset + ctrl_offset_init);
+}
 %}
--- a/dac.pio	Wed Feb 26 11:03:59 2025 +1030
+++ b/dac.pio	Thu Feb 27 13:58:37 2025 +1030
@@ -7,6 +7,7 @@
 ; Need 1 side set pin, the clock
 .side_set 1
 
+PUBLIC init:
 ; Clock in a 0 byte
     mov pins, null side 0
     nop side 1
@@ -17,12 +18,6 @@
 .wrap_target
     out pins 8 side 0 [1]
     nop side 1        [1]
-    out pins 8 side 0 [1]
-    nop side 1        [1]
-    out pins 8 side 0 [1]
-    nop side 1        [1]
-    out pins 8 side 0 [1]
-    nop side 1        [1]
 .wrap
 
 % c-sdk {
@@ -38,22 +33,27 @@
     for (int i = 0; i < 9; i++)
         pio_gpio_init(pio, pin + i);
 
+    // Configure sideset pin to use for clock
+    sm_config_set_sideset_pins(&c, pin + 8);
+
     sm_config_set_out_shift(
         &c,
         true,  // Shift-to-right
         true,  // Autopull enabled
-        32     // Autopull threshold (bits!)
+        8      // Autopull threshold (bits!)
     );
 
-    // Configure sideset pin to use for clock
-    sm_config_set_sideset_pins(&c, pin + 8);
-
     // We only send, so disable the RX FIFO to make the TX FIFO deeper.
     sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
 
     sm_config_set_clkdiv(&c, clkdiv);
 
-    // Load our configuration
+    // Load our configuration (but don't start)
     pio_sm_init(pio, sm, offset, &c);
 }
+
+static inline uint dac_reset_instr (uint offset) {
+    // encode a "jmp init side 0" instruction for the state machine
+    return pio_encode_jmp (offset + dac_offset_init) | pio_encode_sideset (1, 0);
+}
 %}
--- a/modulator.c	Wed Feb 26 11:03:59 2025 +1030
+++ b/modulator.c	Thu Feb 27 13:58:37 2025 +1030
@@ -71,6 +71,9 @@
 uint8_t pulse_data[65536] __attribute__((aligned(4)));
 // Pulse control data
 uint8_t pulse_ctrl[65536] __attribute__((aligned(4)));
+// DMA transfer size for above
+unsigned transfercount;
+
 // PWM slice for PRF timer
 unsigned slice_num = 0;
 
@@ -91,6 +94,9 @@
 // Instruction offset for ctrl PIO program
 uint ctrl_pio_sm_offset;
 
+// Trigger SM
+uint trigger_sm;
+
 /*
  * Use a DMA channel to feed PIO0 SM0 with pulse data.
  * Each DMA transfer is a single pulse.
@@ -104,23 +110,44 @@
  */
 void
 dma_handler(void) {
+  uint32_t tmp;
+
+  if (!dma_channel_get_irq0_status(dac_dma_chan)) {
+    //printf("Mystery DMA IRQ\n");
+    return;
+  }
+
   // Clear the interrupt request.
   dma_hw->ints0 = 1u << dac_dma_chan;
-
-#if 0
-  printf("DAC transfers %lu\n", dma_channel_hw_addr(dac_dma_chan)->transfer_count);
-  printf("Ctrl transfers %lu\n", dma_channel_hw_addr(ctrl_dma_chan)->transfer_count);
-#endif
+  if (((tmp = dma_channel_hw_addr(dac_dma_chan)->transfer_count)) != 0)
+    printf("DAC transfers %lu\n", tmp);
+  if (((tmp = dma_channel_hw_addr(ctrl_dma_chan)->transfer_count)) != 0)
+    printf("Ctrl transfers %lu\n", tmp);
 
   // Reset DAQ & ctrl PIO SMs so they are  waiting for a trigger
-  pio_sm_exec(pulse_pio, dac_sm, pio_encode_jmp(dac_pio_sm_offset));
-  pio_sm_exec(pulse_pio, ctrl_sm, pio_encode_jmp(ctrl_pio_sm_offset));
+  pio_sm_exec_wait_blocking(pulse_pio, dac_sm, dac_reset_instr(dac_pio_sm_offset));
+  pio_sm_exec_wait_blocking(pulse_pio, ctrl_sm, ctrl_reset_instr(ctrl_pio_sm_offset));
+
+  // Abort any existing DMA
+  // Have to do a song and dance for the IRQ generating one due
+  // to errata RP2350-E5
+  dma_channel_set_irq0_enabled(dac_dma_chan, false);
+  dma_channel_abort(dac_dma_chan);
+  dma_channel_acknowledge_irq0(dac_dma_chan);
+  dma_channel_set_irq0_enabled(dac_dma_chan, true);
+  dma_channel_abort(ctrl_dma_chan);
 
   // Setup next pulse data & ctrl DMA addresses
-  dma_channel_wait_for_finish_blocking(dac_dma_chan);
-  dma_channel_set_read_addr(dac_dma_chan, pulse_data, true);
-  dma_channel_wait_for_finish_blocking(ctrl_dma_chan);
-  dma_channel_set_read_addr(ctrl_dma_chan, pulse_ctrl, true);
+  dma_channel_set_read_addr(dac_dma_chan, pulse_data, false);
+  dma_channel_set_trans_count(dac_dma_chan, transfercount, true);
+
+  // Disable and resync/enable DAQ & ctrl PIO SMs so they are  waiting for a trigger
+  pio_set_sm_mask_enabled(pulse_pio, 1u << dac_sm | 1u << ctrl_sm, false);
+  pio_enable_sm_mask_in_sync(pulse_pio, 1u << dac_sm | 1u << ctrl_sm);
+
+  // Setup next pulse data & ctrl DMA addresses
+  dma_channel_set_read_addr(ctrl_dma_chan, pulse_ctrl, false);
+  dma_channel_set_trans_count(ctrl_dma_chan, transfercount, true);
 }
 
 void
@@ -217,6 +244,28 @@
   memset(pulse_data, 0, datalen);
   memset(pulse_ctrl, 0, datalen);
   idx = 0;
+#if 0
+  for (uint16_t i = 0; i < 255 * 200; i++)
+    data[idx++] = i / 200;
+
+  printf("Dummy done\n");
+  return idx;
+#endif
+#if 0
+  data[idx++] = 255;
+  data[idx++] = 0;
+  data[idx++] = 0;
+  data[idx++] = 0;
+  data[idx++] = 0;
+  data[idx++] = 128;
+  data[idx++] = 128;
+  data[idx++] = 0;
+  data[idx++] = 0;
+  data[idx++] = 0;
+  data[idx++] = 0;
+  data[idx++] = 0;
+  data[idx++] = 255;
+#endif
 
   // Up slew
   for (uint16_t i = 0; i < slew1; i++) {
@@ -349,8 +398,8 @@
     unsigned long long diff = absolute_time_diff_us(then, now);
     printf("Pulse computation took %lld usec and created %lu samples - %.1f nsec/sample\n",
 	   diff, idx, (float)diff * 1000.0 / idx);
-    unsigned transfers = (idx + 3) >> 2;
-    printf("Using %u transfers\n", transfers);
+    transfercount = ((idx + 3) >> 2);
+    printf("Using %u transfers\n", transfercount);
     //__breakpoint();
 
     // Load the DAC program, and configure a free state machine
@@ -379,7 +428,7 @@
         &dac_dmac,
         &pulse_pio->txf[dac_sm],   // Write address
         pulse_data,                // Pulse data
-        transfers,	           // Transfer count
+        transfercount,	           // Transfer count
         true			   // Start transfer
     );
 
@@ -413,7 +462,7 @@
         &ctrl_dmac,
         &pulse_pio->txf[ctrl_sm],  // Write address
         pulse_ctrl,                // Ctrl data
-        transfers,	           // Transfer count
+        transfercount,	           // Transfer count
         true			   // Start transfer
     );
     // No IRQ, piggyback on the data one
@@ -426,18 +475,18 @@
       printf("Unable to load trigger program\n");
       __breakpoint();
     }
-    uint trigger_sm = pio_claim_unused_sm(pulse_pio, true);
+    trigger_sm = pio_claim_unused_sm(pulse_pio, true);
     trigger_program_init(pulse_pio, trigger_sm, trigger_pio_sm_offset, TRIGIN_GPIO, 1);
 #endif
 
     // Start & sync all state machines
     // This is necessary to avoid any jitter and to make the
     // trigger sync work correctly
-    pio_enable_sm_mask_in_sync(pulse_pio,
-			       1u << dac_sm |
-			       1u << ctrl_sm |
+    pio_enable_sm_mask_in_sync(pulse_pio, 0
+			       | 1u << dac_sm
+			       | 1u << ctrl_sm
 #ifdef WITH_TRIGGER
-			       1u << trigger_sm
+			       | 1u << trigger_sm
 #endif
 			       );
     //