SimpleFOClibrary 2.4.0
Loading...
Searching...
No Matches
current_sense/hardware_specific/teensy/teensy4_mcu.cpp
Go to the documentation of this file.
1#include "teensy4_mcu.h"
2#include "../../../drivers/hardware_specific/teensy/teensy4_mcu.h"
3// #include "../../../common/lowpass_filter.h"
4#include "../../../common/foc_utils.h"
5#include "../../../communication/SimpleFOCDebug.h"
6
7// if defined
8// - Teensy 4.0
9// - Teensy 4.1
10#if defined(__arm__) && defined(CORE_TEENSY) && ( defined(__IMXRT1062__) || defined(ARDUINO_TEENSY40) || defined(ARDUINO_TEENSY41) || defined(ARDUINO_TEENSY_MICROMOD) )
11
12// #define SIMPLEFOC_TEENSY4_ADC_INTERRUPT_DEBUG
13
14
15volatile uint32_t val0, val1, val2;
16
17// #define _BANDWIDTH_CS 10000.0f // [Hz] bandwidth for the current sense
18// LowPassFilter lp1 = LowPassFilter(1.0/_BANDWIDTH_CS);
19// LowPassFilter lp2 = LowPassFilter(1.0/_BANDWIDTH_CS);
20// LowPassFilter lp3 = LowPassFilter(1.0/_BANDWIDTH_CS);
21
22void read_currents(uint32_t *a, uint32_t*b, uint32_t *c=nullptr){
23 *a = val0;
24 *b = val1;
25 *c = val2;
26}
27
28// interrupt service routine for the ADC_ETC0
29// reading the ADC values and clearing the interrupt
30void adcetc0_isr() {
31#ifdef SIMPLEFOC_TEENSY4_ADC_INTERRUPT_DEBUG
32 digitalWrite(30,HIGH);
33#endif
34 // page 3509 , section 66.5.1.3.3
35 ADC_ETC_DONE0_1_IRQ |= 1; // clear Done0 for trg0 at 1st bit
36 // val0 = lp1(ADC_ETC_TRIG0_RESULT_1_0 & 4095);
37 val0 = (ADC_ETC_TRIG0_RESULT_1_0 & 4095);
38 // val1 = lp2((ADC_ETC_TRIG0_RESULT_1_0 >> 16) & 4095);
39 val1 = (ADC_ETC_TRIG0_RESULT_1_0 >> 16) & 4095;
40#ifdef SIMPLEFOC_TEENSY4_ADC_INTERRUPT_DEBUG
41 digitalWrite(30,LOW);
42#endif
43}
44
45
46void adcetc1_isr() {
47#ifdef SIMPLEFOC_TEENSY4_ADC_INTERRUPT_DEBUG
48 digitalWrite(30,HIGH);
49#endif
50 // page 3509 , section 66.5.1.3.3
51 ADC_ETC_DONE0_1_IRQ |= 1 << 16; // clear Done1 for trg0 at 16th bit
52 val2 = ADC_ETC_TRIG0_RESULT_3_2 & 4095;
53// val2 = lp3( ADC_ETC_TRIG0_RESULT_3_2 & 4095);
54#ifdef SIMPLEFOC_TEENSY4_ADC_INTERRUPT_DEBUG
55 digitalWrite(30,LOW);
56#endif
57}
58
59// function initializing the ADC2
60// and the ADC_ETC trigger for the low side current sensing
61void adc1_init(int pin1, int pin2, int pin3=NOT_SET) {
62 //Tried many configurations, but this seems to be best:
63 ADC1_CFG = ADC_CFG_OVWREN //Allow overwriting of the next converted Data onto the existing
64 | ADC_CFG_ADICLK(0) // input clock select - IPG clock
65 | ADC_CFG_MODE(2) // 12-bit conversion 0 8-bit conversion 1 10-bit conversion 2 12-bit conversion
66 | ADC_CFG_ADIV(2) // Input clock / 2 (0 for /1, 1 for /2 and 2 for / 4) (1 is faster and maybe with some filtering could provide better results but 2 for now)
67 | ADC_CFG_ADSTS(0) // Sample period (ADC clocks) = 3 if ADLSMP=0b
68 | ADC_CFG_ADHSC // High speed operation
69 | ADC_CFG_ADTRG; // Hardware trigger selected
70
71
72 //Calibration of ADC1
73 ADC1_GC |= ADC_GC_CAL; // begin cal ADC1
74 while (ADC1_GC & ADC_GC_CAL) ;
75
76 ADC1_HC0 = 16; // ADC_ETC channel
77 // use the second interrupt if necessary (for more than 2 channels)
78 if(_isset(pin3)) {
79 ADC1_HC1 = 16;
80 }
81}
82
83// function initializing the ADC2
84// and the ADC_ETC trigger for the low side current sensing
85void adc2_init(){
86
87 // configuring ADC2
88 //Tried many configurations, but this seems to be best:
89 ADC1_CFG = ADC_CFG_OVWREN //Allow overwriting of the next converted Data onto the existing
90 | ADC_CFG_ADICLK(0) // input clock select - IPG clock
91 | ADC_CFG_MODE(2) // 12-bit conversion 0 8-bit conversion 1 10-bit conversion 2 12-bit conversion
92 | ADC_CFG_ADIV(2) // Input clock / 2 (0 for /1, 1 for /2 and 2 for / 4)
93 | ADC_CFG_ADSTS(0) // Sample period (ADC clocks) = 3 if ADLSMP=0b
94 | ADC_CFG_ADHSC // High speed operation
95 | ADC_CFG_ADTRG; // Hardware trigger selected
96
97 //Calibration of ADC2
98 ADC2_GC |= ADC_GC_CAL; // begin cal ADC2
99 while (ADC2_GC & ADC_GC_CAL) ;
100
101 ADC2_HC0 = 16; // ADC_ETC channel
102 // use the second interrupt if necessary (for more than 2 channels)
103 // ADC2_HC1 = 16;
104}
105
106// function initializing the ADC_ETC trigger for the low side current sensing
107// it uses only the ADC1
108// if the pin3 is not set it uses only 2 channels
109void adc_etc_init(int pin1, int pin2, int pin3=NOT_SET) {
110 ADC_ETC_CTRL &= ~(1 << 31); // SOFTRST
111 ADC_ETC_CTRL = 0x40000001; // start with trigger 0
112 ADC_ETC_TRIG0_CTRL = ADC_ETC_TRIG_CTRL_TRIG_CHAIN( _isset(pin3) ? 2 : 1) ; // 2 if 3 channels, 1 if 2 channels
113
114 // ADC1 7 8, chain channel, HWTS, IE, B2B
115 // pg 3516, section 66.5.1.8
116 ADC_ETC_TRIG0_CHAIN_1_0 =
117 ADC_ETC_TRIG_CHAIN_IE1(0) | // no interrupt on first or set 2 if interrupt when Done1
118 ADC_ETC_TRIG_CHAIN_B2B1 | // Enable B2B, back to back ADC trigger
119 ADC_ETC_TRIG_CHAIN_HWTS1(1) |
120 ADC_ETC_TRIG_CHAIN_CSEL1(pin_to_channel[pin1]) | // ADC channel 8
121 ADC_ETC_TRIG_CHAIN_IE0(1) | // interrupt when Done0
122 ADC_ETC_TRIG_CHAIN_B2B1 | // Enable B2B, back to back ADC trigger
123 ADC_ETC_TRIG_CHAIN_HWTS0(1) |
124 ADC_ETC_TRIG_CHAIN_CSEL0(pin_to_channel[pin2]); // ADC channel 7
125
126 attachInterruptVector(IRQ_ADC_ETC0, adcetc0_isr);
127 NVIC_ENABLE_IRQ(IRQ_ADC_ETC0);
128 // use the second interrupt if necessary (for more than 2 channels)
129 if(_isset(pin3)) {
130 ADC_ETC_TRIG0_CHAIN_3_2 =
131 ADC_ETC_TRIG_CHAIN_IE0(2) | // interrupt when Done1
132 ADC_ETC_TRIG_CHAIN_B2B0 | // Enable B2B, back to back ADC trigger
133 ADC_ETC_TRIG_CHAIN_HWTS0(1) |
134 ADC_ETC_TRIG_CHAIN_CSEL0(pin_to_channel[pin3]);
135
136 attachInterruptVector(IRQ_ADC_ETC1, adcetc1_isr);
137 NVIC_ENABLE_IRQ(IRQ_ADC_ETC1);
138 }
139}
140
141
142
143// function reading an ADC value and returning the read voltage
144float _readADCVoltageLowSide(const int pinA, const void* cs_params){
145
146 if(!_isset(pinA)) return 0.0; // if the pin is not set return 0
149 if (pinA == params->pins[0]) {
150 return val0 * adc_voltage_conv;
151 } else if (pinA == params->pins[1]) {
152 return val1 * adc_voltage_conv;
153 }else if (pinA == params->pins[2]) {
154 return val2 * adc_voltage_conv;
155 }
156 return 0.0;
157}
158
159// Configure low side for generic mcu
160// cannot do much but
161void* _configureADCLowSide(const void* driver_params, const int pinA,const int pinB,const int pinC){
162 Teensy4DriverParams* par = (Teensy4DriverParams*) ((TeensyDriverParams*)driver_params)->additional_params;
163 if(par == nullptr){
164 SIMPLEFOC_DEBUG("TEENSY-CS: Low side current sense failed, driver not supported!");
166 }
167
168 SIMPLEFOC_DEBUG("TEENSY-CS: Configuring low side current sense!");
169
170#ifdef SIMPLEFOC_TEENSY4_ADC_INTERRUPT_DEBUG
171 pinMode(30,OUTPUT);
172#endif
173
174 if( _isset(pinA) ) pinMode(pinA, INPUT);
175 if( _isset(pinB) ) pinMode(pinB, INPUT);
176 if( _isset(pinC) ) pinMode(pinC, INPUT);
177
178 // check if either of the pins are not set
179 // and dont use it if it isn't
180 int pin_count = 0;
181 int pins[3] = {NOT_SET, NOT_SET, NOT_SET};
182 if(_isset(pinA)) pins[pin_count++] = pinA;
183 if(_isset(pinB)) pins[pin_count++] = pinB;
184 if(_isset(pinC)) pins[pin_count++] = pinC;
185
186
187 adc1_init(pins[0], pins[1], pins[2]);
188 adc_etc_init(pins[0], pins[1], pins[2]);
189
190 xbar_init();
191
193 .pins = {pins[0], pins[1], pins[2] },
194 .adc_voltage_conv = (_ADC_VOLTAGE)/(_ADC_RESOLUTION)
195 };
196 return params;
197}
198
199// sync driver and the adc
200void* _driverSyncLowSide(void* driver_params, void* cs_params){
201 Teensy4DriverParams* par = (Teensy4DriverParams*) ((TeensyDriverParams*)driver_params)->additional_params;
202 IMXRT_FLEXPWM_t* flexpwm = par->flextimers[0];
203 int submodule = par->submodules[0];
204
205 SIMPLEFOC_DEBUG("TEENSY-CS: Syncing low side current sense!");
206 char buff[50];
207 sprintf(buff, "TEENSY-CS: Syncing to FlexPWM: %d, Submodule: %d", flexpwm_to_index(flexpwm), submodule);
208 SIMPLEFOC_DEBUG(buff);
209
210 // find the xbar trigger for the flexpwm
211 int xbar_trig_pwm = flexpwm_submodule_to_trig(flexpwm, submodule);
212 if(xbar_trig_pwm<0) return;
213
214 // allow theFlexPWM to trigger the ADC_ETC
215 xbar_connect((uint32_t)xbar_trig_pwm, XBARA1_OUT_ADC_ETC_TRIG00); //FlexPWM to adc_etc
216
217 // setup the ADC_ETC trigger to be triggered by the FlexPWM channel 1 (val1)
218 //This val1 interrupt on match is in the center of the PWM
219 flexpwm->SM[submodule].TCTRL = FLEXPWM_SMTCTRL_OUT_TRIG_EN(1<<1);
220
221
222 // if needed the interrupt can be moved to some other point in the PWM cycle by using an addional val register example: VAL4
223 // setup the ADC_ETC trigger to be triggered by the FlexPWM channel 4 (val4)
224 // flexpwm->SM[submodule].TCTRL = FLEXPWM_SMTCTRL_OUT_TRIG_EN(1<<4);
225 // setup this val4 for interrupt on match for ADC sync
226 // this code assumes that the val4 is not used for anything else!
227 // reading two ADC takes about 2.5us. So put the interrupt 2.5us befor the center
228 // flexpwm->SM[submodule].VAL4 = int(flexpwm->SM[submodule].VAL1*(1.0f - 2.5e-6*par->pwm_frequency)) ; // 2.5us before center
229
230
231#ifdef SIMPLEFOC_TEENSY4_ADC_INTERRUPT_DEBUG
232 // pin 4 observes out trigger line for 'scope
233 xbar_connect (xbar_trig_pwm, XBARA1_OUT_IOMUX_XBAR_INOUT08) ;
234 IOMUXC_GPR_GPR6 |= IOMUXC_GPR_GPR6_IOMUXC_XBAR_DIR_SEL_8 ; // select output mode for INOUT8
235 // Select alt 3 for EMC_06 (XBAR), rather than original 5 (GPIO)
236 CORE_PIN4_CONFIG = 3 ; // shorthand for IOMUXC_SW_MUX_CTL_PAD_GPIO_EMC_06 = 3 ;
237 // turn up drive & speed as very short pulse
238 IOMUXC_SW_PAD_CTL_PAD_GPIO_EMC_06 = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_SPEED(3) | IOMUXC_PAD_SRE ;
239#endif
240
241
242 // return the cs parameters
243 // successfully initialized
244 // TODO verify if success in future
245 return cs_params;
246}
247
248
249#endif
#define SIMPLEFOC_DEBUG(msg,...)
void * _driverSyncLowSide(void *driver_params, void *cs_params)
#define SIMPLEFOC_CURRENT_SENSE_INIT_FAILED
void * _configureADCLowSide(const void *driver_params, const int pinA, const int pinB, const int pinC=NOT_SET)
float _readADCVoltageLowSide(const int pinA, const void *cs_params)
const int const int const int pinC
GenericCurrentSenseParams * params
return raw_adc *GenericCurrentSenseParams *cs_params adc_voltage_conv
float a
Definition foc_utils.cpp:59
float float * c
Definition foc_utils.cpp:43
#define NOT_SET
Definition foc_utils.h:34
#define _isset(a)
Definition foc_utils.h:13