SatNOGS-COMMS  4.1.0
A COMMS subsystem for CubeSats
Loading...
Searching...
No Matches
emc1702.cpp
Go to the documentation of this file.
1/*
2 * SatNOGS-COMMS control library
3 *
4 * Copyright (C) 2023, Libre Space Foundation <http://libre.space>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * SPDX-License-Identifier: GNU General Public License v3.0 or later
20 */
21#include <cmath>
24
25namespace satnogs::comms::lib
26{
27/* Refer to:
28 * EMC1702 datasheet:
29 * https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/DataSheets/EMC1702-Data-Sheet-DS20006455A.pdf
30 *
31 * Register
32 * Description can be found in datasheet p. 30 - 33
33 */
34#define REG_STATUS 0x34 // Read Only
35#define REG_HIGH_LIMIT_STATUS 0x35 // Read Only
36#define REG_LOW_LIMIT_STATUS 0x36 // Read Only
37#define REG_CRIT_LIMIT_STATUS 0x37 // Read Only
38#define REG_INTERNAL_DIODE_HIGH_BYTE 0x38 // Read Only
39#define REG_INTERNAL_DIODE_LOW_BYTE 0x39 // Read Only
40#define REG_EXTERNAL_DIODE_HIGH_BYTE 0x3A // Read Only
41#define REG_EXTERNAL_DIODE_LOW_BYTE 0x3B // Read Only
42#define REG_AVERAGING_CONTROL 0x40 // R/W
43#define REG_CONFIGURATION 0x03 // R/W
44#define REG_CONVERSION_RATE 0x04 // R/W
45#define REG_INTERNAL_DIODE_HIGH_LIM 0x05 // R/W
46#define REG_INTERNAL_DIODE_LOW_LIM 0x06 // R/W
47#define REG_EXTERNAL_DIODE_HIGH_LIM_HIGH_BYTE 0x07 // R/W
48#define REG_EXTERNAL_DIODE_LOW_LIM_HIGH_BYTE 0x08 // R/W
49#define REG_EXTERNAL_DIODE_HIGH_LIM_LOW_BYTE 0x13 // R/W
50#define REG_EXTERNAL_DIODE_LOW_LIM_LOW_BYTE 0x14 // R/W
51#define REG_EXTERNAL_DIODE_TCRIT_LIM 0x19 // R/W
52#define REG_CHANNEL_MASK_REG 0x1F // R/W
53#define REG_INTERNAL_DIODE_TCRIT_LIM 0x20 // R/W
54#define REG_TCRIT_HYSTERISIS 0x21 // R/W
55#define REG_TCRIT_CONSECUTIVE_ALERT 0x22 // R/W
56#define REG_EXTERNAL_DIODE_BETA_CONFIG 0x25 // R/W
57#define REG_EXTERNAL_DIODE_IDEALITY_FACTOR 0x25 // R/W
58#define REG_ONE_SHOT 0x0F // Write Only
59#define REG_EXTERNAL_DIODE_FAULT 0x1B // Read Only
60#define REG_PRODUCT_FEATURES 0xFC // Read Only
61#define REG_PRODUCT_ID 0xFD // Read Only
62#define REG_MICROCHIP_ID 0xFE // Read Only
63#define REG_REVISION 0xFF // Read Only
64#define VOLTAGE_SAMPLING_CONFIG 0x50 // R/W
65#define CURRENT_SENSE_SAMPLING_CONFIG 0x51 // R/W
66#define PEAK_DETECTION_CONFIG 0x52 // R/W
67#define SENCE_VOLTAGE_HIGH_BYTE 0x54 // Read Only
68#define SENCE_VOLTAGE_LOW_BYTE 0x55 // Read Only
69#define SOURCE_VOLTAGE_HIGH_BYTE 0x58 // Read Only
70#define SOURCE_VOLTAGE_LOW_BYTE 0x59 // Read Only
71#define POWER_RATIO_VOLTAGE_HIGH_BYTE 0x5B // Read Only
72#define POWER_RATIO_VOLTAGE_LOW_BYTE 0x5C // Read Only
73#define SENCE_VOLTAGE_HIGH_LIM 0x60 // R/W
74#define SENCE_VOLTAGE_LOW_LIM 0x61 // R/W
75#define SOURCE_VOLTAGE_HIGH_LIM 0x64 // R/W
76#define SOURCE_VOLTAGE_LOW_LIM 0x65 // R/W
77#define SENCE_VOLTAGE_V_CRIT 0x66 // R/W
78#define SOURCE_VOLTAGE_V_CRIT 0x68 // R/W
79#define SENSE_V_CRIT_HYSTERISIS 0x69 // R/W
80#define SOURCE_V_CRIT_HYSTERISIS 0x6A // R/W
81
135emc1702::emc1702(const char *name, bsp::i2c &i2c, uint16_t addr,
137 : m_name(name),
138 m_i2c(i2c),
139 m_addr(addr),
140 m_ready(false),
141 m_alert(alert),
142 mode(sensor_mode::FULLY_ACTIVE),
143 rate(conversion_rate::PER_1_SEC_8_MEAS),
144 avrg_temp(averaging_control::DISABLED),
145 alert_crit(consecutive_alert_diode_fault::OUT_OF_LIM_MEAS_4),
146 alert_lim(consecutive_alert_diode_fault::OUT_OF_LIM_MEAS_4),
147 beta(beta_config::AUTO),
148 i_factor(ideality_factor::IDEALITY_FACTOR_1_0080),
149 v_source_spike(consecutive_alert_voltage::OUT_OF_LIM_MEAS_4),
150 avrg_v_source(averaging_control::DISABLED),
151 v_sense_spike(consecutive_alert_current::OUT_OF_LIM_MEAS_4),
152 avrg_i_sense(averaging_control::DISABLED),
153 i_sampling(current_sampling_time::S_T_82_MS),
154 v_sense_max(max_expected_voltage::CURRENT_SENSOR_RANGE_10_mV),
155 thres(peak_detection_threshold::THRESHOLD_35_mV),
156 dur(peak_detection_duration::DURATION_5_12_ms),
157 range(),
158 s()
159{
160 try {
161 // Initialise sensor
162 set_config(mode);
163 set_conversion_rate(rate);
164 set_averaging_control(avrg_temp);
165
166 set_int_temp_high_lim();
167 set_int_temp_low_lim();
168 set_ext_temp_high_lim();
169 set_ext_temp_low_lim();
170 set_t_crit();
171
172 set_consecutive_alert(alert_crit, alert_lim);
173 set_beta_configuration(beta);
174 set_ideality_factor(i_factor);
175
176 set_voltage_sampling_config(v_source_spike, avrg_i_sense);
177 set_current_sense_sampling_config(v_sense_spike, avrg_i_sense, i_sampling,
178 v_sense_max);
179 set_peak_detection_config(thres, dur);
180 set_v_sense_lim();
181 set_v_source_lim();
182 set_v_crit_lim();
183 m_ready = true;
184 } catch (...) {
185 // Mark the sensor as invalid
186 }
187}
188
198emc1702::emc1702(const char *name, bsp::i2c &i2c, uint16_t addr)
199 : emc1702(name, i2c, addr, m_dummy)
200{
201}
202
203void
204emc1702::get_measurements(sensor_mode m)
205{
206 float temperature_internal;
207 float temperature_external;
208 float power_ratio;
209 float sense_current;
210 float source_voltage;
211 switch (m) {
213 if (get_crit_limit_status()) {
214 throw emc1702_thermal_shutdown_needed(__FILE__, __LINE__);
215 } else {
216 if (get_sensor_info() == 0) {
217 throw emc1702_incorrect_sensor_info(__FILE__, __LINE__);
218 } else {
219 temperature_internal = get_temperature_internal(); // °C
220 temperature_external = get_temperature_external(); // °C
221 sense_current = get_sense_current(); // A
222 source_voltage = get_source_voltage(); // V
223 power_ratio = get_power(); // ratio
224 }
225 }
226 break;
227
229 if (get_crit_limit_status()) {
230 throw emc1702_thermal_shutdown_needed(__FILE__, __LINE__);
231 } else {
232 if (get_sensor_info() == 0) {
233 throw emc1702_incorrect_sensor_info(__FILE__, __LINE__);
234 } else {
235 sense_current = get_sense_current(); // A
236 source_voltage = get_source_voltage(); // V
237 power_ratio = get_power(); // ratio
238 }
239 }
240 break;
242 if (get_crit_limit_status()) {
243 throw emc1702_thermal_shutdown_needed(__FILE__, __LINE__);
244 } else {
245 if (get_sensor_info() == 0) {
246 throw emc1702_incorrect_sensor_info(__FILE__, __LINE__);
247 } else {
248 temperature_internal = get_temperature_internal(); // °C
249 temperature_external = get_temperature_external(); // °C
250 }
251 }
252 break;
254 if (get_crit_limit_status()) {
255 throw emc1702_thermal_shutdown_needed(__FILE__, __LINE__);
256 } else {
257 if (get_sensor_info() == 0) {
258 throw emc1702_incorrect_sensor_info(__FILE__, __LINE__);
259 } else {
260 // You can request measurements whenever you want calling the
261 // emc1702::get_one_shot_meas()
262 }
263 }
264 break;
265 default:
266 throw inval_arg_exception(__FILE__, __LINE__);
267 }
268 return;
269}
270
277float
279{
280 if (!m_ready) {
281 throw emc1702_inval(__FILE__, __LINE__);
282 }
283 return (get_temperature_internal() + get_temperature_external()) / 2;
284}
285
286float
287emc1702::get_temperature_internal() const
288{
289 uint8_t buf[2] = {0, 0};
290 m_i2c.read(m_addr, REG_INTERNAL_DIODE_HIGH_BYTE, buf, 2);
291 uint16_t bit_value = ((buf[0] << 8) | buf[1]) >> 5;
292 bool sign = (bit_value >> 10) != 0;
293 if (sign) {
294 bit_value = ~bit_value + 1;
295 }
296 // Convert 7-bit integer part to decimal
297 float temp_value = static_cast<float>((bit_value >> 3) & 0x7F);
298 temp_value += static_cast<float>(bit_value & 0x07) * 0.125f;
299 // Apply sign
300 if (sign) {
301 temp_value = -temp_value;
302 }
303 return temp_value;
304 // L1 data (in °C)
305}
306
307float
308emc1702::get_temperature_external() const
309{
310 uint8_t buf[2] = {0, 0};
311 m_i2c.read(m_addr, REG_EXTERNAL_DIODE_HIGH_BYTE, buf, 2);
312 uint16_t bit_value = ((buf[0] << 8) | buf[1]) >> 5;
313 bool sign = (bit_value >> 10) != 0;
314 if (sign) {
315 bit_value = ~bit_value + 1;
316 }
317 // Convert 7-bit integer part to decimal
318 float temp_value = static_cast<float>((bit_value >> 3) & 0x7F);
319 temp_value += static_cast<float>(bit_value & 0x07) * 0.125f;
320 // Apply sign
321 if (sign) {
322 temp_value = -temp_value;
323 }
324 return temp_value;
325 // L1 data (in °C)
326}
327void
329{
330 if (!m_ready) {
331 throw emc1702_inval(__FILE__, __LINE__);
332 }
333 s = {.busy = 0, .crit = 0, .diode_fault = 0, .low = 0, .high = 0, .peak = 0};
334 uint8_t buf = 0;
335 // The Status Register reports general error conditions.
336 m_i2c.read(m_addr, REG_STATUS, &buf, 1);
337 // The channels met or exceeded their programmed Tcrit or Vcrit limit.
338 s.crit = buf & 0b10;
339 // External diode fault was detected
340 s.diode_fault = buf & (1 << 2);
341 // The channels dropped below their low programmed limit
342 s.low = buf & (1 << 3);
343 // The channels met or exceeded their programmed high limit
344 s.high = buf & (1 << 4);
345 // the Peak Detector circuitry has detected a current peak that is greater
346 // than the programmed threshold for longer than the programmed duration
347 s.peak = buf & (1 << 6);
348 s.busy = buf & (1 << 7); // the ADCs is currently converting
349 return;
350}
351
352void
354{
355 uint8_t buf = 0;
356 // Set Basic Configuration
357 switch (m) {
362 buf = static_cast<uint8_t>(m);
363 m_i2c.write(m_addr, REG_CONFIGURATION, &buf, 1);
364 break;
365 default:
366 throw inval_arg_exception(__FILE__, __LINE__);
367 }
368
369 return;
370}
371
372void
373emc1702::set_conversion_rate(conversion_rate r) const
374{
375 uint8_t buf = 0;
376 // Set Conversion Rate
377 switch (r) {
386 buf = static_cast<uint8_t>(r);
387 m_i2c.write(m_addr, REG_CONVERSION_RATE, &buf, 1);
388 break;
389 default:
390 throw inval_arg_exception(__FILE__, __LINE__);
391 }
392 return;
393}
394
395void
396emc1702::set_int_temp_high_lim(float int_temp_high_lim) const
397{
398 uint8_t buf = 0;
399 // Set Internal Diode High Limit Temperature
400 if (int_temp_high_lim >= 127.0f) {
401 buf = 0b01111111;
402 } else if (int_temp_high_lim <= -128.0f) {
403 buf = 0b10000000;
404 } else {
405 if (int_temp_high_lim >= 0.0f) {
406 buf = static_cast<uint8_t>(abs(round(int_temp_high_lim)));
407 } else {
408 buf = static_cast<uint8_t>(abs(round(int_temp_high_lim)));
409 buf = ~buf;
410 buf++;
411 }
412 }
413 m_i2c.write(m_addr, REG_INTERNAL_DIODE_HIGH_LIM, &buf, 1);
414 return;
415}
416
417void
418emc1702::set_int_temp_low_lim(float int_temp_low_lim) const
419{
420 // Set Internal Diode Low Limit Temperature
421 uint8_t buf = 0;
422 if (int_temp_low_lim >= 127.0f) {
423 buf = 0b01111111;
424 } else if (int_temp_low_lim <= -128.0f) {
425 buf = 0b10000000;
426 } else {
427 if (int_temp_low_lim >= 0.0f) {
428 buf = static_cast<uint8_t>(abs(round(int_temp_low_lim)));
429 } else {
430 buf = static_cast<uint8_t>(abs(round(int_temp_low_lim)));
431 buf = ~buf;
432 buf++;
433 }
434 }
435 m_i2c.write(m_addr, REG_INTERNAL_DIODE_LOW_LIM, &buf, 1);
436 return;
437}
438
439void
440emc1702::set_ext_temp_high_lim(float ext_temp_high_lim) const
441{
442 // Set External Diode High Limit Temperature
443 uint8_t buf[2];
444 buf[0] = static_cast<uint8_t>(floor(std::abs(ext_temp_high_lim)));
445 if (ext_temp_high_lim < 0.0f) {
446 buf[0] |= 0x80;
447 }
448 float floatingPart = std::abs(ext_temp_high_lim) -
449 static_cast<int>(std::abs(ext_temp_high_lim));
450 buf[1] = static_cast<int>(floatingPart * 8.0f);
451 buf[1] = buf[1] >> 5;
452 m_i2c.write(m_addr, REG_EXTERNAL_DIODE_HIGH_LIM_HIGH_BYTE, buf, 2);
453 return;
454}
455
456void
457emc1702::set_ext_temp_low_lim(float ext_temp_low_lim) const
458{
459 // Set External Diode Low Limit Temperature
460 uint8_t buf[2];
461 buf[0] = static_cast<uint8_t>(floor(std::abs(ext_temp_low_lim)));
462 if (ext_temp_low_lim < 0.0f) {
463 buf[0] |= 0x80;
464 }
465 float floatingPart =
466 std::abs(ext_temp_low_lim) - static_cast<int>(std::abs(ext_temp_low_lim));
467 buf[1] = static_cast<int>(floatingPart * 8.0f);
468 buf[1] = buf[1] >> 5;
469 m_i2c.write(m_addr, REG_EXTERNAL_DIODE_LOW_LIM_HIGH_BYTE, buf, 2);
470 return;
471}
472
473void
474emc1702::get_one_shot_meas() const
475{
476 // Get One shot measurements
477 uint8_t buf;
478 buf = 0b11111111;
479 m_i2c.write(m_addr, REG_ONE_SHOT, &buf, 1);
480 return;
481}
482
483void
484emc1702::set_t_crit(float ext_t_crit, float int_t_crit,
485 float t_crit_hysterisis) const
486{
487 uint8_t buf;
488 // Set External Diode Critical Temperature
489 if (ext_t_crit >= 127.0f) {
490 buf = 0b01111111;
491 } else if (ext_t_crit <= -128.0f) {
492 buf = 0b10000000;
493 } else {
494 if (ext_t_crit >= 0.0f) {
495 buf = static_cast<uint8_t>(abs(round(ext_t_crit)));
496 } else {
497 buf = static_cast<uint8_t>(abs(round(ext_t_crit)));
498 buf = ~buf;
499 buf++;
500 }
501 }
502 m_i2c.write(m_addr, REG_EXTERNAL_DIODE_TCRIT_LIM, &buf, 1);
503
504 // Set Internal Diode Critical Temperature
505 if (int_t_crit >= 127.0f) {
506 buf = 0b01111111;
507 } else if (int_t_crit <= -128.0f) {
508 buf = 0b10000000;
509 } else {
510 if (int_t_crit >= 0) {
511 buf = static_cast<uint8_t>(abs(round(int_t_crit)));
512 } else {
513 buf = static_cast<uint8_t>(abs(round(int_t_crit)));
514 buf = ~buf;
515 buf++;
516 }
517 }
518 m_i2c.write(m_addr, REG_INTERNAL_DIODE_TCRIT_LIM, &buf, 1);
519
520 // Set Critical Temperature Hysteresis
521 if (t_crit_hysterisis < 0.0f) {
522 throw inval_arg_exception(__FILE__, __LINE__);
523 } else if (t_crit_hysterisis >= 127.0f) {
524 buf = 0b01111111;
525 } else {
526 buf = static_cast<uint8_t>(abs(round(t_crit_hysterisis)));
527 }
528 m_i2c.write(m_addr, REG_TCRIT_HYSTERISIS, &buf, 1);
529}
530
531bool
532emc1702::get_diode_fault() const
533{
534 // Get diode fault
535 // You can get the same information from the status register
536 uint8_t buf;
537 bool diode_fault;
538 m_i2c.read(m_addr, REG_EXTERNAL_DIODE_FAULT, &buf, 1);
539 // If external diode fault was detected
540 diode_fault = (buf & 0b10);
541 return diode_fault;
542}
543
544void
545emc1702::set_consecutive_alert(consecutive_alert_diode_fault c,
546 consecutive_alert_diode_fault l) const
547{
548 // Set how many times an out-of-limit error or diode fault must
549 // be detected in consecutive measurements before the interrupt
550 // status registers are asserted.
551 uint8_t buf;
552 switch (l) {
557 buf = static_cast<uint8_t>(l);
558 break;
559 default:
560 throw inval_arg_exception(__FILE__, __LINE__);
561 }
562 switch (c) {
567 buf |= (static_cast<uint8_t>(c) << 3);
568 m_i2c.write(m_addr, REG_TCRIT_CONSECUTIVE_ALERT, &buf, 1);
569 break;
570 default:
571 throw inval_arg_exception(__FILE__, __LINE__);
572 }
573 return;
574}
575
576void
577emc1702::set_beta_configuration(beta_config b) const
578{
579 // Set beta configuration
580 uint8_t buf = 0;
581 switch (b) {
599 buf = static_cast<uint8_t>(b);
600 m_i2c.write(m_addr, REG_EXTERNAL_DIODE_BETA_CONFIG, &buf, 1);
601 break;
602 default:
603 throw inval_arg_exception(__FILE__, __LINE__);
604 }
605 return;
606}
607
608void
609emc1702::set_ideality_factor(ideality_factor i) const
610{
611 uint8_t buf;
612 // Set ideality factor
613 switch (i) {
622 buf = static_cast<uint8_t>(i);
623 m_i2c.write(m_addr, REG_EXTERNAL_DIODE_IDEALITY_FACTOR, &buf, 1);
624 break;
625 default:
626 throw inval_arg_exception(__FILE__, __LINE__);
627 }
628 return;
629}
630
631etl::vector<bool, 4>
632emc1702::get_high_limit_status() const
633{
634 // Get the status bits that are set when a temperature or voltage channel high
635 // limit is met or exceeded.
636 uint8_t buf;
637 bool i_high;
638 bool e_high;
639 bool vsrc_high;
640 bool vsense_high;
641 m_i2c.read(m_addr, REG_HIGH_LIMIT_STATUS, &buf, 1);
642 // The Internal Diode channel met or exceeded its programmed high limit
643 i_high = (buf & 0b01);
644 // The External Diode channel met or exceeded its programmed high limit
645 e_high = (buf & 0b10);
646 // the VSOURCE value met or exceeded its programmed high limit
647 vsrc_high = buf & (1 << 6);
648 // the VSENSE value met or exceeded its programmed high limit.
649 vsense_high = buf & (1 << 7);
650 etl::vector<bool, 4> v = {i_high, e_high, vsrc_high, vsense_high};
651 return v;
652}
653
654etl::vector<bool, 4>
655emc1702::get_low_limit_status() const
656{
657 // Get the status bits that are set when a temperature or voltage channel low
658 // limit is met or exceeded.
659 uint8_t buf;
660 bool i_low;
661 bool e_low;
662 bool vsrc_low;
663 bool vsense_low;
664 m_i2c.read(m_addr, REG_LOW_LIMIT_STATUS, &buf, 1);
665 // The Internal Diode channel dropped below its programmed low limit
666 i_low = (buf & 0b01);
667 // The External Diode channel dropped below its programmed low limit
668 e_low = (buf & 0b10);
669 // the VSOURCE value dropped below its programmed low limit
670 vsrc_low = buf & (1 << 6);
671 // the VSENSE value dropped below its programmed low limit
672 vsense_low = buf & (1 << 7);
673 etl::vector<bool, 4> v = {i_low, e_low, vsrc_low, vsense_low};
674 return v;
675}
676
677bool
678emc1702::get_crit_limit_status() const
679{
680 // Get the status bits that are set when a temperature or voltage channel
681 // critical limit is met or exceeded.
682 uint8_t buf;
683 bool i_crit;
684 bool e_crit;
685 bool vsrc_crit;
686 bool vsense_crit;
687 m_i2c.read(m_addr, REG_CRIT_LIMIT_STATUS, &buf, 1);
688 // The Internal Diode channel met or exceeded its programmed critical limit
689 i_crit = (buf & 0b01);
690 // The External Diode channel met or exceeded its programmed critical limit
691 e_crit = (buf & 0b10);
692 // the VSOURCE value met or exceeded its programmed critical limit
693 vsrc_crit = buf & (1 << 6);
694 // the VSENSE value met or exceeded its programmed critical limit.
695 vsense_crit = buf & (1 << 7);
696 // IF ANY OF THE PREVIOUS VALUES ARE TRU THE THERM PIN WILL BE ASERTED
697 bool thermal_shutdown_needed = (i_crit || e_crit || vsrc_crit || vsense_crit);
698 return thermal_shutdown_needed;
699}
700
701void
702emc1702::set_averaging_control(averaging_control a) const
703{
704 uint8_t buf;
705 // Set averaging control
706 switch (a) {
711 buf = static_cast<uint8_t>(a);
712 m_i2c.write(m_addr, REG_AVERAGING_CONTROL, &buf, 1);
713 break;
714 default:
715 throw inval_arg_exception(__FILE__, __LINE__);
716 break;
717 }
718 return;
719}
720
721bool
722emc1702::get_sensor_info() const
723{
724 // Get sensor data
725 uint8_t buf[4] = {0, 0, 0, 0};
726 bool ok = false;
727 // Get Product Features
728 m_i2c.read(m_addr, REG_PRODUCT_FEATURES, buf, 4);
729 if ((buf[1] == 0b00111001) && (buf[2] == 0b01011101) &&
730 (buf[3] == 0b10000010)) {
731 ok = true;
732 }
733 return ok;
734}
735
736void
737emc1702::set_voltage_sampling_config(consecutive_alert_voltage v,
738 averaging_control s) const
739{
740 uint8_t buf;
741 switch (v) {
746 buf = static_cast<uint8_t>(v);
747 break;
748 default:
749 throw inval_arg_exception(__FILE__, __LINE__);
750 }
751
752 switch (s) {
757 buf |= static_cast<uint8_t>(s);
758 m_i2c.write(m_addr, VOLTAGE_SAMPLING_CONFIG, &buf, 1);
759 break;
760 default:
761 throw inval_arg_exception(__FILE__, __LINE__);
762 }
763 return;
764}
765
766void
767emc1702::set_current_sense_sampling_config(consecutive_alert_current v,
768 averaging_control i,
769 current_sampling_time t,
770 max_expected_voltage m) const
771{
772 uint8_t buf;
773 switch (v) {
778 buf = static_cast<uint8_t>(v);
779 break;
780 default:
781 throw inval_arg_exception(__FILE__, __LINE__);
782 }
783 switch (i) {
788 buf |= (static_cast<uint8_t>(i) << 4);
789 break;
790 default:
791 throw inval_arg_exception(__FILE__, __LINE__);
792 }
793 switch (t) {
797 buf |= static_cast<uint8_t>(t);
798 break;
799 default:
800 throw inval_arg_exception(__FILE__, __LINE__);
801 }
802 switch (m) {
807 buf |= static_cast<uint8_t>(m);
808 m_i2c.write(m_addr, CURRENT_SENSE_SAMPLING_CONFIG, &buf, 1);
809 break;
810 default:
811 throw inval_arg_exception(__FILE__, __LINE__);
812 }
813 return;
814}
815
816void
817emc1702::set_peak_detection_config(peak_detection_threshold t,
818 peak_detection_duration d)
819{
820 uint8_t buf;
821 switch (t) {
838 buf = static_cast<uint8_t>(t);
839 break;
840 default:
841 throw inval_arg_exception(__FILE__, __LINE__);
842 }
843
844 switch (d) {
861 buf |= static_cast<uint8_t>(d);
862 m_i2c.write(m_addr, PEAK_DETECTION_CONFIG, &buf, 1);
863 break;
864 default:
865 throw inval_arg_exception(__FILE__, __LINE__);
866 }
867 return;
868}
869
870float
871emc1702::get_fsc() const
872{
873 uint8_t buf1;
874 float fsr;
875 m_i2c.read(m_addr, CURRENT_SENSE_SAMPLING_CONFIG, &buf1, 1);
876 uint8_t r = (buf1 & 0b11);
877 max_expected_voltage range = static_cast<max_expected_voltage>(r);
878 switch (range) {
880 fsr = 0.01;
881 break;
883 fsr = 0.02;
884 break;
886 fsr = 0.04;
887 break;
889 fsr = 0.08;
890 break;
891 default:
892 fsr = 0;
893 break;
894 }
895 float fsc = fsr / r_sense;
896 return fsc;
897}
898
904float
906{
907 if (!m_ready) {
908 throw emc1702_inval(__FILE__, __LINE__);
909 }
910 uint8_t buf[2];
911 bool sign;
912 m_i2c.read(m_addr, SENCE_VOLTAGE_HIGH_BYTE, buf, 2);
913 int16_t bit_value = ((buf[0] << 8) | buf[1]) >> 4;
914 sign = (bit_value >> 11) != 0;
915 if (sign) {
916 bit_value = ~bit_value + 1;
917 }
918 return (get_fsc() * bit_value / 2047.0f);
919 // L1 data (in A)
920}
921
927float
929{
930 if (!m_ready) {
931 throw emc1702_inval(__FILE__, __LINE__);
932 }
933 uint8_t buf[2];
934 m_i2c.read(m_addr, SOURCE_VOLTAGE_HIGH_BYTE, buf, 2);
935 int16_t bit_value = ((buf[0] << 8) | buf[1]) >> 5;
936 float source_voltage = fsv * bit_value / 2047.0f;
937 return source_voltage;
938 // L1 data (in V)
939}
940
941float
943{
944 if (!m_ready) {
945 throw emc1702_inval(__FILE__, __LINE__);
946 }
947 uint8_t buf[2] = {0, 0};
948 m_i2c.read(m_addr, POWER_RATIO_VOLTAGE_HIGH_BYTE, buf, 2);
949 uint16_t bit_value = ((buf[0] << 8) | buf[1]);
950 return (get_fsc() * fsv * bit_value / 65535.0f);
951 // L1 data (Power in W)
952}
953
954void
955emc1702::set_v_sense_lim(float v_sense_lim_low, float v_sense_lim_high) const
956{
957 // Set Sense Voltage Limit Registers
958 // Set low limit
959 uint8_t buf = 0;
960 if (v_sense_lim_low >= 2032.0f) {
961 buf = 0b01111111;
962 } else if (v_sense_lim_low <= -2033.0f) {
963 buf = 0b10000000;
964 } else {
965 if (v_sense_lim_low >= 0) {
966 buf =
967 static_cast<uint8_t>(floor((v_sense_lim_low / 16.0f) + 0.5f) * 16.0f);
968 } else {
969 buf =
970 static_cast<uint8_t>(floor((v_sense_lim_low / 16.0f) + 0.5f) * 16.0f);
971 buf = ~buf;
972 buf++;
973 }
974 }
975 m_i2c.write(m_addr, SENCE_VOLTAGE_LOW_LIM, &buf, 1);
976 // Set high limit
977 if (v_sense_lim_high >= 2032.0f) {
978 buf = 0b01111111;
979 } else if (v_sense_lim_high <= -2033.0f) {
980 buf = 0b10000000;
981 } else {
982 if (v_sense_lim_high >= 0.0f) {
983 buf = static_cast<uint8_t>(floor((v_sense_lim_high / 16.0f) + 0.5f) *
984 16.0f);
985 } else {
986 buf = static_cast<uint8_t>(floor((v_sense_lim_high / 16.0f) + 0.5f) *
987 16.0f);
988 buf = ~buf;
989 buf++;
990 }
991 }
992 m_i2c.write(m_addr, SENCE_VOLTAGE_HIGH_LIM, &buf, 1);
993}
994
995void
996emc1702::set_v_source_lim(float v_source_lim_low, float v_source_lim_high) const
997{
998 uint8_t buf[2] = {0, 0};
999 if (v_source_lim_low < 0) {
1000 throw inval_arg_exception(__FILE__, __LINE__);
1001 } else if (v_source_lim_low >= 23.9063f) {
1002 buf[1] = 0b11111111;
1003 } else {
1004 buf[1] = static_cast<uint8_t>(round(v_source_lim_low * 10.67f));
1005 }
1006 if (v_source_lim_high < 0) {
1007 throw inval_arg_exception(__FILE__, __LINE__);
1008 } else if (v_source_lim_high >= 23.9063f) {
1009 buf[0] = 0b11111111;
1010 } else {
1011 buf[0] = static_cast<uint8_t>(round(v_source_lim_high * 10.67f));
1012 }
1013 m_i2c.write(m_addr, SOURCE_VOLTAGE_HIGH_LIM, buf, 2);
1014}
1015
1016void
1017emc1702::set_v_crit_lim(float v_sense_lim_crit, float v_source_lim_crit,
1018 float v_sense_hysterisis,
1019 float v_source_hysterisis) const
1020{
1021 // Set Critical Voltage Limit Registers
1022 uint8_t buf = 0;
1023 if (v_sense_lim_crit >= 2032.0f) {
1024 buf = 0b01111111;
1025 } else if (v_sense_lim_crit <= -2033.0f) {
1026 buf = 0b10000000;
1027 } else {
1028 if (v_sense_lim_crit >= 0.0f) {
1029 buf = static_cast<uint8_t>(floor((v_sense_lim_crit / 16.0f) + 0.5f) *
1030 16.0f);
1031 } else {
1032 buf = static_cast<uint8_t>(floor((v_sense_lim_crit / 16.0f) + 0.5f) *
1033 16.0f);
1034 buf = ~buf;
1035 buf++;
1036 }
1037 }
1038 m_i2c.write(m_addr, SENCE_VOLTAGE_V_CRIT, &buf, 1);
1039
1040 if (v_sense_hysterisis >= 496.0f) {
1041 buf = 0b00011111;
1042 } else if (v_sense_hysterisis < 0.0f) {
1043 throw inval_arg_exception(__FILE__, __LINE__);
1044 } else {
1045 buf = static_cast<uint8_t>(floor((v_sense_hysterisis / 16.0f) + 0.5f) *
1046 16.0f);
1047 }
1048 m_i2c.write(m_addr, SENSE_V_CRIT_HYSTERISIS, &buf, 1);
1049
1050 if (v_source_lim_crit < 0.0f) {
1051 throw inval_arg_exception(__FILE__, __LINE__);
1052 } else if (v_source_lim_crit >= 23.9063f) {
1053 buf = 0b11111111;
1054 } else {
1055 buf = static_cast<uint8_t>(round(v_source_lim_crit * 10.67f));
1056 }
1057 m_i2c.write(m_addr, SOURCE_VOLTAGE_V_CRIT, &buf, 1);
1058 if (v_source_hysterisis < 0.0f) {
1059 throw inval_arg_exception(__FILE__, __LINE__);
1060 } else if (v_source_hysterisis >= 2.9063f) {
1061 buf = 0b00011111;
1062 } else {
1063 buf = static_cast<uint8_t>(round(v_source_hysterisis * 10.67f));
1064 }
1065 m_i2c.write(m_addr, SOURCE_V_CRIT_HYSTERISIS, &buf, 1);
1066}
1067
1068bool
1070{
1071 if (!m_ready) {
1072 throw emc1702_inval(__FILE__, __LINE__);
1073 }
1074 return m_alert.get();
1075}
1076
1077} // namespace satnogs::comms::lib
GPIO device abstraction.
Definition gpio.hpp:38
I2C device abstraction.
Definition i2c.hpp:40
virtual void read(uint16_t addr, uint8_t *rx, size_t rxlen, const uint8_t *tx, size_t txlen)=0
Performs an I2C read operation.
virtual void write(uint16_t addr, const uint8_t *tx, size_t len)=0
Performs an I2C write operation.
Exception thrown when the EMC1702 has not be initialized properly.
Definition emc1702.hpp:546
Exception thrown when a thermal shutdown is required.
Definition emc1702.hpp:487
ideality_factor
Settings to set the Ideality Factor in the External Diode Ideality Factor Registers.
Definition emc1702.hpp:229
float get_sense_current() const
Retrieves current measurement from the EMC1702 sensor.
Definition emc1702.cpp:905
float get_temperature_average() const
Retrieves temperature from the EMC1702 sensor by averaging the internal and external diode measuremen...
Definition emc1702.cpp:278
averaging_control
Settings to set the digital averaging on mesurements in the Averaging Control Register,...
Definition emc1702.hpp:251
sensor_mode
Selects the mode of operation of the EMC1702 sensor.
Definition emc1702.hpp:93
conversion_rate
Settings to set the frequency of measurements in the Conversion Rate Register.
Definition emc1702.hpp:109
void get_status(status &s)
Definition emc1702.cpp:328
consecutive_alert_voltage
Settings to set the threshold for consecutive voltage out-of-limit measurements in the Voltage Sampli...
Definition emc1702.hpp:146
emc1702(const char *name, bsp::i2c &i2c, uint16_t addr, bsp::gpio &alert)
Constructs an EMC1702 sensor object with an ALERT GPIO pin.
Definition emc1702.cpp:135
current_sampling_time
Settings to set the Current Sensing Sampling Time in the Current Sense Sampling Configuration Registe...
Definition emc1702.hpp:270
static constexpr float fsv
Full Scale Voltage in volts.
Definition emc1702.hpp:69
static constexpr float r_sense
External sense resistor value in Ohms.
Definition emc1702.hpp:74
max_expected_voltage
Settings to set the Current Sense maximum expected voltage (full scale range) in the Current Sense Sa...
Definition emc1702.hpp:281
consecutive_alert_current
Settings to set the threshold for consecutive current out-of-limit measurements in the Current Sense ...
Definition emc1702.hpp:162
float get_source_voltage() const
Retrieves source voltage measurement from the EMC1702 sensor.
Definition emc1702.cpp:928
peak_detection_duration
Settings to set the peak detector minimum time threshold in the Peak Detection Configuration Register...
Definition emc1702.hpp:318
peak_detection_threshold
Settings to set the peak detector threshold level in the Peak Detection Configuration Register.
Definition emc1702.hpp:294
beta_config
Settings to set the Beta Compensation factor in the Beta Configuration Registers.
Definition emc1702.hpp:192
void set_config(sensor_mode m) const
Definition emc1702.cpp:353
consecutive_alert_diode_fault
Settings to set the threshold for consecutive diode fault alerts in the Consecutive Alert Register.
Definition emc1702.hpp:130
Generic exception indicating an invalid argument.
#define POWER_RATIO_VOLTAGE_HIGH_BYTE
Definition emc1702.cpp:71
#define REG_INTERNAL_DIODE_HIGH_LIM
Definition emc1702.cpp:45
#define REG_EXTERNAL_DIODE_TCRIT_LIM
Definition emc1702.cpp:51
#define VOLTAGE_SAMPLING_CONFIG
Definition emc1702.cpp:64
#define REG_STATUS
Definition emc1702.cpp:34
#define SOURCE_VOLTAGE_HIGH_BYTE
Definition emc1702.cpp:69
#define SOURCE_VOLTAGE_HIGH_LIM
Definition emc1702.cpp:75
#define PEAK_DETECTION_CONFIG
Definition emc1702.cpp:66
#define REG_CRIT_LIMIT_STATUS
Definition emc1702.cpp:37
#define REG_TCRIT_HYSTERISIS
Definition emc1702.cpp:54
#define REG_CONVERSION_RATE
Definition emc1702.cpp:44
#define SENCE_VOLTAGE_LOW_LIM
Definition emc1702.cpp:74
#define REG_AVERAGING_CONTROL
Definition emc1702.cpp:42
#define REG_TCRIT_CONSECUTIVE_ALERT
Definition emc1702.cpp:55
#define REG_EXTERNAL_DIODE_BETA_CONFIG
Definition emc1702.cpp:56
#define SENSE_V_CRIT_HYSTERISIS
Definition emc1702.cpp:79
#define REG_EXTERNAL_DIODE_HIGH_LIM_HIGH_BYTE
Definition emc1702.cpp:47
#define SENCE_VOLTAGE_HIGH_LIM
Definition emc1702.cpp:73
#define REG_HIGH_LIMIT_STATUS
Definition emc1702.cpp:35
#define REG_INTERNAL_DIODE_HIGH_BYTE
Definition emc1702.cpp:38
#define REG_EXTERNAL_DIODE_IDEALITY_FACTOR
Definition emc1702.cpp:57
#define REG_INTERNAL_DIODE_TCRIT_LIM
Definition emc1702.cpp:53
#define REG_PRODUCT_FEATURES
Definition emc1702.cpp:60
#define REG_EXTERNAL_DIODE_HIGH_BYTE
Definition emc1702.cpp:40
#define SENCE_VOLTAGE_V_CRIT
Definition emc1702.cpp:77
#define REG_ONE_SHOT
Definition emc1702.cpp:58
#define REG_EXTERNAL_DIODE_FAULT
Definition emc1702.cpp:59
#define REG_EXTERNAL_DIODE_LOW_LIM_HIGH_BYTE
Definition emc1702.cpp:48
#define REG_INTERNAL_DIODE_LOW_LIM
Definition emc1702.cpp:46
#define SOURCE_VOLTAGE_V_CRIT
Definition emc1702.cpp:78
#define SOURCE_V_CRIT_HYSTERISIS
Definition emc1702.cpp:80
#define SENCE_VOLTAGE_HIGH_BYTE
Definition emc1702.cpp:67
#define REG_LOW_LIMIT_STATUS
Definition emc1702.cpp:36
#define CURRENT_SENSE_SAMPLING_CONFIG
Definition emc1702.cpp:65
#define REG_CONFIGURATION
Definition emc1702.cpp:43
uint8_t buf[chunk_bytes]