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