| Linduino 1.3.0 Linear Technology Arduino-Compatible Demonstration Board

retention.ino
Go to the documentation of this file.
1 /*
2 Linear Technology DC1962A/C Demonstration Board
3 LTC3880, LTC2974, LTC2977/8: Power Management Solution for Application Processors
4 Example application of NVM Retention
5
6 @verbatim
7
8 NOTES
9 Setup:
10 Set the terminal baud rate to 115200 and select the newline terminator.
11
12 @endverbatim
13
14 http://www.linear.com/product/LTC3880
15 http://www.linear.com/product/LTC2974
16 http://www.linear.com/product/LTC2977
17
18 http://www.linear.com/demo/DC1962C
19
20
21 Copyright 2018(c) Analog Devices, Inc.
22
23 All rights reserved.
24
25 Redistribution and use in source and binary forms, with or without
26 modification, are permitted provided that the following conditions are met:
27 - Redistributions of source code must retain the above copyright
28 notice, this list of conditions and the following disclaimer.
29 - Redistributions in binary form must reproduce the above copyright
30 notice, this list of conditions and the following disclaimer in
31 the documentation and/or other materials provided with the
32 distribution.
33 - Neither the name of Analog Devices, Inc. nor the names of its
34 contributors may be used to endorse or promote products derived
35 from this software without specific prior written permission.
36 - The use of this software may or may not infringe the patent rights
37 of one or more patent holders. This license does not release you
38 from the requirement that you obtain separate licenses from these
39 patent holders to use this software.
40 - Use of the software either in source or binary form, must be run
41 on or directly connected to an Analog Devices Inc. component.
42
43 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
44 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
45 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
46 IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
47 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
48 LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
49 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
50 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
51 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
52 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
53 */
54
55 #include <Arduino.h>
56 #include <Linduino.h>
57 #include <UserInterface.h>
58 #include <avr/boot.h>
59
60 #include <LT_SMBus.h>
61 #include <LT_SMBusPec.h>
62 #include <LT_SMBusNoPec.h>
63 #include <LT_SMBusGroup.h>
64 #include <LT_PMBusMath.h>
65
66 // Some bit definitions for MFR_COMMON
67 #define CML 1
68 #define BUSY 7
69 #define RESERVED2 2
70
71 // Control over polling with PEND
72 // Set USE_PEND to 0 for LTC3883 which does not support PEND
73 #define USE_PEND 1
74
75 #define NOT_BUSY 1 << 6
76 #define NOT_TRANS 1 << 4
77 #ifdef USE_PEND
78 #define NOT_PENDING 1 << 5
79 #else
80 #define NOT_PENDING 0
81 #endif
82
83 // PMBus Commands
84 #define PAGE 0x00
85 #define CLEAR_FAULTS 0x03
86 #define STORE_USER_ALL 0x15
87 #define RESTORE_USER_ALL 0x16
88 #define STATUS_BYTE 0x78
89 #define STATUS_WORD 0x79
90 #define STATUS_CML 0x7E
91 #define STATUS_MFR_SPECIFIC 0x80
92 #define READ_ITEMP_2977_8 0x8D
93 #define READ_ITEMP 0x8E
94 #define USER_DATA_04 0xB4
95 #define MFR_EE_UNLOCK 0xBD
96 #define MFR_EE_ERASE 0xBE
97 #define MFR_EE_DATA 0xBF
98 #define MFR_PAGE_FF_MASK 0xE4
99 #define MFR_FAULT_LOG_STORE 0xEA
100 #define MFR_FAULT_LOG_RESTORE 0xEB
101 #define MFR_FAULT_LOG_CLEAR 0xEC
102 #define MFR_SPECIAL_ID 0xE7
103 #define MFR_COMMON 0xEF
104 #define MFR_EEPROM_STATUS 0xF1
105 #define MFR_SPARE_0 0xF7
106 #define MFR_RESET 0xFD
107
108 // Bit definitions for STATUS_CML
109 #define STATUS_CML_CMD_FAULT 0x80
110 #define STATUS_CML_DATA_FAULT 0x40
111 #define STATUS_CML_PEC_FAULT 0x20
112 #define STATUS_CML_MEM_FAULT 0x10
113 #define STATUS_CML_PROC_FAULT 0x04
114 #define STATUS_CML_PMBUS_FAULT 0x02
115 #define STATUS_CML_UNKNOWN_FAULT 0x01
116
117 // Bit definitions for STATUS_MFR_SPECIFIC
118 #define STATUS_MFR_SPECIFIC_NVM_CRC 0x20
119
120 // Bit definitions for STATUS_WORD
121 #define STATUS_WORD_POWER_GOOD_B 0x0800
122
123 #define LTC3880_I2C_ADDRESS 0x30
124 #define LTC2974_I2C_ADDRESS 0x32
125 // (Covers DC1962A/C. A has LTC2978, C has LTC2977)
126 #define LTC2977_8_I2C_ADDRESS 0x33
127
128 // Used for reading and writing NVM.
129 // Read will allocate or reallocate data.
130 // Write will free it and set the pointer to NULL.
131 static uint16_t *ltc3880data;
132 static uint16_t ltc3880dataCount;
133 static uint16_t *ltc2974data;
134 static uint16_t ltc2974dataCount;
135 static uint16_t *ltc2977data;
136 static uint16_t ltc2977dataCount;
137
138 // Used to talk to SMBus
139 LT_SMBusGroup *smbus = (LT_SMBusGroup *) new LT_SMBusNoPec();
140
141 bool is_ltc297x(uint8_t address)
142 {
143 uint16_t chipId;
144
145 chipId = smbus->readWord(address, MFR_SPECIAL_ID) >> 8;
146 if (
147 (chipId == 0x021) // LTC2974
148 || (chipId == 0x022) // LTC2975
149 || (chipId == 0x013) // LTC2977
150 || (chipId == 0x803) // LTC2980
151 || (chipId == 0x804) // LTC2980
152 || (chipId == 0x801) // LTM2987
153 || (chipId == 0x802) // LTM2987
154 || (chipId == 0x011) // LTC2978
155 || (chipId == 0x012) // LTC2978
156 )
157 return true;
158 else
159 return false;
160 }
161
162 bool is_ltc2977(uint8_t address)
163 {
164 uint16_t chipId;
165
166 chipId = smbus->readWord(address, MFR_SPECIAL_ID) >> 8;
167 if (
168 (chipId == 0x013) // LTC2977
169 || (chipId == 0x803) // LTC2980
170 || (chipId == 0x804) // LTC2980
171 || (chipId == 0x801) // LTM2987
172 || (chipId == 0x802) // LTM2987
173 )
174 return true;
175 else
176 return false;
177 }
178
179 bool is_ltc2978(uint8_t address)
180 {
181 bool is_ltc2978;
182 uint8_t mfr_common;
183 mfr_common = smbus->readByte(address, MFR_COMMON);
184 is_ltc2978 = ((mfr_common & (1 << RESERVED2)) == 0);
185 return is_ltc2978;
186 }
187
188 uint8_t wait_for_ack(uint8_t address, uint8_t command)
189 {
190 uint8_t data;
191 // A real application should timeout at 4.1 seconds.
192 uint16_t timeout = 8192;
193 while (timeout-- > 0)
194 {
195 if (0 == smbus->i2cbus()->readByteData(address, command, &data))
196 return 1;
197 }
198 return 0;
199 }
200
201 void wait_for_ready(uint8_t address)
202 {
203 uint8_t status;
204 uint8_t mask;
205 uint8_t page;
206
207 // All devices poll on Ack, but the LTC2978/A will assert ALERTB if busy.
208 // By waiting 1ms, the only ALERTBs will be during a store or restore user all.
209 // This value can be tuned lower based on the clock rate, but should be well
210 // tested if the expectation is no faults except on store/restore.
211 delay(1);
212 wait_for_ack(address, MFR_COMMON);
213 if (is_ltc2978(address))
214 {
215 // Check if there is a CML or BUSY fault, and clear faults,
216 // but only if there are no other faults, because another
217 // thread or function may be interested in them.
218
219 // Make sure we can use PAGE 0xFF to clear faults, but save
220 // off the mask and page so it can be restored.
221 mask = smbus->readByte(address, MFR_PAGE_FF_MASK);
222 smbus->writeByte(address, MFR_PAGE_FF_MASK, 0xFF);
223 page = smbus->readByte(address, PAGE);
224 smbus->writeByte(address, PAGE, 0xFF);
225
226 // Clear if CML/BUSY but not other faults.
227 status = smbus->readByte(address, STATUS_BYTE);
228 if ((status & ((1 << CML) | (1 << BUSY))) &&
229 !(status & ~((1 << CML) | (1 << BUSY))))
230 smbus->sendByte(address, CLEAR_FAULTS);
231
232 // Restore page and mask.
233 smbus->writeByte(address, PAGE, page);
234 smbus->writeByte(address, MFR_PAGE_FF_MASK, mask);
235 }
236 else
237 // All other devices have a busy bit to poll.
238 // Controllers also have a EEPROM register that can be
239 // polled to wait for internal operations to complete.
240 // This is not in general polling, because controllers
241 // still operate during this time.
242 wait_for_not_busy(address);
243 }
244
245 uint8_t wait_for_not_busy(uint8_t address)
246 {
247 uint8_t mfr_common;
248 // A real application should timeout at 4.1 seconds.
249 uint16_t timeout = 8192;
250
251 while (timeout-- > 0)
252 {
253 mfr_common = smbus->readByte(address, MFR_COMMON);
254 // If too busy to answer, poll again.
255 if (mfr_common == 0xFF)
256 continue;
257 if ((mfr_common & (NOT_BUSY | NOT_PENDING | NOT_TRANS)) == (NOT_BUSY | NOT_PENDING | NOT_TRANS))
258 return 1;
259 }
260 return 0;
261 }
262
263 uint8_t wait_for_nvm_done(uint8_t address)
264 {
265 uint8_t mfr_eeprom_status;
266 // A real application should timeout at 4.1 seconds.
267 uint16_t timeout = 8192;
268
269 while (timeout-- > 0)
270 {
271 wait_for_ack(address, 0x00);
272 wait_for_not_busy(address);
273 mfr_eeprom_status = smbus->readByte(address, MFR_EEPROM_STATUS);
274 if (mfr_eeprom_status == 0xFF)
275 continue;
276 if ((mfr_eeprom_status & 0xC0) == 0)
277 return 1;
278 }
279 return 0;
280 }
281
282 void store_fault_logs()
283 {
284 smbus->sendByte(0x5B, MFR_FAULT_LOG_STORE);
285 }
286
287 void clear_fault_logs()
288 {
289 smbus->sendByte(0x5B, MFR_FAULT_LOG_CLEAR);
290 }
291
292 void clear_faults_global(void)
293 {
294 // This clear assumes the MASK regsiter of managers is set to 0xFF.
295 // If not, there is no general way to globally clear faults, as the code
296 // would have to know all the device addresses, types, etc. It also assumes that
297 // any other code that depends on PAGE will reset the page. In the
298 // context of refresh, it means that clear faults global disturbs
299 // the state and other code may have side effects if not dealt with.
300 // This reset does not work for LTC2978/A which does not work with page 0xFF.
301
302 // This clear is good for controllers/managers which respond to page 0xFF
303 // during the clear. This is all PSM devices except LTC2978/A
304 smbus->writeByte(0x5B, PAGE, 0xFF);
305 smbus->sendByte(0x5B, CLEAR_FAULTS);
306
307 // This clear will clear page 0x00 of a LTC2978/A, however to
308 // really clear an LTC2978/A, requres a loop with pages, as
309 // shown in the commented code. There is no general way to clear
310 // faults on a LTC2978/A without a restore or power cycle.
311
312 // for (int page; page < 8; page++) {
313 // smbus->writeByte(0x5B, PAGE, page);
314 smbus->writeByte(0x5B, PAGE, 0x00);
315 smbus->sendByte(0x5B, CLEAR_FAULTS);
316 //}
317
318 }
319
320 void lock_nvm(uint8_t address)
321 {
322 smbus->writeByte(address, MFR_EE_UNLOCK, 0x00);
323 wait_for_ready(address);
324 }
325
326 void unlock_nvm(uint8_t address)
327 {
328 // Unlock device for write normal data, not all data
329 smbus->writeByte(address, MFR_EE_UNLOCK, 0x2B);
330 wait_for_ready(address);
331 if (smbus->pecEnabled())
332 smbus->writeByte(address, MFR_EE_UNLOCK, 0xD5);
333 else
334 smbus->writeByte(address, MFR_EE_UNLOCK, 0xD4);
335 wait_for_ready(address);
336 }
337
338 void nvm_lock_reset(uint8_t address)
339 {
340 lock_nvm(address);
341 unlock_nvm(address);
342 lock_nvm(address);
343 }
344
345 bool check_nvm_data_checksum(uint8_t address)
346 {
347 uint16_t w;
348 uint8_t bs[32];
349 uint16_t count;
350 uint8_t bpos = 0, wpos;
351 bool nok = false;
352
353 // Unlock
354 unlock_nvm(address);
355
356 // Read preamble and count
357 smbus->readWord(address, MFR_EE_DATA);
358 wait_for_ready(address);
359 count = smbus->readWord(address, MFR_EE_DATA);
360 wait_for_ready(address);
361
362 for (wpos = 0; wpos < count/16; wpos++)
363 {
364 while (bpos < 32)
365 {
366 w = smbus->readWord(address, MFR_EE_DATA);
367 wait_for_ready(address);
368 bs[bpos++] = w & 0xFF;
369 bs[bpos++] = (w >> 8) & 0xFF;
370 }
371 // Compute CRC on 32 byte boundary
372 nok |= smbus->checkCRC(bs);
373 bpos = 0;
374 }
375
376 lock_nvm(address);
377 return nok;
378 }
379
380 void erase(uint8_t address, uint16_t **data)
381 {
382 if (is_ltc2978(address))
383 Serial.println(F(" Erase not supported on LTC2978"));
384 if (*data == NULL)
385 {
386 Serial.println(F(" No Data, please read data before erasing"));
387 }
388 else
389 {
390 unlock_nvm(address);
391 smbus->writeByte(address, MFR_EE_ERASE, 0x2B); // Erase
392 wait_for_ready(address);
393 lock_nvm(address);
394 }
395 }
396
397 // If a device has a memory fault, and has been through a power cycle or reset, communcation
398 // will probably fail during the check, as the address of the device may not be correct.
399 bool check_health(uint8_t address)
400 {
401 bool res = true;
402
403 if (is_ltc2978(address))
404 {
405 if (smbus->readByte(address, STATUS_CML) & STATUS_CML_MEM_FAULT)
406 {
407 res = false;
408 Serial.println(F(" Device has a Memory Fault"));
409 }
410 else if (smbus->readWord(address, STATUS_WORD) & ~STATUS_WORD_POWER_GOOD_B) // Assumes chann
411 {
412 res = false;
413 Serial.println(F(" Device has a Fault"));
414 }
415 else if (readItemp2977_8(address) > 85.0) // Really ITemp on LTC297X
416 {
417 res = false;
418 Serial.println(F(" Device is too hot"));
419 }
420 else
421 {
422 Serial.println(F(" Checksum not verified (LTC2978/A does not support direct read of NVM)"));
423 Serial.println(F(" Device is Ok (No Memory Fault, Not Hot)"));
424 }
425 }
426 else
427 {
428 if (smbus->readByte(address, STATUS_CML) & STATUS_CML_MEM_FAULT)
429 {
430 res = false;
431 Serial.println(F(" Device has a Memory Fault"));
432 }
433 else if (smbus->readWord(address, STATUS_WORD) & ~STATUS_WORD_POWER_GOOD_B)
434 {
435 res = false;
436 Serial.println(F(" Device has a Fault"));
437 }
438 // This could be converted to a positive check rather than a negative check.
439 // This depends on left to right execution.
440 else if ((!is_ltc297x(address)) && ((smbus->readByte(address, STATUS_MFR_SPECIFIC) & STATUS_MFR_SPECIFIC_NVM_CRC)))
441 {
442 res = false;
443 Serial.println(F(" Device has a Memory Fault"));
444 }
445 // This depends on left to right execution.
446 else if ((is_ltc2977(address) && (readItemp2977_8(address) > 85.0)) || (!is_ltc2977(address) && (readItemp(address) > 85.0)))
447 {
448 res = false;
449 Serial.println(F(" Device is hot"));
450 }
451 else if (check_nvm_data_checksum(address))
452 {
453 res = false;
454 Serial.println(F(" Device has an invalid CRC"));
455 }
456 else
457 Serial.println(F(" Device is Ok (No Memory Fault, Not Hot, CRC is Good)"));
458 }
459 return res;
460 }
461
462
463 void increment_counter(uint8_t address)
464 {
465 // For LTC388X and LTC2974/5/7 use USER_DATA_4
466 // For LTC2978/A use MFR_SPARE_0
467
468 uint16_t user;
469
470 if (is_ltc2978(address))
471 {
472 user = smbus->readWord(address, MFR_SPARE_0);
473 user++;
474 smbus->writeWord(address, MFR_SPARE_0, user);
475 // No need to read again in typical application
476 user = smbus->readWord(address, MFR_SPARE_0);
477 }
478 else
479 {
480 user = smbus->readWord(address, USER_DATA_04);
481 user++;
482 smbus->writeWord(address, USER_DATA_04, user);
483 // No need to read again in typical application
484 user = smbus->readWord(address, USER_DATA_04);
485 }
486 }
487
488 void print_counter(uint8_t address)
489 {
490 // For LTC388X and LTC2974/5/7 use USER_DATA_4
491 // For LTC2978/A use MFR_SPARE_0
492
493 uint16_t user;
494
495 if (is_ltc2978(address))
496 {
497 user = smbus->readWord(address, MFR_SPARE_0);
498 Serial.println(user, DEC);
499 }
500 else
501 {
502 user = smbus->readWord(address, USER_DATA_04);
503 Serial.println(user, DEC);
504 }
505 }
506
507 void store ()
508 {
509 smbus->sendByte(0x5B, STORE_USER_ALL);
510 }
511
512 void restore ()
513 {
514 smbus->sendByte(0x5B, RESTORE_USER_ALL);
515 }
516
517 void read_bytes(uint8_t address, uint16_t **data, uint16_t *count)
518 {
519 int i;
520
521 // Ensure we are not busy
522 wait_for_ready(address);
523
524 nvm_lock_reset(address);
525 unlock_nvm(address);
526
527 // Read preamble
528 smbus->readWord(address, MFR_EE_DATA); // Read ID
529 wait_for_ready(address);
530 *count = smbus->readWord(address, MFR_EE_DATA);
531 wait_for_ready(address);
532
533 // If we don't have memory yet, get some.
534 if (*data == NULL)
535 *data = (uint16_t *) malloc((*count) * sizeof(uint16_t));
536 else
537 {
538 free(*data);
539 *data = (uint16_t *) malloc((*count) * sizeof(uint16_t));
540 }
541
542 // Read the data word at a time.
543 for (i = 0; i < *count; i++)
544 {
545 (*data)[i] = smbus->readWord(address, MFR_EE_DATA);
546 wait_for_ready(address);
547 }
548
549 lock_nvm(address);
550 }
551
552 void write_bytes(uint8_t address, uint16_t **data, uint16_t *count)
553 {
554 int i;
555 uint16_t d;
556
557 if (*data == NULL)
558 {
559 Serial.println(F(" No Data, please read data before writing"));
560 }
561 else
562 {
563 // Ensure we are not busy
564 wait_for_ready(address);
565
566 // To improve reliability
567 nvm_lock_reset(address);
568
569 // Erase the data to enable write
570 unlock_nvm(address);
571 smbus->writeByte(address, MFR_EE_ERASE, 0x2B); // Erase
572 // Very important to wait here
573 wait_for_ready(address);
574 lock_nvm(address);
575
576 // Write the data
577 unlock_nvm(address);
578 for (i = 0; i < *count; i++)
579 {
580 smbus->writeWord(address, MFR_EE_DATA, (*data)[i]);
581 // Very important to wait here
582 wait_for_ready(address);
583 }
584 lock_nvm(address);
585
586 // Verify the data
587 unlock_nvm(address); // Read preamble
588 smbus->readWord(address, MFR_EE_DATA); // Read ID
589 wait_for_ready(address);
590 *count = smbus->readWord(address, MFR_EE_DATA);
591 wait_for_ready(address);
592 // Read the data word at a time.
593 for (i = 0; i < *count; i++)
594 {
595 if (d = (smbus->readWord(address, MFR_EE_DATA) != (*data)[i]))
596 {
597 Serial.print(F(" Data Mismatch ("));
598 Serial.print(i, DEC);
599 Serial.print(F(","));
600 Serial.print(d, HEX);
601 Serial.print(F(","));
602 Serial.print((*data)[i], HEX);
603 Serial.println(F(")"));
604 }
605 }
606 lock_nvm(address);
607 }
608 }
609
610 float readItemp2977_8(uint8_t address)
611 {
612 uint16_t temp_L11;
613
614 // read the output current as an L11
615 temp_L11 = smbus->readWord(address, READ_ITEMP_2977_8);
616
617 // convert L11 value to floating point value
618 return math_.lin11_to_float(temp_L11); //! 2) Convert from Lin11
619 }
620
621 float readItemp(uint8_t address)
622 {
623 uint16_t temp_L11;
624
625 // read the output current as an L11
626 temp_L11 = smbus->readWord(address, READ_ITEMP);
627
628 // convert L11 value to floating point value
629 return math_.lin11_to_float(temp_L11); //! 2) Convert from Lin11
630 }
631
632 //! Print all status bytes and words
633 //! @return void
634 void print_all_status()
635 {
636 uint8_t b;
637 uint16_t w;
638 uint8_t page;
639
640 for (page = 0; page < 2; page++)
641 {
642 Serial.print(F("PAGE "));
643 Serial.println(page, DEC);
644 smbus->writeByte(LTC3880_I2C_ADDRESS, PAGE, page);
645 w = smbus->readWord(LTC3880_I2C_ADDRESS, STATUS_WORD);
646 Serial.print(F("LTC3880 STATUS WORD 0x"));
647 Serial.println(w, HEX);
648 b = smbus->readWord(LTC3880_I2C_ADDRESS, STATUS_MFR_SPECIFIC);
649 Serial.print(F("LTC3880 MFR STATUS BYTE 0x"));
650 Serial.println(b, HEX);
651 }
652
653 for (page = 0; page < 4; page++)
654 {
655 Serial.print(F("PAGE "));
656 Serial.println(page, DEC);
657 smbus->writeByte(LTC2974_I2C_ADDRESS, PAGE, page);
658 w = smbus->readWord(LTC2974_I2C_ADDRESS, STATUS_WORD);
659 Serial.print(F("LTC2974 STATUS WORD 0x"));
660 Serial.println(w, HEX);
661 b = smbus->readWord(LTC2974_I2C_ADDRESS, STATUS_MFR_SPECIFIC);
662 Serial.print(F("LTC2974 MFR STATUS BYTE 0x"));
663 Serial.println(b, HEX);
664 }
665
666 for (page = 0; page < 8; page++)
667 {
668 Serial.print(F("PAGE "));
669 Serial.println(page, DEC);
670 smbus->writeByte(LTC2977_8_I2C_ADDRESS, PAGE, page);
671 w = smbus->readWord(LTC2977_8_I2C_ADDRESS, STATUS_WORD);
672 Serial.print(F("LTC2977 STATUS WORD 0x"));
673 Serial.println(w, HEX);
674 b = smbus->readWord(LTC2977_8_I2C_ADDRESS, STATUS_MFR_SPECIFIC);
675 Serial.print(F("LTC2977MFR STATUS BYTE 0x"));
676 Serial.println(b, HEX);
677 }
678 }
679
680 void setup()
681 {
682 Serial.begin(115200); //! Initialize the serial port to the PC
683
684 // There is not enough memory in an Uno, so make noise if necessary.
685 byte sig0;
686 byte sig2;
687 byte sig4;
688 sig0 = boot_signature_byte_get (0);
689 sig2 = boot_signature_byte_get (2);
690 sig4 = boot_signature_byte_get (4);
691 if (sig0 != 0x1E || sig2 != 0x98 | sig4 != 0x01)
692 {
693 Serial.println("Sketch only runs on Mega 2560");
694 return;
695 }
696
697 print_title();
698 print_prompt();
699 }
700
701 void loop()
702 {
703 uint8_t user_command;
704 uint8_t res;
705 uint8_t model[7];
706 uint8_t revision[10];
707 uint8_t *addresses = NULL;
708
709 if (Serial.available()) //! Checks for user input
710 {
711 user_command = read_int(); //! Reads the user command
712 if (user_command != 'm')
713 Serial.println(user_command);
714
715 switch (user_command) //! Prints the appropriate submenu
716 {
717 case 1:
718 Serial.println(F("Check LTC3880 NVM"));
719 check_health(LTC3880_I2C_ADDRESS);
720 Serial.println(F("Check LTC2974 NVM"));
721 check_health(LTC2974_I2C_ADDRESS);
722 Serial.println(F("Check LTC2977/8 NVM"));
723 check_health(LTC2977_8_I2C_ADDRESS);
724 break;
725 case 2:
726 print_all_status();
727 break;
728 case 3:
729 Serial.println(F("Store All Fault Logs"));
730 store_fault_logs();
731 wait_for_ready(LTC3880_I2C_ADDRESS);
732 wait_for_ready(LTC2974_I2C_ADDRESS);
733 wait_for_ready(LTC2977_8_I2C_ADDRESS);
734 break;
735 case 4:
736 Serial.print(F("LTC3880 Counter "));
737 print_counter(LTC3880_I2C_ADDRESS);
738 Serial.print(F("LTC2974 Counter "));
739 print_counter(LTC2974_I2C_ADDRESS);
740 Serial.print(F("LTC2977/8 Counter "));
741 print_counter(LTC2977_8_I2C_ADDRESS);
742 break;
743 case 5:
744 erase(LTC3880_I2C_ADDRESS, &ltc3880data);
745 Serial.println(F("Erased LTC3880 Data"));
746 erase(LTC2974_I2C_ADDRESS, &ltc2974data);
747 Serial.println(F("Erased LTC2974 Data"));
748 erase(LTC2977_8_I2C_ADDRESS, &ltc2977data);
749 Serial.println(F("Erased LTC2977 Data"));
750 wait_for_ready(LTC3880_I2C_ADDRESS);
751 wait_for_ready(LTC2974_I2C_ADDRESS);
752 wait_for_ready(LTC2977_8_I2C_ADDRESS);
753 break;
754 case 6: // (technique does not work with LTC2978/A)
755 read_bytes(LTC3880_I2C_ADDRESS, &ltc3880data, &ltc3880dataCount);
756 Serial.println(F("Read LTC3880 Data"));
757 read_bytes(LTC2974_I2C_ADDRESS, &ltc2974data, &ltc2974dataCount);
758 Serial.println(F("Read LTC2974 Data"));
759 if (is_ltc2978(LTC2977_8_I2C_ADDRESS))
760 Serial.println("LTC2978/A data not read (LTC2978/A does not support direct read of NVM)");
761 else
762 {
763 read_bytes(LTC2977_8_I2C_ADDRESS, &ltc2977data, &ltc2977dataCount);
764 Serial.println(F("Read LTC2977 Data"));
765 }
766 break;
767 case 7: // (technique does not work with LTC2978/A)
768 write_bytes(LTC3880_I2C_ADDRESS, &ltc3880data, &ltc3880dataCount);
769 Serial.println(F("LTC3880 Data written to NVM"));
770 write_bytes(LTC2974_I2C_ADDRESS, &ltc2974data, &ltc2974dataCount);
771 Serial.println(F("LTC2974 Data written to NVM"));
772 if (is_ltc2978(LTC2977_8_I2C_ADDRESS))
773 Serial.println("LTC2978/A data not written (LTC2978/A does not support direct read of NVM)");
774 else
775 {
776 write_bytes(LTC2977_8_I2C_ADDRESS, &ltc2977data, &ltc2977dataCount);
777 Serial.println(F("LTC2977 Data written to NVM"));
778 }
779 // Uncomment to free memory
780 //free(ltc3880data);
781 //ltc3880data = NULL;
782 //free(ltc2974data);
783 //ltc2974data = NULL;
784 //free(ltc2977data);
785 //ltc2977data = NULL;
786 break;
787 case 8: // (technique works on all PSM devices)
788 // This clears the status register so that tools observing on the
789 // bus can observe restore behavior. It is not neccessary
790 // for correct operation.
791 smbus->writeByte(LTC3880_I2C_ADDRESS, MFR_EEPROM_STATUS, 0x00);
792
793 // Example of something like a real application without retry,
794 // but no policy, such as protection of over programming or
795 // scheduling randomness.
796
797 // Make sure the world is sane. This does not allow
798 // storing with NVM/EEPROM CRC errors, but you can
799 // change the code to do that.
800 Serial.println(F("Check EEPROM"));
801 // This check requires no faults.
802 if (check_health(LTC3880_I2C_ADDRESS) && check_health(LTC2974_I2C_ADDRESS) && check_health(LTC2977_8_I2C_ADDRESS))
803 {
804 // Store fault logs so the devices cannot be busy with a fault log.
805 store_fault_logs();
806 wait_for_ready(LTC3880_I2C_ADDRESS);
807 wait_for_ready(LTC2974_I2C_ADDRESS);
808 wait_for_ready(LTC2977_8_I2C_ADDRESS);
809
810 // Bump the counters.
811 increment_counter(LTC3880_I2C_ADDRESS);
812 increment_counter(LTC2974_I2C_ADDRESS);
813 increment_counter(LTC2977_8_I2C_ADDRESS);
814 Serial.println(F(" Storing with STORE_USER_ALL...\n"));
815 // Store all data in parallel.
816 smbus->sendByte(0x5B, STORE_USER_ALL);
817 wait_for_ready(LTC3880_I2C_ADDRESS);
818 wait_for_nvm_done(LTC3880_I2C_ADDRESS);
819 wait_for_ready(LTC2974_I2C_ADDRESS);
820 wait_for_ready(LTC2977_8_I2C_ADDRESS);
821
822 // Clear any faults so that health check wont fail from some spurious fault.
823 clear_faults_global();
824 wait_for_ready(LTC3880_I2C_ADDRESS);
825 wait_for_ready(LTC2974_I2C_ADDRESS);
826 wait_for_ready(LTC2977_8_I2C_ADDRESS);
827
828 // All is ok, so clear the fault logs so they can be used if enabled.
829 clear_fault_logs();
830 wait_for_ready(LTC3880_I2C_ADDRESS);
831 wait_for_ready(LTC2974_I2C_ADDRESS);
832 wait_for_ready(LTC2977_8_I2C_ADDRESS);
833
834 // Do not restore or reset here or there will be
835 // a power cycle and rails with turn off and on.
836 Serial.println(F("Check NVM"));
837 if (!check_health(LTC3880_I2C_ADDRESS))
838 {
839 Serial.println(F("LTC3880 failed health check"));
840 // Implement code to try again if CRC fails, etc.
841 }
842 if (!check_health(LTC2974_I2C_ADDRESS))
843 {
844 Serial.println(F("LTC2974 failed health check"));
845 // Implement code to try again if CRC fails, etc.
846 }
847 if (!check_health(LTC2977_8_I2C_ADDRESS))
848 {
849 Serial.println(F("LTC2977/8 failed health check"));
850 // Implement code to try again if CRC fails, etc.
851 }
852
853 }
854 Serial.println(F("NVM (EEPROM) is Updated"));
855 break;
856 case 9:
857 Serial.println(F("Clear All Fault Logs"));
858 clear_fault_logs();
859 wait_for_ready(LTC3880_I2C_ADDRESS);
860 wait_for_ready(LTC2974_I2C_ADDRESS);
861 wait_for_ready(LTC2977_8_I2C_ADDRESS);
862 break;
863 case 10:
864 clear_faults_global();
865 break;
866 case 11:
867 addresses = smbus->probe(0);
868 while (*addresses != 0)
869 {
870 Serial.print(F("ADDR 0x"));
871 Serial.println(*addresses++, HEX);
872 }
873 break;
874 case 12:
875 // Group protocol is a way to send multiple devices in one command as an atomic transaction.
876 // It begins with a start, follows with address/command transactions, and ends in a stop.
877 // At the stop, all devices respond to their command at the same time. It is not legal
878 // or defined how things behave if it sends more than one command to a device withing one
879 // group protocol transaction..
880
881 // The reason for using this is that the managers do not have a reset command like the controllers,
882 // so the code next to mix restore commands to managers with reset commands to controllers.
883
884 // Tell the PMBus object to start saving commands, but don't do anything on PMBus.
885 smbus->beginStoring();
886 // Add commands to the list
887 smbus->sendByte(LTC3880_I2C_ADDRESS, MFR_RESET);
888 smbus->sendByte(LTC2974_I2C_ADDRESS, RESTORE_USER_ALL);
889 smbus->sendByte(LTC2977_8_I2C_ADDRESS, RESTORE_USER_ALL);
890 // Tell the PMBus object to send all the comands atomically as a Group Command Protocol transaction.
891 // At the stop the controller will reset, and the managers will do a restore. This effectivly restarts
892 // all devices at the same time so that proper sequencing takes place.
893 smbus->execute();
894
895 // Wait for each device to finish.
896 wait_for_ready(LTC3880_I2C_ADDRESS);
897 wait_for_ready(LTC2974_I2C_ADDRESS);
898 wait_for_ready(LTC2977_8_I2C_ADDRESS);
899
900 break;
901 default:
902 Serial.println(F("Incorrect Option"));
903 break;
904 }
905 print_prompt();
906 }
907 }
908
909 //! Prints the title block when program first starts.
910 void print_title()
911 {
912 Serial.print(F("\n********************************************************************\n"));
913 Serial.print(F("* DC1962C Store/Restore User All *\n"));
914 Serial.print(F("* *\n"));
915 Serial.print(F("* This program demonstrates how to store and restore EEPROM. *\n"));
916 Serial.print(F("* *\n"));
917 Serial.print(F("* Set the baud rate to 115200 and select the newline terminator. *\n"));
918 Serial.print(F("* *\n"));
919 Serial.print(F("********************************************************************\n"));
920 }
921
922 //! Prints main menu.
923 void print_prompt()
924 {
925 Serial.print(F("\n 1 -Check NVM (EEPROM) is Ok to Program\n"));
926 Serial.print(F(" 2 -Read All Status\n"));
927 Serial.print(F(" 3 -Force Fault Logs (EEPROM)\n"));
928 Serial.print(F(" 4 -Print Counter (RAM)\n"));
929 Serial.print(F(" 5 -Erase NVM (EEPROM)\n"));
930 Serial.print(F(" 6 -Bulk Read NVM (EEPROM)\n"));
931 Serial.print(F(" 7 -Bulk Write NVM (EEPROM)\n"));
932 Serial.print(F(" 8 -Store (STORE_USER_ALL)\n"));
933 Serial.print(F(" 9 -Clear/Erase Fault Logs (EEPROM)\n"));
934 Serial.print(F(" 10 -Clear Faults (RAM)\n"));
935 Serial.print(F(" 11 -Bus Probe\n"));
936 Serial.print(F(" 12 -Reset (Will Power Cycle)\n"));
937 Serial.print(F("\nEnter a command:"));
938 }
MFR_SPECIAL_ID
#define MFR_SPECIAL_ID
Definition: retention.ino:102
CLEAR_FAULTS
#define CLEAR_FAULTS
Definition: retention.ino:85
readItemp
static float readItemp(uint8_t address)
Definition: retention.ino:621
MFR_EE_UNLOCK
#define MFR_EE_UNLOCK
Definition: retention.ino:95
LT_SMBusGroup::readByte
uint8_t readByte(uint8_t address, uint8_t command)
SMBus read byte command.
Definition: LT_SMBusGroup.cpp:91
print_prompt
static void print_prompt()
Prints main menu.
Definition: retention.ino:923
user_command
unsigned char user_command
Definition: Serial_EEPROM_Test.ino:75
nvm_lock_reset
static void nvm_lock_reset(uint8_t address)
Definition: retention.ino:338
LT_SMBus.h
LTC SMBus Support: API for a shared SMBus layer.
RESERVED2
#define RESERVED2
Definition: retention.ino:69
CML
#define CML
Definition: retention.ino:67
STORE_USER_ALL
#define STORE_USER_ALL
Definition: retention.ino:86
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
store
static void store()
Definition: retention.ino:507
LTC2974_I2C_ADDRESS
#define LTC2974_I2C_ADDRESS
Definition: retention.ino:124
LT_SMBusGroup.h
LTC SMBus Support: Implementation for a shared SMBus layer.
STATUS_WORD
#define STATUS_WORD
Definition: retention.ino:89
LT_SMBusBase::i2cbus
LT_I2CBus * i2cbus(void)
Definition: LT_SMBusBase.h:73
LT_SMBusPec.h
LTC SMBus Support: Implementation for a shared SMBus layer.
LT_SMBusBase::probe
uint8_t * probe(uint8_t command)
SMBus bus probe.
Definition: LT_SMBusBase.cpp:119
NOT_PENDING
#define NOT_PENDING
Definition: retention.ino:78
status
String status(void)
Returns a descriptive string based on status of pins.
Definition: DC2364A.ino:217
write_bytes
static void write_bytes(uint8_t address, uint16_t **data, uint16_t *count)
Definition: retention.ino:552
READ_ITEMP
#define READ_ITEMP
Definition: retention.ino:93
MFR_SPARE_0
#define MFR_SPARE_0
Definition: retention.ino:105
Linduino.h
Header File for Linduino Libraries and Demo Code.
check_nvm_data_checksum
bool check_nvm_data_checksum(uint8_t address)
Definition: retention.ino:345
is_ltc2977
bool is_ltc2977(uint8_t address)
Definition: retention.ino:162
LT_SMBusNoPec
Definition: LT_SMBusNoPec.h:60
LT_SMBus::pecEnabled
bool pecEnabled(void)
Check if PEC is enabled.
Definition: LT_SMBus.h:92
LT_SMBusGroup::beginStoring
void beginStoring()
Group Protocol Begin.
Definition: LT_SMBusGroup.cpp:151
LT_SMBusGroup::execute
void execute()
Group Protocol Execute queued commands.
Definition: LT_SMBusGroup.cpp:175
LT_SMBusGroup::writeByte
void writeByte(uint8_t address, uint8_t command, uint8_t data)
SMBus write byte command.
Definition: LT_SMBusGroup.cpp:75
math_
LT_PMBusMath math_
Definition: LT_PMBusMath.cpp:460
STATUS_CML_MEM_FAULT
#define STATUS_CML_MEM_FAULT
Definition: retention.ino:112
MFR_EE_DATA
#define MFR_EE_DATA
Definition: retention.ino:97
LT_PMBusMath::lin11_to_float
float lin11_to_float(lin11_t xin)
Definition: LT_PMBusMath.cpp:427
read_bytes
static void read_bytes(uint8_t address, uint16_t **data, uint16_t *count)
Definition: retention.ino:517
MFR_FAULT_LOG_CLEAR
#define MFR_FAULT_LOG_CLEAR
Definition: retention.ino:101
STATUS_MFR_SPECIFIC_NVM_CRC
#define STATUS_MFR_SPECIFIC_NVM_CRC
Definition: retention.ino:118
wait_for_ready
static void wait_for_ready(uint8_t address)
Definition: retention.ino:201
wait_for_nvm_done
static uint8_t wait_for_nvm_done(uint8_t address)
Definition: retention.ino:263
NOT_TRANS
#define NOT_TRANS
Definition: retention.ino:76
increment_counter
static void increment_counter(uint8_t address)
Definition: retention.ino:463
address
static uint8_t address
Definition: DC2091A.ino:83
smbus
LT_SMBusGroup * smbus
Definition: retention.ino:139
data
union LT_union_int32_4bytes data
Definition: DC2094A.ino:138
check_health
bool check_health(uint8_t address)
Definition: retention.ino:399
READ_ITEMP_2977_8
#define READ_ITEMP_2977_8
Definition: retention.ino:92
USER_DATA_04
#define USER_DATA_04
Definition: retention.ino:94
clear_faults_global
static void clear_faults_global(void)
Definition: retention.ino:292
LT_SMBus::checkCRC
bool checkCRC(uint8_t *data)
Check CRC of block data organized as 31 data bytes plus CRC.
Definition: LT_SMBus.cpp:200
erase
static void erase(uint8_t address, uint16_t **data)
Definition: retention.ino:380
STATUS_BYTE
#define STATUS_BYTE
Definition: retention.ino:88
BUSY
#define BUSY
Definition: retention.ino:68
loop
static void loop()
Definition: retention.ino:701
restore
static void restore()
Definition: retention.ino:512
LT_SMBusGroup::writeWord
void writeWord(uint8_t address, uint8_t command, uint16_t data)
SMBus write word command.
Definition: LT_SMBusGroup.cpp:99
print_title
static void print_title()
Prints the title block when program first starts.
Definition: retention.ino:910
LTC3880_I2C_ADDRESS
#define LTC3880_I2C_ADDRESS
Definition: retention.ino:123
LT_SMBusGroup
Definition: LT_SMBusGroup.h:60
STATUS_WORD_POWER_GOOD_B
#define STATUS_WORD_POWER_GOOD_B
Definition: retention.ino:121
ltc2974dataCount
static uint16_t ltc2974dataCount
Definition: retention.ino:134
store_fault_logs
static void store_fault_logs()
Definition: retention.ino:282
print_counter
static void print_counter(uint8_t address)
Definition: retention.ino:488
lock_nvm
static void lock_nvm(uint8_t address)
Definition: retention.ino:320
MFR_EEPROM_STATUS
#define MFR_EEPROM_STATUS
Definition: retention.ino:104
STATUS_CML
#define STATUS_CML
Definition: retention.ino:90
ltc2974data
static uint16_t * ltc2974data
Definition: retention.ino:133
LT_SMBusGroup::readWord
uint16_t readWord(uint8_t address, uint8_t command)
SMBus read word command.
Definition: LT_SMBusGroup.cpp:107
PAGE
#define PAGE
Definition: retention.ino:84
clear_fault_logs
static void clear_fault_logs()
Definition: retention.ino:287
timeout
long timeout
Definition: EVAL-AD7124-8.ino:144
readItemp2977_8
static float readItemp2977_8(uint8_t address)
Definition: retention.ino:610
LT_SMBusGroup::sendByte
void sendByte(uint8_t address, uint8_t command)
SMBus send byte command.
Definition: LT_SMBusGroup.cpp:142
LT_SMBusNoPec.h
LTC SMBus Support: Implementation for a shared SMBus layer.
ltc2977data
static uint16_t * ltc2977data
Definition: retention.ino:135
ltc3880dataCount
static uint16_t ltc3880dataCount
Definition: retention.ino:132
UserInterface.h
read_int
int32_t read_int()
Definition: UserInterface.cpp:93
ltc2977dataCount
static uint16_t ltc2977dataCount
Definition: retention.ino:136
is_ltc297x
bool is_ltc297x(uint8_t address)
Definition: retention.ino:141
MFR_PAGE_FF_MASK
#define MFR_PAGE_FF_MASK
Definition: retention.ino:98
print_all_status
static void print_all_status()
Print all status bytes and words.
Definition: retention.ino:634
ltc3880data
static uint16_t * ltc3880data
Definition: retention.ino:131
MFR_FAULT_LOG_STORE
#define MFR_FAULT_LOG_STORE
Definition: retention.ino:99
is_ltc2978
bool is_ltc2978(uint8_t address)
Definition: retention.ino:179
NOT_BUSY
#define NOT_BUSY
Definition: retention.ino:75
MFR_RESET
#define MFR_RESET
Definition: retention.ino:106
i
static int i
Definition: DC2430A.ino:184
wait_for_ack
static uint8_t wait_for_ack(uint8_t address, uint8_t command)
Definition: retention.ino:188
MFR_COMMON
#define MFR_COMMON
Definition: retention.ino:103
LTC2977_8_I2C_ADDRESS
#define LTC2977_8_I2C_ADDRESS
Definition: retention.ino:126
STATUS_MFR_SPECIFIC
#define STATUS_MFR_SPECIFIC
Definition: retention.ino:91
LT_PMBusMath.h
LTC PMBus Support: Math conversion routines.
setup
static void setup()
Definition: retention.ino:680
wait_for_not_busy
static uint8_t wait_for_not_busy(uint8_t address)
Definition: retention.ino:245
MFR_EE_ERASE
#define MFR_EE_ERASE
Definition: retention.ino:96
RESTORE_USER_ALL
#define RESTORE_USER_ALL
Definition: retention.ino:87
unlock_nvm
static void unlock_nvm(uint8_t address)
Definition: retention.ino:326