Skip to content

Commit 9af38fa

Browse files
committed
SAMDCurrentSenseADCDMA class
1 parent e6d77b0 commit 9af38fa

File tree

4 files changed

+91
-148
lines changed

4 files changed

+91
-148
lines changed

src/current_sense/LowSideCurrentSense.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ PhaseCurrent_s LowSideCurrentSense::getPhaseCurrents(){
5555
// current.b = (_readADCVoltage(pinB) - offset_ib)*gain_b;// amps
5656
// current.c = (!_isset(pinC)) ? 0 : (_readADCVoltage(pinC) - offset_ic)*gain_c; // amps
5757

58-
adc._read3PinsDMA(pinA, pinB, pinC, current.a, current.b, current.c);
59-
adc._start3PinsDMA();
58+
adc.readResults(current.a, current.b, current.c);
59+
adc.startADCScan();
6060

6161
return current;
6262
}

src/current_sense/LowSideCurrentSense.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class LowSideCurrentSense: public CurrentSense{
5353
double offset_ib; //!< zero current B voltage value (center of the adc reading)
5454
double offset_ic; //!< zero current C voltage value (center of the adc reading)
5555

56-
SAMDCurrentSensceADC adc;
56+
SAMDCurrentSenseADCDMA adc;
5757

5858
};
5959

src/current_sense/hardware_specific/samd21_mcu.cpp

Lines changed: 54 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11

22
#include "samd21_mcu.h"
33

4+
// Credit: significant portions of this code were pulled from Paul Gould's git https://github.com/gouldpa/FOC-Arduino-Brushless
45

5-
void adc_stop_with_DMA(void);
6-
void adc_start_with_DMA(void);
6+
static void adcStopWithDMA(void);
7+
static void adcStartWithDMA(void);
78

