From dfd583180f96e5394b6d77264bd2e93000168e9a Mon Sep 17 00:00:00 2001
From: Christos Gentsos <christos.gentsos@cern.ch>
Date: Tue, 12 Oct 2021 16:31:23 +0200
Subject: [PATCH] I2C: Clear error bit on bus error, add STATUS_BYTE and
 STATUS_CML

When a bus error happened, the I2C peripheral's error bit remained
set. This caused it to respond erroneously in future transactions.

Now, when a bus error occurs, we're clearing the error bit and setting
the error flags in the STATUS_BYTE and STATUS_CML PMBus registers.
After the user reads those registers (using commands 0x78 and 0x7E),
their error flags are cleared.
---
 bootloader/src/main.c  |  2 ++
 common/src/i2c_slave.c | 16 ++++++++++--
 main_fw/src/i2c_impl.c | 59 ++++++++++++++++++++++++++++--------------
 main_fw/src/main.c     |  2 ++
 4 files changed, 57 insertions(+), 22 deletions(-)

diff --git a/bootloader/src/main.c b/bootloader/src/main.c
index d2a0944..253e0f9 100644
--- a/bootloader/src/main.c
+++ b/bootloader/src/main.c
@@ -12,6 +12,8 @@ extern cmd_space_t cmds;
 //! Our custom commmands structure
 extern cmd_space_t ext_cmds;
 
+uint8_t status_b;
+
 int main(void)
 {
         system_init();
diff --git a/common/src/i2c_slave.c b/common/src/i2c_slave.c
index ef1eb75..3f07208 100644
--- a/common/src/i2c_slave.c
+++ b/common/src/i2c_slave.c
@@ -36,6 +36,9 @@ static uint16_t added_tx_pec __xMR = 0;
 static uint16_t sent_checksum __xMR = 0;
 static uint8_t tx_tmp;
 
+extern uint8_t status_b;
+uint8_t status_cml;
+
 int16_t in_addr_space(cmd_space_t *addr_space, uint8_t addr)
 {
         for (uint8_t i = 0; i < addr_space->n_cmds; ++i)
@@ -179,8 +182,11 @@ static void __xMR I2C_rx_complete(const struct i2c_s_async_descriptor *const des
                         send_ack(descr);
                         if (cmds->cmds[cmd_index].w_callback)
                                 cmds->cmds[cmd_index].w_callback();
-                } else
+                } else {
+                        status_b |= 0x01;
+                        status_cml = 0x20; // PEC error
                         send_nack(descr);
+                }
                 set_cmd(descr, 2);
                 rx_state = CMD;
                 break;
@@ -190,8 +196,11 @@ static void __xMR I2C_rx_complete(const struct i2c_s_async_descriptor *const des
                         send_ack(descr);
                         if (ext_cmds->cmds[cmd_index].w_callback)
                                 ext_cmds->cmds[cmd_index].w_callback();
-                } else
+                } else {
+                        status_b |= 0x01;
+                        status_cml = 0x20; // PEC error
                         send_nack(descr);
+                }
                 set_cmd(descr, 2);
                 rx_state = CMD;
                 break;
