forked from abezukor/rpi-ads8689
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrpi-ads8689.cpp
More file actions
159 lines (137 loc) · 4.53 KB
/
Copy pathrpi-ads8689.cpp
File metadata and controls
159 lines (137 loc) · 4.53 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#include "rpi-ads8689.hpp"
using namespace ads8689;
//main constructor
ADS8689::ADS8689(SPIs spi, ChipSelects cs, Ranges range, References reference=Internal, double referenceVoltage=4.096)
: spi(spi), cs(cs), range(range), reference(reference), referenceVoltage(referenceVoltage) {
if(reference==References::Internal && referenceVoltage!=internalReferenceVoltage){
throw std::runtime_error("Invalid Internal Reference Voltage");
}
//initializeing SPI
//Initializes BCM library
if (!bcm2835_init())
{
throw std::runtime_error("bcm2835_init failed. Are you running as root??\n");
}
//change tp bcm2835_aux_spi_begin() if using SPI1
bool spi_begin = false;
switch(spi){
case SPIs::SPI_0:
spi_begin = bcm2835_spi_begin();
break;
case SPIs::SPI_AUX:
spi_begin = bcm2835_aux_spi_begin();
break;
default:
break;
}
if (!spi_begin)
{
throw std::runtime_error("bcm2835_spi_begin failed. Are you running as root??\n");
}
//wait a bit for initialazation to finish
struct timespec delay;
delay.tv_sec = 1;
delay.tv_nsec = 2005;
nanosleep(&delay, NULL);
delay.tv_sec = 0;
//set SPI Settings
uint8_t csint = static_cast<bool>(cs);
switch(spi){
case SPIs::SPI_AUX:
{
uint16_t clockDivider = bcm2835_aux_spi_CalcClockDivider(3125000);
bcm2835_aux_spi_setClockDivider(clockDivider);
break;
}
case SPIs::SPI_0:
{
bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);
bcm2835_spi_setDataMode(BCM2835_SPI_MODE0);
bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_128);
bcm2835_spi_chipSelect(csint);
bcm2835_spi_setChipSelectPolarity(csint, LOW);
break;
}
default:
throw std::runtime_error("Choose SPI_AUX or SPI_0\n");
break;
}
//set the ADS to the requested interval
uint16_t got = 0;
uint32_t command = range | reference;
do
{
sendCommand(Commands::WRITE, Registers::RANGE_SEL_REG_7_0, command);
nanosleep(&delay, NULL);
sendCommand(Commands::READ_HWORD, Registers::RANGE_SEL_REG_7_0, 0x0000);
got = sendCommand(Commands::NOP, Registers::NO_OP_REG, 0x0000);
//std::clog << "Got: " << got >> 8 << " " << (got & 0x00FF) << std::endl;
nanosleep(&delay, NULL);
}while(got != command);
sendCommand(Commands::NOP, Registers::NO_OP_REG, 0x0000);
return;
}
//Send a command
uint16_t ADS8689::sendCommand(Commands command, Registers address, uint16_t data)
{
char buff[4] = {0};
buff[0] = static_cast<uint8_t>(command);/*(op | (address >> 7))*/;
buff[1] = static_cast<uint8_t>(address)/*(address << 1)*/;
buff[2] = (data >> 8);
buff[3] = data;
//printf("Sending: %.2x %.2x %.2x %.2x\n", buff[0], buff[1], buff[2], buff[3]);
if(spi == SPIs::SPI_AUX)
bcm2835_aux_spi_transfern(buff, sizeof(buff));
else
bcm2835_spi_transfern(buff, sizeof(buff));
//printf("Got: %.2x %.2x %.2x %.2x\n", buff[0], buff[1], buff[2], buff[3]);
return ((buff[0] << 8) | buff[1]);
}
//you will actually get the value of the adc on any command
//but nop makes sure it doesn't execute anything and you just get the value
//it's best to send all configuration commands before sampling
uint16_t ADS8689::readPlainADC()
{
return sendCommand(Commands::NOP, Registers::NO_OP_REG, 0x0000);
}
//Uses read planeadc but also does scaling math
double ADS8689::readADC(){
double val = (double) readPlainADC();
double scalefactor = 0.0;
//Find the scalefactor from the range
switch(this->range)
{
case pm3Vref: case p3Vref:
scalefactor = referenceVoltage*3/std::numeric_limits<uint16_t>::max();
break;
case pm25Vref: case p25Vref:
scalefactor = referenceVoltage*25/std::numeric_limits<uint16_t>::max();
break;
case pm15Vref: case p15Vref:
scalefactor = referenceVoltage*1.5/std::numeric_limits<uint16_t>::max();
break;
case pm125Vref: case p125Vref:
scalefactor = referenceVoltage*1.25/std::numeric_limits<uint16_t>::max();
break;
case pm0625Vref:
scalefactor = referenceVoltage*0.625/std::numeric_limits<uint16_t>::max();
break;
default:
throw std::runtime_error("Invalid Range \n");
}
//Check if unipolar or bi-polar. If bipolar, double range and shift down by half the max value so its centered at zero
switch(range)
{
case pm3Vref: case pm25Vref: case pm15Vref: case pm125Vref: case pm0625Vref:
val = val-0.5*std::numeric_limits<uint16_t>::max();
scalefactor *= 2;
break;
case p3Vref: case p25Vref: case p15Vref: case p125Vref:
//scalefactor = this->referenceVoltage*1.25/std::numeric_limits<uint16_t>::max();
break;
default:
throw std::runtime_error("Invalid Range \n");
}
//Calculate and refturn the scaled value.
return val*scalefactor;
}