Mercurial > ~darius > hgwebdir.cgi > modulator
annotate modulator.c @ 16:56a79dce90e9
Commit WIP ctrl code
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Tue, 25 Feb 2025 13:31:27 +1030 |
parents | e9d12b36cfcc |
children | a249e4727b01 |
rev | line source |
---|---|
0
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
1 /****************************************************************** |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
2 ******************************************************************* |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
3 ** |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
4 ** This is proprietary unpublished source code, property |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
5 ** of Genesis Software. Use or disclosure without prior |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
6 ** agreement is expressly prohibited. |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
7 ** |
16 | 8 ** Copyright (c) 2025 Genesis Software, all rights reserved. |
0
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
9 ** |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
10 ******************************************************************* |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
11 ******************************************************************/ |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
12 |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
13 /* |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
14 ** MODULATOR.C |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
15 ** |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
16 ** Create modulation shape |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
17 ** |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
18 */ |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
19 |
5 | 20 #include <stdio.h> |
21 #include <string.h> | |
22 | |
23 #pragma GCC diagnostic push | |
24 #pragma GCC diagnostic ignored "-Wtype-limits" | |
25 #pragma GCC diagnostic ignored "-Wsign-compare" | |
0
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
26 #include "pico/stdlib.h" |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
27 #include "hardware/clocks.h" |
3
b10097c3383d
DMA test data repeatedly into PIO FIFO
Daniel O'Connor <darius@dons.net.au>
parents:
2
diff
changeset
|
28 #include "hardware/dma.h" |
5 | 29 #include "hardware/interp.h" |
3
b10097c3383d
DMA test data repeatedly into PIO FIFO
Daniel O'Connor <darius@dons.net.au>
parents:
2
diff
changeset
|
30 #include "hardware/irq.h" |
5 | 31 #include "hardware/pll.h" |
0
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
32 #include "hardware/pio.h" |
5 | 33 #include "hardware/pwm.h" |
34 #include "hardware/structs/pll.h" | |
35 #include "hardware/structs/clocks.h" | |
36 #pragma GCC diagnostic pop | |
0
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
37 |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
38 #include "dac.pio.h" |
16 | 39 #include "ctrl.pio.h" |
9 | 40 #include "trigger.pio.h" |
0
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
41 |
5 | 42 // https://github.com/howerj/q |
7
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
43 // Modified to be Q20.12 rather than Q16.16 |
5 | 44 #include "q/q.h" |
0
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
45 |
5 | 46 #include "shaped-trap.h" |
3
b10097c3383d
DMA test data repeatedly into PIO FIFO
Daniel O'Connor <darius@dons.net.au>
parents:
2
diff
changeset
|
47 |
11
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
48 // Base of DAC pins |
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
49 #define DACOUT_GPIO 7 |
16 | 50 // Base of ctrl pins |
51 #define CTRLOUT_GPIO 16 | |
11
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
52 // PWM output pin |
16 | 53 #define TRIGOUT_GPIO 23 |
11
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
54 // PIO SM trigger input pin (connected to above for testing) |
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
55 #define TRIGIN_GPIO 27 |
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
56 |
9 | 57 // Pulse control bits |
16 | 58 #define PACTIVE 0x01 |
59 #define PHINV 0x02 | |
60 #define SENSE1 0x04 | |
61 #define SENSE2 0x08 | |
62 #define GATE 0x10 | |
63 #define TRSW 0x20 | |
64 | |
65 // Pulse shape data | |
66 uint8_t pulse_data[65536] __attribute__((aligned(4))); | |
67 // Pulse control data | |
68 uint8_t pulse_ctrl[65536] __attribute__((aligned(4))); | |
69 // PWM slice for PRF timer | |
70 unsigned slice_num = 0; | |
71 | |
72 // PIO for pulse generation | |
73 PIO pulse_pio = pio0; | |
9 | 74 |
10
98880b18bcc1
Reset DAC PIO and use force trigger to do manual trigger.
Daniel O'Connor <darius@dons.net.au>
parents:
9
diff
changeset
|
75 // DMA channel to feed DAC PIO |
16 | 76 static int dac_dma_chan; |
10
98880b18bcc1
Reset DAC PIO and use force trigger to do manual trigger.
Daniel O'Connor <darius@dons.net.au>
parents:
9
diff
changeset
|
77 // DAC SM |
16 | 78 uint dac_sm; |
10
98880b18bcc1
Reset DAC PIO and use force trigger to do manual trigger.
Daniel O'Connor <darius@dons.net.au>
parents:
9
diff
changeset
|
79 // Instruction offset for DAC PIO program |
16 | 80 uint dac_pio_sm_offset; |
81 | |
82 // DMA channel to feed ctrl PIO | |
83 static int ctrl_dma_chan; | |
84 // Ctrl SM | |
85 uint ctrl_sm; | |
86 // Instruction offset for ctrl PIO program | |
87 uint ctrl_pio_sm_offset; | |
88 | |
9 | 89 /* |
90 * Use a DMA channel to feed PIO0 SM0 with pulse data. | |
91 * Each DMA transfer is a single pulse. | |
92 * | |
93 * The PIO state machine waits to be triggered before starting | |
94 * so we can use another state machine to look for the trigger edge. | |
95 * | |
96 * When the DMA is done the IRQ handler will configure it for the next | |
97 * pulse (or not if it should stop). ie reset the PIO state machine | |
98 * back to waiting for an edge and re-arm the DMA. | |
99 */ | |
3
b10097c3383d
DMA test data repeatedly into PIO FIFO
Daniel O'Connor <darius@dons.net.au>
parents:
2
diff
changeset
|
100 void |
b10097c3383d
DMA test data repeatedly into PIO FIFO
Daniel O'Connor <darius@dons.net.au>
parents:
2
diff
changeset
|
101 dma_handler(void) { |
11
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
102 // Clear the interrupt request. |
16 | 103 dma_hw->ints0 = 1u << dac_dma_chan; |
11
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
104 |
16 | 105 // Disabled for now, manual trigger only |
106 #if 0 | |
107 // Reset DAQ & ctrl PIO SMs so they are waiting for a trigger | |
108 pio_sm_exec(pulse_pio, dac_sm, pio_encode_jmp(dac_pio_sm_offset)); | |
109 pio_sm_exec(pulse_pio, ctrl_sm, pio_encode_jmp(ctrl_pio_sm_offset)); | |
11
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
110 |
16 | 111 // Setup next pulse data & ctrl DMA addresses |
112 dma_channel_set_read_addr(dac_dma_chan, pulse_data, true); | |
113 dma_channel_set_read_addr(ctrl_dma_chan, pulse_ctrl, true); | |
114 #endif | |
5 | 115 } |
116 | |
117 | |
118 void | |
119 pwm_wrap(void) { | |
120 pwm_clear_irq(slice_num); | |
16 | 121 |
122 // Reset DAQ & ctrl PIO SMs so they are waiting for a trigger | |
123 pio_sm_exec(pulse_pio, dac_sm, pio_encode_jmp(dac_pio_sm_offset)); | |
124 pio_sm_exec(pulse_pio, ctrl_sm, pio_encode_jmp(ctrl_pio_sm_offset)); | |
125 | |
126 printf("DAC: transfers %lu\n", dma_channel_hw_addr(dac_dma_chan)->transfer_count); | |
127 printf("DAC: transfers %lu\n", dma_channel_hw_addr(ctrl_dma_chan)->transfer_count); | |
128 | |
129 // Setup next pulse data & ctrl DMA addresses | |
130 dma_channel_wait_for_finish_blocking(dac_dma_chan); | |
131 dma_channel_set_read_addr(dac_dma_chan, pulse_data, true); | |
132 dma_channel_wait_for_finish_blocking(ctrl_dma_chan); | |
133 dma_channel_set_read_addr(ctrl_dma_chan, pulse_ctrl, true); | |
134 | |
135 // Manually trigger DAQ SM (cleared by SM) | |
136 pio0->irq_force = 1 << 0; | |
137 | |
138 // 'scope trigger | |
139 gpio_put(2, 1); | |
140 gpio_put(2, 0); | |
5 | 141 } |
142 | |
143 // Calculate pulse shape data | |
8
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
144 // TODO: predistortion, proper sense, gate, phase, active, T/R switch |
5 | 145 // Could encode them as bit stream like data but more compact would be |
146 // (say) a list of counts to toggle pins at | |
147 // Need to add pre/postgate/sense/phase counters | |
148 unsigned | |
149 compute_pulse(uint8_t *data, uint8_t *ctrl, unsigned datalen, uint16_t plen, char *code, uint8_t ncode, const uint8_t *shape, uint8_t shapelen, uint8_t codegap, uint8_t slew1, uint8_t slew2, uint8_t dcofs) { | |
7
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
150 uint32_t shapesamples, nsamples, idx, bit1startup, bit1stopup; |
5 | 151 q_t dcscale, stepsize; |
152 char tmps[20]; | |
7
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
153 interp_config cfg; |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
154 |
8
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
155 if (ncode == 1) { |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
156 // Number of samples for half of the pulse |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
157 // Do division first so we don't overflow Q16.16 |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
158 shapesamples = qtoi(qmul(qdiv(qint(plen), qint(100)), qint(shapelen / 2))); |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
159 // Number of samples for everything |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
160 // XXX: Need the +1 otherwise slew2 is truncated |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
161 nsamples = shapesamples * 2 + slew1 + slew2 + 1; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
162 } else { |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
163 shapesamples = plen / 2; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
164 nsamples = shapesamples * 2 * ncode + codegap * (ncode - 1) + slew1 + slew2 + 1; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
165 } |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
166 |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
167 // Number of steps per samples in the pulse shape |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
168 stepsize = qdiv(qint(shapelen), qint(shapesamples)); |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
169 qsprint(stepsize, tmps, sizeof(tmps)); |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
170 printf("shapelen = %d shapesamples = %lu nsamples = %lu stepsize = %s\n", shapelen, shapesamples, nsamples, tmps); |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
171 |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
172 // Check the requested pulse will not overflow given data |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
173 if (nsamples > datalen) { |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
174 printf("Pulse too long (%ld > %u)\n", nsamples, datalen); |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
175 return 0; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
176 } |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
177 // Check it is not too short |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
178 if (shapesamples < 2) { |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
179 printf("Pulse too short (%lu < %d)\n", shapesamples, 2); |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
180 return 0; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
181 } |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
182 // Or too long (will overflow for loop variable) |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
183 if (qtoi(shapesamples) > 65535) { |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
184 printf("Shape too long (%u > %d)\n", qtoi(shapesamples), 65535); |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
185 return 0; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
186 } |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
187 |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
188 // Setup interp 0 lane 0 to generate index into shape table |
7
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
189 // Mask start is 0 because we use 8 bit samples |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
190 cfg = interp_default_config(); |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
191 interp_config_set_shift(&cfg, QBITS); |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
192 interp_config_set_mask(&cfg, 0, 32 - QBITS); |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
193 interp_config_set_blend(&cfg, true); |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
194 interp_set_config(interp0, 0, &cfg); |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
195 |
8
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
196 // Setup interp 0 lane 1 to LERP each sample pair |
7
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
197 cfg = interp_default_config(); |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
198 interp_config_set_shift(&cfg, QBITS - 8); |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
199 interp_config_set_signed(&cfg, false); |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
200 interp_config_set_cross_input(&cfg, true); // unsigned blending |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
201 interp_set_config(interp0, 1, &cfg); |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
202 |
8
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
203 // Setup interp 1 lane 0 to clamp 0-255 |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
204 cfg = interp_default_config(); |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
205 interp_config_set_clamp(&cfg, true); |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
206 interp_config_set_shift(&cfg, 0); |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
207 interp_config_set_mask(&cfg, 0, 8); |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
208 interp_config_set_signed(&cfg, false); |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
209 interp_set_config(interp1, 0, &cfg); |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
210 interp1->base[0] = 0; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
211 interp1->base[1] = 255; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
212 |
7
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
213 interp0->accum[0] = 0; // Initial offset into shape table |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
214 interp0->base[2] = (uintptr_t)shape; // Start of shape table |
5 | 215 |
8
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
216 dcscale = qdiv(qsub(qint(256), qint(dcofs)), qint(255)); |
5 | 217 qsprint(dcscale, tmps, sizeof(tmps)); |
218 printf("dcscale = %s\n", tmps); | |
219 | |
16 | 220 memset(pulse_data, 0, datalen); |
221 memset(pulse_ctrl, 0, datalen); | |
5 | 222 idx = 0; |
223 | |
224 // Up slew | |
225 for (uint16_t i = 0; i < slew1; i++) { | |
226 data[idx++] = qtoi(qdiv(qmul(qint(dcofs), qint(i)), qint(slew1))); | |
227 ctrl[idx] |= PACTIVE; | |
228 } | |
229 for (uint16_t c = 0; c < ncode; c++) { | |
7
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
230 if (c == 0) |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
231 bit1startup = idx; |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
232 |
5 | 233 uint ctrltmp = PACTIVE; |
234 if (code[c] == '0') | |
235 ctrltmp |= PHINV; | |
236 | |
237 // Pulse up | |
8
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
238 if (c == 0) { |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
239 interp0->accum[0] = 0; // Initial offset into shape table |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
240 interp0->base[2] = (uintptr_t)shape; // Start of shape table |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
241 } |
5 | 242 for (uint16_t i = 0; i < shapesamples; i++) { |
8
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
243 if (c == 0) { |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
244 // Get sample pair |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
245 uint8_t *sample_pair = (uint8_t *) interp0->peek[2]; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
246 // Ask lane 1 for a LERP, using the lane 0 accumulator |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
247 interp0->base[0] = sample_pair[0]; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
248 interp0->base[1] = sample_pair[1]; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
249 uint8_t peek = interp0->peek[1]; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
250 // Apply DC offset scaling & clamp |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
251 interp1->accum[0] = dcofs + qtoi(qmul(qint(peek), dcscale)); |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
252 data[idx++] = interp1->peek[0]; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
253 // Update interpolator for next point |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
254 interp0->add_raw[0] = stepsize; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
255 } else |
7
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
256 // Already done it before, just copy the previous instance |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
257 data[idx++] = data[bit1startup + i]; |
5 | 258 ctrl[idx] = ctrltmp; |
259 } | |
7
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
260 if (c == 0) |
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
261 bit1stopup = idx - 1; |
5 | 262 // Pulse down |
7
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
263 // Since the pulse is symmetrical just copy the up slope in reverse |
8
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
264 // XXX: if we had asymmetrical predistortion this wouldn't be true |
5 | 265 for (uint16_t i = 0; i < shapesamples; i++) { |
7
4ad473648949
Copy pulse up in reverse for pulse down.
Daniel O'Connor <darius@dons.net.au>
parents:
6
diff
changeset
|
266 data[idx++] = data[bit1stopup - i]; |
5 | 267 // Could replace this with a separate loop to poke it into place |
268 // Similarly for TR switch when implemented | |
269 if (i == 0 && c == 0) | |
16 | 270 ctrl[idx] = ctrltmp | SENSE1; |
5 | 271 else |
272 ctrl[idx] = ctrltmp; | |
273 } | |
274 | |
275 // Code gap | |
276 if (c < ncode - 1) | |
277 for (uint16_t i = 0; i < codegap; i++) { | |
278 data[idx++] = dcofs; | |
279 ctrl[idx] = ctrltmp; | |
280 } | |
281 } | |
282 | |
283 // Down slew | |
8
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
284 for (uint16_t i = 0; i < slew2 + 1; i++) { |
5 | 285 data[idx++] = qtoi(qdiv(qmul(qint(dcofs), qint(slew2 - i)), qint(slew2))); |
286 ctrl[idx] |= PACTIVE; | |
287 } | |
11
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
288 |
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
289 data[idx++] = 0; |
16 | 290 ctrl[idx] = 0; |
11
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
291 |
16 | 292 return idx + 1; |
5 | 293 } |
294 | |
0
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
295 int |
3
b10097c3383d
DMA test data repeatedly into PIO FIFO
Daniel O'Connor <darius@dons.net.au>
parents:
2
diff
changeset
|
296 main(void) { |
5 | 297 absolute_time_t then, now; |
298 | |
299 // Set sysclk to 120MHz | |
300 set_sys_clock_khz(120000, true); | |
0
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
301 |
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
302 stdio_init_all(); |
5 | 303 printf("\n\n\nIniting\n"); |
0
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
304 |
5 | 305 // Needed otherwise timer related functions hang under debugging |
306 // https://github.com/raspberrypi/pico-sdk/issues/1152#issuecomment-1418248639 | |
307 timer_hw->dbgpause = 0; | |
308 | |
309 gpio_init(PICO_DEFAULT_LED_PIN); | |
310 gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT); | |
9 | 311 gpio_init(2); |
312 gpio_set_dir(2, GPIO_OUT); | |
11
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
313 |
9 | 314 #if 0 |
16 | 315 // GPIO tester to check breadboard wiring |
9 | 316 for (unsigned i = 7; i < 7 + 9; i++) { |
317 printf("GPIO %d\n", i); | |
318 gpio_init(i); | |
319 gpio_set_dir(i, GPIO_OUT); | |
320 printf("on\n"); | |
321 gpio_put(i, 1); | |
322 __breakpoint(); | |
323 printf("off\n"); | |
324 gpio_put(i, 0); | |
325 __breakpoint(); | |
326 } | |
327 #endif | |
5 | 328 |
329 uint32_t idx; | |
8
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
330 uint16_t plen; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
331 char *code; |
9 | 332 if (1) { |
8
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
333 plen = 8000; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
334 code = "1110010"; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
335 } else { |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
336 plen = 53000; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
337 code = "1"; |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
338 } |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
339 |
5 | 340 uint8_t codegap = 4; |
341 uint8_t slew1 = 10; | |
342 uint8_t slew2 = 10; | |
343 uint8_t dcofs = 110; | |
344 then = get_absolute_time(); | |
345 if ((idx = compute_pulse(pulse_data, pulse_ctrl, sizeof(pulse_data), | |
346 plen, code, strlen(code), | |
347 shaped_trap, sizeof(shaped_trap), | |
348 codegap, slew1, slew2, dcofs)) == 0) { | |
349 printf("Failed to compute pulse\n"); | |
350 while (1) | |
351 ; | |
352 } | |
353 now = get_absolute_time(); | |
8
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
354 unsigned long long diff = absolute_time_diff_us(then, now); |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
355 printf("Pulse computation took %lld usec and created %lu samples - %.1f nsec/sample\n", |
0249d0cecac4
Use interpolator to compute pulse up.
Daniel O'Connor <darius@dons.net.au>
parents:
7
diff
changeset
|
356 diff, idx, (float)diff * 1000.0 / idx); |
10
98880b18bcc1
Reset DAC PIO and use force trigger to do manual trigger.
Daniel O'Connor <darius@dons.net.au>
parents:
9
diff
changeset
|
357 //__breakpoint(); |
9 | 358 |
11
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
359 // Load the DAC program, and configure a free state machine |
9 | 360 // to run the program. |
16 | 361 dac_pio_sm_offset = pio_add_program(pulse_pio, &dac_program); |
362 if (dac_pio_sm_offset < 0) { | |
363 printf("Unable to load DAC program\n"); | |
364 __breakpoint(); | |
365 } | |
366 dac_sm = pio_claim_unused_sm(pulse_pio, true); | |
9 | 367 // Data is GPIO7 to GPIO14, clock is GPIO15 |
368 // Clock divisor of 2 so it runs at 60MHz and | |
369 // generates a 30MHz clock | |
16 | 370 dac_program_init(pulse_pio, dac_sm, dac_pio_sm_offset, DACOUT_GPIO, 2); |
9 | 371 |
372 // Configure a channel to write 32 bits at a time to PIO0 | |
373 // SM0's TX FIFO, paced by the data request signal from that peripheral. | |
16 | 374 dac_dma_chan = dma_claim_unused_channel(true); |
375 dma_channel_config dac_dmac = dma_channel_get_default_config(dac_dma_chan); | |
376 channel_config_set_transfer_data_size(&dac_dmac, DMA_SIZE_32); | |
377 channel_config_set_read_increment(&dac_dmac, true); | |
378 channel_config_set_dreq(&dac_dmac, PIO_DREQ_NUM(pulse_pio, dac_sm, true)); | |
9 | 379 |
380 dma_channel_configure( | |
16 | 381 dac_dma_chan, |
382 &dac_dmac, | |
383 &pulse_pio->txf[dac_sm], // Write address | |
384 pulse_data, // Pulse data | |
385 (idx + 3) >> 2, // Transfer count (round up to 4 bytes) | |
386 true // Start, SM will wait for trigger | |
9 | 387 ); |
388 | |
389 // Tell the DMA to raise IRQ line 0 when the channel finishes a block | |
16 | 390 dma_channel_set_irq0_enabled(dac_dma_chan, true); |
9 | 391 |
392 // Configure the processor to run dma_handler() when DMA IRQ 0 is asserted | |
393 irq_set_exclusive_handler(DMA_IRQ_0, dma_handler); | |
394 irq_set_enabled(DMA_IRQ_0, true); | |
395 | |
16 | 396 // Load the ctrl program, and configure a free state machine |
397 // to run the program. | |
398 ctrl_pio_sm_offset = pio_add_program(pulse_pio, &ctrl_program); | |
399 if (ctrl_pio_sm_offset < 0) { | |
400 printf("Unable to load ctrl program\n"); | |
401 __breakpoint(); | |
402 } | |
403 ctrl_sm = pio_claim_unused_sm(pulse_pio, true); | |
404 ctrl_program_init(pulse_pio, ctrl_sm, ctrl_pio_sm_offset, CTRLOUT_GPIO, 2); | |
405 | |
406 // Configure a channel to write 32 bits at a time to PIO0 | |
407 // SM0's TX FIFO, paced by the data request signal from that peripheral. | |
408 ctrl_dma_chan = dma_claim_unused_channel(true); | |
409 dma_channel_config ctrl_dmac = dma_channel_get_default_config(ctrl_dma_chan); | |
410 channel_config_set_transfer_data_size(&ctrl_dmac, DMA_SIZE_32); | |
411 channel_config_set_read_increment(&ctrl_dmac, true); | |
412 channel_config_set_dreq(&ctrl_dmac, PIO_DREQ_NUM(pulse_pio, ctrl_sm, true)); | |
413 | |
414 dma_channel_configure( | |
415 ctrl_dma_chan, | |
416 &ctrl_dmac, | |
417 &pulse_pio->txf[ctrl_sm], // Write address | |
418 pulse_ctrl, // Ctrl data | |
419 (idx + 3) >> 2, // Transfer count (round up to 4 bytes) | |
420 true // Start, SM will wait for trigger | |
421 ); | |
422 // No IRQ, piggyback on the data one | |
423 | |
424 #if 0 | |
11
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
425 // Load the trigger program, and configure a free state machine |
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
426 // to run the program. |
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
427 uint trigger_pio_sm_offset = pio_add_program(pulse_pio, &trigger_program); |
16 | 428 if (trigger_pio_sm_offset < 0) { |
429 printf("Unable to load trigger program\n"); | |
430 __breakpoint(); | |
431 } | |
11
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
432 uint trigger_sm = pio_claim_unused_sm(pulse_pio, true); |
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
433 trigger_program_init(pulse_pio, trigger_sm, trigger_pio_sm_offset, TRIGIN_GPIO, 2); |
16 | 434 #endif |
11
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
435 // |
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
436 // Setup PWM |
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
437 // Used here to output a trigger which gets fed back into the trigger SM |
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
438 // |
5 | 439 // 120MHz / 250 = 480kHz base |
440 // Maximum divisor is only 256 which limits the low end, | |
441 // could further subdivide in the IRQ handler | |
9 | 442 pwm_config c = pwm_get_default_config(); |
5 | 443 pwm_config_set_clkdiv_int(&c, 250); |
444 // 8Hz | |
445 pwm_config_set_wrap(&c, 60000 - 1); | |
11
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
446 |
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
447 gpio_set_function(TRIGOUT_GPIO, GPIO_FUNC_PWM); |
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
448 |
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
449 slice_num = pwm_gpio_to_slice_num(TRIGOUT_GPIO); |
5 | 450 pwm_init(slice_num, &c, true); |
451 pwm_clear_irq(slice_num); | |
11
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
452 pwm_set_chan_level(slice_num, PWM_CHAN_A, 1); |
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
453 pwm_set_enabled(slice_num, 1); |
5 | 454 pwm_set_irq_enabled(slice_num, true); |
455 irq_set_exclusive_handler(PWM_IRQ_WRAP, pwm_wrap); | |
456 irq_set_enabled(PWM_IRQ_WRAP, true); | |
11
e9d12b36cfcc
Use PWM output to feed PIO trigger
Daniel O'Connor <darius@dons.net.au>
parents:
10
diff
changeset
|
457 |
3
b10097c3383d
DMA test data repeatedly into PIO FIFO
Daniel O'Connor <darius@dons.net.au>
parents:
2
diff
changeset
|
458 // Everything else from this point is interrupt-driven. The processor has |
b10097c3383d
DMA test data repeatedly into PIO FIFO
Daniel O'Connor <darius@dons.net.au>
parents:
2
diff
changeset
|
459 // time to sit and think about its early retirement -- maybe open a bakery? |
0
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
460 while (true) { |
5 | 461 gpio_put(PICO_DEFAULT_LED_PIN, 1); |
462 sleep_ms(100); | |
463 gpio_put(PICO_DEFAULT_LED_PIN, 0); | |
2
0d653f60dec8
Actually get data moving out.
Daniel O'Connor <darius@dons.net.au>
parents:
0
diff
changeset
|
464 sleep_ms(100); |
0
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
465 } |
5 | 466 |
467 __breakpoint(); | |
0
a55e39064a71
First commit of code that compiles.
Daniel O'Connor <darius@dons.net.au>
parents:
diff
changeset
|
468 } |