STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
STAR_ADS126X.cpp
Go to the documentation of this file.
1#include "STAR_ADS126X.h"
2#include <SPI.h>
3#include <Arduino.h>
4
5/*!< Initial ADC Setup */
6
9
10void ADS126X::begin(uint8_t chip_select) {
11 begin(chip_select, &SPI);
12}
13
14void ADS126X::begin(uint8_t chip_select, SPIClass *spi) {
15 cs_used = true;
16 cs_pin = chip_select;
19
20 _spi = spi;
21 _spi->begin();
22
25}
26
27/*!< Regular ADC Commands */
28
32
34 sendCommand(ADS126X_RESET); // send reset command
35}
36
37void ADS126X::startADC1() {
39}
40
41void ADS126X::stopADC1() {
43}
44
48
52
53// int32_t ADS126X::readADC1(uint8_t pos_pin, uint8_t neg_pin) {
54// digitalWrite(cs_pin, LOW);
55
56// // create buffer to hold transmission
57// uint8_t buff[10] = {0}; // plenty of room, all zeros
58
59// union { // create a structure to hold all the data
60// struct {
61// uint32_t DATA4:8; // bits 0.. 7
62// uint32_t DATA3:8; // bits 8.. 15
63// uint32_t DATA2:8; // bits 16.. 23
64// uint32_t DATA1:8; // bits 24.. 31
65// } bit;
66// uint32_t reg;
67// } ADC_BYTES;
68// ADC_BYTES.reg = 0; // clear the ram just in case
69
70// // Only write to multiplex register if desired pins are different
71// if((REGISTER.INPMUX.bit.MUXN != neg_pin) || (REGISTER.INPMUX.bit.MUXP != pos_pin)) {
72// REGISTER.INPMUX.bit.MUXN = neg_pin;
73// REGISTER.INPMUX.bit.MUXP = pos_pin;
74// ADS126X::writeRegister(ADS126X_INPMUX);
75// }
76
77// uint8_t i = 0; // current place in outgoing buffer
78// buff[i] = ADS126X_RDATA1; // the read adc1 command
79// i++;
80
81// if(REGISTER.INTERFACE.bit.STATUS) i++; // place to hold status byte
82// i += 4; // place to hold adc data
83// if(REGISTER.INTERFACE.bit.CRC>0) i++; // place to hold checksum/crc byte
84
85// _ads126x_spi_rw(buff,i); // write spi, save values on buff
86
87// uint8_t j = 1; // start at byte 1, either status or first adc value
88
89// if(REGISTER.INTERFACE.bit.STATUS) { // if status is being read
90// STATUS.reg = buff[j]; // save status byte
91// j++; // increment position counter
92// }
93
94// // save the data bytes
95// ADC_BYTES.bit.DATA1 = buff[j]; j++;
96// ADC_BYTES.bit.DATA2 = buff[j]; j++;
97// ADC_BYTES.bit.DATA3 = buff[j]; j++;
98// ADC_BYTES.bit.DATA4 = buff[j]; j++;
99
100// // if(REGISTER.INTERFACE.bit.CRC==ADS126X_CHECKSUM) {
101// // uint8_t checkbyte = buff[j];
102
103// // // if(ADS126X::find_checksum(ADC_BYTES.reg,checkbyte)){
104// // // }
105// // }
106// // else if(REGISTER.INTERFACE.bit.CRC==ADS126X_CHECK_CRC) {
107// // uint8_t checkbyte = buff[j];
108// // CHECKSUM = ADS126X::find_crc(ADC_BYTES.reg,checkbyte);
109// // }
110
111// digitalWrite(cs_pin, HIGH);
112// return ADC_BYTES.reg;
113// }
114
115void ADS126X::setInputMux(uint8_t pos_pin, uint8_t neg_pin){
116 if((REGISTER.INPMUX.bit.MUXN != neg_pin) || (REGISTER.INPMUX.bit.MUXP != pos_pin)) {
118 REGISTER.INPMUX.bit.MUXP = pos_pin;
120 }
121}
122
123void ADS126X::setADC2Mux(uint8_t pos_pin, uint8_t neg_pin){
124 if((REGISTER.ADC2MUX.bit.MUXN != neg_pin) || (REGISTER.ADC2MUX.bit.MUXP != pos_pin)) {
125 REGISTER.ADC2MUX.bit.MUXN = neg_pin;
126 REGISTER.ADC2MUX.bit.MUXP = pos_pin;
128 }
129}
130
133
134 // Create buffer to hold transmission
135 uint8_t buff[10] = {0};
136
137 // Union to hold ADC data
138 union { // create a structure to hold all the data
139 struct {
140 uint32_t DATA4:8; // bits 0.. 7
141 uint32_t DATA3:8; // bits 8.. 15
142 uint32_t DATA2:8; // bits 16.. 23
143 uint32_t DATA1:8; // bits 24.. 31
144 } bit;
145 uint32_t reg;
146 } ADC_BYTES;
147 ADC_BYTES.reg = 0; // clear the ram just in case
148
149 uint8_t i = 0;
150 buff[i++] = ADS126X_RDATA1;
151
152 if(REGISTER.INTERFACE.bit.STATUS) i++; // Space for status byte
153 i += 4; // Space for ADC data (4 bytes)
154 if(REGISTER.INTERFACE.bit.CRC > 0) i++;
155
156 ADS126X::spi_rw(buff, i);
157
158 uint8_t j = 1;
159
160 if(REGISTER.INTERFACE.bit.STATUS) {
161 STATUS.reg = buff[j++]; // Save status byte
162 }
163
164 ADC_BYTES.bit.DATA1 = buff[j++];
165 ADC_BYTES.bit.DATA2 = buff[j++];
166 ADC_BYTES.bit.DATA3 = buff[j++];
167 ADC_BYTES.bit.DATA4 = buff[j++];
168
170
171 bool checksumValid = true;
172 if(REGISTER.INTERFACE.bit.CRC==ADS126X_CHECKSUM) {
173 uint8_t checkbyte = buff[j];
174 checksumValid = ADS126X::check_checksum(ADC_BYTES.reg,checkbyte);
175 }
176 else if(REGISTER.INTERFACE.bit.CRC==ADS126X_CHECK_CRC) {
177 uint8_t checkbyte = buff[j];
178 checksumValid = ADS126X::check_crc(ADC_BYTES.reg,checkbyte);
179 }
180 CHECKSUM = checksumValid;
181
182 ADS126X::ADCReading result;
183 result.value = static_cast<int32_t>(ADC_BYTES.reg);
184 result.checksumValid = checksumValid;
185 return result;
186}
187
190 return ADS126X::readADC1();
191}
192
195
196 // create buffer to hold transmission
197 uint8_t buff[10] = {0}; // plenty of room, all zeros
198
199 union { // create a structure to hold all the data
200 struct {
201 uint32_t DATA3:8; // bits 0.. 7
202 uint32_t DATA2:8; // bits 8.. 15
203 uint32_t DATA1:8; // bits 16.. 23
204 uint32_t :8; // bits 24.. 31
205 } bit;
206 uint32_t reg;
207 } ADC_BYTES;
208 ADC_BYTES.reg = 0; // clear so pad byte is 0
209
210 uint8_t i = 0; // current place in outgoing buffer
211 buff[i] = ADS126X_RDATA2; // the read adc2 command
212 i++;
213
214 if(REGISTER.INTERFACE.bit.STATUS) i++; // place to hold status byte
215 i += 3; // place to hold adc data
216 i++; // place to hold pad byte
217 if(REGISTER.INTERFACE.bit.CRC>0) i++; // place to hold checksum/crc byte
218
219 ADS126X::spi_rw(buff,i); // write spi, save values on buff
220
221 uint8_t j = 1; // start at byte 1, either status or first adc value
222
223 if(REGISTER.INTERFACE.bit.STATUS) { // if status is being read
224 STATUS.reg = buff[j]; // save status byte
225 j++; // increment position counter
226 }
227
228 // save the data bytes
229 ADC_BYTES.bit.DATA1 = buff[j]; j++;
230 ADC_BYTES.bit.DATA2 = buff[j]; j++;
231 ADC_BYTES.bit.DATA3 = buff[j]; j++;
232 j++; // skip pad byte
233
234 bool checksumValid = true;
235 if(REGISTER.INTERFACE.bit.CRC==ADS126X_CHECKSUM) {
236 uint8_t checkbyte = buff[j];
237 checksumValid = ADS126X::check_checksum(ADC_BYTES.reg,checkbyte);
238 }
239 else if(REGISTER.INTERFACE.bit.CRC==ADS126X_CHECK_CRC) {
240 uint8_t checkbyte = buff[j];
241 checksumValid = ADS126X::check_crc(ADC_BYTES.reg,checkbyte);
242 }
243 CHECKSUM = checksumValid;
244
246
248 result.value = static_cast<int32_t>(ADC_BYTES.reg);
249 result.checksumValid = checksumValid;
250 return result;
251}
252
255 return ADS126X::readADC2();
256}
257
258
259/*!< SPI Communication Commands */
260void ADS126X::sendCommand(uint8_t command) {
262
263 uint8_t buff[1] = {command};
264 ADS126X::spi_rw(buff,1);
265
267}
268
269// See datasheet page 87
270// Reads specified number of registers, starting at start_reg and adding one to the address each time
271void ADS126X::writeRegisters(uint8_t start_reg, uint8_t num) {
273
274 uint8_t buff[50] = {0}; // plenty of room, all zeros
275
276 start_reg = start_reg & 0x1F;
277
278 buff[0] = start_reg | ADS126X_WREG; // See page 85
279 buff[1] = num-1; // How many registers we are going to write to, see datasheet
280
281 // Put the desired register data in buffer
282 for(uint8_t i = 0; i < num; i++) {
283 buff[i+2] = REGISTER_ARRAY[i+start_reg];
284 }
285
286 // Have the microcontroller send the amounts, plus the commands
287 ADS126X::spi_rw(buff, num + 2);
288
290}
291
292// See datasheet page 86
293// Reads specified number of registers, starting at start_reg and adding one to the address each time
294// Saves the values into the REGISTER_ARRAY which can be read using read_register
295void ADS126X::readRegisters(uint8_t start_reg, uint8_t num) {
297
298 uint8_t buff[50] = {0}; // plenty of room, all zeros
299
300 start_reg = start_reg & 0x1F;
301
302 buff[0] = start_reg | ADS126X_RREG; // first byte is starting register with read command
303 buff[1] = num-1; // tell how many registers to read, see datasheet
304
305 ADS126X::spi_rw(buff, num + 2); // have the microcontroller read the amounts, plus send the commands
306
307 // save the commands to the register
308 for(uint8_t i = 0; i < num; i++) {
309 REGISTER_ARRAY[i+start_reg] = buff[i+2];
310 }
311
313}
314
315
316// Writes to a single register
320
321// Read all of the registers, their results are stored
323 ADS126X::readRegisters(0,ADS126X_REG_NUM); // read all the registers
324}
325
326// Reads from a single register and returns the value
327uint8_t ADS126X::readRegister(uint8_t reg) {
329 return REGISTER_ARRAY[reg];
330}
331
332/*!< SPI Communication Commands */
333
334// Takes in the value returned by the ADC and the checksum byte, return true if no corruption
335bool ADS126X::check_checksum(uint32_t val, uint8_t checksum) {
336 uint8_t sum = 0;
337 uint8_t mask = -1; // 8 bit mask of all 1s
338 while(val) {
339 sum += val & mask; // Add the lowest byte
340 val >>= 8; // Shift to do the next byte
341 }
342 sum += ADS126X_CHECK_BYTE;
343
344 // Allow ±1 error tolerance for noisy SPI environments
345 // Calculate arithmetic difference (wraps around for uint8_t)
346 uint8_t diff = sum - checksum; // If checksum > sum, this wraps to 255, 254, etc.
347 return (diff == 0 || diff == 1 || diff == 255); // Accept exact match or ±1
348}
349
350// Takes in the value returned by the ADC and the CRC byte, return true if no corruption
351bool ADS126X::check_crc(uint32_t val, uint8_t CRC) {
352 uint64_t num = val; // put val into a 64 bit number
353 num <<= 8; // shift by 8
354 uint8_t fin = -1; // 8 bit mask of all 1s
355
356 while( (num & fin) ^ num ) { // while num is greater than 8 bits
357 uint8_t msb_pos = ADS126X::msb_pos(num); // find the position of the greatest bit
358 uint64_t divisor = ADS126X_CRC_BYTE; // set the divisor to 64 bit
359 divisor <<= (msb_pos-9); // shift divisor to match greatest bit
360 num ^= divisor; // XOR it
361 }
362 return ((num ^ CRC) == 0);
363}
364
365// Returns position of the most significant bit
366// An input of 0 will return 0
367// Used for CRC
368uint8_t ADS126X::msb_pos(uint64_t val) {
369 uint8_t pos = 1;
370 while(val >>= 1) pos++;
371 return pos;
372}
373
374
375/*!< MODE0 register */
376
381
386
387void ADS126X::setChopMode(uint8_t mode) {
388 REGISTER.MODE0.bit.CHOP = mode;
390}
391
392void ADS126X::setDelay(uint8_t del) {
393 REGISTER.MODE0.bit.DELAY = del;
395}
396
397
398
399/*!< MODE1 register */
400
401void ADS126X::setFilter(uint8_t filter) {
402 REGISTER.MODE1.bit.FILTER = filter;
404}
405
406void ADS126X::setBiasADC(uint8_t adc_choice) {
407 REGISTER.MODE1.bit.SBADC = adc_choice;
409}
410
411void ADS126X::setBiasPolarity(uint8_t polarity) {
412 REGISTER.MODE1.bit.SBPOL = polarity;
414}
415
416void ADS126X::setBiasMagnitude(uint8_t mag) {
417 REGISTER.MODE1.bit.SBMAG = mag;
419}
420
421
422
423/*!< MODE2 register */
424
429
430void ADS126X::bypassPGA() {
433}
434
435void ADS126X::setGain(uint8_t gain) {
436 REGISTER.MODE2.bit.GAIN = gain;
438}
439
440void ADS126X::setRate(uint8_t rate) {
441 REGISTER.MODE2.bit.DR = rate;
443}
444
445void ADS126X::setReference(uint8_t negativeReference, uint8_t positiveReference)
446{
447 REGISTER.REFMUX.bit.RMUXN = negativeReference;
448 REGISTER.REFMUX.bit.RMUXP = positiveReference;
450}
451
452
453
454
455/*!< TDAC Registers */
456
457// TDACP (positive TDAC)
459 // enable TDACP output connected to AIN6
460 REGISTER.TDACP.bit.OUTP = enable ? 1 : 0;
462}
463/*
464void ADS126X::setReservedTDACP() {
465 // clear reserved bits (bit5..6) to be safe
466 // can't access unnamed bitfields directly, so operate on the full reg
467 REGISTER.TDACP.reg &= ~( (1u << 5) | (1u << 6) );
468 ADS126X::writeRegister(ADS126X_TDACP);
469}
470*/
471
472void ADS126X::setOutputmagnitudeTDACP(uint8_t mag) {
473 // default magnitude = mid-scale (0x10). MAGP is 5 bits (0..31).
474 REGISTER.TDACP.bit.MAGP = mag & 0x1F;
476
477}
478
479// TDACN (negative TDAC)
481 // enable TDACN output connected to AIN7
482 REGISTER.TDACN.bit.OUTN = enable ? 1 : 0;
484}
485/*
486void ADS126X::setReservedTDACN() {
487 // clear reserved bits (bit5..6) to be safe
488 REGISTER.TDACN.reg &= ~( (1u << 5) | (1u << 6) );
489 ADS126X::writeRegister(ADS126X_TDACN);
490}
491*/
492
493void ADS126X::setOutputmagnitudeTDACN(uint8_t mag) {
494 // default magnitude = mid-scale (0x10). MAGN is 5 bits (0..31).
495 REGISTER.TDACN.bit.MAGN = mag & 0x1F;
497}
498
499/*!< IDAC functionality */
500
501void ADS126X::setIDAC1Pin(uint8_t pin) {
502 #ifndef __AVR__
503 REGISTER.IDACMUX.bit.MUX1 = pin;
504 #else
505 REGISTER.IDACMUX.bit.ADS_MUX1 = pin;
506 #endif
508}
509void ADS126X::setIDAC2Pin(uint8_t pin) {
510
511 #ifndef __AVR__
512 REGISTER.IDACMUX.bit.MUX2 = pin;
513 #else
514 REGISTER.IDACMUX.bit.ADS_MUX2 = pin;
515 #endif
516
518}
519void ADS126X::setIDAC1Mag(uint8_t magnitude) {
520 REGISTER.IDACMAG.bit.MAG1 = magnitude;
522}
523void ADS126X::setIDAC2Mag(uint8_t magnitude) {
524 REGISTER.IDACMAG.bit.MAG2 = magnitude;
526}
527
528// write buffer to spi, save results over the buffer
529void ADS126X::spi_rw(uint8_t buff[],uint8_t len) {
530 _spi->beginTransaction( SPISettings(2000000, MSBFIRST, SPI_MODE1) ); // 2 MHz
531
532 for(uint8_t i=0;i<len;i++) {
533 buff[i] = _spi->transfer(buff[i]);
534 }
535
536 _spi->endTransaction();
537}
#define HIGH
Definition Arduino.h:19
void pinMode(int, int)
Definition Arduino.h:46
#define OUTPUT
Definition Arduino.h:22
#define SPI_MODE1
Definition Arduino.h:131
#define LOW
Definition Arduino.h:20
void digitalWrite(int, int)
Definition Arduino.h:48
#define ADS126X_MODE0
#define ADS126X_RDATA2
#define ADS126X_START1
#define ADS126X_START2
#define ADS126X_INPMUX
#define ADS126X_RDATA1
#define ADS126X_REFMUX
#define ADS126X_PGA_ENABLE
#define ADS126X_CHECK_CRC
#define ADS126X_ADC2MUX
#define ADS126X_WREG
#define ADS126X_STOP1
#define ADS126X_TDACP
#define ADS126X_NOP
#define ADS126X_CHECKSUM
#define ADS126X_CHECK_BYTE
#define ADS126X_IDACMUX
#define ADS126X_REG_NUM
#define ADS126X_MODE2
#define ADS126X_CONV_PULSE
#define ADS126X_MODE1
#define ADS126X_PGA_BYPASS
#define ADS126X_STOP2
#define ADS126X_TDACN
#define ADS126X_CRC_BYTE
#define ADS126X_IDACMAG
#define ADS126X_RREG
#define ADS126X_RESET
#define ADS126X_CONV_CONT
static void enable(board_bringup_t *b, uint16_t device_id)
void setIDAC2Pin(uint8_t pin)
void setBiasMagnitude(uint8_t mag)
MODE2 register.
void setPulseMode(void)
uint8_t cs_pin
void setInputMux(uint8_t pos, uint8_t neg)
__IO unsigned char * REGISTER_ARRAY
void stopADC1()
void setADC2Mux(uint8_t pos_pin, uint8_t neg_pin)
ADS126X_REGISTER_Type REGISTER
uint8_t msb_pos(uint64_t val)
MODE0 register.
void setOutputTDACN(uint8_t on)
void setBiasADC(uint8_t adc)
void begin(void)
void writeRegisters(uint8_t start_reg, uint8_t num)
void spi_rw(uint8_t buff[], uint8_t len)
uint8_t readRegister(uint8_t reg)
SPI Communication Commands.
void setRate(uint8_t rate)
void readRegisters(uint8_t start_reg, uint8_t num)
ads126x_reading readADC1()
ADS126X(void)
< Initial ADC Setup
bool cs_used
void writeRegister(uint8_t reg)
void startADC1()
bool CHECKSUM
void setIDAC2Mag(uint8_t mag)
void setOutputmagnitudeTDACN(uint8_t mag)
IDAC functionality.
ADS126X_STATUS_Type STATUS
void setContinuousMode(void)
void setIDAC1Pin(uint8_t pin)
void setDelay(uint8_t del)
MODE1 register.
void startADC2(void)
ADCReading readADC2()
bool check_checksum(uint32_t val, uint8_t byt)
void setGain(uint8_t gain)
void setFilter(uint8_t filter)
void setBiasPolarity(uint8_t pol)
void noOperation(void)
void readAllRegisters()
void setReference(uint8_t neg, uint8_t pos)
TDAC Registers.
void setIDAC1Mag(uint8_t mag)
void enablePGA(void)
void setChopMode(uint8_t mode)
void stopADC2(void)
bool check_crc(uint32_t val, uint8_t byt)
void reset(void)
SPIClass * _spi
void bypassPGA()
void sendCommand(uint8_t command)
void setOutputTDACP(uint8_t on)
void setOutputmagnitudeTDACP(uint8_t mag)
uint8_t neg_pin
Definition constants.h:6
uint8_t reg
#define CRC
json_pointer result
Definition json.hpp:14064
__IO ADS126X_MODE2_Type MODE2
Offset: 0x05 (R/W 8) Mode2.
__IO ADS126X_REFMUX_Type REFMUX
Offset: 0x0F (R/W 8) Reference Multiplexer.
__IO ADS126X_INPMUX_Type INPMUX
Offset: 0x06 (R/W 8) Input Multiplexer.
__IO ADS126X_MODE1_Type MODE1
Offset: 0x04 (R/W 8) Mode1.
__IO ADS126X_IDACMAG_Type IDACMAG
Offset: 0x0E (R/W 8) IDAC Magnitude.
__IO ADS126X_TDACN_Type TDACN
Offset: 0x11 (R/W 8) TDACN Negative Output.
__IO ADS126X_TDACP_Type TDACP
Offset: 0x10 (R/W 8) TDACP Output.
static int32_t diff(uint32_t a, uint32_t b)
struct ADS126X_IDACMAG_Type::@353202372365344174342272011233344036156024036201 bit
struct ADS126X_INPMUX_Type::@276355074023256147213077305335246170160306344016 bit
struct ADS126X_MODE1_Type::@146370014303124046124161220200075144230057366052 bit
uint8_t SBADC
bit: 4 Sensor Bias ADC Connection
uint8_t BYPASS
bit: 7 PGA Bypass Mode
struct ADS126X_MODE2_Type::@374226322312305146344122106072274053065142352262 bit
struct ADS126X_REFMUX_Type::@222230233150137302323333152365263246000363132324 bit
struct ADS126X_TDACN_Type::@317360277033272274106333105076057224307330123376 bit
struct ADS126X_TDACP_Type::@350072060036023132022230077113021320333252136175 bit