Skip to content

Commit ce75219

Browse files
committed
FEAT esp32 adc wrapper
1 parent 0b7839f commit ce75219

File tree

11 files changed

+581
-57
lines changed

11 files changed

+581
-57
lines changed

keywords.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ StepperDriver KEYWORD1
1818
PIDController KEYWORD1
1919
LowPassFilter KEYWORD1
2020
InlineCurrentSense KEYWORD1
21+
LowsideCurrentSense KEYWORD1
2122
CurrentSense KEYWORD1
2223
Commander KEYWORD1
2324
StepDirListener KEYWORD1

src/SimpleFOC.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ void loop() {
109109
#include "drivers/StepperDriver4PWM.h"
110110
#include "drivers/StepperDriver2PWM.h"
111111
#include "current_sense/InlineCurrentSense.h"
112+
#include "current_sense/LowSideCurrentSense.h"
112113
#include "communication/Commander.h"
113114
#include "communication/StepDirListener.h"
114115

src/current_sense/LowsideCurrentSense.cpp

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,24 @@ void LowsideCurrentSense::init(){
2727
calibrateOffsets();
2828
}
2929
// Function finding zero offsets of the ADC
30-
void LowsideCurrentSense::calibrateOffsets(){
30+
void LowsideCurrentSense::calibrateOffsets(){
31+
const int calibration_rounds = 1000;
32+
3133
// find adc offset = zero current voltage
32-
offset_ia =0;
33-
offset_ib= 0;
34-
offset_ic= 0;
34+
offset_ia = 0;
35+
offset_ib = 0;
36+
offset_ic = 0;
3537
// read the adc voltage 1000 times ( arbitrary number )
36-
for (int i = 0; i < 1000; i++) {
38+
for (int i = 0; i < calibration_rounds; i++) {
3739
offset_ia += _readADCVoltageLowSide(pinA);
3840
offset_ib += _readADCVoltageLowSide(pinB);
3941
if(_isset(pinC)) offset_ic += _readADCVoltageLowSide(pinC);
4042
_delay(1);
4143
}
4244
// calculate the mean offsets
43-
offset_ia = offset_ia / 1000.0;
44-
offset_ib = offset_ib / 1000.0;
45-
if(_isset(pinC)) offset_ic = offset_ic / 1000.0;
45+
offset_ia = offset_ia / calibration_rounds;
46+
offset_ib = offset_ib / calibration_rounds;
47+
if(_isset(pinC)) offset_ic = offset_ic / calibration_rounds;
4648
}
4749

4850
// read all three phase currents (if possible 2 or 3)
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#include "../hardware_api.h"
2+
3+
#if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega328PB__)
4+
5+
#define _ADC_VOLTAGE 5.0
6+
#define _ADC_RESOLUTION 1024.0
7+
8+
// adc counts to voltage conversion ratio
9+
// some optimizing for faster execution
10+
#define _ADC_CONV ( (_ADC_VOLTAGE) / (_ADC_RESOLUTION) )
11+
12+
#ifndef cbi
13+
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
14+
#endif
15+
#ifndef sbi
16+
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
17+
#endif
18+
19+
// adc counts to voltage conversion ratio
20+
// some optimizing for faster execution
21+
#define _ADC_CONV ( (_ADC_VOLTAGE) / (_ADC_RESOLUTION) )
22+
23+
// function reading an ADC value and returning the read voltage
24+
float _readADCVoltageInline(const int pinA){
25+
uint32_t raw_adc = analogRead(pinA);
26+
return raw_adc * _ADC_CONV;
27+
}
28+
// function reading an ADC value and returning the read voltage
29+
void _configureADCInline(const int pinA,const int pinB,const int pinC){
30+
pinMode(pinA, INPUT);
31+
pinMode(pinB, INPUT);
32+
if( _isset(pinC) ) pinMode(pinC, INPUT);
33+
34+
// set hight frequency adc - ADPS2,ADPS1,ADPS0 | 001 (16mhz/2) | 010 ( 16mhz/4 ) | 011 (16mhz/8) | 100(16mhz/16) | 101 (16mhz/32) | 110 (16mhz/64) | 111 (16mhz/128 default)
35+
// set divisor to 8 - adc frequency 16mhz/8 = 2 mhz
36+
// arduino takes 25 conversions per sample so - 2mhz/25 = 80k samples per second - 12.5us per sample
37+
cbi(ADCSRA, ADPS2);
38+
sbi(ADCSRA, ADPS1);
39+
sbi(ADCSRA, ADPS0);
40+
}
41+
42+
43+
// function reading an ADC value and returning the read voltage
44+
float _readADCVoltageLowSide(const int pinA){
45+
return _readADCVoltageInline(pinA);
46+
}
47+
// Configure low side for generic mcu
48+
// cannot do much but
49+
void _configureADCLowSide(const int pinA,const int pinB,const int pinC){
50+
pinMode(pinA, INPUT);
51+
pinMode(pinB, INPUT);
52+
if( _isset(pinC) ) pinMode(pinC, INPUT);
53+
}
54+
55+
#endif
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#include "../hardware_api.h"
2+
3+
#if defined(__arm__) && defined(__SAM3X8E__)
4+
5+
#define _ADC_VOLTAGE 3.3
6+
#define _ADC_RESOLUTION 1024.0
7+
8+
// adc counts to voltage conversion ratio
9+
// some optimizing for faster execution
10+
#define _ADC_CONV ( (_ADC_VOLTAGE) / (_ADC_RESOLUTION) )
11+
12+
// function reading an ADC value and returning the read voltage
13+
float _readADCVoltageInline(const int pinA){
14+
uint32_t raw_adc = analogRead(pinA);
15+
return raw_adc * _ADC_CONV;
16+
}
17+
// function reading an ADC value and returning the read voltage
18+
void _configureADCInline(const int pinA,const int pinB,const int pinC){
19+
pinMode(pinA, INPUT);
20+
pinMode(pinB, INPUT);
21+
if( _isset(pinC) ) pinMode(pinC, INPUT);
22+
}
23+
24+
25+
// function reading an ADC value and returning the read voltage
26+
float _readADCVoltageLowSide(const int pinA){
27+
return _readADCVoltageInline(pinA);
28+
}
29+
// Configure low side for generic mcu
30+
// cannot do much but
31+
void _configureADCLowSide(const int pinA,const int pinB,const int pinC){
32+
pinMode(pinA, INPUT);
33+
pinMode(pinB, INPUT);
34+
if( _isset(pinC) ) pinMode(pinC, INPUT);
35+
}
36+
37+
38+
#endif
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#if defined(ESP_H)
16+
17+
#include "esp32_adc_driver.h"
18+
#include "Arduino.h"
19+
20+
#include "freertos/FreeRTOS.h"
21+
#include "freertos/task.h"
22+
#include "rom/ets_sys.h"
23+
#include "esp_attr.h"
24+
#include "esp_intr.h"
25+
#include "soc/rtc_io_reg.h"
26+
#include "soc/rtc_cntl_reg.h"
27+
#include "soc/sens_reg.h"
28+
29+
static uint8_t __analogAttenuation = 3;//11db
30+
static uint8_t __analogWidth = 3;//12 bits
31+
static uint8_t __analogCycles = 8;
32+
static uint8_t __analogSamples = 0;//1 sample
33+
static uint8_t __analogClockDiv = 1;
34+
35+
// Width of returned answer ()
36+
static uint8_t __analogReturnedWidth = 12;
37+
38+
void __analogSetWidth(uint8_t bits){
39+
if(bits < 9){
40+
bits = 9;
41+
} else if(bits > 12){
42+
bits = 12;
43+
}
44+
__analogReturnedWidth = bits;
45+
__analogWidth = bits - 9;
46+
SET_PERI_REG_BITS(SENS_SAR_START_FORCE_REG, SENS_SAR1_BIT_WIDTH, __analogWidth, SENS_SAR1_BIT_WIDTH_S);
47+
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_BIT, __analogWidth, SENS_SAR1_SAMPLE_BIT_S);
48+
49+
SET_PERI_REG_BITS(SENS_SAR_START_FORCE_REG, SENS_SAR2_BIT_WIDTH, __analogWidth, SENS_SAR2_BIT_WIDTH_S);
50+
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_SAMPLE_BIT, __analogWidth, SENS_SAR2_SAMPLE_BIT_S);
51+
}
52+
53+
void __analogSetCycles(uint8_t cycles){
54+
__analogCycles = cycles;
55+
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_CYCLE, __analogCycles, SENS_SAR1_SAMPLE_CYCLE_S);
56+
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_SAMPLE_CYCLE, __analogCycles, SENS_SAR2_SAMPLE_CYCLE_S);
57+
}
58+
59+
void __analogSetSamples(uint8_t samples){
60+
if(!samples){
61+
return;
62+
}
63+
__analogSamples = samples - 1;
64+
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_SAMPLE_NUM, __analogSamples, SENS_SAR1_SAMPLE_NUM_S);
65+
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_SAMPLE_NUM, __analogSamples, SENS_SAR2_SAMPLE_NUM_S);
66+
}
67+
68+
void __analogSetClockDiv(uint8_t clockDiv){
69+
if(!clockDiv){
70+
return;
71+
}
72+
__analogClockDiv = clockDiv;
73+
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL_REG, SENS_SAR1_CLK_DIV, __analogClockDiv, SENS_SAR1_CLK_DIV_S);
74+
SET_PERI_REG_BITS(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_CLK_DIV, __analogClockDiv, SENS_SAR2_CLK_DIV_S);
75+
}
76+
77+
void __analogSetAttenuation(uint8_t attenuation)
78+
{
79+
__analogAttenuation = attenuation & 3;
80+
uint32_t att_data = 0;
81+
int i = 10;
82+
while(i--){
83+
att_data |= __analogAttenuation << (i * 2);
84+
}
85+
WRITE_PERI_REG(SENS_SAR_ATTEN1_REG, att_data & 0xFFFF);//ADC1 has 8 channels
86+
WRITE_PERI_REG(SENS_SAR_ATTEN2_REG, att_data);
87+
}
88+
89+
void IRAM_ATTR __analogInit(){
90+
static bool initialized = false;
91+
if(initialized){
92+
return;
93+
}
94+
95+
__analogSetAttenuation(__analogAttenuation);
96+
__analogSetCycles(__analogCycles);
97+
__analogSetSamples(__analogSamples + 1);//in samples
98+
__analogSetClockDiv(__analogClockDiv);
99+
__analogSetWidth(__analogWidth + 9);//in bits
100+
101+
SET_PERI_REG_MASK(SENS_SAR_READ_CTRL_REG, SENS_SAR1_DATA_INV);
102+
SET_PERI_REG_MASK(SENS_SAR_READ_CTRL2_REG, SENS_SAR2_DATA_INV);
103+
104+
SET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_FORCE_M); //SAR ADC1 controller (in RTC) is started by SW
105+
SET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_SAR1_EN_PAD_FORCE_M); //SAR ADC1 pad enable bitmap is controlled by SW
106+
SET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_FORCE_M); //SAR ADC2 controller (in RTC) is started by SW
107+
SET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD_FORCE_M); //SAR ADC2 pad enable bitmap is controlled by SW
108+
109+
CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_SAR_M); //force XPD_SAR=0, use XPD_FSM
110+
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_FORCE_XPD_AMP, 0x2, SENS_FORCE_XPD_AMP_S); //force XPD_AMP=0
111+
112+
CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_CTRL_REG, 0xfff << SENS_AMP_RST_FB_FSM_S); //clear FSM
113+
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT1_REG, SENS_SAR_AMP_WAIT1, 0x1, SENS_SAR_AMP_WAIT1_S);
114+
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT1_REG, SENS_SAR_AMP_WAIT2, 0x1, SENS_SAR_AMP_WAIT2_S);
115+
SET_PERI_REG_BITS(SENS_SAR_MEAS_WAIT2_REG, SENS_SAR_AMP_WAIT3, 0x1, SENS_SAR_AMP_WAIT3_S);
116+
while (GET_PERI_REG_BITS2(SENS_SAR_SLAVE_ADDR1_REG, 0x7, SENS_MEAS_STATUS_S) != 0); //wait det_fsm==
117+
118+
initialized = true;
119+
}
120+
121+
void __analogSetPinAttenuation(uint8_t pin, uint8_t attenuation)
122+
{
123+
int8_t channel = digitalPinToAnalogChannel(pin);
124+
if(channel < 0 || attenuation > 3){
125+
return ;
126+
}
127+
__analogInit();
128+
if(channel > 7){
129+
SET_PERI_REG_BITS(SENS_SAR_ATTEN2_REG, 3, attenuation, ((channel - 10) * 2));
130+
} else {
131+
SET_PERI_REG_BITS(SENS_SAR_ATTEN1_REG, 3, attenuation, (channel * 2));
132+
}
133+
}
134+
135+
bool IRAM_ATTR __adcAttachPin(uint8_t pin){
136+
137+
int8_t channel = digitalPinToAnalogChannel(pin);
138+
if(channel < 0){
139+
return false;//not adc pin
140+
}
141+
142+
int8_t pad = digitalPinToTouchChannel(pin);
143+
if(pad >= 0){
144+
uint32_t touch = READ_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG);
145+
if(touch & (1 << pad)){
146+
touch &= ~((1 << (pad + SENS_TOUCH_PAD_OUTEN2_S))
147+
| (1 << (pad + SENS_TOUCH_PAD_OUTEN1_S))
148+
| (1 << (pad + SENS_TOUCH_PAD_WORKEN_S)));
149+
WRITE_PERI_REG(SENS_SAR_TOUCH_ENABLE_REG, touch);
150+
}
151+
} else if(pin == 25){
152+
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC1_REG, RTC_IO_PDAC1_XPD_DAC | RTC_IO_PDAC1_DAC_XPD_FORCE); //stop dac1
153+
} else if(pin == 26){
154+
CLEAR_PERI_REG_MASK(RTC_IO_PAD_DAC2_REG, RTC_IO_PDAC2_XPD_DAC | RTC_IO_PDAC2_DAC_XPD_FORCE); //stop dac2
155+
}
156+
157+
pinMode(pin, ANALOG);
158+
159+
__analogInit();
160+
return true;
161+
}
162+
163+
bool IRAM_ATTR __adcStart(uint8_t pin){
164+
165+
int8_t channel = digitalPinToAnalogChannel(pin);
166+
if(channel < 0){
167+
return false;//not adc pin
168+
}
169+
170+
if(channel > 9){
171+
channel -= 10;
172+
CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_SAR_M);
173+
SET_PERI_REG_BITS(SENS_SAR_MEAS_START2_REG, SENS_SAR2_EN_PAD, (1 << channel), SENS_SAR2_EN_PAD_S);
174+
SET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_START_SAR_M);
175+
} else {
176+
CLEAR_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_SAR_M);
177+
SET_PERI_REG_BITS(SENS_SAR_MEAS_START1_REG, SENS_SAR1_EN_PAD, (1 << channel), SENS_SAR1_EN_PAD_S);
178+
SET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_START_SAR_M);
179+
}
180+
return true;
181+
}
182+
183+
bool IRAM_ATTR __adcBusy(uint8_t pin){
184+
185+
int8_t channel = digitalPinToAnalogChannel(pin);
186+
if(channel < 0){
187+
return false;//not adc pin
188+
}
189+
190+
if(channel > 7){
191+
return (GET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DONE_SAR) == 0);
192+
}
193+
return (GET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DONE_SAR) == 0);
194+
}
195+
196+
uint16_t IRAM_ATTR __adcEnd(uint8_t pin)
197+
{
198+
199+
uint16_t value = 0;
200+
int8_t channel = digitalPinToAnalogChannel(pin);
201+
if(channel < 0){
202+
return 0;//not adc pin
203+
}
204+
if(channel > 7){
205+
while (GET_PERI_REG_MASK(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DONE_SAR) == 0); //wait for conversion
206+
value = GET_PERI_REG_BITS2(SENS_SAR_MEAS_START2_REG, SENS_MEAS2_DATA_SAR, SENS_MEAS2_DATA_SAR_S);
207+
} else {
208+
while (GET_PERI_REG_MASK(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DONE_SAR) == 0); //wait for conversion
209+
value = GET_PERI_REG_BITS2(SENS_SAR_MEAS_START1_REG, SENS_MEAS1_DATA_SAR, SENS_MEAS1_DATA_SAR_S);
210+
}
211+
212+
// Shift result if necessary
213+
uint8_t from = __analogWidth + 9;
214+
if (from == __analogReturnedWidth) {
215+
return value;
216+
}
217+
if (from > __analogReturnedWidth) {
218+
return value >> (from - __analogReturnedWidth);
219+
}
220+
return value << (__analogReturnedWidth - from);
221+
}
222+
223+
void __analogReadResolution(uint8_t bits)
224+
{
225+
if(!bits || bits > 16){
226+
return;
227+
}
228+
__analogSetWidth(bits); // hadware from 9 to 12
229+
__analogReturnedWidth = bits; // software from 1 to 16
230+
}
231+
232+
uint16_t IRAM_ATTR adcRead(uint8_t pin)
233+
{
234+
if(!__adcAttachPin(pin) || !__adcStart(pin)){
235+
return 0;
236+
}
237+
return __adcEnd(pin);
238+
}
239+
240+
#endif

0 commit comments

Comments
 (0)