Mercurial > ~darius > hgwebdir.cgi > modulator
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 ); //