1
+
2
+ #if defined(TARGET_RP2040)
3
+
4
+
5
+ #include " ../../hardware_api.h"
6
+ #include " ./rp2040_mcu.h"
7
+ #include " ../../../drivers/hardware_specific/rp2040_mcu.h"
8
+ #include " communication/SimpleFOCDebug.h"
9
+
10
+ #include " hardware/dma.h"
11
+ #include " hardware/irq.h"
12
+ #include " hardware/pwm.h"
13
+
14
+
15
+ /* Singleton instance of the ADC engine */
16
+ RP2040ADCEngine engine;
17
+
18
+ alignas (32 ) const uint32_t trigger_value = ADC_CS_START_ONCE_BITS; // start once
19
+
20
+ /* Hardware API implementation */
21
+
22
+ float _readADCVoltageInline (const int pinA, const void * cs_params) {
23
+ // not super-happy with this. Here we have to return 1 phase current at a time, when actually we want to
24
+ // return readings from the same ADC conversion run. The ADC on RP2040 is anyway in round robin mode :-(
25
+ // like this we have block interrupts 3x instead of just once, and of course have the chance of reading across
26
+ // new ADC conversions, which probably won't improve the accuracy.
27
+
28
+ if (pinA>=26 && pinA<=29 && engine.channelsEnabled [pinA-26 ]) {
29
+ return engine.lastResults [pinA-26 ]*engine.adc_conv ;
30
+ }
31
+
32
+ // otherwise return NaN
33
+ return NAN;
34
+ };
35
+
36
+
37
+ void * _configureADCInline (const void *driver_params, const int pinA, const int pinB, const int pinC) {
38
+ if ( _isset (pinA) )
39
+ engine.addPin (pinA);
40
+ if ( _isset (pinB) )
41
+ engine.addPin (pinB);
42
+ if ( _isset (pinC) )
43
+ engine.addPin (pinC);
44
+ engine.init (); // TODO this has to happen later if we want to support more than one motor...
45
+ engine.start ();
46
+ return &engine;
47
+ };
48
+
49
+
50
+ void * _configureADCLowSide (const void *driver_params, const int pinA, const int pinB, const int pinC) {
51
+ if ( _isset (pinA) )
52
+ engine.addPin (pinA);
53
+ if ( _isset (pinB) )
54
+ engine.addPin (pinB);
55
+ if ( _isset (pinC) )
56
+ engine.addPin (pinC);
57
+ engine.setPWMTrigger (((RP2040DriverParams*)driver_params)->slice [0 ]);
58
+ engine.init ();
59
+ engine.start ();
60
+ return &engine;
61
+ };
62
+
63
+
64
+ void _startADC3PinConversionLowSide () {
65
+ // what is this for?
66
+ };
67
+
68
+
69
+ float _readADCVoltageLowSide (const int pinA, const void * cs_params) {
70
+ // not super-happy with this. Here we have to return 1 phase current at a time, when actually we want to
71
+ // return readings from the same ADC conversion run. The ADC on RP2040 is anyway in round robin mode :-(
72
+ // like this we have block interrupts 3x instead of just once, and of course have the chance of reading across
73
+ // new ADC conversions, which probably won't improve the accuracy.
74
+
75
+ if (pinA>=26 && pinA<=29 && engine.channelsEnabled [pinA-26 ]) {
76
+ return engine.lastResults [pinA-26 ]*engine.adc_conv ;
77
+ }
78
+
79
+ // otherwise return NaN
80
+ return NAN;
81
+ };
82
+
83
+
84
+ void _driverSyncLowSide (void * driver_params, void * cs_params) {
85
+ // nothing to do
86
+ };
87
+
88
+
89
+
90
+ volatile int rp2040_intcount = 0 ;
91
+
92
+ void _adcConversionFinishedHandler () {
93
+ // conversion of all channels finished. copy results.
94
+ volatile uint8_t * from = engine.samples ;
95
+ if (engine.channelsEnabled [0 ])
96
+ engine.lastResults [0 ] = (*from++);
97
+ if (engine.channelsEnabled [1 ])
98
+ engine.lastResults [1 ] = (*from++);
99
+ if (engine.channelsEnabled [2 ])
100
+ engine.lastResults [2 ] = (*from++);
101
+ if (engine.channelsEnabled [3 ])
102
+ engine.lastResults [3 ] = (*from++);
103
+ // TODO clear interrupt? dma_hw->ints0 = 1u << channel;
104
+ // irq_clear(DMA_IRQ_0);
105
+ // dma_channel_acknowledge_irq0(engine.copyDMAChannel);
106
+ // dma_start_channel_mask( (1u << engine.readDMAChannel) | (1u << engine.copyDMAChannel) );
107
+ dma_hw->ints0 = 1u << engine.readDMAChannel ;
108
+ // dma_start_channel_mask( (1u << engine.readDMAChannel) );
109
+ dma_channel_set_write_addr (engine.readDMAChannel , engine.samples , true );
110
+ if (engine.triggerPWMSlice >=0 )
111
+ dma_channel_set_trans_count (engine.triggerDMAChannel , 1 , true );
112
+ rp2040_intcount++;
113
+ };
114
+
115
+
116
+
117
+ /* ADC engine implementation */
118
+
119
+
120
+ RP2040ADCEngine::RP2040ADCEngine () {
121
+ channelsEnabled[0 ] = false ;
122
+ channelsEnabled[1 ] = false ;
123
+ channelsEnabled[2 ] = false ;
124
+ channelsEnabled[3 ] = false ;
125
+ initialized = false ;
126
+ };
127
+
128
+
129
+
130
+ void RP2040ADCEngine::addPin (int pin){
131
+ if (pin>=26 && pin<=29 )
132
+ channelsEnabled[pin-26 ] = true ;
133
+ else
134
+ SIMPLEFOC_DEBUG (" RP2040-CUR: ERR: Not an ADC pin: " , pin);
135
+ };
136
+
137
+
138
+
139
+ void RP2040ADCEngine::setPWMTrigger (uint slice){
140
+ triggerPWMSlice = slice;
141
+ };
142
+
143
+
144
+
145
+
146
+ bool RP2040ADCEngine::init (){
147
+ if (initialized)
148
+ return true ;
149
+
150
+ adc_init ();
151
+ int enableMask = 0x00 ;
152
+ int channelCount = 0 ;
153
+ for (int i = 3 ; i>=0 ; i--) {
154
+ if (channelsEnabled[i]){
155
+ adc_gpio_init (i+26 );
156
+ enableMask |= 0x01 ;
157
+ channelCount++;
158
+ }
159
+ enableMask = (enableMask<<1 );
160
+ }
161
+ adc_set_round_robin (enableMask);
162
+ adc_fifo_setup (
163
+ true , // Write each completed conversion to the sample FIFO
164
+ true , // Enable DMA data request (DREQ)
165
+ channelCount, // DREQ (and IRQ) asserted when all samples present
166
+ false , // We won't see the ERR bit because of 8 bit reads; disable.
167
+ true // Shift each sample to 8 bits when pushing to FIFO
168
+ );
169
+ samples_per_second = 20000 ;
170
+ if (samples_per_second<1 || samples_per_second>=500000 ) {
171
+ samples_per_second = 0 ;
172
+ adc_set_clkdiv (0 );
173
+ }
174
+ else
175
+ adc_set_clkdiv (48000000 /samples_per_second);
176
+ SIMPLEFOC_DEBUG (" RP2040-CUR: ADC init" );
177
+
178
+ readDMAChannel = dma_claim_unused_channel (true );
179
+ dma_channel_config cc1 = dma_channel_get_default_config (readDMAChannel);
180
+ channel_config_set_transfer_data_size (&cc1, DMA_SIZE_8);
181
+ channel_config_set_read_increment (&cc1, false );
182
+ channel_config_set_write_increment (&cc1, true );
183
+ channel_config_set_dreq (&cc1, DREQ_ADC);
184
+ channel_config_set_irq_quiet (&cc1, false );
185
+ dma_channel_configure (readDMAChannel,
186
+ &cc1,
187
+ samples, // dest
188
+ &adc_hw->fifo , // source
189
+ channelCount, // count
190
+ false // defer start
191
+ );
192
+ dma_channel_set_irq0_enabled (readDMAChannel, true );
193
+ irq_add_shared_handler (DMA_IRQ_0, _adcConversionFinishedHandler, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
194
+
195
+ // copyDMAChannel = dma_claim_unused_channel(true);
196
+ // dma_channel_config cc2 = dma_channel_get_default_config(copyDMAChannel);
197
+ // channel_config_set_transfer_data_size(&cc2, DMA_SIZE_32);
198
+ // channel_config_set_read_increment(&cc2, false);
199
+ // channel_config_set_write_increment(&cc2, false);
200
+ // channel_config_set_chain_to(&cc2, readDMAChannel);
201
+ // channel_config_set_irq_quiet(&cc2, false);
202
+ // dma_channel_configure(copyDMAChannel,
203
+ // &cc2,
204
+ // nextResults, // dest
205
+ // samples, // source
206
+ // 1, // count
207
+ // false // defer start
208
+ // );
209
+ // dma_channel_set_irq0_enabled(copyDMAChannel, true);
210
+ // irq_add_shared_handler(DMA_IRQ_0, _adcConversionFinishedHandler, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
211
+ SIMPLEFOC_DEBUG (" RP2040-CUR: DMA init" );
212
+
213
+ if (triggerPWMSlice>=0 ) { // if we have a trigger
214
+ triggerDMAChannel = dma_claim_unused_channel (true );
215
+ dma_channel_config cc3 = dma_channel_get_default_config (triggerDMAChannel);
216
+ channel_config_set_transfer_data_size (&cc3, DMA_SIZE_32);
217
+ channel_config_set_read_increment (&cc3, false );
218
+ channel_config_set_write_increment (&cc3, false );
219
+ channel_config_set_irq_quiet (&cc3, true );
220
+ channel_config_set_dreq (&cc3, DREQ_PWM_WRAP0+triggerPWMSlice); // pwm_get_dreq(triggerPWMSlice));
221
+ pwm_set_irq_enabled (triggerPWMSlice, true );
222
+ dma_channel_configure (triggerDMAChannel,
223
+ &cc3,
224
+ hw_set_alias_untyped (&adc_hw->cs ), // dest
225
+ &trigger_value, // source
226
+ 1 , // count
227
+ true // defer start
228
+ );
229
+ SIMPLEFOC_DEBUG (" RP2040-CUR: PWM trigger init slice " , triggerPWMSlice);
230
+ }
231
+
232
+ initialized = true ;
233
+ return initialized;
234
+ };
235
+
236
+
237
+
238
+
239
+ void RP2040ADCEngine::start (){
240
+ SIMPLEFOC_DEBUG (" RP2040-CUR: ADC engine starting" );
241
+ irq_set_enabled (DMA_IRQ_0, true );
242
+ dma_start_channel_mask ( (1u << readDMAChannel) ); // | (1u << copyDMAChannel));
243
+ for (int i=0 ;i<4 ;i++) {
244
+ if (channelsEnabled[i]) {
245
+ adc_select_input (i); // set input to first enabled channel
246
+ break ;
247
+ }
248
+ }
249
+ if (triggerPWMSlice>=0 ) {
250
+ dma_start_channel_mask ( (1u << triggerDMAChannel) );
251
+ // hw_set_bits(&adc_hw->cs, trigger_value);
252
+ }
253
+ else
254
+ adc_run (true );
255
+ SIMPLEFOC_DEBUG (" RP2040-CUR: ADC engine started" );
256
+ };
257
+
258
+ void RP2040ADCEngine::stop (){
259
+ adc_run (false );
260
+ dma_channel_abort (readDMAChannel);
261
+ if (triggerPWMSlice>=0 )
262
+ dma_channel_abort (triggerDMAChannel);
263
+ adc_fifo_drain ();
264
+ SIMPLEFOC_DEBUG (" RP2040-CUR: ADC engine stopped" );
265
+ };
266
+
267
+
268
+ #endif
0 commit comments