Mcp320x
Mcp320x.cpp
Go to the documentation of this file.
1 
5 #include "Mcp320x.h"
6 
7 // divide n by d and round to next integer
8 #define div_round(n,d) (((n) + ((d) >> 2)) / (d))
9 
10 // channel configurations
15 
16 template <typename T>
17 MCP320x<T>::MCP320x(uint16_t vref, uint8_t csPin, SPIClass *spi)
18  : mVref(vref)
19  , mCsPin(csPin)
20  , mSplSpeed(0)
21  , mSpi(spi) {}
22 
23 template <typename T>
24 MCP320x<T>::MCP320x(uint16_t vref, uint8_t csPin)
25  : MCP320x(vref, csPin, &SPI) {}
26 
27 template <typename T>
29 {
30  mSplSpeed = testSplSpeed(ch, 256);
31 }
32 
33 template <typename T>
34 uint16_t MCP320x<T>::read(Channel ch) const
35 {
36  return execute(createCmd(ch));
37 }
38 
39 template <typename T>
41 {
42  return testSplSpeed(ch, 64);
43 }
44 
45 template <typename T>
46 uint32_t MCP320x<T>::testSplSpeed(Channel ch, uint16_t num) const
47 {
48  auto cmd = createCmd(ch);
49  // start time
50  uint32_t t1 = micros();
51  // perform sampling
52  for (uint16_t i = 0; i < num; i++) execute(cmd);
53  // stop time
54  uint32_t t2 = micros();
55 
56  // return average sampling speed
57  return div_round((t2 - t1) * 1000, num);
58 }
59 
60 template <typename T>
61 uint32_t MCP320x<T>::testSplSpeed(Channel ch, uint16_t num, uint32_t splFreq)
62 {
63  // required delay
64  uint16_t delay = getSplDelay(ch, splFreq);
65 
66  auto cmd = createCmd(ch);
67  // start time
68  uint32_t t1 = micros();
69  // perform sampling
70  for (uint16_t i = 0; i < num; i++) {
71  execute(cmd);
72  delayMicroseconds(delay);
73  }
74  // stop time
75  uint32_t t2 = micros();
76 
77  // return average sampling speed
78  return div_round((t2 - t1) * 1000, num);
79 }
80 
81 template <typename T>
82 uint16_t MCP320x<T>::toAnalog(uint16_t raw) const
83 {
84  return (static_cast<uint32_t>(raw) * mVref) / (kRes - 1);
85 }
86 
87 template <typename T>
88 uint16_t MCP320x<T>::toDigital(uint16_t val) const
89 {
90  return (static_cast<uint32_t>(val) * (kRes - 1)) / mVref;
91 }
92 
93 template <typename T>
94 uint16_t MCP320x<T>::getVref() const
95 {
96  return mVref;
97 }
98 
99 template <typename T>
100 uint16_t MCP320x<T>::getAnalogRes() const
101 {
102  return (static_cast<uint32_t>(mVref) * 1000) / (kRes - 1);
103 }
104 
105 template <typename T>
106 uint16_t MCP320x<T>::getSplDelay(Channel ch, uint32_t splFreq)
107 {
108  // requested sampling period (ns)
109  uint32_t splTime = div_round(1000000000, splFreq);
110 
111  // measure speed if uncalibrated
112  if (!mSplSpeed) calibrate(ch);
113 
114  // calculate delay in us
115  int16_t delay = (splTime - mSplSpeed) / 1000;
116  return (delay < 0) ? 0 : static_cast<uint16_t>(delay);
117 }
118 
119 template <>
121 {
122  // no command required
123  return {};
124 }
125 
126 template <>
128 {
129  // base command structure
130  // 0b00000001cc100000
131  // c: channel config
132  return {
133  // add channel to basic command structure
134  .value = static_cast<uint16_t>((0x0120 | (ch << 6)))
135  };
136 }
137 
138 template <>
140 {
141  // base command structure
142  // 0b000001cxcc000000
143  // c: channel config
144  return {
145  // add channel to basic command structure
146  .value = static_cast<uint16_t>((0x0400 | (ch << 6)))
147  };
148 }
149 
150 template <>
152 {
153  // base command structure
154  // 0b000001cccc000000
155  // c: channel config
156  return {
157  // add channel to basic command structure
158  .value = static_cast<uint16_t>((0x0400 | (ch << 6)))
159  };
160 }
161 
162 template <>
164 {
165  return transfer();
166 }
167 
168 template <>
169 uint16_t MCP3202::execute(Command<MCP3202Ch> cmd) const
170 {
171  return transfer(cmd);
172 }
173 
174 template <>
175 uint16_t MCP3204::execute(Command<MCP3204Ch> cmd) const
176 {
177  return transfer(cmd);
178 }
179 
180 template <>
181 uint16_t MCP3208::execute(Command<MCP3208Ch> cmd) const
182 {
183  return transfer(cmd);
184 }
185 
186 template <typename T>
187 uint16_t MCP320x<T>::transfer() const
188 {
189  SpiData adc;
190 
191  // activate ADC with chip select
192  digitalWrite(mCsPin, LOW);
193 
194  // receive first(msb) 5 bits
195  adc.hiByte = mSpi->transfer(0x00) & 0x1F;
196  // receive last(lsb) 8 bits
197  adc.loByte = mSpi->transfer(0x00);
198 
199  // deactivate ADC with slave select
200  digitalWrite(mCsPin, HIGH);
201 
202  // correct bit offset
203  // |x|x|x|11|10|9|8|7| |6|5|4|3|2|1|0|1
204  return (adc.value >> 1);
205 }
206 
207 template <typename T>
208 uint16_t MCP320x<T>::transfer(SpiData cmd) const
209 {
210  SpiData adc;
211 
212  // activate ADC with chip select
213  digitalWrite(mCsPin, LOW);
214 
215  // send first command byte
216  mSpi->transfer(cmd.hiByte);
217  // send second command byte and receive first(msb) 4 bits
218  adc.hiByte = mSpi->transfer(cmd.loByte) & 0x0F;
219  // receive last(lsb) 8 bits
220  adc.loByte = mSpi->transfer(0x00);
221 
222  // deactivate ADC with slave select
223  digitalWrite(mCsPin, HIGH);
224 
225  return adc.value;
226 }
227 
228 /*
229  * Explicit template instantiation for the channel types.
230  */
231 template class MCP320x<MCP3201Ch>;
232 template class MCP320x<MCP3202Ch>;
233 template class MCP320x<MCP3204Ch>;
234 template class MCP320x<MCP3208Ch>;
uint16_t read(Channel ch) const
Definition: Mcp320x.cpp:34
uint16_t getAnalogRes() const
Definition: Mcp320x.cpp:100
uint16_t toDigital(uint16_t val) const
Definition: Mcp320x.cpp:88
uint16_t execute(Command< Channel > cmd) const
Definition: Mcp320x.cpp:163
uint16_t getVref() const
Definition: Mcp320x.cpp:94
uint32_t mSplSpeed
Definition: Mcp320x.h:449
uint16_t mVref
Definition: Mcp320x.h:447
MCP320x(uint16_t vref, uint8_t csPin, SPIClass *spi)
Definition: Mcp320x.cpp:17
uint16_t toAnalog(uint16_t raw) const
Definition: Mcp320x.cpp:82
MCP320xTypes::MCP3202::Channel MCP3202Ch
Definition: Mcp320x.cpp:12
MCP320xTypes::MCP3204::Channel MCP3204Ch
Definition: Mcp320x.cpp:13
uint8_t hiByte
Definition: Mcp320x.h:367
#define div_round(n, d)
Definition: Mcp320x.cpp:8
static const uint16_t kRes
Definition: Mcp320x.h:122
ChannelType Channel
Definition: Mcp320x.h:125
uint32_t testSplSpeed(Channel ch) const
Definition: Mcp320x.cpp:40
MCP320xTypes::MCP3208::Channel MCP3208Ch
Definition: Mcp320x.cpp:14
void calibrate(Channel ch)
Definition: Mcp320x.cpp:28
uint16_t value
Definition: Mcp320x.h:364
SPIClass * mSpi
Definition: Mcp320x.h:450
MCP320xTypes::MCP3201::Channel MCP3201Ch
Definition: Mcp320x.cpp:11
uint8_t loByte
Definition: Mcp320x.h:366
static Command< Channel > createCmd(Channel ch)
Definition: Mcp320x.cpp:120
uint16_t getSplDelay(Channel ch, uint32_t splFreq)
Definition: Mcp320x.cpp:106
uint16_t transfer() const
Definition: Mcp320x.cpp:187
uint8_t mCsPin
Definition: Mcp320x.h:448