Skip to content

Commit 6ee3c24

Browse files
committed
Adds sfe_bus outline
* Almost entirely unmodified * Formatting is not right * Name of read and write may change
1 parent f4935ca commit 6ee3c24

File tree

2 files changed

+445
-0
lines changed

2 files changed

+445
-0
lines changed

src/sfe_bus.cpp

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

0 commit comments

Comments
 (0)