Linduino  1.3.0
Linear Technology Arduino-Compatible Demonstration Board
EasySMU.cpp
Go to the documentation of this file.
1 /*!
2 EasySMU: I2C Address Translator Demonstration and a Simple Multi-Channel Source Measurement Unit
3 
4 [User Guide](http://www.linear.com/docs/58670 "EasySMU User Guide") \n
5 [Schematic](http://www.linear.com/docs/58671 "Schematic") \n
6 [Top-Level Linduino Firmware for EasySMU](file:EasySMU__Run_8ino.html "Top-Level Linduino Firmware for EasySMU") \n
7 [EasySMU Class Reference](file:classEasySMU.html "EasySMU Class Reference") \n
8 [EasySMU_IOpanel Class Reference](file:classEasySMU__IOpanel.html "EasySMU_IOpanel Class Reference") \n
9 [EasySMU Webpage](http://www.linear.com/solutions/7943 "EasySMU Webpage") \n
10 
11 @verbatim
12 EasySMU: I2C Address Translator Demonstration and a Simple Multi-Channel Source Measurement Unit
13 
14 LTC4316: Single I2C/SMBus Address Translator
15 LT1970A: Power Op Amp with Adjustable Precision Current Limit
16 LT5400: Quad Matched Resistor Network
17 LTC2655: Quad I2C 16-/12-Bit Rail-to-Rail DACs with 10ppm/°C Max Reference
18 LTC3265: Low Noise Dual Supply with Boost and Inverting Charge Pumps
19 LTC2051: Dual Zero-Drift Operational Amplifier
20 LT3010: 50mA, 3V to 80V Low Dropout Micropower Linear Regulator
21 LT1991: Precision, 100µA Gain Selectable Amplifier
22 LTC6655: 0.25ppm Noise, Low Drift Precision Reference
23 LTC2485: 24-Bit ΔΣ ADC with Easy Drive Input Current Cancellation and I2C Interface
24 
25 EasySMU is a single-channel ±12V/40mA programmable-voltage/programmable-current
26 source with accurate voltage/current measurement capability. The LTC4316 I2C
27 Address Translator enables up to eight independent EasySMUs to be controlled
28 by a single I2C master.
29 
30 In this demonstration, each EasySMU board contains four I2C slaves and the
31 associated components to implement a single-channel ±12V/40mA programmable-
32 voltage/programmable-current source. The LTC4316 translates the I2C addresses
33 of each EasySMU to a unique set of addresses, enabling up to eight EasySMU
34 boards to be stacked on a single Linduino (I2C master). In this form, it
35 resembles a multi-channel automated test system. Alternatively, an optional
36 touchscreen allows the user to interactively control up to four channels,
37 forming a compact multi-channel programmable-voltage/programmable-current
38 bench source for lab testing, powered from a single 12V AC wall adapter.
39 
40 The primary purpose of the EasySMU is to demonstrate the LTC4316 I2C Address
41 Translator. The programmable-voltage/programmable-current source and meter
42 also provide a convenient demonstration of the associated components: LT1970A,
43 LT5400-3, LTC2655-H, LTC3265, LTC2051, LT3010, LT1991, LTC6655, and LTC2485.
44 While the EasySMU is not designed to demonstrate the ultimate performance that
45 can be obtained from each of those components, the EasySMU does provide
46 impressive results from a reasonably simple circuit.
47 
48 @endverbatim
49 */
50 
51 
52 /*! @ingroup Example_Designs
53 @{
54 @defgroup EasySMU EasySMU: I2C Address Translator Demonstration and a Simple Multi-Channel Source Measurement Unit
55 @}
56 */
57 
58 /*! @file
59  @ingroup EasySMU
60  EasySMU Class: I2C Address Translator Demonstration and a Simple Multi-Channel Source Measurement Unit
61 */
62 
63 #include "EasySMU.h"
64 #include "EEPROM.h"
65 #include "UserInterface.h"
66 
67 //! Maximum time allowed for LTC2485 conversion. If this time is exceeded, something is wrong.
68 #define LTC2485_TIMEOUT (_LTC2485_CONVERSION_TIME)
69 
70 EasySMU::EasySMU(uint8_t EEPROM_I2C_address_param, uint8_t DAC_I2C_address_param, uint8_t ADC_Vsense_I2C_address_param, uint8_t ADC_Isense_I2C_address_param)
71 {
72  EasySMU_EEPROM_I2C_address_=EEPROM_I2C_address_param;
73  DAC_I2C_address_=DAC_I2C_address_param;
74  ADC_Vsense_I2C_address_=ADC_Vsense_I2C_address_param;
75  ADC_Isense_I2C_address_=ADC_Isense_I2C_address_param;
76 }
77 
78 
80 {
81  int8_t ack;
82 
84 
85  return (ack);
86 }
87 
88 int8_t EasySMU::codeSetCommitVoltageSource(int32_t code_voltage_setting)
89 {
90  if (code_voltage_setting<0)
91  {
92  Vdac_code_=0;
93  }
94  else if (code_voltage_setting>0xFFFF)
95  {
96  Vdac_code_=0xFFFF;
97  }
98  else
99  {
100  Vdac_code_=code_voltage_setting;
101  }
102 
104 }
105 
107 {
108  int32_t code_voltage_setting = Vdac_code_-step_size;
109  Vdac_code_ = (code_voltage_setting < 0x000) ? 0x0000 :
110  ((code_voltage_setting > 0xFFFF) ? 0xFFFF : (uint16_t) code_voltage_setting);
111 }
112 
113 int8_t EasySMU::fltSetCommitVoltageSource(float flt_voltage_setting) //Later make this a float version of voltageSet with operators, etc.
114 {
115  int32_t code_voltage_setting = eeprom.calibration.voltage_source_offset-round(flt_voltage_setting/eeprom.calibration.voltage_source_LSB);
116 
117  return codeSetCommitVoltageSource(code_voltage_setting); //voltageSet handles the <0 and >0xFFFF conditions
118 }
119 
120 float EasySMU::fltReadVoltageSourceSetting() //Later make this a float version of voltageSet with operators, etc.
121 {
122  return ( ((float)((int32_t)Vdac_code_-(int32_t)round(eeprom.calibration.voltage_source_offset))*(-1)*eeprom.calibration.voltage_source_LSB ));
123 }
124 
125 
127 {
128  int8_t ack;
131  return (ack);
132 }
133 
134 #define float_current_source_setting_equation(Idac_pullup_code,current_source_pullup_offset,current_source_pullup_LSB) (((int32_t)Idac_pullup_code_ + (int32_t)current_source_pullup_offset) * current_source_pullup_LSB)
135 
136 int8_t EasySMU::fltSetCommitCurrentSource(float flt_current_setting, int8_t source_both_sink)
137 {
138  int32_t code_current_pullup_setting = (flt_current_setting/eeprom.calibration.current_source_pullup_LSB)-eeprom.calibration.current_source_pullup_offset;
139 
140  if (code_current_pullup_setting<0)
141  {
143  }
144  else if (code_current_pullup_setting>0xFFFF)
145  {
146  Idac_pullup_code_=0xFFFF;
147  }
148  else
149  {
150  Idac_pullup_code_=code_current_pullup_setting;
151  }
152 
153  int32_t code_current_pulldown_setting = (flt_current_setting/eeprom.calibration.current_source_pulldown_LSB)-eeprom.calibration.current_source_pulldown_offset;
154 
155  if (code_current_pulldown_setting<0)
156  {
158  }
159  else if (code_current_pulldown_setting>0xFFFF)
160  {
161  Idac_pulldown_code_=0xFFFF;
162  }
163  else
164  {
165  Idac_pulldown_code_=code_current_pulldown_setting;
166  }
167  //Used the #defined equation above because this is also used elsewhere in the code. Without the above equation definition, later mistaken changes to the code might affect one but not the other.
168  //float_current_source_setting_ = (Idac_pullup_code_ + eeprom.calibration.current_source_pullup_offset) * eeprom.calibration.current_source_pullup_LSB;
171  {
173  }
174  if (source_both_sink==_SINK_ONLY)
175  {
177  }
178  else if (source_both_sink==_SOURCE_ONLY)
179  {
181  }
183 
184 }
185 
186 void EasySMU::fltStepCurrentSourceSetting(float flt_step_size)
187 {
188 
189  //Consider removing the following step_size test. It could unnecessarily use extra memory.
190  //If the stepsize results in less than 1LSB of change, make it exactly 1LSB.
191  if (abs(flt_step_size/eeprom.calibration.current_source_pullup_LSB) < 1)
192  {
193  if (flt_step_size > 0)
194  {
195  flt_step_size=1.2*eeprom.calibration.current_source_pullup_LSB;
196  }
197  else
198  {
199  flt_step_size=-1.2*eeprom.calibration.current_source_pullup_LSB;
200  }
201  }
202 
203  //Hardcoding a 0.6mA minimum current setting to avoid confusion between mismatched pullup and pulldown minimum settings.
204  if ((float_current_source_setting_+flt_step_size)<0.0006)
205  {
206  flt_step_size=0.0006-float_current_source_setting_;
207  }
208 
211  int32_t code_delta_pullup_pulldown_setting=code_current_pulldown_setting-code_current_pullup_setting;
212 
213  if ((code_current_pullup_setting < 0x000) || (code_current_pulldown_setting < code_delta_pullup_pulldown_setting))
214  {
215  Idac_pullup_code_ = 0x0000;
216  Idac_pulldown_code_=code_delta_pullup_pulldown_setting;
217  }
218  else if ((code_current_pullup_setting > (0xFFFF-code_delta_pullup_pulldown_setting)) || (code_current_pulldown_setting > 0xFFFF))
219  {
220  Idac_pullup_code_ = 0xFFFF-code_delta_pullup_pulldown_setting;
221  Idac_pulldown_code_ = 0xFFFF;
222  }
223  else
224  {
225  Idac_pullup_code_ = code_current_pullup_setting;
226  Idac_pulldown_code_=code_current_pulldown_setting;
227  }
228 
230  {
231  Idac_pulldown_code_ = 0 ;
233  }
234 
235  //float_current_source_setting_ = ((int32_t)Idac_pullup_code_ + (int32_t)eeprom.calibration.current_source_pullup_offset) * eeprom.calibration.current_source_pullup_LSB;
237 
238 }
239 
241 {
242 
244 
245 }
246 
248 {
249 
250  int8_t ack=0;
253 
256  return (ack);
257 }
258 
260 {
261  delay(1);
264  //Restore voltage and current settings for next read from ADC, and read the previous temperature information.
265  int32_t temperature_of_Iadc_code, temperature_of_Vadc_code;
266 
267  LTC2485_read(ADC_Isense_I2C_address_, LTC2485_SPEED_1X | LTC2485_R60, &temperature_of_Iadc_code, _LTC2485_CONVERSION_TIME_1X*2); //Forcing 1X conversion time since 2X is not possible for temperature reading.
269 
270  flt_temperature_of_Iadc_=((float)(uint32_t) temperature_of_Iadc_code)/(uint32_t) eeprom.calibration.temperature_Iadc_code * (25+273) - 273;
271  flt_temperature_of_Vadc_=((float)(uint32_t) temperature_of_Vadc_code)/(uint32_t) eeprom.calibration.temperature_Vadc_code * (25+273) - 273;
272 }
273 
274 void EasySMU::MeasureTemperatureOfADCs(int32_t *temperature_of_Vadc_code, int32_t *temperature_of_Iadc_code)
275 {
276  delay(1);
279  //Restore voltage and current settings for next read from ADC, and read the previous temperature information.
280 
281  LTC2485_read(ADC_Isense_I2C_address_, LTC2485_SPEED_1X | LTC2485_R60, *(&temperature_of_Iadc_code), _LTC2485_CONVERSION_TIME_1X*2); //Forcing 1X conversion time since 2X is not possible for temperature reading.
283 
284  flt_temperature_of_Iadc_=((float)(uint32_t) temperature_of_Iadc_code)/(uint32_t) eeprom.calibration.temperature_Iadc_code * (25+273) - 273;
285  flt_temperature_of_Vadc_=((float)(uint32_t) temperature_of_Vadc_code)/(uint32_t) eeprom.calibration.temperature_Vadc_code * (25+273) - 273;
286 }
287 
289 {
290 
293 
295 
296 }
297 
298 float EasySMU::MeasureVoltage() //Remove _fVout if not needed.
299 {
300 
302 
304 
305 }
306 
308 {
310 }
311 
313 {
315 }
316 
317 //Reset the calibration to a typical value. This will rarely be used, as it is not factory calibration, but instead, a typical value.
319 {
320 
321 
324  eeprom.calibration.voltage_source_LSB=-0.0006852983;
331  eeprom.calibration.current_measure_LSB=-6.538718E-09;
336 
337 }
338 
339 int8_t EasySMU::SetCalibrationSinglePoint(uint16_t code_voltage_setting, uint16_t code_current_setting, const char prompt[], float *flt_user_input, int32_t *code_voltage_measure, int32_t *code_current_measure)
340 {
341  codeSetCommitVoltageSource(code_voltage_setting);
342  Idac_pullup_code_=code_current_setting;
343  Idac_pulldown_code_=code_current_setting;
345  if (prompt[0]!='\0')
346  {
347  Serial.print(prompt);
348  *flt_user_input=read_float();
349  Serial.println(*flt_user_input,6);
350  }
351  delay(200);
352 
355  *code_voltage_measure = Vadc_code_;
356  *code_current_measure = Iadc_code_;
357 
358  return (0); //Later allow a return failed condition placed on user input?
359 }
360 
362 {
363  float fltVsetP5V, fltVsetM5V;
364  int32_t lngVoutP5V, lngVoutM5V;
365 
366  Serial.println(F("Connect to voltmeter and wait ten seconds."));
367 
368  //Force about +5V and -5V to determine LSB. Voltage offset will be determined in subsequent step.
369  const uint16_t _VSET_P5V=44337, _VSET_M5V=15234;
370  const uint16_t _ISET=48000;
371  codeSetCommitVoltageSource(_VSET_P5V); //Set conditions and let temperature settle for 10 seconds.
372  Idac_pullup_code_=_ISET;
373  Idac_pulldown_code_=_ISET;
375 
376  delay(10000);
377  int32_t temperature_Vadc_code, temperature_Iadc_code;
378  MeasureTemperatureOfADCs(&temperature_Vadc_code, &temperature_Iadc_code);
379  eeprom.calibration.temperature_Vadc_code=temperature_Vadc_code;
380  eeprom.calibration.temperature_Iadc_code=temperature_Iadc_code;
381 
382 
383 
384  //Force +5V output and prompt user for value measured by voltmeter.
385  int32_t lngThrowaway; //This is a throwaway.
386  SetCalibrationSinglePoint(_VSET_P5V,_ISET, "(V)? ", &fltVsetP5V, &lngVoutP5V, &lngThrowaway);
387 
388  //Force -5V output and prompt user for value measured by voltmeter.
389  SetCalibrationSinglePoint(_VSET_M5V,_ISET, "(V)? ", &fltVsetM5V, &lngVoutM5V, &lngThrowaway);
390 
391  //Remember fltVsetP5V and fltVsetM5V were the accurate values entered by the user.
392  eeprom.calibration.voltage_measure_LSB=(fltVsetM5V-fltVsetP5V)/(float)(lngVoutM5V-lngVoutP5V);
393 
394  //Calculate Read and Set LSB's from -5V and +5V readings.
395  eeprom.calibration.voltage_source_LSB=(fltVsetM5V-fltVsetP5V)/(_VSET_P5V-_VSET_M5V);
396 
397  //Estimate 0V offset from the above +5V and -5V readings. But calculate more accurately in subsequent step.
400 
401  //Now calculate 0V offset more accurately.
402  float fltVoff;
403  int32_t lngVoutOff;
404  SetCalibrationSinglePoint(eeprom.calibration.voltage_source_offset,_ISET, "(mV)? ", &fltVoff, &lngVoutOff, &lngThrowaway);
405  fltVoff=fltVoff/1000;
406  //Serial.print((int16_t) round(fltVoff/eeprom.calibration.voltage_source_LSB));
407 
409  //Serial.print("VMeasure Offset: ");
410  //Serial.println(eeprom.calibration.voltage_measure_offset);
411  //delay(100);
412  //DJE: The output voltage accuracy could be improved by storing the actual floating point value where the code transition near 0V occurs.
413  //Then, the code value could be determined to within 1/2LSB.
415  //Serial.print(eeprom.calibration.voltage_source_offset);
417 
418  //Remove remaining offset from voltage measurement. If there was sub-millivolt drift in source voltage, it still affects the offset cancellation based on user input.
419  float fltTemp;
420  //SetCalibrationSinglePoint(eeprom.calibration.voltage_source_offset, 0, "Short outputs. Press Enter.", &fltTemp, &lngVoutOff, &lngThrowaway);
421  //eeprom.calibration.voltage_measure_offset=lngVoutOff;
422  //Serial.println(lngVoutOff);
423 
424  Serial.println(F("Disconnect meter. Press ENTER"));
425 
426  read_float(); //Just waiting for Enter.
427 
428  //float fltTemp;
429  int32_t lngIoutP5;
430  SetCalibrationSinglePoint(_VSET_P5V,_ISET, "", &fltTemp, &lngThrowaway, &lngIoutP5);
431  //Serial.print("+Iout: ");
432  //Serial.println(lngIoutP5);
433  //delay(100);
434 
435  int32_t lngIoutM5;
436  SetCalibrationSinglePoint(_VSET_M5V,_ISET, "", &fltTemp, &lngThrowaway, &lngIoutM5);
437  //Serial.print("-Iout: ");
438  //Serial.println(lngIoutM5);
439  //delay(100);
440 
441  float Rout;
442  Rout=-1*(lngIoutM5-lngIoutP5)/(float)(lngVoutM5V-lngVoutP5V);
444  //Serial.print("Rout: ");
445  //Serial.println(Rout,16);
446  //delay(100);
447 
448  int32_t lngIout0V, lngVout0V;
449  SetCalibrationSinglePoint(eeprom.calibration.voltage_source_offset, _ISET, "", &fltTemp, &lngVout0V, &lngIout0V);
450  //Serial.print("lngVout0V: ");
451  //Serial.println(lngVout0V);
452  //Serial.print("lngIout0V: ");
453  //Serial.print(lngIout0V);
454  //delay(100);
455 
457  //Serial.print("Ioffset: ");
458  //Serial.println(eeprom.calibration.current_measure_offset);
459  //delay(100);
460 
461  uint16_t _ISET_8=48000;
462  int32_t lngIout8, lngVout8;
463  float fltIout8;
464  SetCalibrationSinglePoint(_VSET_P5V, _ISET_8, "(mA)?", &fltIout8, &lngVout8, &lngIout8);
465  //Serial.print("+Iout: ");
466  //Serial.println(lngIout8);
467  //delay(100);
468 
469  fltIout8=fltIout8/1000;
470 
471  uint16_t _ISET_9=48000;
472  int32_t lngIout9, lngVout9;
473  float fltIout9;
474  SetCalibrationSinglePoint(_VSET_M5V, _ISET_9, "(mA)?", &fltIout9, &lngVout9, &lngIout9);
475  //Serial.print("-Iout: ");
476  //Serial.println(lngIout9);
477  //delay(100);
478 
479  fltIout9=fltIout9/1000;
480 
481  eeprom.calibration.current_measure_LSB=(fltIout8-fltIout9)/((lngIout8-lngIout9)+(int32_t)(eeprom.calibration.current_measure_output_resistance*(lngVout8-lngVout9)));
482  //Serial.print("ILSB: ");
483  //Serial.println(eeprom.calibration.current_measure_LSB, 16);
484  //delay(100);
485 
486  //Calibrate Iset offset and LSB
487 
488 // uint16_t _ISET_8=20000;
489  _ISET_8=20000;
490  //int32_t lngIout8;
491  //float fltIout8;
492  SetCalibrationSinglePoint(_VSET_P5V, _ISET_8, "(mA)?", &fltIout8, &lngThrowaway, &lngIout8);
493 
494  fltIout8=fltIout8/1000;
495 
496 // uint16_t _ISET_9=5000;
497  _ISET_9=5000;
498  //int32_t lngIout9;
499  //float fltIout9;
500  SetCalibrationSinglePoint(_VSET_P5V, _ISET_9, "(mA)?", &fltIout9, &lngThrowaway, &lngIout9);
501  fltIout9=fltIout9/1000;
502 
503  eeprom.calibration.current_source_pullup_LSB=(fltIout8-fltIout9)/(_ISET_8-_ISET_9);
505 
506  SetCalibrationSinglePoint(_VSET_M5V, _ISET_8, "(mA)?", &fltIout8, &lngThrowaway, &lngIout8);
507  fltIout8=-1*fltIout8/1000;
508 
509  SetCalibrationSinglePoint(_VSET_M5V, _ISET_9, "(mA)?", &fltIout9, &lngThrowaway, &lngIout9);
510  fltIout9=-1*fltIout9/1000;
511 
512  eeprom.calibration.current_source_pulldown_LSB=(fltIout8-fltIout9)/(_ISET_8-_ISET_9);
514 
515  eeprom.calibration.current_source_pulldown_LSB=(fltIout8-fltIout9)/(_ISET_8-_ISET_9);
517 
519 
520  Serial.print(F("Save calibration? (Y/N)"));
521  char user_char=read_char();
522  if (user_char!='y' || user_char!='Y')
523  {
524  if (user_char=='L' && read_char() == 'T' && read_char()=='C')
525  {
526  char buffer[CAL_INFO_STRLEN];
528  Serial.println(F("Info: "));
529  Serial.setTimeout(30000); //Allow thirty seconds for response
530  size_t numbytes = Serial.readBytesUntil('\r', buffer, CAL_INFO_STRLEN-1); //Need to leave one last character for the null termination.
531 
532  buffer[numbytes] = '\0'; //readBytesUntil stored the <CR> terminates the string. This removes it.
533 
535  Serial.println(buffer);
536  Serial.setTimeout(1000); //Restore 1 second timeout default
537  }
538  else
539  {
540  return false;
541  }
542  }
543 
545 
547 
548  while (Serial.peek()=='\n' || Serial.peek()=='\r') Serial.read();
549 
550  Serial.println(F("Written"));
551  return true;
552 
553 }
554 
556 {
557  int16_t cal_key;
558 
560  {
561  present_=0;
562  return (1);
563  }
564 
565  present_=1;
566 
567  // Read the cal key from the EEPROM
568 
570 
571  if (cal_key == EEPROM_CAL_KEY)
572  {
574  return (0);
575  }
576  //printError(_PRINT_ERROR_NO_CALIBRATION_DATA_FOUND);
577  ResetCalibration(); //If a valid calibration were present in the EEPROM, this function would already have hit return(0); Instead read a default value.
578  return (1);
579 
580 }
581 
583 {
584 
586  //Unfortunately, the eeprom_write_byte_array takes an 8-bit address rather than 7-bit
588 }
589 
591 {
592 
594  //Unfortunately, the eeprom_write_byte_array takes an 8-bit address rather than 7-bit
596 }
597 
599 {
600  int16_t cal_key;
601 
603  {
604  return (1);
605  }
606 
607  char calInfo[CAL_INFO_STRLEN];
609  Serial.print(calInfo);
610 
611  return (0);
612 }
613 
615 {
616  int16_t cal_key;
617 
619  {
620  return (1);
621  }
622 
624  Serial.println(buffer);
625 
626  return (0);
627 }
628 
630 {
631 
632  uint8_t num_bytes=sizeof(eeprom_data_union);
633  uint8_t i;
634  char data[1];
635  for (i = 0; i < num_bytes; i++)
636  {
638  {
639  //printError(_PRINT_ERROR_FACTORY_CALIBRATION_RESTORE_FAILED_CATASTROPHICALLY);
640  break;
641  }
643  {
644  //printError(_PRINT_ERROR_FACTORY_CALIBRATION_RESTORE_FAILED_CATASTROPHICALLY);
645  break;
646  }
647  }
648  //Serial.println(F("RESTORED"));
649  return (i);
650 
651 }
652 
654 {
655  return (present_);
656 }
657 
658 
659 /*!
660 Copyright 2018(c) Analog Devices, Inc.
661 
662 All rights reserved.
663 
664 Redistribution and use in source and binary forms, with or without
665 modification, are permitted provided that the following conditions are met:
666  - Redistributions of source code must retain the above copyright
667  notice, this list of conditions and the following disclaimer.
668  - Redistributions in binary form must reproduce the above copyright
669  notice, this list of conditions and the following disclaimer in
670  the documentation and/or other materials provided with the
671  distribution.
672  - Neither the name of Analog Devices, Inc. nor the names of its
673  contributors may be used to endorse or promote products derived
674  from this software without specific prior written permission.
675  - The use of this software may or may not infringe the patent rights
676  of one or more patent holders. This license does not release you
677  from the requirement that you obtain separate licenses from these
678  patent holders to use this software.
679  - Use of the software either in source or binary form, must be run
680  on or directly connected to an Analog Devices Inc. component.
681 
682 THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR
683 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT,
684 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
685 IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT,
686 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
687 LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, PROCUREMENT OF SUBSTITUTE GOODS OR
688 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
689 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
690 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
691 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
692 */
float current_source_pullup_LSB
the current of one LSB in amps from the current pullup DAC channel
Definition: EasySMU.h:301
uint8_t eeprom_read_byte_array(uint8_t i2c_address, char *data, uint16_t address, uint8_t num_bytes)
Read a data byte at address from the EEPROM with i2c_address.
float MeasureCurrent()
Measure the current (with ADC).
Definition: EasySMU.cpp:288
int8_t eeprom_poll(uint8_t i2c_address)
Determine if the EEPROM is ready for communication by writing the address+!write byte and looking for...
float MeasureVoltage()
Measure the voltage (with ADC).
Definition: EasySMU.cpp:298
#define _SINK_ONLY
Definition: EasySMU.h:113
#define LTC2485_SPEED_1X
Definition: LTC2485.h:97
uint8_t DAC_I2C_address_
I2C address of LTC2655 used to control voltage and current settings.
Definition: EasySMU.h:138
uint8_t eeprom_read_int16(uint8_t i2c_address, int16_t *read_data, uint16_t address)
Read the two byte integer data from the EEPROM starting at address.
int32_t current_measure_offset
the code from the current ADC that corresponds to 0A at the output
Definition: EasySMU.h:308
uint8_t eeprom_write_byte(uint8_t i2c_address, char data, uint16_t address)
Write the data byte to the EEPROM with i2c_address starting at EEPROM address.
float voltage_source_LSB
the voltage of one LSB in volts (from the voltage channel of the DAC)
Definition: EasySMU.h:299
void codeStepVoltageSourceSetting(int16_t stepSize)
Increase or decrease the voltage source setting.
Definition: EasySMU.cpp:106
#define LTC2485_R60
Definition: LTC2485.h:103
void fltStepCurrentSourceSetting(float fltStepSize)
Increase or decrease the current source setting by this value in amps.
Definition: EasySMU.cpp:186
int16_t WriteCalibration()
Write calibration to EEPROM.
Definition: EasySMU.cpp:582
float flt_measured_current_
measured current (in amps)
Definition: EasySMU.h:145
#define _EASYSMU_VOLTAGE_DAC
Definition: EasySMU.h:85
uint8_t eeprom_write_byte_array(uint8_t i2c_address, char data[], uint16_t address, uint8_t num_bytes)
Write the data byte array to the EEPROM with i2c_address starting at EEPROM address.
int8_t MeasureVoltageCurrent()
Measure the voltage and current (with ADCs).
Definition: EasySMU.cpp:247
float current_measure_output_resistance
This value is used to modify the output current measurement result based on output voltage...
Definition: EasySMU.h:307
int16_t IsPresent()
Check if this EasySMU is present.
Definition: EasySMU.cpp:653
int8_t codeSetCommitVoltageSource(int32_t lngVoltageSetParam)
Set and commit the voltage source setting immediately.
Definition: EasySMU.cpp:88
int16_t current_source_pulldown_offset
current DAC code that ideally would result in 0A at output, if the output current could be configured...
Definition: EasySMU.h:302
int8_t fltSetCommitVoltageSource(float fVoltage)
Commit the voltage source setting immediately to this float value.
Definition: EasySMU.cpp:113
int16_t ReadCalibration()
Read calibration from EEPROM.
Definition: EasySMU.cpp:555
union LT_union_int32_4bytes data
Definition: DC2094A.ino:138
Class Library Header File for EasySMU: I2C Address Translator Demonstration and a Simple Multi-Channe...
uint8_t ADC_Vsense_I2C_address_
I2C address of LTC2485 used to measure output voltage.
Definition: EasySMU.h:139
float fltReadCurrentSourceSetting()
Read the current source setting.
Definition: EasySMU.cpp:240
float float_current_source_setting_
Current source setting.
Definition: EasySMU.h:151
union EasySMU::eeprom_data_union eeprom
#define _EASYSMU_CURRENT_PULLDOWN_DAC
Channel C of the DAC configures the maximum pulldown current.
Definition: EasySMU.h:89
int32_t Iadc_code_
raw code of current ADC
Definition: EasySMU.h:142
int8_t LTC2485_read(uint8_t i2c_address, uint8_t adc_command, int32_t *adc_code, uint16_t eoc_timeout)
Reads from LTC2485 ADC that accepts an 8 bit configuration and returns a 24 bit result.
Definition: LTC2485.cpp:70
uint8_t eeprom_read_byte(uint8_t i2c_address, char *data, uint16_t address)
Read a data byte at address from the EEPROM with i2c_address.
int8_t SetCalibration()
Perform calibration.
Definition: EasySMU.cpp:361
int8_t LTC2655_write(uint8_t i2c_address, uint8_t dac_command, uint8_t dac_address, uint16_t dac_code)
Write a 16-bit dac_code to the LTC2655.
Definition: LTC2655.cpp:82
#define _LTC2485_CONVERSION_TIME_1X
Definition: EasySMU.h:97
void DisableOutput()
Disables the LT1970 output.
Definition: EasySMU.cpp:312
EasySMU(uint8_t EEPROM_I2C_address_param, uint8_t DAC_I2C_address_param, uint8_t ADC_Vsense_I2C_address_param, uint8_t ADC_Isense_I2C_address_param)
EasySMU constructor. Remember each EasySMU instance has unique I2C addresses, so this configures each...
Definition: EasySMU.cpp:70
float voltage_measure_LSB
the voltage of one LSB in volts from the voltage ADC
Definition: EasySMU.h:305
#define EEPROM_CAL_STATUS_ADDRESS
float flt_measured_voltage_
measured voltage (in volts)
Definition: EasySMU.h:145
float fltReadVoltageSourceSetting()
Read the voltage source setting.
Definition: EasySMU.cpp:120
#define EEPROM_FACTORY_CAL_STATUS_ADDRESS
A backup version of the factory calibration is stored at this address. Factory calibration may be rec...
Definition: EasySMU.h:105
float current_measure_LSB
the current of one LSB in amps from the current ADC
Definition: EasySMU.h:306
void ResetCalibration()
Reset the calibration to a typical value.
Definition: EasySMU.cpp:318
int8_t SetCalibrationSinglePoint(uint16_t voltageSetValue, uint16_t currentSetValue, const char prompt[], float *fltUserOutput, int32_t *lngVadc_code, int32_t *lngIadc_code)
Configure a voltage and current setting and prompt for measurement from lab-grade multimeter...
Definition: EasySMU.cpp:339
int16_t cal_key
If this is set to the proper value, it indicates that a calibration has been performed.
Definition: EasySMU.h:296
int16_t WriteFactoryCalibration()
FOR FACTORY USE ONLY! Write calibration to factory calibration section of EEPROM. ...
Definition: EasySMU.cpp:590
float flt_temperature_of_Iadc_
current output setting (float)
Definition: EasySMU.h:148
#define float_current_source_setting_equation(Idac_pullup_code, current_source_pullup_offset, current_source_pullup_LSB)
Definition: EasySMU.cpp:134
void MeasureTemperatureOfADCs()
Measure the temperature of the voltage and current ADCs.
Definition: EasySMU.cpp:259
uint8_t RestoreFactoryCalibration()
Restore factory calibration from the EEPROM.
Definition: EasySMU.cpp:629
int8_t CommitVoltageSourceSetting()
Commit the voltage source setting.
Definition: EasySMU.cpp:79
#define LTC2485_INTERNAL_TEMP
Definition: LTC2485.h:99
#define LTC2485_TIMEOUT
Maximum time allowed for LTC2485 conversion. If this time is exceeded, something is wrong...
Definition: EasySMU.cpp:68
void EnableOutput()
Enables the LT1970 output.
Definition: EasySMU.cpp:307
uint8_t EasySMU_EEPROM_I2C_address_
I2C address of the EEPROM that stores calibration data.
Definition: EasySMU.h:137
#define EEPROM_FACTORY_CAL_INFO_ADDRESS
Channel ID information returned by *IDN? command.
Definition: EasySMU.h:107
#define _SOURCE_ONLY
Definition: EasySMU.h:111
float read_float()
#define LTC2655_CMD_WRITE_UPDATE
Definition: LTC2655.h:150
int16_t PrintFactoryCalibrationInfo()
Prints the factory calibration info from EEPROM to the serial port.
Definition: EasySMU.cpp:598
int32_t voltage_measure_offset
the voltage ADC code that corresponds to 0V at the output
Definition: EasySMU.h:304
prompt
Used to keep track to print voltage or print code.
Definition: DC934A.ino:113
int32_t temperature_Vadc_code
This is the temperature code read from the voltage ADC during calibration.
Definition: EasySMU.h:309
int8_t present_
Indicates if this channel is present.
Definition: EasySMU.h:136
Union that defines the calibration data stored in the EasySMU EEPROM.
Definition: EasySMU.h:290
#define CAL_INFO_STRLEN
Defines length of the calibartion info string (serial number) which is stored in the EEPROM...
Definition: EasySMU.h:117
uint16_t Idac_pulldown_code_
raw code of current pulldown DAC
Definition: EasySMU.h:153
float flt_temperature_of_Vadc_
Temperature of voltage ADC.
Definition: EasySMU.h:148
int32_t temperature_Iadc_code
This is the temperature code read from the current ADC during calibration.
Definition: EasySMU.h:310
static int i
Definition: DC2430A.ino:184
#define _EASYSMU_ENABLE_OUTPUT_DAC
Channel D of the DAC is used to enable or disable the LTC1970&#39;s output. It is essentially used as a b...
Definition: EasySMU.h:91
int16_t voltage_source_offset
The output voltage is 0V when this code is stored in the voltage channel of the DAC.
Definition: EasySMU.h:298
int16_t current_source_pullup_offset
current DAC code that ideally would result in 0A at output, if the output current could be configured...
Definition: EasySMU.h:300
int8_t CommitCurrentSourceSetting()
Commit the current source setting.
Definition: EasySMU.cpp:126
uint16_t Idac_pullup_code_
raw code of current pullup DAC
Definition: EasySMU.h:153
struct EasySMU::eeprom_data_union::data_struct_type calibration
uint16_t Vdac_code_
raw code of voltage DAC
Definition: EasySMU.h:153
uint8_t ADC_Isense_I2C_address_
I2C address of LTC2485 used to measure output current.
Definition: EasySMU.h:140
int32_t Vadc_code_
raw code of voltage ADC
Definition: EasySMU.h:142
#define EEPROM_CAL_KEY
int8_t read_char()
int8_t fltSetCommitCurrentSource(float fCurrent, int8_t up_down_both)
Change the current source setting immediately.
Definition: EasySMU.cpp:136
float current_source_pulldown_LSB
the current of one LSB in amps from the current pulldown DAC channel
Definition: EasySMU.h:303
#define _EASYSMU_CURRENT_PULLUP_DAC
Channel B of the DAC configures the maximum pullup current.
Definition: EasySMU.h:87
char byte_array[sizeof(data_struct_type)]
Definition: EasySMU.h:314
int16_t WriteFactoryCalibrationInfo(char *buffer)
Write factory calibration info to EEPROM.
Definition: EasySMU.cpp:614