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
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 
283 {
284  smbus->sendByte(0x5B, MFR_FAULT_LOG_STORE);
285 }
286 
288 {
289  smbus->sendByte(0x5B, MFR_FAULT_LOG_CLEAR);
290 }
291 
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 
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 
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
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);
646  Serial.print(F("LTC3880 STATUS WORD 0x"));
647  Serial.println(w, HEX);
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);
659  Serial.print(F("LTC2974 STATUS WORD 0x"));
660  Serial.println(w, HEX);
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);
672  Serial.print(F("LTC2977 STATUS WORD 0x"));
673  Serial.println(w, HEX);
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"));
720  Serial.println(F("Check LTC2974 NVM"));
722  Serial.println(F("Check LTC2977/8 NVM"));
724  break;
725  case 2:
727  break;
728  case 3:
729  Serial.println(F("Store All Fault Logs"));
734  break;
735  case 4:
736  Serial.print(F("LTC3880 Counter "));
738  Serial.print(F("LTC2974 Counter "));
740  Serial.print(F("LTC2977/8 Counter "));
742  break;
743  case 5:
745  Serial.println(F("Erased LTC3880 Data"));
747  Serial.println(F("Erased LTC2974 Data"));
749  Serial.println(F("Erased LTC2977 Data"));
753  break;
754  case 6: // (technique does not work with LTC2978/A)
756  Serial.println(F("Read LTC3880 Data"));
758  Serial.println(F("Read LTC2974 Data"));
760  Serial.println("LTC2978/A data not read (LTC2978/A does not support direct read of NVM)");
761  else
762  {
764  Serial.println(F("Read LTC2977 Data"));
765  }
766  break;
767  case 7: // (technique does not work with LTC2978/A)
769  Serial.println(F("LTC3880 Data written to NVM"));
771  Serial.println(F("LTC2974 Data written to NVM"));
773  Serial.println("LTC2978/A data not written (LTC2978/A does not support direct read of NVM)");
774  else
775  {
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.
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.
803  {
804  // Store fault logs so the devices cannot be busy with a fault log.
809 
810  // Bump the counters.
814  Serial.println(F(" Storing with STORE_USER_ALL...\n"));
815  // Store all data in parallel.
816  smbus->sendByte(0x5B, STORE_USER_ALL);
821 
822  // Clear any faults so that health check wont fail from some spurious fault.
827 
828  // All is ok, so clear the fault logs so they can be used if enabled.
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"));
838  {
839  Serial.println(F("LTC3880 failed health check"));
840  // Implement code to try again if CRC fails, etc.
841  }
843  {
844  Serial.println(F("LTC2974 failed health check"));
845  // Implement code to try again if CRC fails, etc.
846  }
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"));
862  break;
863  case 10:
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
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.
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.
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.
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 }
#define MFR_SPECIAL_ID
Definition: retention.ino:102
#define CLEAR_FAULTS
Definition: retention.ino:85
static float readItemp(uint8_t address)
Definition: retention.ino:621
#define MFR_EE_UNLOCK
Definition: retention.ino:95
uint8_t readByte(uint8_t address, uint8_t command)
SMBus read byte command.
static void print_prompt()
Prints main menu.
Definition: retention.ino:923
unsigned char user_command
static void nvm_lock_reset(uint8_t address)
Definition: retention.ino:338
LTC SMBus Support: API for a shared SMBus layer.
#define RESERVED2
Definition: retention.ino:69
#define CML
Definition: retention.ino:67
#define STORE_USER_ALL
Definition: retention.ino:86
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
static void store()
Definition: retention.ino:507
#define LTC2974_I2C_ADDRESS
Definition: retention.ino:124
LTC SMBus Support: Implementation for a shared SMBus layer.
#define STATUS_WORD
Definition: retention.ino:89
LT_I2CBus * i2cbus(void)
Definition: LT_SMBusBase.h:73
LTC SMBus Support: Implementation for a shared SMBus layer.
uint8_t * probe(uint8_t command)
SMBus bus probe.
#define NOT_PENDING
Definition: retention.ino:78
String status(void)
Returns a descriptive string based on status of pins.
Definition: DC2364A.ino:217
static void write_bytes(uint8_t address, uint16_t **data, uint16_t *count)
Definition: retention.ino:552
#define READ_ITEMP
Definition: retention.ino:93
#define MFR_SPARE_0
Definition: retention.ino:105
Header File for Linduino Libraries and Demo Code.
bool check_nvm_data_checksum(uint8_t address)
Definition: retention.ino:345
bool is_ltc2977(uint8_t address)
Definition: retention.ino:162
bool pecEnabled(void)
Check if PEC is enabled.
Definition: LT_SMBus.h:92
void beginStoring()
Group Protocol Begin.
void execute()
Group Protocol Execute queued commands.
void writeByte(uint8_t address, uint8_t command, uint8_t data)
SMBus write byte command.
LT_PMBusMath math_
#define STATUS_CML_MEM_FAULT
Definition: retention.ino:112
#define MFR_EE_DATA
Definition: retention.ino:97
float lin11_to_float(lin11_t xin)
static void read_bytes(uint8_t address, uint16_t **data, uint16_t *count)
Definition: retention.ino:517
#define MFR_FAULT_LOG_CLEAR
Definition: retention.ino:101
#define STATUS_MFR_SPECIFIC_NVM_CRC
Definition: retention.ino:118
static void wait_for_ready(uint8_t address)
Definition: retention.ino:201
static uint8_t wait_for_nvm_done(uint8_t address)
Definition: retention.ino:263
#define NOT_TRANS
Definition: retention.ino:76
static void increment_counter(uint8_t address)
Definition: retention.ino:463
static uint8_t address
Definition: DC2091A.ino:83
LT_SMBusGroup * smbus
Definition: retention.ino:139
union LT_union_int32_4bytes data
Definition: DC2094A.ino:138
bool check_health(uint8_t address)
Definition: retention.ino:399
#define READ_ITEMP_2977_8
Definition: retention.ino:92
#define USER_DATA_04
Definition: retention.ino:94
static void clear_faults_global(void)
Definition: retention.ino:292
bool checkCRC(uint8_t *data)
Check CRC of block data organized as 31 data bytes plus CRC.
Definition: LT_SMBus.cpp:200
static void erase(uint8_t address, uint16_t **data)
Definition: retention.ino:380
#define STATUS_BYTE
Definition: retention.ino:88
#define BUSY
Definition: retention.ino:68
static void loop()
Definition: retention.ino:701
static void restore()
Definition: retention.ino:512
void writeWord(uint8_t address, uint8_t command, uint16_t data)
SMBus write word command.
static void print_title()
Prints the title block when program first starts.
Definition: retention.ino:910
#define LTC3880_I2C_ADDRESS
Definition: retention.ino:123
#define STATUS_WORD_POWER_GOOD_B
Definition: retention.ino:121
static uint16_t ltc2974dataCount
Definition: retention.ino:134
static void store_fault_logs()
Definition: retention.ino:282
static void print_counter(uint8_t address)
Definition: retention.ino:488
static void lock_nvm(uint8_t address)
Definition: retention.ino:320
#define MFR_EEPROM_STATUS
Definition: retention.ino:104
#define STATUS_CML
Definition: retention.ino:90
static uint16_t * ltc2974data
Definition: retention.ino:133
uint16_t readWord(uint8_t address, uint8_t command)
SMBus read word command.
#define PAGE
Definition: retention.ino:84
static void clear_fault_logs()
Definition: retention.ino:287
long timeout
static float readItemp2977_8(uint8_t address)
Definition: retention.ino:610
void sendByte(uint8_t address, uint8_t command)
SMBus send byte command.
LTC SMBus Support: Implementation for a shared SMBus layer.
static uint16_t * ltc2977data
Definition: retention.ino:135
static uint16_t ltc3880dataCount
Definition: retention.ino:132
int32_t read_int()
static uint16_t ltc2977dataCount
Definition: retention.ino:136
bool is_ltc297x(uint8_t address)
Definition: retention.ino:141
#define MFR_PAGE_FF_MASK
Definition: retention.ino:98
static void print_all_status()
Print all status bytes and words.
Definition: retention.ino:634
static uint16_t * ltc3880data
Definition: retention.ino:131
#define MFR_FAULT_LOG_STORE
Definition: retention.ino:99
bool is_ltc2978(uint8_t address)
Definition: retention.ino:179
#define NOT_BUSY
Definition: retention.ino:75
#define MFR_RESET
Definition: retention.ino:106
static int i
Definition: DC2430A.ino:184
static uint8_t wait_for_ack(uint8_t address, uint8_t command)
Definition: retention.ino:188
#define MFR_COMMON
Definition: retention.ino:103
#define LTC2977_8_I2C_ADDRESS
Definition: retention.ino:126
#define STATUS_MFR_SPECIFIC
Definition: retention.ino:91
LTC PMBus Support: Math conversion routines.
static void setup()
Definition: retention.ino:680
static uint8_t wait_for_not_busy(uint8_t address)
Definition: retention.ino:245
#define MFR_EE_ERASE
Definition: retention.ino:96
#define RESTORE_USER_ALL
Definition: retention.ino:87
static void unlock_nvm(uint8_t address)
Definition: retention.ino:326