Mercurial > ~darius > hgwebdir.cgi > modulator
changeset 11:e9d12b36cfcc
Use PWM output to feed PIO trigger
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Mon, 24 Feb 2025 15:58:57 +1030 |
parents | 98880b18bcc1 |
children | 283955273884 |
files | modulator.c |
diffstat | 1 files changed, 45 insertions(+), 27 deletions(-) [+] |
line wrap: on
line diff
--- a/modulator.c Mon Feb 24 12:12:09 2025 +1030 +++ b/modulator.c Mon Feb 24 15:58:57 2025 +1030 @@ -45,6 +45,13 @@ #include "shaped-trap.h" +// Base of DAC pins +#define DACOUT_GPIO 7 +// PWM output pin +#define TRIGOUT_GPIO 22 +// PIO SM trigger input pin (connected to above for testing) +#define TRIGIN_GPIO 27 + // Pulse control bits #define SENSE 0x01 #define GATE 0x02 @@ -78,32 +85,20 @@ */ void dma_handler(void) { - // Clear the interrupt request. - dma_hw->ints0 = 1u << dma_chan; + // Clear the interrupt request. + dma_hw->ints0 = 1u << dma_chan; + + // Reset DAQ PIO SM so it is waiting for a trigger + pio_sm_exec(pulse_pio, pulse_sm, pio_encode_jmp(pulse_pio_sm_offset)); + + // Setup next pulse DMA address + dma_channel_set_read_addr(dma_chan, pulse_data, true); } void pwm_wrap(void) { pwm_clear_irq(slice_num); -#if 0 - static unsigned state = 0; - - gpio_put(PICO_DEFAULT_LED_PIN, state); - state = !state; -#endif - - // Reset DAQ PIO SM so it is waiting for a trigger - pio_sm_exec(pulse_pio, pulse_sm, pio_encode_jmp(pulse_pio_sm_offset)); - - // Setup next pulse DMA address - dma_channel_set_read_addr(dma_chan, pulse_data, true); - - // Manually trigger DAQ SM (cleared by SM) - pio0->irq_force = 1 << 0; - - gpio_put(2, 1); - gpio_put(2, 0); } // Calculate pulse shape data @@ -251,7 +246,10 @@ data[idx++] = qtoi(qdiv(qmul(qint(dcofs), qint(slew2 - i)), qint(slew2))); ctrl[idx] |= PACTIVE; } - return idx - 1; + + data[idx++] = 0; + + return idx; } int @@ -272,6 +270,7 @@ gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); gpio_init(2); gpio_set_dir(2, GPIO_OUT); + #if 0 for (unsigned i = 7; i < 7 + 9; i++) { printf("GPIO %d\n", i); @@ -316,14 +315,14 @@ diff, idx, (float)diff * 1000.0 / idx); //__breakpoint(); - // Load the clocked_input program, and configure a free state machine + // Load the DAC program, and configure a free state machine // to run the program. pulse_pio_sm_offset = pio_add_program(pulse_pio, &dac_program); - uint pulse_sm = pio_claim_unused_sm(pulse_pio, true); + pulse_sm = pio_claim_unused_sm(pulse_pio, true); // Data is GPIO7 to GPIO14, clock is GPIO15 // Clock divisor of 2 so it runs at 60MHz and // generates a 30MHz clock - dac_program_init(pulse_pio, pulse_sm, pulse_pio_sm_offset, 7, 2); + dac_program_init(pulse_pio, pulse_sm, pulse_pio_sm_offset, DACOUT_GPIO, 2); // Configure a channel to write 32 bits at a time to PIO0 // SM0's TX FIFO, paced by the data request signal from that peripheral. @@ -338,7 +337,7 @@ &dmac, &pio0_hw->txf[0], // Write address (only need to set this once) NULL, // Don't provide a read address yet - (idx + 1) >> 2, // Transfer count (round up to 4 bytes) + (idx + 3) >> 2, // Transfer count (round up to 4 bytes) false // Don't start yet ); @@ -349,6 +348,16 @@ irq_set_exclusive_handler(DMA_IRQ_0, dma_handler); irq_set_enabled(DMA_IRQ_0, true); + // Load the trigger program, and configure a free state machine + // to run the program. + uint trigger_pio_sm_offset = pio_add_program(pulse_pio, &trigger_program); + uint trigger_sm = pio_claim_unused_sm(pulse_pio, true); + trigger_program_init(pulse_pio, trigger_sm, trigger_pio_sm_offset, TRIGIN_GPIO, 2); + + // + // Setup PWM + // Used here to output a trigger which gets fed back into the trigger SM + // // 120MHz / 250 = 480kHz base // Maximum divisor is only 256 which limits the low end, // could further subdivide in the IRQ handler @@ -356,17 +365,26 @@ pwm_config_set_clkdiv_int(&c, 250); // 8Hz pwm_config_set_wrap(&c, 60000 - 1); + + gpio_set_function(TRIGOUT_GPIO, GPIO_FUNC_PWM); + + slice_num = pwm_gpio_to_slice_num(TRIGOUT_GPIO); pwm_init(slice_num, &c, true); pwm_clear_irq(slice_num); + pwm_set_chan_level(slice_num, PWM_CHAN_A, 1); + pwm_set_enabled(slice_num, 1); pwm_set_irq_enabled(slice_num, true); irq_set_exclusive_handler(PWM_IRQ_WRAP, pwm_wrap); irq_set_enabled(PWM_IRQ_WRAP, true); - pwm_init(slice_num, &c, true); + + // Setup next pulse DMA address + // XXX: This works but telling dma_channel_configure above to start + // immediately does not + dma_channel_set_read_addr(dma_chan, pulse_data, true); // 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) { - dma_channel_wait_for_finish_blocking(dma_chan); gpio_put(PICO_DEFAULT_LED_PIN, 1); sleep_ms(100); gpio_put(PICO_DEFAULT_LED_PIN, 0);