| Linduino 1.3.0 Linear Technology Arduino-Compatible Demonstration Board

LT_SMBusBase.cpp
Go to the documentation of this file.
1 /*!
2 LTC SMBus Support: API for a shared SMBus layer
3
4 @verbatim
5
6 This API is shared with Linduino and RTOS code. End users should code to this
7 API to enable use of the PMBus code without modifications.
8
9 @endverbatim
10
11
12 Copyright 2018(c) Analog Devices, Inc.
13
14 All rights reserved.
15
16 Redistribution and use in source and binary forms, with or without
17 modification, are permitted provided that the following conditions are met:
18 - Redistributions of source code must retain the above copyright
19 notice, this list of conditions and the following disclaimer.
20 - Redistributions in binary form must reproduce the above copyright
21 notice, this list of conditions and the following disclaimer in
22 the documentation and/or other materials provided with the
23 distribution.
24 - Neither the name of Analog Devices, Inc. nor the names of its
25 contributors may be used to endorse or promote products derived
26 from this software without specific prior written permission.
27 - The use of this software may or may not infringe the patent rights
28 of one or more patent holders. This license does not release you
29 from the requirement that you obtain separate licenses from these
30 patent holders to use this software.
31 - Use of the software either in source or binary form, must be run
32 on or directly connected to an Analog Devices Inc. component.
33
34 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
35 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
36 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
37 IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
38 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39 LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
40 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
41 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
43 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44 */
45
46 //! @ingroup PMBus_SMBus
47 //! @{
48 //! @defgroup LT_SMBusBase LT_SMBusBase: Implementation of SMBus
49 //! @}
50
51 /*! @file
52 @ingroup LT_SMBusBase
53 Library Header File for LT_SMBusBase
54 */
55
56 #include "LT_SMBusBase.h"
57
58 #define USE_BLOCK_TRANSACTION 0
59 #define FOUND_SIZE 0x79
60
61 bool LT_SMBusBase::open_ = false;
62 uint8_t LT_SMBusBase::found_address_[FOUND_SIZE + 1];
63
64 LT_SMBusBase::LT_SMBusBase()
65 {
66 i2cbus_ = new LT_I2CBus();
67
68 if (open_ == false)
69 {
70 i2cbus_->quikevalI2CInit(); //! Initializes Linduino I2C port.
71 i2cbus_->quikevalI2CConnect(); //! Connects I2C port to the QuikEval connector
72
73 open_ = true;
74 }
75 }
76
77 LT_SMBusBase::LT_SMBusBase(uint32_t speed)
78 {
79 i2cbus_ = new LT_I2CBus(speed);
80
81 if (open_ == false)
82 {
83 i2cbus_->quikevalI2CInit(); //! Initializes Linduino I2C port.
84 i2cbus_->quikevalI2CConnect(); //! Connects I2C port to the QuikEval connector
85
86 open_ = true;
87 }
88 }
89
90 LT_SMBusBase::~LT_SMBusBase()
91 {
92 delete i2cbus_;
93 }
94
95 uint8_t LT_SMBusBase::readAlert(void)
96 {
97 uint8_t address;
98
99 if (i2cbus_->readByte(0x0C, &address))
100 Serial.print(F("Read Alert: fail.\n"));
101
102 return (address >> 1);
103 }
104
105 uint8_t LT_SMBusBase::waitForAck(uint8_t address, uint8_t command)
106 {
107 uint8_t data;
108 // A real application should timeout at 4.1 seconds.
109 uint16_t timeout = 8192;
110 while (timeout-- > 0)
111 {
112 if (0 == i2cbus_->readByteData(address, command, &data))
113 return SUCCESS;
114 }
115 return FAILURE;
116 }
117
118
119 uint8_t *LT_SMBusBase::probe(uint8_t command)
120 {
121 uint8_t address;
122 uint8_t found = 0;
123
124 for (address = 0x10; address < 0x7F; address++)
125 {
126 if (address == 0x0C)
127 continue;
128
129 if (0==i2cbus_->writeByte(address, command))
130 {
131
132 if (found < FOUND_SIZE)
133 found_address_[found++] = address;
134
135 }
136
137
138 }
139
140 found_address_[found] = 0;
141
142 return found_address_;
143 }
144
145 uint8_t *LT_SMBusBase::probeUnique(uint8_t command)
146 {
147 uint8_t address;
148 uint8_t found = 0;
149
150 for (address = 0x10; address < 0x7F; address++)
151 {
152 if (address == 0x0C)
153 continue;
154 if (address == 0x5B)
155 continue;
156 if (address == 0x5A)
157 continue;
158 if (address == 0x7C)
159 continue;
160
161 if (0==i2cbus_->writeByte(address, command))
162 {
163
164 if (found < FOUND_SIZE)
165 found_address_[found++] = address;
166
167 }
168
169
170 }
171
172 found_address_[found] = 0;
173
174 return found_address_;
175 }
176
177 void LT_SMBusBase::writeByte(uint8_t address, uint8_t command, uint8_t data)
178 {
179 if (pec_enabled_)
180 {
181 uint8_t buffer[2];
182 buffer[0] = data;
183
184 pecClear();
185 pecAdd(address << 1);
186 pecAdd(command);
187 pecAdd(data);
188 buffer[1] = pecGet();
189 if (i2cbus_->writeBlockData(address, command, 2, buffer))
190 Serial.print(F("Write Byte With Pec: fail.\n"));
191 }
192 else
193 {
194 if (i2cbus_->writeByteData(address, command, data))
195 Serial.print(F("Write Byte: fail.\n"));
196 }
197 }
198
199 void LT_SMBusBase::writeBytes(uint8_t *addresses, uint8_t *commands,
200 uint8_t *data, uint8_t no_addresses)
201 {
202 if (pec_enabled_)
203 {
204 uint8_t buffer[2];
205 uint16_t index = 0;
206
207 while (index < no_addresses)
208 {
209 buffer[0] = data[index];
210 pecClear();
211 pecAdd(addresses[index] << 1);
212 pecAdd(commands[index]);
213 pecAdd(data[index]);
214 buffer[1] = pecGet();
215
216 if (i2cbus_->writeBlockData(addresses[index], commands[index], 2, buffer))
217 Serial.print(F("Write Bytes With Pec: fail.\n"));
218 index++;
219 }
220 }
221 else
222 {
223 uint16_t index = 0;
224
225 while (index < no_addresses)
226 {
227 if (i2cbus_->writeBlockData(addresses[index], commands[index], 1, &data[index]))
228 Serial.print(F("Write Bytes: fail.\n"));
229 index++;
230 }
231 }
232 }
233
234 uint8_t LT_SMBusBase::readByte(uint8_t address, uint8_t command)
235 {
236 if (pec_enabled_)
237 {
238 uint8_t input[2];
239 input[0] = 0x00;
240 input[1] = 0x00;
241
242 pecClear();
243 pecAdd(address << 1);
244 pecAdd(command);
245 pecAdd((address << 1) | 0x01);
246 if (i2cbus_->readBlockData(address, command, 2, input))
247 Serial.print(F("Read Byte With Pec: fail.\n"));
248
249 pecAdd(input[0]);
250 if (pecGet() != input[1])
251 Serial.print(F("Read Byte With Pec: fail pec\n"));
252
253 return input[0];
254 }
255 else
256 {
257 uint8_t result;
258
259 if (i2cbus_->readByteData(address, command, &result))
260 Serial.print(F("Read Byte: fail.\n"));
261 return result;
262 }
263 }
264
265 void LT_SMBusBase::writeWord(uint8_t address, uint8_t command, uint16_t data)
266 {
267 if (pec_enabled_)
268 {
269 uint8_t buffer[3];
270 buffer[0] = (uint8_t) (data & 0xff);
271 buffer[1] = (uint8_t) (data >> 8);
272
273 pecClear();
274 pecAdd(address << 1);
275 pecAdd(command);
276 pecAdd(data & 0xff);
277 pecAdd(data >> 8);
278 buffer[2] = pecGet();
279 if (i2cbus_->writeBlockData(address, command, 3, buffer))
280 Serial.print(F("Write Word With Pec: fail.\n"));
281 }
282 else
283 {
284
285 #if USE_BLOCK_TRANSACTION
286 uint8_t buffer[2];
287 buffer[0] = (uint8_t) (data & 0xff);
288 buffer[1] = (uint8_t) (data >> 8);
289
290 if (i2cbus_->writeBlockData(address, command, 2, buffer))
291 Serial.print(F("Write Word: fail.\n"));
292 #else
293 uint16_t rdata;
294 rdata = (data << 8) | (data >> 8);
295 if (i2cbus_->writeWordData(address, command, rdata))
296 Serial.print(F("Write Word: fail.\n"));
297 #endif
298 }
299 }
300
301 uint16_t LT_SMBusBase::readWord(uint8_t address, uint8_t command)
302 {
303 if (pec_enabled_)
304 {
305 uint8_t input[3];
306 input[0] = 0x00;
307 input[1] = 0x00;
308 input[2] = 0x00;
309
310 pecClear();
311 pecAdd(address << 1);
312 pecAdd(command);
313 pecAdd((address << 1) | 0x01);
314
315 if (i2cbus_->readBlockData(address, command, 3, input))
316 Serial.print(F("Read Word With Pec: fail.\n"));
317
318 pecAdd(input[0]);
319 pecAdd(input[1]);
320 if (pecGet() != input[2])
321 Serial.print(F("Read Word With Pec: fail pec\n"));
322
323 return input[1] << 8 | input[0];
324 }
325 else
326 {
327
328 #if USE_BLOCK_TRANSACTION
329 uint8_t input[2];
330 input[0] = 0x00;
331 input[1] = 0x00;
332
333 if (i2cbus_->readBlockData(address, command, 2, input))
334 Serial.print(F("Read Word: fail.\n"));
335 return input[1] << 8 | input[0];
336 #else
337 uint16_t rdata;
338 if (i2cbus_->readWordData(address, command, &rdata))
339 Serial.print(F("Read Word: fail.\n"));
340 return (rdata << 8) | (rdata >> 8);
341 #endif
342 }
343 }
344
345 void LT_SMBusBase::writeBlock(uint8_t address, uint8_t command,
346 uint8_t *block, uint16_t block_size)
347 {
348 if (pec_enabled_)
349 {
350 uint16_t pos = 0;
351
352 pecClear();
353 pecAdd(address << 1);
354 pecAdd(command);
355 pecAdd(block_size);
356
357 while (pos < block_size)
358 pecAdd(block[pos++]);
359 uint8_t pec = pecGet();
360
361 uint8_t *data_with_pec = (uint8_t *) malloc(block_size + 2);
362 data_with_pec[0] = block_size;
363 memcpy(data_with_pec + 1, block, block_size);
364 data_with_pec[block_size + 1] = pec;
365
366 if (i2cbus_->writeBlockData(address, command, block_size + 2, data_with_pec))
367 Serial.print(F("Write Block With Pec: fail.\n"));
368 free(data_with_pec);
369 }
370 else
371 {
372 uint8_t *buffer = (uint8_t *)malloc(block_size + 1);
373 buffer[0] = block_size;
374 memcpy(buffer + 1, block, block_size);
375 if (i2cbus_->writeBlockData(address, command, block_size + 1, buffer))
376 Serial.print(F("Write Block: fail.\n"));
377 free(buffer);
378 }
379 }
380
381 uint8_t LT_SMBusBase::writeReadBlock(uint8_t address, uint8_t command,
382 uint8_t *block_out, uint16_t block_out_size, uint8_t *block_in, uint16_t block_in_size)
383 {
384 if (pec_enabled_)
385 {
386 uint16_t pos = 0;
387 uint8_t actual_block_size;
388
389 pecClear();
390 pecAdd(address << 1);
391 pecAdd(command);
392 pecAdd(block_out_size);
393 while (pos < block_out_size)
394 pecAdd(block_out[pos++]);
395
396
397 uint8_t *buffer = (uint8_t *)malloc(block_out_size + 1);
398 buffer[0] = block_out_size;
399 memcpy(buffer + 1, block_out, block_out_size);
400
401 i2cbus_->startGroupProtocol();
402 if (i2cbus_->writeBlockData(address, command, block_out_size + 1, buffer))
403 Serial.print(F("Write/Read Block w/PEC: write fail\n"));
404 free(buffer);
405
406
407
408 pecAdd((address << 1) | 0x01);
409
410 i2cbus_->endGroupProtocol();
411 buffer = (uint8_t *)malloc(block_in_size + 2);
412 if (i2cbus_->readBlockData(address, block_in_size + 2, buffer))
413 Serial.print(F("Write/Read Block w/PEC: read fail.\n"));
414 if (buffer[0] > block_in_size)
415 {
416 Serial.print(F("Write/Read Block w/PEC: fail read size too big.\n"));
417 }
418 memcpy(block_in, buffer + 1, block_in_size);
419
420 for (pos = 0; pos<buffer[0] + 1u; pos++)
421 pecAdd(buffer[pos]);
422 if (pecGet() != buffer[buffer[0]+1])
423 Serial.print(F("Write/Read Block w/Pec: fail pec\n"));
424
425 actual_block_size = buffer[0];
426 free(buffer);
427 return actual_block_size;
428 }
429 else
430 {
431 uint8_t *buffer = (uint8_t *)malloc(block_out_size + 1);
432 uint8_t actual_block_size;
433
434 buffer[0] = block_out_size;
435 memcpy(buffer + 1, block_out, block_out_size);
436
437 i2cbus_->startGroupProtocol();
438 if (i2cbus_->writeBlockData(address, command, block_out_size + 1, buffer))
439 Serial.print(F("Write/Read Block write fail\n"));
440 free(buffer);
441
442 i2cbus_->endGroupProtocol();
443 buffer = (uint8_t *)malloc(block_in_size + 1);
444 if (i2cbus_->readBlockData(address, block_in_size + 1, buffer))
445 Serial.print(F("Write/Read Block: read fail.\n"));
446 if (buffer[0] > block_in_size)
447 {
448 Serial.print(F("Write/Read Block: fail size too big.\n"));
449 }
450 memcpy(block_in, buffer + 1, block_in_size);
451
452 actual_block_size = buffer[0];
453 free(buffer);
454 return actual_block_size;
455 }
456
457 }
458
459 uint8_t LT_SMBusBase::readBlock(uint8_t address, uint8_t command,
460 uint8_t *block, uint16_t block_size)
461 {
462 if (pec_enabled_)
463 {
464 uint16_t pos;
465 uint8_t *buffer = (uint8_t *)malloc(block_size + 2);
466 uint8_t actual_block_size;
467
468 pecClear();
469 pecAdd(address << 1);
470 pecAdd(command);
471 pecAdd((address << 1) | 0x01);
472
473 if (i2cbus_->readBlockData(address, command, block_size + 2, buffer))
474
475 if (buffer[0] > block_size)
476 Serial.print(F("Read Block with PEC: fail size too big.\n"));
477
478 memcpy(block, buffer + 1, block_size);
479
480 for (pos = 0; pos<buffer[0] + 1u; pos++)
481 pecAdd(buffer[pos]);
482 if (pecGet() != buffer[buffer[0]+1])
483 Serial.print(F("Read Block With Pec: fail pec\n"));
484
485 actual_block_size = buffer[0];
486 free(buffer);
487 return actual_block_size;
488 }
489 else
490 {
491 uint8_t *buffer = (uint8_t *)malloc(block_size + 1);
492 uint8_t actual_block_size;
493
494 if (i2cbus_->readBlockData(address, command, block_size + 1, buffer))
495 Serial.print(F("Read Block: fail.\n"));
496 if (buffer[0] > block_size)
497 {
498 Serial.print(F("Read Block: fail size too big.\n"));
499 }
500 memcpy(block, buffer + 1, block_size);
501
502 actual_block_size = buffer[0];
503 free(buffer);
504 return actual_block_size;
505 }
506 }
507
508 void LT_SMBusBase::sendByte(uint8_t address, uint8_t command)
509 {
510 if (pec_enabled_)
511 {
512 uint8_t pec;
513
514 pecClear();
515 pecAdd(address << 1);
516 pecAdd(command);
517 pec = pecGet();
518
519 if (i2cbus_->writeBlockData(address, command, 1, &pec))
520 Serial.print(F("Send Byte With Pec: fail.\n"));
521 }
522 else
523 {
524 if (i2cbus_->writeByte(address, command))
525 Serial.print(F("Send Byte: fail.\n"));
526 }
527 }
LT_SMBusBase::sendByte
void sendByte(uint8_t address, uint8_t command)
SMBus send byte command.
Definition: LT_SMBusBase.cpp:508
LT_I2CBus::endGroupProtocol
void endGroupProtocol(void)
ends group protocol so I2CBus knows to send STOPs again.
Definition: LT_I2CBus.cpp:244
LT_I2CBus::quikevalI2CInit
void quikevalI2CInit(void)
Initializes Linduino I2C port.
Definition: LT_I2CBus.cpp:225
LT_I2CBus::writeWordData
int8_t writeWordData(uint8_t address, uint8_t command, uint16_t value)
Write a 16-bit word of data to register specified by "command".
Definition: LT_I2CBus.cpp:148
LT_SMBusBase::found_address_
static uint8_t found_address_[]
Definition: LT_SMBusBase.h:64
LT_I2CBus::readByteData
int8_t readByteData(uint8_t address, uint8_t command, uint8_t *value)
Read a byte of data at register specified by "command", store in "value".
Definition: LT_I2CBus.cpp:106
LT_SMBusBase::writeWord
void writeWord(uint8_t address, uint8_t command, uint16_t data)
SMBus write word command.
Definition: LT_SMBusBase.cpp:265
LT_SMBusBase::probe
uint8_t * probe(uint8_t command)
SMBus bus probe.
Definition: LT_SMBusBase.cpp:119
LT_I2CBus::readBlockData
int8_t readBlockData(uint8_t address, uint8_t command, uint16_t length, uint8_t *values)
Read a block of data, starting at register specified by "command" and ending at (command + length - 1...
Definition: LT_I2CBus.cpp:161
LT_I2CBus::writeBlockData
int8_t writeBlockData(uint8_t address, uint8_t command, uint16_t length, uint8_t *values)
Write a block of data, starting at register specified by "command" and ending at (command + length - ...
Definition: LT_I2CBus.cpp:187
LT_SMBusBase::~LT_SMBusBase
virtual ~LT_SMBusBase()
Definition: LT_SMBusBase.cpp:90
FAILURE
#define FAILURE
Definition: LT_PMBus.h:63
LT_SMBusBase::i2cbus_
LT_I2CBus * i2cbus_
Definition: LT_SMBusBase.h:65
LT_SMBusBase::writeByte
void writeByte(uint8_t address, uint8_t command, uint8_t data)
SMBus write byte command.
Definition: LT_SMBusBase.cpp:177
FOUND_SIZE
#define FOUND_SIZE
Definition: LT_SMBusBase.cpp:59
LT_I2CBus::startGroupProtocol
void startGroupProtocol(void)
starts group protocol so I2CBus knows to repeat START instead of STOP.
Definition: LT_I2CBus.cpp:240
LT_SMBus::pec_enabled_
bool pec_enabled_
Definition: LT_SMBus.h:64
LT_SMBusBase::probeUnique
uint8_t * probeUnique(uint8_t command)
SMBus bus probe.
Definition: LT_SMBusBase.cpp:145
LT_SMBusBase::readAlert
uint8_t readAlert(void)
Perform ARA.
Definition: LT_SMBusBase.cpp:95
address
static uint8_t address
Definition: DC2091A.ino:83
data
union LT_union_int32_4bytes data
Definition: DC2094A.ino:138
pos
static int16_t pos
Definition: Precision_Voltage_Source.ino:73
LT_SMBus::pecGet
uint8_t pecGet(void)
Get the current pec result.
Definition: LT_SMBus.cpp:192
LT_SMBusBase::open_
static bool open_
Used to ensure initialisation of i2c once.
Definition: LT_SMBusBase.h:63
LT_SMBusBase::writeBytes
void writeBytes(uint8_t *addresses, uint8_t *commands, uint8_t *data, uint8_t no_addresses)
SMBus write byte command for a list of addresses.
Definition: LT_SMBusBase.cpp:199
LT_I2CBus::readWordData
int8_t readWordData(uint8_t address, uint8_t command, uint16_t *value)
Read a 16-bit word of data from register specified by "command".
Definition: LT_I2CBus.cpp:131
LT_SMBusBase::readByte
uint8_t readByte(uint8_t address, uint8_t command)
SMBus read byte command.
Definition: LT_SMBusBase.cpp:234
LT_I2CBus
Definition: LT_I2CBus.h:50
input
#define input(pin)
Return the state of pin "pin".
Definition: Linduino.h:79
pec
static bool pec
Definition: program.ino:88
LT_I2CBus::quikevalI2CConnect
void quikevalI2CConnect(void)
Switch MUX to connect I2C pins to QuikEval connector.
Definition: LT_I2CBus.cpp:232
LT_SMBusBase::readBlock
uint8_t readBlock(uint8_t address, uint8_t command, uint8_t *block, uint16_t block_size)
SMBus read block command.
Definition: LT_SMBusBase.cpp:459
LT_I2CBus::writeByte
int8_t writeByte(uint8_t address, uint8_t value)
Write "value" byte to device at "address".
Definition: LT_I2CBus.cpp:95
timeout
long timeout
Definition: EVAL-AD7124-8.ino:144
index
static int index
Definition: device_logger.ino:91
LT_SMBus::pecClear
void pecClear(void)
Clear the pec value so it can start a new calculation.
Definition: LT_SMBus.cpp:162
LT_SMBusBase::writeBlock
void writeBlock(uint8_t address, uint8_t command, uint8_t *block, uint16_t block_size)
SMBus write block command.
Definition: LT_SMBusBase.cpp:345
SUCCESS
#define SUCCESS
Definition: LT_PMBus.h:62
LT_I2CBus::writeByteData
int8_t writeByteData(uint8_t address, uint8_t command, uint8_t value)
Write a byte of data to register specified by "command".
Definition: LT_I2CBus.cpp:119
LT_SMBus::pecAdd
void pecAdd(uint8_t byte_value)
Add a byte to the pec calculation.
Definition: LT_SMBus.cpp:170
LT_I2CBus::readByte
int8_t readByte(uint8_t address, uint8_t *value)
Read a byte, store in "value".
Definition: LT_I2CBus.cpp:84
LT_SMBusBase.h
LTC SMBus Support: Implementation for a shared SMBus layer.
LT_SMBusBase::LT_SMBusBase
LT_SMBusBase()
Definition: LT_SMBusBase.cpp:64
LT_SMBusBase::readWord
uint16_t readWord(uint8_t address, uint8_t command)
SMBus read word command.
Definition: LT_SMBusBase.cpp:301
LT_SMBusBase::waitForAck
uint8_t waitForAck(uint8_t address, uint8_t command)
Read with the address and command in loop until ack, then issue stop.
Definition: LT_SMBusBase.cpp:105
LT_SMBusBase::writeReadBlock
uint8_t writeReadBlock(uint8_t address, uint8_t command, uint8_t *block_out, uint16_t block_out_size, uint8_t *block_in, uint16_t block_in_size)
SMBus write then read block command.
Definition: LT_SMBusBase.cpp:381