STAR
Cal STAR — firmware, DAQ server, and engine design
Loading...
Searching...
No Matches
sfe_bus.cpp
Go to the documentation of this file.
1// sfe_bus.cpp
2//
3// This is a library written for SparkFun Qwiic ISM330DHCX boards
4//
5// SparkFun sells these bpards at its website: www.sparkfun.com
6//
7// Do you like this library? Help support SparkFun. Buy a board!
8//
9//SparkFun Qwiic 6DoF - ISM330DHCX https://www.sparkfun.com/products/19764
10//
11// Written by Kirk Benell @ SparkFun Electronics
12// Modified by Elias Santistevan @ SparkFun Electronics, April 2022
13//
14// Repository:
15// https://github.com/sparkfun/SparkFun_6DoF_ISM330DHCX_Arduino_Library
16//
17//
18// SparkFun code, firmware, and software is released under the MIT
19// License(http://opensource.org/licenses/MIT).
20//
21// SPDX-License-Identifier: MIT
22//
23// The MIT License (MIT)
24//
25// Copyright (c) 2022 SparkFun Electronics
26// Permission is hereby granted, free of charge, to any person obtaining a
27// copy of this software and associated documentation files (the "Software"),
28// to deal in the Software without restriction, including without limitation
29// the rights to use, copy, modify, merge, publish, distribute, sublicense,
30// and/or sell copies of the Software, and to permit persons to whom the
31// Software is furnished to do so, subject to the following conditions: The
32// above copyright notice and this permission notice shall be included in all
33// copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
34// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
35// NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
36// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
37// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
38// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
39// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
40
41
42// The following classes specify the behavior for communicating
43// over the respective data buses: Inter-Integrated Circuit (I2C)
44// and Serial Peripheral Interface (SPI).
45
46#include "sfe_bus.h"
47#include <Arduino.h>
48
49#define kMaxTransferBuffer 32
50#define SPI_READ 0x80
51
52// What we use for transfer chunk size
53const static uint16_t kChunkSize = kMaxTransferBuffer;
54
55//////////////////////////////////////////////////////////////////////////////////////////////////
56// Constructor
57//
58
59namespace sfe_ISM330DHCX {
60
62{
63}
64
65//////////////////////////////////////////////////////////////////////////////////////////////////
66// I2C init()
67//
68// Methods to init/setup this device. The caller can provide a Wire Port, or this class
69// will use the default
70
71bool QwI2C::init(TwoWire &wirePort, bool bInit)
72{
73
74 // if we don't have a wire port already
75 if( !_i2cPort )
76 {
77 _i2cPort = &wirePort;
78
79 if( bInit )
80 _i2cPort->begin();
81 }
82
83 return true;
84}
85
86//////////////////////////////////////////////////////////////////////////////////////////////////
87// I2C init()
88//
89// Methods to init/setup this device. The caller can provide a Wire Port, or this class
90// will use the default
92{
93 if( !_i2cPort )
94 return init(Wire);
95 else
96 return false;
97}
98
99
100
101//////////////////////////////////////////////////////////////////////////////////////////////////
102// ping()
103//
104// Is a device connected?
105bool QwI2C::ping(uint8_t i2c_address)
106{
107
108 if( !_i2cPort )
109 return false;
110
111 _i2cPort->beginTransmission(i2c_address);
112 return _i2cPort->endTransmission() == 0;
113}
114
115//////////////////////////////////////////////////////////////////////////////////////////////////
116// writeRegisterByte()
117//
118// Write a byte to a register
119
120bool QwI2C::writeRegisterByte(uint8_t i2c_address, uint8_t offset, uint8_t dataToWrite)
121{
122
123 if (!_i2cPort)
124 return false;
125
126 _i2cPort->beginTransmission(i2c_address);
127 _i2cPort->write(offset);
128 _i2cPort->write(dataToWrite);
129 return _i2cPort->endTransmission() == 0;
130}
131
132
133
134//////////////////////////////////////////////////////////////////////////////////////////////////
135// writeRegisterRegion()
136//
137// Write a block of data to a device.
138
139int QwI2C::writeRegisterRegion(uint8_t i2c_address, uint8_t offset, const uint8_t *data, uint16_t length)
140{
141
142 _i2cPort->beginTransmission(i2c_address);
143 _i2cPort->write(offset);
144 _i2cPort->write(data, (int)length);
145
146 return _i2cPort->endTransmission() ? -1 : 0; // -1 = error, 0 = success
147}
148
149////////////////////////////////////////////////////////////////////////////////////////////////////////////
150// readRegisterRegion()
151//
152// Reads a block of data from an i2c register on the devices.
153//
154// For large buffers, the data is chuncked over KMaxI2CBufferLength at a time
155//
156//
157int QwI2C::readRegisterRegion(uint8_t addr, uint8_t reg, uint8_t *data, uint16_t numBytes)
158{
159 uint8_t nChunk;
160 uint16_t nReturned;
161
162 if (!_i2cPort)
163 return -1;
164
165 int i; // counter in loop
166 bool bFirstInter = true; // Flag for first iteration - used to send register
167
168 while (numBytes > 0)
169 {
170 _i2cPort->beginTransmission(addr);
171
172 if (bFirstInter)
173 {
174 _i2cPort->write(reg);
175 bFirstInter = false;
176 }
177
178 if (_i2cPort->endTransmission() != 0)
179 return -1; // error with the end transmission
180
181 // We're chunking in data - keeping the max chunk to kMaxI2CBufferLength
182 nChunk = numBytes > kChunkSize ? kChunkSize : numBytes;
183
184 nReturned = _i2cPort->requestFrom((int)addr, (int)nChunk, (int)true);
185
186 // No data returned, no dice
187 if (nReturned == 0)
188 return -1; // error
189
190 // Copy the retrieved data chunk to the current index in the data segment
191 for (i = 0; i < nReturned; i++){
192 *data++ = _i2cPort->read();
193 }
194
195 // Decrement the amount of data recieved from the overall data request amount
196 numBytes = numBytes - nReturned;
197
198 } // end while
199
200 return 0; // Success
201}
202
203
204
205//////////////////////////////////////////////////////////////////////////////////////////////////
206// Constructor
207//
208
210{
211}
212
213////////////////////////////////////////////////////////////////////////////////////////////////
214// SPI init()
215//
216// Methods to init/setup this device. The caller can provide a SPI Port, or this class
217// will use the default
218
219
220bool SfeSPI::init(SPIClass &spiPort, SPISettings& ismSPISettings, uint8_t cs, bool bInit)
221{
222
223 // if we don't have a SPI port already
224 if( !_spiPort )
225 {
226 _spiPort = &spiPort;
227
228 if( bInit )
229 _spiPort->begin();
230 }
231
232
233 // SPI settings are needed for every transaction
234 _sfeSPISettings = ismSPISettings;
235
236 // The chip select pin can vary from platform to platform and project to project
237 // and so it must be given by the user.
238 if( !cs )
239 return false;
240
241 _cs = cs;
242
243 return true;
244}
245
246////////////////////////////////////////////////////////////////////////////////////////////////
247// SPI init()
248//
249// Methods to init/setup this device. The caller can provide a SPI Port, or this class
250// will use the default
251bool SfeSPI::init(uint8_t cs, bool bInit)
252{
253
254 //If the transaction settings are not provided by the user they are built here.
255 SPISettings spiSettings = SPISettings(3000000, MSBFIRST, SPI_MODE3);
256
257 //In addition of the port is not provided by the user, it defaults to SPI here.
258 return init(SPI, spiSettings, cs, bInit);
259
260}
261
262
263//////////////////////////////////////////////////////////////////////////////////////////////////
264// ping()
265//
266// Is a device connected? The SPI ping is not relevant but is defined here to keep consistency with
267// I2C class i.e. provided for the interface.
268//
269
270
271bool SfeSPI::ping(uint8_t i2c_address)
272{
273 return true;
274}
275
276//////////////////////////////////////////////////////////////////////////////////////////////////
277// writeRegisterByte()
278//
279// Write a byte to a register
280
281bool SfeSPI::writeRegisterByte(uint8_t i2c_address, uint8_t offset, uint8_t dataToWrite)
282{
283
284 if( !_spiPort )
285 return false;
286
287 // Apply settings
288 _spiPort->beginTransaction(_sfeSPISettings);
289 // Signal communication start
291
292 _spiPort->transfer(offset);
293 _spiPort->transfer(dataToWrite);
294
295 // End communcation
297 _spiPort->endTransaction();
298
299 return true;
300}
301
302
303//////////////////////////////////////////////////////////////////////////////////////////////////
304// writeRegisterRegion()
305//
306// Write a block of data to a device.
307
308int SfeSPI::writeRegisterRegion(uint8_t i2c_address, uint8_t offset, const uint8_t *data, uint16_t length)
309{
310
311 int i;
312
313 // Apply settings
314 _spiPort->beginTransaction(_sfeSPISettings);
315 // Signal communication start
317 _spiPort->transfer(offset);
318
319 for(i = 0; i < length; i++)
320 {
321 _spiPort->transfer(*data++);
322 }
323
324 // End communication
326 _spiPort->endTransaction();
327 return 0;
328}
329
330////////////////////////////////////////////////////////////////////////////////////////////////////////////
331// readRegisterRegion()
332//
333// Reads a block of data from the register on the device.
334//
335//
336//
337
338
339int SfeSPI::readRegisterRegion(uint8_t addr, uint8_t reg, uint8_t *data, uint16_t numBytes)
340{
341 if (!_spiPort)
342 return -1;
343
344 int i; // counter in loop
345
346 // Apply settings
347 _spiPort->beginTransaction(_sfeSPISettings);
348 // Signal communication start
350 // A leading "1" must be added to transfer with register to indicate a "read"
351 reg = (reg | SPI_READ);
352 _spiPort->transfer(reg);
353
354 for(i = 0; i < numBytes; i++)
355 {
356 *data++ = _spiPort->transfer(0x00);
357 }
358
359 // End transaction
361 _spiPort->endTransaction();
362 return 0;
363
364}
365
366}
#define HIGH
Definition Arduino.h:19
#define LOW
Definition Arduino.h:20
void digitalWrite(int, int)
Definition Arduino.h:48
TwoWire * _i2cPort
Definition sfe_bus.h:92
bool ping(uint8_t address)
Definition sfe_bus.cpp:105
int writeRegisterRegion(uint8_t address, uint8_t offset, const uint8_t *data, uint16_t length)
Definition sfe_bus.cpp:139
bool writeRegisterByte(uint8_t address, uint8_t offset, uint8_t data)
Definition sfe_bus.cpp:120
int readRegisterRegion(uint8_t addr, uint8_t reg, uint8_t *data, uint16_t numBytes)
Definition sfe_bus.cpp:157
int readRegisterRegion(uint8_t addr, uint8_t reg, uint8_t *data, uint16_t numBytes)
Definition sfe_bus.cpp:339
bool writeRegisterByte(uint8_t address, uint8_t offset, uint8_t data)
Definition sfe_bus.cpp:281
SPISettings _sfeSPISettings
Definition sfe_bus.h:121
SPIClass * _spiPort
Definition sfe_bus.h:119
int writeRegisterRegion(uint8_t address, uint8_t offset, const uint8_t *data, uint16_t length)
Definition sfe_bus.cpp:308
bool init(uint8_t cs, bool bInit=false)
Definition sfe_bus.cpp:251
bool ping(uint8_t address)
Definition sfe_bus.cpp:271
#define SPI_READ
uint8_t reg
*brief remove last reference token *sa JSON pointer has no nullptr
Definition json.hpp:13968
static const uint16_t kChunkSize
Definition sfe_bus.cpp:53
#define kMaxTransferBuffer
Definition sfe_bus.cpp:49