89
/**
910
* @brief ADC sync wait
@@ -16,91 +17,66 @@ static void ADCsync() {
1617

1718
// ADC DMA sequential free running (6) with Interrupts /////////////////
1819

19-
typedef struct {
20-
uint16_t btctrl;
21-
uint16_t btcnt;
22-
uint32_t srcaddr;
23-
uint32_t dstaddr;
24-
uint32_t descaddr;
25-
} dmacdescriptor ;
26-
volatile dmacdescriptor wrb[12] __attribute__ ((aligned (16)));
27-
dmacdescriptor descriptor_section[12] __attribute__ ((aligned (16)));
28-
dmacdescriptor descriptor __attribute__ ((aligned (16)));
29-
DmacDescriptor *desc; // DMA descriptor address (so we can change contents)
3020

3121

3222

33-
SAMDCurrentSensceADC::SAMDCurrentSensceADC(int pinA, int pinB, int pinC, float arefaVoltage, uint32_t adcBits)
34-
: _ADC_VOLTAGE(arefaVoltage), _ADC_RESOLUTION(1 << adcBits)
23+
24+
SAMDCurrentSenseADCDMA::SAMDCurrentSenseADCDMA(int pinA, int pinB, int pinC, int pinAREF, float voltageAREF, uint32_t adcBits, uint32_t channelDMA)
25+
: pinA(pinA), pinB(pinB), pinC(pinC), pinAREF(pinAREF), channelDMA(channelDMA), voltageAREF(voltageAREF), maxCountsADC(1 << adcBits)
3526
{
36-
ADC_CONV_ = ( _ADC_VOLTAGE / _ADC_RESOLUTION );
37-
this->pinA = pinA;
38-
this->pinB = pinB;
39-
this->pinC = pinC;
27+
countsToVolts = ( voltageAREF / maxCountsADC );
4028
}
4129

42-
void SAMDCurrentSensceADC::init()
43-
{
44-
_configure3PinsDMA();
45-
_start3PinsDMA(); //s
30+
void SAMDCurrentSenseADCDMA::init(){
31+
initPins();
32+
initADC();
33+
initDMA();
34+
startADCScan(); //so we have something to read next time we call readResults()
4635
}
4736

4837

49-
void SAMDCurrentSensceADC::_start3PinsDMA()
50-
{
51-
adc_dma(adcBuffer + ADC_OneBeforeFirstPin, BufferSize);
52-
adc_start_with_DMA();
38+
void SAMDCurrentSenseADCDMA::startADCScan(){
39+
adcToDMATransfer(adcBuffer + oneBeforeFirstAIN, BufferSize);
40+
adcStartWithDMA();
5341
}
54-
void SAMDCurrentSensceADC::_read3PinsDMA(const int pinA,const int pinB,const int pinC, float & a, float & b, float & c)
55-
{
42+
43+
void SAMDCurrentSenseADCDMA::readResults(float & a, float & b, float & c){
5644
while(ADC->CTRLA.bit.ENABLE) ;
57-
uint32_t adcA = g_APinDescription[pinA].ulADCChannelNumber;
58-
uint32_t adcB = g_APinDescription[pinB].ulADCChannelNumber;
59-
a = adcBuffer[adcA] * ADC_CONV_;
60-
b = adcBuffer[adcB] * ADC_CONV_;
45+
uint32_t ainA = g_APinDescription[pinA].ulADCChannelNumber;
46+
uint32_t ainB = g_APinDescription[pinB].ulADCChannelNumber;
47+
uint32_t ainC = g_APinDescription[pinC].ulADCChannelNumber;
48+
a = adcBuffer[ainA] * countsToVolts;
49+
b = adcBuffer[ainB] * countsToVolts;
6150
if(_isset(pinC))
6251
{
63-
uint32_t adcC = g_APinDescription[pinC].ulADCChannelNumber;
64-
c = adcBuffer[adcC] * ADC_CONV_;
52+
c = adcBuffer[ainC] * countsToVolts;
6553
}
6654
}
6755

68-
// function reading an ADC value and returning the read voltage
69-
void SAMDCurrentSensceADC::_configure3PinsDMA(){
56+
void SAMDCurrentSenseADCDMA::initPins(){
7057

71-
uint32_t adcA = g_APinDescription[pinA].ulADCChannelNumber;
72-
uint32_t adcB = g_APinDescription[pinB].ulADCChannelNumber;
73-
uint32_t adcC = g_APinDescription[pinC].ulADCChannelNumber;
74-
75-
pinMode(42, INPUT);
76-
ADC_FirstPin = min(adcA, adcB);
77-
ADC_LastPin = max(adcA, adcB);
58+
pinMode(pinAREF, INPUT);
7859
pinMode(pinA, INPUT);
7960
pinMode(pinB, INPUT);
61+
62+
uint32_t ainA = g_APinDescription[pinA].ulADCChannelNumber;
63+
uint32_t ainB = g_APinDescription[pinB].ulADCChannelNumber;
64+
uint32_t ainC = g_APinDescription[pinC].ulADCChannelNumber;
65+
firstAIN = min(ainA, ainB);
66+
lastAIN = max(ainA, ainB);
8067
if( _isset(pinC) )
8168
{
8269
pinMode(pinC, INPUT);
83-
ADC_FirstPin = min(ADC_FirstPin, adcC);
84-
ADC_LastPin = max(ADC_LastPin, adcC);
70+
firstAIN = min(firstAIN, ainC);
71+
lastAIN = max(lastAIN, ainC);
8572
}
8673

87-
ADC_OneBeforeFirstPin = ADC_FirstPin - 1; //hack to discard noisy first readout
88-
BufferSize = ADC_LastPin - ADC_OneBeforeFirstPin + 1;
74+
oneBeforeFirstAIN = firstAIN - 1; //hack to discard noisy first readout
75+
BufferSize = lastAIN - oneBeforeFirstAIN + 1;
8976

90-
// ADC and DMA
91-
adc_init();
92-
dma_init();
9377
}
9478

95-
96-
97-
98-
99-
/**
100-
* @brief Initialize ADC
101-
* @retval void
102-
*/
103-
void SAMDCurrentSensceADC::adc_init(){
79+
void SAMDCurrentSenseADCDMA::initADC(){
10480

10581
analogRead(pinA); // do some pin init pinPeripheral()
10682
analogRead(pinB); // do some pin init pinPeripheral()
@@ -155,9 +131,9 @@ void SAMDCurrentSensceADC::adc_init(){
155131
0x1C DAC DAC output
156132
0x1D-0x1F Reserved
157133
*/
158-
ADC->INPUTCTRL.bit.MUXPOS = ADC_OneBeforeFirstPin;
134+
ADC->INPUTCTRL.bit.MUXPOS = oneBeforeFirstAIN;
159135
ADCsync();
160-
ADC->INPUTCTRL.bit.INPUTSCAN = ADC_LastPin; // so the adc will scan from AIN[1] to AIN[ADC_Number+1]
136+
ADC->INPUTCTRL.bit.INPUTSCAN = lastAIN; // so the adc will scan from oneBeforeFirstAIN to lastAIN (inclusive)
161137
ADCsync();
162138
ADC->INPUTCTRL.bit.INPUTOFFSET = 0; //input scan cursor
163139
ADCsync();
@@ -169,12 +145,9 @@ void SAMDCurrentSensceADC::adc_init(){
169145
ADCsync();
170146
}
171147

148+
volatile dmacdescriptor wrb[12] __attribute__ ((aligned (16)));
172149

173-
/**
174-
* @brief dma_init
175-
* @retval void
176-
*/
177-
void SAMDCurrentSensceADC::dma_init() {
150+
void SAMDCurrentSenseADCDMA::initDMA() {
178151
// probably on by default
179152
PM->AHBMASK.reg |= PM_AHBMASK_DMAC ;
180153
PM->APBBMASK.reg |= PM_APBBMASK_DMAC ;
@@ -184,68 +157,46 @@ void SAMDCurrentSensceADC::dma_init() {
184157
DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf);
185158
}
186159

187-
/**
188-
* @brief adc_dma
189-
* @retval void
190-
*/
191-
void SAMDCurrentSensceADC::adc_dma(void *rxdata, size_t hwords) {
192-
uint32_t temp_CHCTRLB_reg;
193160

194-
DMAC->CHID.reg = DMAC_CHID_ID(ADC_DMA_chnl);
161+
void SAMDCurrentSenseADCDMA::adcToDMATransfer(void *rxdata, size_t hwords) {
162+
163+
DMAC->CHID.reg = DMAC_CHID_ID(channelDMA);
195164
DMAC->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE;
196165
DMAC->CHCTRLA.reg = DMAC_CHCTRLA_SWRST;
197-
DMAC->SWTRIGCTRL.reg &= (uint32_t)(~(1 << ADC_DMA_chnl));
198-
temp_CHCTRLB_reg = DMAC_CHCTRLB_LVL(0) |
199-
DMAC_CHCTRLB_TRIGSRC(ADC_DMAC_ID_RESRDY) | DMAC_CHCTRLB_TRIGACT_BEAT;
200-
DMAC->CHCTRLB.reg = temp_CHCTRLB_reg;
166+
DMAC->SWTRIGCTRL.reg &= (uint32_t)(~(1 << channelDMA));
167+
168+
DMAC->CHCTRLB.reg = DMAC_CHCTRLB_LVL(0)
169+
| DMAC_CHCTRLB_TRIGSRC(ADC_DMAC_ID_RESRDY)
170+
| DMAC_CHCTRLB_TRIGACT_BEAT;
201171
DMAC->CHINTENSET.reg = DMAC_CHINTENSET_MASK ; // enable all 3 interrupts
202172
descriptor.descaddr = 0;
203173
descriptor.srcaddr = (uint32_t) &ADC->RESULT.reg;
204174
descriptor.btcnt = hwords;
205175
descriptor.dstaddr = (uint32_t)rxdata + hwords*2; // end address
206176
descriptor.btctrl = DMAC_BTCTRL_BEATSIZE_HWORD | DMAC_BTCTRL_DSTINC | DMAC_BTCTRL_VALID;
207-
memcpy(&descriptor_section[ADC_DMA_chnl],&descriptor, sizeof(dmacdescriptor));
177+
memcpy(&descriptor_section[channelDMA],&descriptor, sizeof(dmacdescriptor));
208178

209179
// start channel
210-
DMAC->CHID.reg = DMAC_CHID_ID(ADC_DMA_chnl);
180+
DMAC->CHID.reg = DMAC_CHID_ID(channelDMA);
211181
DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE;
212182
}
213183

214184

215-
216-
217-
/**
218-
* @brief adc_stop_with_DMA
219-
* @retval void
220-
*/
221-
void adc_stop_with_DMA(void)
222-
{
185+
void adcStopWithDMA(void){
223186
ADC->CTRLA.bit.ENABLE = 0x00;
224-
// SerialUSB.println("DMA stopped!");
225187
}
226188

227-
/**
228-
* @brief adc_start_with_DMA
229-
* @retval void
230-
*/
231-
void adc_start_with_DMA(void)
232-
{
233-
// SerialUSB.println("strating DMA...");
234-
// ADC->INPUTCTRL.bit.MUXPOS = ADC_OneBeforeFirstPin;
235-
// ADC->INPUTCTRL.bit.INPUTSCAN = ADC_LastPin;
189+
void adcStartWithDMA(void){
236190
ADC->INPUTCTRL.bit.INPUTOFFSET = 0;
237191
ADC->SWTRIG.bit.FLUSH = 1;
238192
ADC->CTRLA.bit.ENABLE = 0x01;
239193
}
240-
/**
241-
* @brief DMAC_Handler
242-
* @retval void
243-
*/
194+
244195
void DMAC_Handler() {
245196
uint8_t active_channel;
246197
active_channel = DMAC->INTPEND.reg & DMAC_INTPEND_ID_Msk; // get channel number
247198
DMAC->CHID.reg = DMAC_CHID_ID(active_channel);
248-
adc_stop_with_DMA();
199+
adcStopWithDMA();
249200
DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_TCMPL; // clear
250201
DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_TERR;
251202
DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_SUSP;
Lines changed: 34 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,52 @@
11

22
#include "../hardware_api.h"
33

4-
5-
class SAMDCurrentSensceADC
4+
typedef struct {
5+
uint16_t btctrl;
6+
uint16_t btcnt;
7+
uint32_t srcaddr;
8+
uint32_t dstaddr;
9+
uint32_t descaddr;
10+
} dmacdescriptor ;
11+
12+
class SAMDCurrentSenseADCDMA
613
{
714

815
public:
916

10-
SAMDCurrentSensceADC(int pinA, int pinB, int pinC, float arefaVoltage = 3.3, uint32_t adcBits = 12);
17+
SAMDCurrentSenseADCDMA(int pinA, int pinB, int pinC, int pinAREF = 42, float voltageAREF = 3.3, uint32_t adcBits = 12, uint32_t channelDMA = 3);
1118

1219
void init();
13-
// this code was pulled from Paul Gould's git https://github.com/gouldpa/FOC-Arduino-Brushless
14-
uint32_t ADC_OneBeforeFirstPin; // hack to discard first noisy readout
15-
uint32_t ADC_FirstPin; // PA04
16-
uint32_t ADC_LastPin; // PA06
17-
uint32_t BufferSize = 0;
18-
19-
uint16_t adcBuffer[20];
20-
21-
22-
uint32_t pinA = A4;
23-
uint32_t pinB = A5;
24-
uint32_t pinC = 8;
25-
26-
float _ADC_VOLTAGE;
27-
float _ADC_RESOLUTION;
28-
float ADC_CONV_;
20+
void startADCScan();
21+
void readResults(float & a, float & b, float & c);
2922

30-
void _start3PinsDMA();
31-
void _read3PinsDMA(const int pinA,const int pinB,const int pinC, float & a, float & b, float & c);
32-
// function reading an ADC value and returning the read voltage
33-
void _configure3PinsDMA();
23+
private:
3424

25+
void adcToDMATransfer(void *rxdata, size_t hwords);
3526

27+
void initPins();
28+
void initADC();
29+
void initDMA();
30+
31+
uint32_t oneBeforeFirstAIN; // hack to discard first noisy readout
32+
uint32_t firstAIN;
33+
uint32_t lastAIN;
34+
uint32_t BufferSize = 0;
3635

37-
38-
uint32_t ADC_DMA_chnl = 3; // DMA channel
39-
40-
41-
/**
42-
* @brief Initialize ADC
43-
* @retval void
44-
*/
45-
void adc_init();
36+
uint16_t adcBuffer[20];
4637

4738

48-
/**
49-
* @brief dma_init
50-
* @retval void
51-
*/
52-
void dma_init();
39+
uint32_t pinA;
40+
uint32_t pinB;
41+
uint32_t pinC;
42+
uint32_t pinAREF;
43+
uint32_t channelDMA; // DMA channel
5344

54-
/**
55-
* @brief adc_dma
56-
* @retval void
57-
*/
58-
void adc_dma(void *rxdata, size_t hwords);
45+
float voltageAREF;
46+
float maxCountsADC;
47+
float countsToVolts;
48+
49+
dmacdescriptor descriptor_section[12] __attribute__ ((aligned (16)));
50+
dmacdescriptor descriptor __attribute__ ((aligned (16)));
5951

6052
};

0 commit comments

Comments
 (0)