Mercurial > ~darius > hgwebdir.cgi > modulator
comparison modulator.c @ 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 |
comparison
equal
deleted
inserted
replaced
27:e1d8fe3e418a | 28:600a394629e6 |
---|---|
69 | 69 |
70 // Pulse shape data | 70 // Pulse shape data |
71 uint8_t pulse_data[65536] __attribute__((aligned(4))); | 71 uint8_t pulse_data[65536] __attribute__((aligned(4))); |
72 // Pulse control data | 72 // Pulse control data |
73 uint8_t pulse_ctrl[65536] __attribute__((aligned(4))); | 73 uint8_t pulse_ctrl[65536] __attribute__((aligned(4))); |
74 // DMA transfer size for above | |
75 unsigned transfercount; | |
76 | |
74 // PWM slice for PRF timer | 77 // PWM slice for PRF timer |
75 unsigned slice_num = 0; | 78 unsigned slice_num = 0; |
76 | 79 |
77 // PIO for pulse generation | 80 // PIO for pulse generation |
78 PIO pulse_pio = pio0; | 81 PIO pulse_pio = pio0; |
88 static int ctrl_dma_chan; | 91 static int ctrl_dma_chan; |
89 // Ctrl SM | 92 // Ctrl SM |
90 uint ctrl_sm; | 93 uint ctrl_sm; |
91 // Instruction offset for ctrl PIO program | 94 // Instruction offset for ctrl PIO program |
92 uint ctrl_pio_sm_offset; | 95 uint ctrl_pio_sm_offset; |
96 | |
97 // Trigger SM | |
98 uint trigger_sm; | |
93 | 99 |
94 /* | 100 /* |
95 * Use a DMA channel to feed PIO0 SM0 with pulse data. | 101 * Use a DMA channel to feed PIO0 SM0 with pulse data. |
96 * Each DMA transfer is a single pulse. | 102 * Each DMA transfer is a single pulse. |
97 * | 103 * |
102 * pulse (or not if it should stop). ie reset the PIO state machine | 108 * pulse (or not if it should stop). ie reset the PIO state machine |
103 * back to waiting for an edge and re-arm the DMA. | 109 * back to waiting for an edge and re-arm the DMA. |
104 */ | 110 */ |
105 void | 111 void |
106 dma_handler(void) { | 112 dma_handler(void) { |
113 uint32_t tmp; | |
114 | |
115 if (!dma_channel_get_irq0_status(dac_dma_chan)) { | |
116 //printf("Mystery DMA IRQ\n"); | |
117 return; | |
118 } | |
119 | |
107 // Clear the interrupt request. | 120 // Clear the interrupt request. |
108 dma_hw->ints0 = 1u << dac_dma_chan; | 121 dma_hw->ints0 = 1u << dac_dma_chan; |
109 | 122 if (((tmp = dma_channel_hw_addr(dac_dma_chan)->transfer_count)) != 0) |
110 #if 0 | 123 printf("DAC transfers %lu\n", tmp); |
111 printf("DAC transfers %lu\n", dma_channel_hw_addr(dac_dma_chan)->transfer_count); | 124 if (((tmp = dma_channel_hw_addr(ctrl_dma_chan)->transfer_count)) != 0) |
112 printf("Ctrl transfers %lu\n", dma_channel_hw_addr(ctrl_dma_chan)->transfer_count); | 125 printf("Ctrl transfers %lu\n", tmp); |
113 #endif | |
114 | 126 |
115 // Reset DAQ & ctrl PIO SMs so they are waiting for a trigger | 127 // Reset DAQ & ctrl PIO SMs so they are waiting for a trigger |
116 pio_sm_exec(pulse_pio, dac_sm, pio_encode_jmp(dac_pio_sm_offset)); | 128 pio_sm_exec_wait_blocking(pulse_pio, dac_sm, dac_reset_instr(dac_pio_sm_offset)); |
117 pio_sm_exec(pulse_pio, ctrl_sm, pio_encode_jmp(ctrl_pio_sm_offset)); | 129 pio_sm_exec_wait_blocking(pulse_pio, ctrl_sm, ctrl_reset_instr(ctrl_pio_sm_offset)); |
130 | |
131 // Abort any existing DMA | |
132 // Have to do a song and dance for the IRQ generating one due | |
133 // to errata RP2350-E5 | |
134 dma_channel_set_irq0_enabled(dac_dma_chan, false); | |
135 dma_channel_abort(dac_dma_chan); | |
136 dma_channel_acknowledge_irq0(dac_dma_chan); | |
137 dma_channel_set_irq0_enabled(dac_dma_chan, true); | |
138 dma_channel_abort(ctrl_dma_chan); | |
118 | 139 |
119 // Setup next pulse data & ctrl DMA addresses | 140 // Setup next pulse data & ctrl DMA addresses |
120 dma_channel_wait_for_finish_blocking(dac_dma_chan); | 141 dma_channel_set_read_addr(dac_dma_chan, pulse_data, false); |
121 dma_channel_set_read_addr(dac_dma_chan, pulse_data, true); | 142 dma_channel_set_trans_count(dac_dma_chan, transfercount, true); |
122 dma_channel_wait_for_finish_blocking(ctrl_dma_chan); | 143 |
123 dma_channel_set_read_addr(ctrl_dma_chan, pulse_ctrl, true); | 144 // Disable and resync/enable DAQ & ctrl PIO SMs so they are waiting for a trigger |
145 pio_set_sm_mask_enabled(pulse_pio, 1u << dac_sm | 1u << ctrl_sm, false); | |
146 pio_enable_sm_mask_in_sync(pulse_pio, 1u << dac_sm | 1u << ctrl_sm); | |
147 | |
148 // Setup next pulse data & ctrl DMA addresses | |
149 dma_channel_set_read_addr(ctrl_dma_chan, pulse_ctrl, false); | |
150 dma_channel_set_trans_count(ctrl_dma_chan, transfercount, true); | |
124 } | 151 } |
125 | 152 |
126 void | 153 void |
127 pwm_wrap(void) { | 154 pwm_wrap(void) { |
128 pwm_clear_irq(slice_num); | 155 pwm_clear_irq(slice_num); |
215 printf("dcscale = %s\n", tmps); | 242 printf("dcscale = %s\n", tmps); |
216 | 243 |
217 memset(pulse_data, 0, datalen); | 244 memset(pulse_data, 0, datalen); |
218 memset(pulse_ctrl, 0, datalen); | 245 memset(pulse_ctrl, 0, datalen); |
219 idx = 0; | 246 idx = 0; |
247 #if 0 | |
248 for (uint16_t i = 0; i < 255 * 200; i++) | |
249 data[idx++] = i / 200; | |
250 | |
251 printf("Dummy done\n"); | |
252 return idx; | |
253 #endif | |
254 #if 0 | |
255 data[idx++] = 255; | |
256 data[idx++] = 0; | |
257 data[idx++] = 0; | |
258 data[idx++] = 0; | |
259 data[idx++] = 0; | |
260 data[idx++] = 128; | |
261 data[idx++] = 128; | |
262 data[idx++] = 0; | |
263 data[idx++] = 0; | |
264 data[idx++] = 0; | |
265 data[idx++] = 0; | |
266 data[idx++] = 0; | |
267 data[idx++] = 255; | |
268 #endif | |
220 | 269 |
221 // Up slew | 270 // Up slew |
222 for (uint16_t i = 0; i < slew1; i++) { | 271 for (uint16_t i = 0; i < slew1; i++) { |
223 data[idx++] = qtoi(qdiv(qmul(qint(dcofs), qint(i)), qint(slew1))); | 272 data[idx++] = qtoi(qdiv(qmul(qint(dcofs), qint(i)), qint(slew1))); |
224 } | 273 } |
347 } | 396 } |
348 now = get_absolute_time(); | 397 now = get_absolute_time(); |
349 unsigned long long diff = absolute_time_diff_us(then, now); | 398 unsigned long long diff = absolute_time_diff_us(then, now); |
350 printf("Pulse computation took %lld usec and created %lu samples - %.1f nsec/sample\n", | 399 printf("Pulse computation took %lld usec and created %lu samples - %.1f nsec/sample\n", |
351 diff, idx, (float)diff * 1000.0 / idx); | 400 diff, idx, (float)diff * 1000.0 / idx); |
352 unsigned transfers = (idx + 3) >> 2; | 401 transfercount = ((idx + 3) >> 2); |
353 printf("Using %u transfers\n", transfers); | 402 printf("Using %u transfers\n", transfercount); |
354 //__breakpoint(); | 403 //__breakpoint(); |
355 | 404 |
356 // Load the DAC program, and configure a free state machine | 405 // Load the DAC program, and configure a free state machine |
357 // to run the program. | 406 // to run the program. |
358 dac_pio_sm_offset = pio_add_program(pulse_pio, &dac_program); | 407 dac_pio_sm_offset = pio_add_program(pulse_pio, &dac_program); |
377 dma_channel_configure( | 426 dma_channel_configure( |
378 dac_dma_chan, | 427 dac_dma_chan, |
379 &dac_dmac, | 428 &dac_dmac, |
380 &pulse_pio->txf[dac_sm], // Write address | 429 &pulse_pio->txf[dac_sm], // Write address |
381 pulse_data, // Pulse data | 430 pulse_data, // Pulse data |
382 transfers, // Transfer count | 431 transfercount, // Transfer count |
383 true // Start transfer | 432 true // Start transfer |
384 ); | 433 ); |
385 | 434 |
386 // Tell the DMA to raise IRQ line 0 when the channel finishes a block | 435 // Tell the DMA to raise IRQ line 0 when the channel finishes a block |
387 dma_channel_set_irq0_enabled(dac_dma_chan, true); | 436 dma_channel_set_irq0_enabled(dac_dma_chan, true); |
411 dma_channel_configure( | 460 dma_channel_configure( |
412 ctrl_dma_chan, | 461 ctrl_dma_chan, |
413 &ctrl_dmac, | 462 &ctrl_dmac, |
414 &pulse_pio->txf[ctrl_sm], // Write address | 463 &pulse_pio->txf[ctrl_sm], // Write address |
415 pulse_ctrl, // Ctrl data | 464 pulse_ctrl, // Ctrl data |
416 transfers, // Transfer count | 465 transfercount, // Transfer count |
417 true // Start transfer | 466 true // Start transfer |
418 ); | 467 ); |
419 // No IRQ, piggyback on the data one | 468 // No IRQ, piggyback on the data one |
420 | 469 |
421 #ifdef WITH_TRIGGER | 470 #ifdef WITH_TRIGGER |
424 uint trigger_pio_sm_offset = pio_add_program(pulse_pio, &trigger_program); | 473 uint trigger_pio_sm_offset = pio_add_program(pulse_pio, &trigger_program); |
425 if (trigger_pio_sm_offset < 0) { | 474 if (trigger_pio_sm_offset < 0) { |
426 printf("Unable to load trigger program\n"); | 475 printf("Unable to load trigger program\n"); |
427 __breakpoint(); | 476 __breakpoint(); |
428 } | 477 } |
429 uint trigger_sm = pio_claim_unused_sm(pulse_pio, true); | 478 trigger_sm = pio_claim_unused_sm(pulse_pio, true); |
430 trigger_program_init(pulse_pio, trigger_sm, trigger_pio_sm_offset, TRIGIN_GPIO, 1); | 479 trigger_program_init(pulse_pio, trigger_sm, trigger_pio_sm_offset, TRIGIN_GPIO, 1); |
431 #endif | 480 #endif |
432 | 481 |
433 // Start & sync all state machines | 482 // Start & sync all state machines |
434 // This is necessary to avoid any jitter and to make the | 483 // This is necessary to avoid any jitter and to make the |
435 // trigger sync work correctly | 484 // trigger sync work correctly |
436 pio_enable_sm_mask_in_sync(pulse_pio, | 485 pio_enable_sm_mask_in_sync(pulse_pio, 0 |
437 1u << dac_sm | | 486 | 1u << dac_sm |
438 1u << ctrl_sm | | 487 | 1u << ctrl_sm |
439 #ifdef WITH_TRIGGER | 488 #ifdef WITH_TRIGGER |
440 1u << trigger_sm | 489 | 1u << trigger_sm |
441 #endif | 490 #endif |
442 ); | 491 ); |
443 // | 492 // |
444 // Setup PWM | 493 // Setup PWM |
445 // Used here to output a trigger which gets fed back into the trigger SM | 494 // Used here to output a trigger which gets fed back into the trigger SM |