@@ -280,6 +289,9 @@ static void __xMR I2C_tx_complete(const struct i2c_s_async_descriptor *const des
 /*! we get here when something bad has happened */
 static void __xMR I2C_error(const struct i2c_s_async_descriptor *const descr)
 {
+        status_b |= 0x01;
+        status_cml = 0x02; // Other comm fault
+        hri_sercomi2cs_clear_INTFLAG_ERROR_bit(descr->device.hw);
         set_cmd(descr, 2);
 }
 
diff --git a/main_fw/src/i2c_impl.c b/main_fw/src/i2c_impl.c
index 08a9947..b3e6caf 100644
--- a/main_fw/src/i2c_impl.c
+++ b/main_fw/src/i2c_impl.c
@@ -32,6 +32,11 @@ extern uint16_t use_pec __xMR;
 uint8_t use_pec_tmp;
 void set_pec();
 
+void read_status_b();
+void read_status_cml();
+extern uint8_t status_b;
+extern uint8_t status_cml;
+
 void accvolt();
 void acccurr();
 void accpowr();
@@ -85,6 +90,8 @@ extern uint16_t fan_ppr[3] __xMR;
 static const int8_t cmd_data_lengths[] = {
         1,                         // 0x00
         -1,                        // 0x1A
+        1,                         // 0x78
+        1,                         // 0x7E
         2,                         // 0x8B
         2,                         // 0x8C
         2,                         // 0x8D
@@ -112,26 +119,28 @@ static int8_t cmd_data_length_query = -1;
 static cmd_t cmds_cmds[] = (cmd_t[]){
         {0x00, (int8_t *)&cmd_data_lengths[0], (uint8_t *)&page_tmp,     (fp_t)NULL, &page_chk,  (fp_t)NULL, QUERY_WR | QUERY_RD | QUERY_FMT_8B, 0},
         {0x1A, (int8_t *)&cmd_data_length_query, (uint8_t *)&query_r,  (fp_t)NULL, &query_prp, (fp_t)NULL, QUERY_SUP, 1},
-        {0x8B, (int8_t *)&cmd_data_lengths[2], (uint8_t *)&curpage_volt, &accvolt, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
-        {0x8C, (int8_t *)&cmd_data_lengths[3], (uint8_t *)&curpage_curr, &acccurr, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
-        {0x8D, (int8_t *)&cmd_data_lengths[4], (uint8_t *)&temps_lin[0], (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
-        {0x8E, (int8_t *)&cmd_data_lengths[5], (uint8_t *)&temps_lin[1], (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
-        {0x8F, (int8_t *)&cmd_data_lengths[6], (uint8_t *)&temps_lin[2], (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
-        {0x90, (int8_t *)&cmd_data_lengths[7], (uint8_t *)&frpms_lin[0], (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
-        {0x91, (int8_t *)&cmd_data_lengths[8], (uint8_t *)&frpms_lin[1], (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
-        {0x92, (int8_t *)&cmd_data_lengths[9], (uint8_t *)&frpms_lin[2], (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
-        {0x96, (int8_t *)&cmd_data_lengths[10], (uint8_t *)&curpage_powr, &accpowr, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
-        {0x99, (int8_t *)&cmd_data_lengths[11], (uint8_t *)&MFR_ID,   (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_NAN, 0},
-        {0x9A, (int8_t *)&cmd_data_lengths[12], (uint8_t *)&MFR_MDL,  (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_NAN, 0},
-        {0x9B, (int8_t *)&cmd_data_lengths[13], (uint8_t *)&MFR_REV,  (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_NAN, 0},
-        {0x9C, (int8_t *)&cmd_data_lengths[14], (uint8_t *)&MFR_LOC,  (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_NAN, 0},
-        {0x9D, (int8_t *)&cmd_data_lengths[15], (uint8_t *)&MFR_DAT,  (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_NAN, 0},
-        {0x9E, (int8_t *)&cmd_data_lengths[16], (uint8_t *)&MFR_SER,  (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_NAN, 0},
-        {0x3A, (int8_t *)&cmd_data_lengths[17], (uint8_t *)&fan_config_1_2, (fp_t)NULL, &fan_config, (fp_t)NULL, QUERY_WR | QUERY_FMT_NAN, 0},
-        {0x3B, (int8_t *)&cmd_data_lengths[18], (uint8_t *)&setfrpms_lin[0], (fp_t)NULL, &set_frpms, (fp_t)NULL, QUERY_WR | QUERY_FMT_LIN, 0},
-        {0x3C, (int8_t *)&cmd_data_lengths[19], (uint8_t *)&setfrpms_lin[1], (fp_t)NULL, &set_frpms, (fp_t)NULL, QUERY_WR | QUERY_FMT_LIN, 0},
-        {0x3D, (int8_t *)&cmd_data_lengths[20], (uint8_t *)&fan_config_3_4, (fp_t)NULL, &fan_config, (fp_t)NULL, QUERY_WR | QUERY_FMT_NAN, 0},
-        {0x3E, (int8_t *)&cmd_data_lengths[21], (uint8_t *)&setfrpms_lin[2], (fp_t)NULL, &set_frpms, (fp_t)NULL, QUERY_WR | QUERY_FMT_LIN, 0}};
+        {0x78, (int8_t *)&cmd_data_lengths[2], (uint8_t *)&status_b, (fp_t)NULL, (fp_t)NULL, &read_status_b, QUERY_RD, 0},
+        {0x7E, (int8_t *)&cmd_data_lengths[3], (uint8_t *)&status_cml, (fp_t)NULL, (fp_t)NULL, &read_status_cml, QUERY_RD, 0},
+        {0x8B, (int8_t *)&cmd_data_lengths[4], (uint8_t *)&curpage_volt, &accvolt, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
+        {0x8C, (int8_t *)&cmd_data_lengths[5], (uint8_t *)&curpage_curr, &acccurr, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
+        {0x8D, (int8_t *)&cmd_data_lengths[6], (uint8_t *)&temps_lin[0], (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
+        {0x8E, (int8_t *)&cmd_data_lengths[7], (uint8_t *)&temps_lin[1], (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
+        {0x8F, (int8_t *)&cmd_data_lengths[8], (uint8_t *)&temps_lin[2], (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
+        {0x90, (int8_t *)&cmd_data_lengths[9], (uint8_t *)&frpms_lin[0], (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
+        {0x91, (int8_t *)&cmd_data_lengths[10], (uint8_t *)&frpms_lin[1], (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
+        {0x92, (int8_t *)&cmd_data_lengths[11], (uint8_t *)&frpms_lin[2], (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
+        {0x96, (int8_t *)&cmd_data_lengths[12], (uint8_t *)&curpage_powr, &accpowr, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_LIN, 0},
+        {0x99, (int8_t *)&cmd_data_lengths[13], (uint8_t *)&MFR_ID,   (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_NAN, 0},
+        {0x9A, (int8_t *)&cmd_data_lengths[14], (uint8_t *)&MFR_MDL,  (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_NAN, 0},
+        {0x9B, (int8_t *)&cmd_data_lengths[15], (uint8_t *)&MFR_REV,  (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_NAN, 0},
+        {0x9C, (int8_t *)&cmd_data_lengths[16], (uint8_t *)&MFR_LOC,  (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_NAN, 0},
+        {0x9D, (int8_t *)&cmd_data_lengths[17], (uint8_t *)&MFR_DAT,  (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_NAN, 0},
+        {0x9E, (int8_t *)&cmd_data_lengths[18], (uint8_t *)&MFR_SER,  (fp_t)NULL, (fp_t)NULL, (fp_t)NULL, QUERY_RD | QUERY_FMT_NAN, 0},
+        {0x3A, (int8_t *)&cmd_data_lengths[19], (uint8_t *)&fan_config_1_2, (fp_t)NULL, &fan_config, (fp_t)NULL, QUERY_WR | QUERY_FMT_NAN, 0},
+        {0x3B, (int8_t *)&cmd_data_lengths[20], (uint8_t *)&setfrpms_lin[0], (fp_t)NULL, &set_frpms, (fp_t)NULL, QUERY_WR | QUERY_FMT_LIN, 0},
+        {0x3C, (int8_t *)&cmd_data_lengths[21], (uint8_t *)&setfrpms_lin[1], (fp_t)NULL, &set_frpms, (fp_t)NULL, QUERY_WR | QUERY_FMT_LIN, 0},
+        {0x3D, (int8_t *)&cmd_data_lengths[22], (uint8_t *)&fan_config_3_4, (fp_t)NULL, &fan_config, (fp_t)NULL, QUERY_WR | QUERY_FMT_NAN, 0},
+        {0x3E, (int8_t *)&cmd_data_lengths[23], (uint8_t *)&setfrpms_lin[2], (fp_t)NULL, &set_frpms, (fp_t)NULL, QUERY_WR | QUERY_FMT_LIN, 0}};
 
 cmd_space_t cmds = {
         sizeof(cmds_cmds)/sizeof(cmd_t),
@@ -239,6 +248,16 @@ void __xMR set_pec()
         use_pec = use_pec_tmp;
 }
 
+void read_status_b()
+{
+        status_b &= 0xFE;
+}
+
+void read_status_cml()
+{
+        status_cml = 0;
+}
+
 #if defined(MMFANT) || defined(MMPROT)
 
 void __xMR fan_config()
diff --git a/main_fw/src/main.c b/main_fw/src/main.c
index 46bb4d3..9fff074 100644
--- a/main_fw/src/main.c
+++ b/main_fw/src/main.c
@@ -127,6 +127,8 @@ float temps[3];
 float volts[4];
 float currs[3];
 
+uint8_t status_b;
+
 uint16_t trig_adc_next_second __xMR = 0;
 
 #if defined(MMFANT) || defined(MMPROT)
-- 
GitLab