Skip to content

Commit 81db3f5

Browse files
committed
added support for more than 2/3 adc pins
1 parent b34bd62 commit 81db3f5

File tree

1 file changed

+67
-22
lines changed

1 file changed

+67
-22
lines changed

src/current_sense/hardware_specific/teensy/teensy4_mcu.cpp

Lines changed: 67 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "teensy4_mcu.h"
22
#include "../../../drivers/hardware_specific/teensy/teensy4_mcu.h"
3+
#include "../../../common/foc_utils.h"
34

45
// if defined
56
// - Teensy 4.0
@@ -12,7 +13,7 @@
1213
//
1314
// the flags are defined in the imxrt.h file
1415
// https://github.com/PaulStoffregen/cores/blob/dd6aa8419ee173a0a6593eab669fbff54ed85f48/teensy4/imxrt.h#L9662
15-
int flextim__submodule_to_trig(IMXRT_FLEXPWM_t* flexpwm, int submodule){
16+
int flexpwm_submodule_to_trig(IMXRT_FLEXPWM_t* flexpwm, int submodule){
1617
if(submodule <0 && submodule > 3) return -1;
1718
if(flexpwm == &IMXRT_FLEXPWM1){
1819
return XBARA1_IN_FLEXPWM1_PWM1_OUT_TRIG0 + submodule;
@@ -26,32 +27,45 @@ int flextim__submodule_to_trig(IMXRT_FLEXPWM_t* flexpwm, int submodule){
2627
return -1;
2728
}
2829

29-
volatile uint32_t val0, val1;
30+
volatile uint32_t val0, val1, val2;
3031

31-
void read_currents(uint32_t *a, uint32_t*b){
32+
void read_currents(uint32_t *a, uint32_t*b, uint32_t *c=nullptr){
3233
*a = val0;
3334
*b = val1;
35+
*c = val2;
3436
}
3537

3638
// interrupt service routine for the ADC_ETC0
3739
// reading the ADC values and clearing the interrupt
3840
void adcetc0_isr() {
3941
digitalWrite(30,HIGH);
40-
ADC_ETC_DONE0_1_IRQ |= 1; // clear
42+
// page 3509 , section 66.5.1.3.3
43+
ADC_ETC_DONE0_1_IRQ |= 1; // clear Done0 for trg0 at 1st bit
4144
val0 = ADC_ETC_TRIG0_RESULT_1_0 & 4095;
4245
val1 = (ADC_ETC_TRIG0_RESULT_1_0 >> 16) & 4095;
4346
asm("dsb");
4447
digitalWrite(30,LOW);
4548
}
4649

50+
51+
void adcetc1_isr() {
52+
digitalWrite(30,HIGH);
53+
// page 3509 , section 66.5.1.3.3
54+
ADC_ETC_DONE0_1_IRQ |= 1 << 16; // clear Done1 for trg0 at 16th bit
55+
val2 = ADC_ETC_TRIG0_RESULT_3_2 & 4095;
56+
// val2 = (ADC_ETC_TRIG0_RESULT_3_2 >> 16) & 4095;
57+
asm("dsb");
58+
digitalWrite(30,LOW);
59+
}
60+
4761
// function initializing the ADC2
4862
// and the ADC_ETC trigger for the low side current sensing
49-
void adc1_init() {
63+
void adc1_init(int pin1, int pin2, int pin3=NOT_SET) {
5064
//Tried many configurations, but this seems to be best:
5165
ADC1_CFG = ADC_CFG_OVWREN //Allow overwriting of the next converted Data onto the existing
5266
| ADC_CFG_ADICLK(0) // input clock select - IPG clock
5367
| ADC_CFG_MODE(2) // 12-bit conversion 0 8-bit conversion 1 10-bit conversion 2 12-bit conversion
54-
| ADC_CFG_ADIV(2) // Input clock / 4
68+
| ADC_CFG_ADIV(1) // Input clock / 2 (0 for /1, 1 for /2 and 2 for / 4)
5569
| ADC_CFG_ADSTS(0) // Sample period (ADC clocks) = 3 if ADLSMP=0b
5670
| ADC_CFG_ADHSC // High speed operation
5771
| ADC_CFG_ADTRG; // Hardware trigger selected
@@ -63,7 +77,9 @@ void adc1_init() {
6377

6478
ADC1_HC0 = 16; // ADC_ETC channel
6579
// use the second interrupt if necessary (for more than 2 channels)
66-
// ADC1_HC1 = 16;
80+
if(_isset(pin3)) {
81+
ADC1_HC1 = 16;
82+
}
6783
}
6884

6985
// function initializing the ADC2
@@ -75,7 +91,7 @@ void adc2_init(){
7591
ADC1_CFG = ADC_CFG_OVWREN //Allow overwriting of the next converted Data onto the existing
7692
| ADC_CFG_ADICLK(0) // input clock select - IPG clock
7793
| ADC_CFG_MODE(2) // 12-bit conversion 0 8-bit conversion 1 10-bit conversion 2 12-bit conversion
78-
| ADC_CFG_ADIV(2) // Input clock / 4
94+
| ADC_CFG_ADIV(1) // Input clock / 2 (0 for /1, 1 for /2 and 2 for / 4)
7995
| ADC_CFG_ADSTS(0) // Sample period (ADC clocks) = 3 if ADLSMP=0b
8096
| ADC_CFG_ADHSC // High speed operation
8197
| ADC_CFG_ADTRG; // Hardware trigger selected
@@ -89,10 +105,13 @@ void adc2_init(){
89105
// ADC2_HC1 = 16;
90106
}
91107

92-
void adc_etc_init(int pin1, int pin2) {
108+
// function initializing the ADC_ETC trigger for the low side current sensing
109+
// it uses only the ADC1
110+
// if the pin3 is not set it uses only 2 channels
111+
void adc_etc_init(int pin1, int pin2, int pin3=NOT_SET) {
93112
ADC_ETC_CTRL &= ~(1 << 31); // SOFTRST
94113
ADC_ETC_CTRL = 0x40000001; // start with trigger 0
95-
ADC_ETC_TRIG0_CTRL = 0x100; // chainlength -1
114+
ADC_ETC_TRIG0_CTRL = ADC_ETC_TRIG_CTRL_TRIG_CHAIN( _isset(pin3) ? 2 : 1) ; // 2 if 3 channels, 1 if 2 channels
96115

97116
// ADC1 7 8, chain channel, HWTS, IE, B2B
98117
// pg 3516, section 66.5.1.8
@@ -109,11 +128,18 @@ void adc_etc_init(int pin1, int pin2) {
109128
attachInterruptVector(IRQ_ADC_ETC0, adcetc0_isr);
110129
NVIC_ENABLE_IRQ(IRQ_ADC_ETC0);
111130
// use the second interrupt if necessary (for more than 2 channels)
112-
// attachInterruptVector(IRQ_ADC_ETC1, adcetc1_isr);
113-
// NVIC_ENABLE_IRQ(IRQ_ADC_ETC1);
131+
if(_isset(pin3)) {
132+
ADC_ETC_TRIG0_CHAIN_3_2 =
133+
ADC_ETC_TRIG_CHAIN_IE0(2) | // interrupt when Done1
134+
ADC_ETC_TRIG_CHAIN_B2B0 | // Enable B2B, back to back ADC trigger
135+
ADC_ETC_TRIG_CHAIN_HWTS0(1) |
136+
ADC_ETC_TRIG_CHAIN_CSEL0(pin_to_channel[pin3]);
137+
138+
attachInterruptVector(IRQ_ADC_ETC1, adcetc1_isr);
139+
NVIC_ENABLE_IRQ(IRQ_ADC_ETC1);
140+
}
114141
}
115142

116-
117143
void xbar_connect(unsigned int input, unsigned int output)
118144
{
119145
if (input >= 88) return;
@@ -135,12 +161,15 @@ void xbar_init() {
135161
// function reading an ADC value and returning the read voltage
136162
float _readADCVoltageLowSide(const int pinA, const void* cs_params){
137163

164+
if(!_isset(pinA)) return 0.0; // if the pin is not set return 0
138165
GenericCurrentSenseParams* params = (GenericCurrentSenseParams*) cs_params;
139166
float adc_voltage_conv = params->adc_voltage_conv;
140167
if (pinA == params->pins[0]) {
141168
return val0 * adc_voltage_conv;
142169
} else if (pinA == params->pins[1]) {
143170
return val1 * adc_voltage_conv;
171+
}else if (pinA == params->pins[2]) {
172+
return val2 * adc_voltage_conv;
144173
}
145174
return 0.0;
146175
}
@@ -149,18 +178,33 @@ float _readADCVoltageLowSide(const int pinA, const void* cs_params){
149178
// cannot do much but
150179
void* _configureADCLowSide(const void* driver_params, const int pinA,const int pinB,const int pinC){
151180
_UNUSED(driver_params);
181+
// _UNUSED(pinC);
152182

153183
pinMode(30,OUTPUT);
154184

155185
if( _isset(pinA) ) pinMode(pinA, INPUT);
156186
if( _isset(pinB) ) pinMode(pinB, INPUT);
157187
if( _isset(pinC) ) pinMode(pinC, INPUT);
158188

159-
adc1_init();
160-
adc_etc_init(pinA, pinB);
189+
// check if either of the pins are not set
190+
// and dont use it if it isn't
191+
int pin_count = 0;
192+
int pins[3] = {NOT_SET, NOT_SET, NOT_SET};
193+
if(_isset(pinA)) pins[pin_count++] = pinA;
194+
if(_isset(pinB)) pins[pin_count++] = pinB;
195+
if(_isset(pinC)) pins[pin_count++] = pinC;
196+
197+
198+
adc1_init(pins[0], pins[1], pins[2]);
199+
SIMPLEFOC_DEBUG("pins: ",pins[0]);
200+
SIMPLEFOC_DEBUG("pins: ",pins[1]);
201+
SIMPLEFOC_DEBUG("pins: ",pins[2]);
202+
adc_etc_init(pins[0], pins[1], pins[2]);
203+
161204
xbar_init();
205+
162206
GenericCurrentSenseParams* params = new GenericCurrentSenseParams {
163-
.pins = { pinA, pinB, pinC },
207+
.pins = {pins[0], pins[1], pins[2] },
164208
.adc_voltage_conv = (_ADC_VOLTAGE)/(_ADC_RESOLUTION)
165209
};
166210
return params;
@@ -172,17 +216,18 @@ void _driverSyncLowSide(void* driver_params, void* cs_params){
172216
IMXRT_FLEXPWM_t* flexpwm = par->flextimers[0];
173217
int submodule = par->submodules[0];
174218

175-
// do xbar connect here
176-
177-
int xbar_trig_pwm = flextim__submodule_to_trig(flexpwm, submodule);
219+
// find the xbar trigger for the flexpwm
220+
int xbar_trig_pwm = flexpwm_submodule_to_trig(flexpwm, submodule);
178221
if(xbar_trig_pwm<0) return;
179222

223+
// allow theFlexPWM to trigger the ADC_ETC
180224
xbar_connect((uint32_t)xbar_trig_pwm, XBARA1_OUT_ADC_ETC_TRIG00); //FlexPWM to adc_etc
181225

182-
// setup the ADC_ETC trigger
226+
// setup the ADC_ETC trigger to be triggered by the FlexPWM channel 4 (val4)
183227
flexpwm->SM[submodule].TCTRL = FLEXPWM_SMTCTRL_OUT_TRIG_EN(1<<4);
184-
// setup this val4 for interrupt on val5 match for ADC sync
185-
// reading two ARC takes about 5us. So put the interrupt 2.5us befor the center
228+
// setup this val4 for interrupt on match for ADC sync
229+
// this code assumes that the val4 is not used for anything else!
230+
// reading two ADC takes about 2.5us. So put the interrupt 2.5us befor the center
186231
flexpwm->SM[submodule].VAL4 = -int(2.5e-6*par->pwm_frequency*flexpwm->SM[submodule].VAL1) ; // 2.5us before center
187232

188233
}

0 commit comments

Comments
 (0)