smart sensor code initial version

Dependencies:   mbed-src-KL05Z-smart-sensor

Revision:
1:587e0346abca
Parent:
0:10bf1bb6d2b5
Child:
2:5dacfd690a75
--- a/kl05-smart-sensor.cpp	Tue Mar 26 10:37:02 2019 +0000
+++ b/kl05-smart-sensor.cpp	Tue Mar 26 10:41:49 2019 +0000
@@ -14,15 +14,75 @@
 *
 ****************************************************************************************/
 
+/****************************************************************************************
+* Add a uart trace instead of I2C
+* For the uart trace:
+*   * add a timestamp (returns the timestamp of the current measure)
+*   * do not average the measures:
+*       + add a paramter to the existing function to set the number of samples to be
+*           averaged (I2C legacy)
+*   * set to 0 the different settling time:
+*       + do not see dysfunction so far for the FET settling time neither for the voltage
+*           divider
+*       + do not see the need in case of the voltage or current measurement. It is
+*           mentionned that this is for the B2902A settling time, so i guess this when the
+*           SMU is used. It should not be the case by default anyway!
+*
+* Use few defines to instrument the code as below:
+*
+* | USEI2CNOTUART  |  DEBUG  |  TRACEPRINT  |  BUFFMEASURES  | comment
+* | 1              |  0      |  0           |  0             | legacy mode - modify the KL25Z code to output the sensor number, voltage and current information
+* | 0              |  0      |  0           |  0             | uart trace: print thru the uart console the result of the measures: timestamp, voltage, current
+* | 0              |  0      |  1           |  0             | same as above but print also the time consumes to print those data!
+* | 0              |  1      |  0           |  0             | uart trace: print thru the uart console many measures (see define below) but impact the sampling rate
+* | 0              |  1      |  1           |  0             | same as above but uprint also the time consumes to print those data!
+* | 0              |  0      |  0           |  1             | use a buffer to store the measures and print the entire buffer one it is full; improve the sampling rate but the buffer size is limited
+*
+****************************************************************************************/
 #include <mbed.h>
 
+// Select the I2C trace or the uart trace for debug
 #define USEI2CNOTUART 0
 
+// Custom setup in case of I2C
+#define I2CCUSTOM 0
+
+// If BUFFMEASURES == 1 : fill up a buffer of measures (timestamp, vdd & current only) and then send the whole buffer thru the uart console & loop
+//                          * buffer size is limited to the 4k of RAM (1 measure of timestamp or volt or current is a float, each of 4 bytes)
+#define BUFFMEASURES 0
+
+// If TRACEPRINT == 1 : trace the time comnsumes by the printf to the uart console
+#define TRACEPRINT 1
+
+// If DEBUG == 1 : do not buffer the measures but send the measures thru the uart console (measures duration (volt + current), sensor number, timestamps, voltage, current, high current, mid current, low current
+#define DEBUG 1
+
 // set things up...
 #if (USEI2CNOTUART == 1) 
 I2CSlave slave(PTB4, PTB3);
+#if (I2CCUSTOM == 1)
+int n_meas=1; // number of averages when measuring...
+#else
+int n_meas=25; // number of averages when measuring...
+#endif
 #else
 Serial uart(PTB3, PTB4); // tx, rx
+int n_meas=1; // number of averages when measuring...
+Timer timer; // I2C trace isn't prototype with timestamp
+float timestamp;
+#endif
+
+#if (BUFFMEASURES == 1)
+// Define BUFFERSIZE to 250
+//   * 250 * 3 (float) * 4 (4 bytes for each float) = 3000 bytes almost 3kBytes out of the 4
+#define BUFFERSIZE 200
+
+// buffer to store timestamp, voltage & current
+float buffer[BUFFERSIZE][3];
+#endif
+
+#ifndef BUFFERSIZE
+#define BUFFERSIZE 0
 #endif
 
 // These will be used for identifying smart sensor build options:
@@ -47,7 +107,8 @@
 DigitalOut LOW1(PTB2);          // turns on Q5, turning off Q2, disconnecting shunt R1
 DigitalOut LOW2(PTB1);          // turns on Q6, turning off Q3, disconnecting shunt R2
 
-
+//VB
+//DigitalOut OPT3(PTB13);
 
 // set initial, default I2C listening address...
 // same one for all sensors so we don't need to individually program each one...
@@ -69,32 +130,41 @@
      int ival;
    } u, v;
 
-//union u_current {
-//  float high;
-//  float mid;
-//  float low;
-//} current;
-float current[3];
 
 // define measurement result and status variables...
 float measurement1;
 float measurement2;
 char status=0;
-//int n_meas=25; // number of averages when measuring...
-int n_meas=1; // number of averages when measuring...
+
 float vref =3.3;
 float factor_H  = vref / 0.8;
 float factor_L1 = vref / (0.05 * 1000);
 float factor_L2 = vref / (2 * 1000);
 
+#if (USEI2CNOTUART == 1)
+#if (I2CCUSTOM == 1)
+int wait_mbbb = 0;
+int wait_high = 0;
+int wait_low1 = 0;
+int wait_low2 = 0;
+int wait_vrail = 0;
+#else
 int wait_mbbb = 5;
 int wait_high = 250;
 int wait_low1 = 250;
 int wait_low2 = 500;
 int wait_vrail = 200;
+#endif
+#else
+int wait_mbbb = 5;//VB
+int wait_high = 250;//VB
+int wait_low1 = 250;//VB
+int wait_low2 = 500;//VB
+int wait_vrail = 200;//VB
+#endif
 
-Timer timer;
-float timestamp;
+// Store the 3 current sensors' value
+float current[3];
 
 /***********************************************************************************
 *
@@ -104,30 +174,43 @@
 
 void enableHighRange(){
     LOW_ENABLE = 0;     // short both low current shunts, close Q1
+//VB    #if (USEI2CNOTUART == 1 && CUSTOM == 0)
     wait_us(wait_mbbb);         // delay for FET to settle... (make before break)
+//VB    #endif
     LOW1 = 0; LOW2 = 0; // connect both shunts to make lower series resistance
-    VRAIL_MEAS = 0;     // disconnect rail voltage divider    
+    VRAIL_MEAS = 0;     // disconnect rail voltage divider 
+//VB    #if (USEI2CNOTUART == 1 && CUSTOM == 0)   
     wait_us(wait_high);       // wait for B2902A settling... 
+//VB    #endif
 }
 
 void enableLow1Range(){
     LOW1 = 0; LOW2 = 1; // disconnect LOW2 shunt so LOW1 can measure
+//VB    #if (USEI2CNOTUART == 1 && CUSTOM == 0)
     wait_us(wait_mbbb);         // delay for FET to settle... (make before break)
+//VB    #endif
     LOW_ENABLE = 1;     // unshort low current shunts, open Q1
     VRAIL_MEAS = 0;     // disconnect rail voltage divider
+//VB    #if (USEI2CNOTUART == 1 && CUSTOM == 0)
     wait_us(wait_low1);       // wait for B2902A settling...
+//VB    #endif
 }
 
 void enableLow2Range(){
     LOW1 = 1; LOW2 = 0; // disconnect LOW1 shunt so LOW2 can measure
+//VB    #if (USEI2CNOTUART == 1 && CUSTOM == 0)
     wait_us(wait_mbbb);         // delay for FET to settle... (make before break)
+//VB    #endif
     LOW_ENABLE = 1;     // unshort low current shunts, open Q1
     VRAIL_MEAS = 0;     // disconnect rail voltage divider    
+//VB    #if (USEI2CNOTUART == 1 && CUSTOM == 0)
     wait_us(wait_low2);       // wait for B2902A settling...
+//VB    #endif
 }
 
 void enableRailV(){
     VRAIL_MEAS = 1;     // turn on Q7, to enable R3-R4 voltage divider    
+//VB    #if (USEI2CNOTUART == 1 && CUSTOM == 0)
     wait_us(wait_vrail);       // wait for divider to settle... 
                         // Compensation cap can be used to make 
                         // voltage at ADC a "square wave" but it is
@@ -140,6 +223,7 @@
                         // because of the depletion region changes in the 
                         // FET. Reminiscent of grad school and DLTS. 
                         // Gotta love device physics...
+//VB   #endif
 }
 
 // when a divider is present, turn it off to remove the current it draws...
@@ -155,7 +239,9 @@
         highI += HIGH_ADC;
     }
     highI = factor_H * highI/nbMeas;
+    #if (USEI2CNOTUART == 0)
     timestamp = timer.read();
+    #endif
     return highI;
 }
 
@@ -168,7 +254,9 @@
     }
     if (!autorange) enableHighRange();
     low1I = factor_L1 * low1I/nbMeas;
+    #if (USEI2CNOTUART == 0)
     timestamp = timer.read();
+    #endif
     return low1I;
 }
 
@@ -181,7 +269,9 @@
     }
     if (!autorange) enableHighRange();
     low2I = factor_L2 * low2I/nbMeas;
+    #if (USEI2CNOTUART == 0)
     timestamp = timer.read();
+    #endif
     return low2I;
 }
 
@@ -189,80 +279,47 @@
 // to get the best measurement...
 // hard coded values for switching ranges needs to be made 
 // dynamic so 4.125A/1.65A ranges can be used...
-#if (USEI2CNOTUART == 1) 
-float measureAutoI(){
+
+
+float measureAutoI(int nbMeas){
     float tempI;
     enableHighRange();  // this should already be the case, but do it anyway...
-    tempI = measureHigh();
-    status = 1;
-    // if current is below this threshold, use LOW1 to measure... 
-    if (tempI < 0.060) {
-        enableLow1Range();
-        tempI = measureLow1(false); // call function 
-        status = 2;
-        // if current is below this threshold, use LOW2 to measure...
-        if (tempI < 0.0009){
-            enableLow2Range();  // change FETs to enable LOW2 measurement...
-            tempI = measureLow2(false);
-            status = 3;
-        }
-    enableHighRange();
-    }
-    return tempI;
-}    
-#else
-float measureAutoI_uart(int nbMeas){
-//void measureAutoI_uart(int nbMeas){
-    float tempI;
-    
-    enableHighRange();  // this should already be the case, but do it anyway...
+    #if (USEI2CNOTUART == 0)
     current[0] = 0;
     current[1] = 0;
     current[2] = 0;
+    #endif
     tempI = measureHigh(nbMeas);
-//    uart.printf("\r\nnb samples: %d - measureHigh:%f A", nbMeas, tempI);
+    #if (USEI2CNOTUART == 0)
     current[0] = tempI;
+    #endif
     status = 1;
     // if current is below this threshold, use LOW1 to measure... 
     if (tempI < 0.060) {
         enableLow1Range();
         tempI = measureLow1(false, nbMeas); // call function 
-//        uart.printf("\r\nnb samples: %d - measureLow1:%f A", nbMeas, tempI);
+        #if (USEI2CNOTUART == 0)
         current[1] = tempI;
+        #endif
         status = 2;
         // if current is below this threshold, use LOW2 to measure...
         if (tempI < 0.0009){
             enableLow2Range();  // change FETs to enable LOW2 measurement...
             tempI = measureLow2(false, nbMeas);
-//            uart.printf("\r\nnb samples: %d - measureLow2:%f A", nbMeas, tempI);
+            #if (USEI2CNOTUART == 0)
             current[2] = tempI;
+            #endif
             status = 3;
         }
     enableHighRange();
     }
     return tempI;
 }
-#endif
 
 
 // measure the rail voltage, default being with 
 // need to add logic for 5V/12V/arbitraryV range...
-#if (USEI2CNOTUART == 1) 
-float measureRailV(){
-    float railv=0;
-    enableRailV();  // switch FETs so divider is connected...
-    for (i = 0; i < n_meas; i++){
-        railv += VRAIL_ADC;  // read voltage at divider output...
-    }
-    disableRailV();     // now disconnect the voltage divider
-    railv = vref * (railv/n_meas);    // compute average 
-                        // Convert to voltage by multiplying by "mult"
-    timestamp = timer.read();
-    if (vref==12.0) railv = railv * 0.24770642201;
-    return railv;
-}    
-#else
-float measureRailV_uart(int nbMeas){
+float measureRailV(int nbMeas){
     float railv=0;
     enableRailV();  // switch FETs so divider is connected...
     for (i = 0; i < nbMeas; i++){
@@ -272,24 +329,28 @@
     railv = vref * (railv/nbMeas);    // compute average 
                         // Convert to voltage by multiplying by "mult"
     if (vref==12.0) railv = railv * 0.24770642201;
-//    uart.printf("\r\nnb samples: %d - measureRailV:%f V\n", nbMeas, railv);
     return railv;
 }
-#endif
+
+
+
+
+
+#if (USEI2CNOTUART == 1) 
 /***********************************************************************************
 *
 *  INTERRUPT SERVICE ROUTINE
 * 
 ************************************************************************************/
-#if (USEI2CNOTUART == 1) 
+
 // measurements are only taken during ISR, triggered by aggregator on IRQ line...
 // this could have been implemented differently, but this was simple...
 // If coulomb counting is desired, this code would probably need to change...
 void interrupt_service(){
     // make measurement... (this is currently just a placeholder...)
     status = 0; // clear status byte.. allow measurement functions to modify...
-    measurement1 = measureAutoI();   
-    measurement2 = measureRailV();   
+    measurement1 = measureAutoI(n_meas);
+    measurement2 = measureRailV(n_meas);
     n += 10; //increment interrupt counter...
     
     // prepare data for transport, in the event that aggregator asks for short format... 
@@ -326,25 +387,14 @@
     buf[8] = status; 
 
     // transfer compressed measurement data to output buffers...
-//    for (j=0; j<9; j++) obuf[j] = buf[j];
-//    for (j=0; j<4; j++) cbuf[j] = buf[j+10];
-    for (j=0; j<9; j++) obuf[j] = j*10;
-    for (j=0; j<4; j++) cbuf[j] = j*10+10;
+    for (j=0; j<9; j++) obuf[j] = buf[j];
+    for (j=0; j<4; j++) cbuf[j] = buf[j+10];
     
 } //ISR
 #endif
-#if (USEI2CNOTUART == 0)
-// input used for triggering measurement...
-// will eventually need to be set up as an interrupt so it minimizes delay before measurement
-InterruptIn trigger(PTA0);        // use as a trigger to make measurement...
+
 
-// test function to see if trigger pin is being hit...
-// intended for use later to do timed triggering of measurements...
-void triggerIn(){
-    uart.printf("You're triggering me! \r\n");
-    //measureAll();
-}
-#endif
+
 
 /***********************************************************************************
 *
@@ -355,69 +405,178 @@
 // main...
 int main() {
 
-  int sensor = 0;
+  buf[0] = 0;
+
+  #if (USEI2CNOTUART == 0)
   float volt = 0;
   float curr_sensor = 0;
-  int begin=0, end=0;
+  #if (DEBUG == 1)
+    int sensor = 0;
+    int timeStart=0, timeEnd=0;
+  #endif
+  #if (TRACEPRINT == 1)
+  float before_printf=0, after_printf=0;
+  #endif
+
+  uart.baud(115200);
+  uart.printf("\r\nData from current sensor...\n");
+  uart.printf("\r\nNumber of sample(s) for averaging measurement: %d", n_meas);
+  uart.printf("\r\nModes:");
+  if (DEBUG) {
+    uart.printf("\r\n  DEBUG: YES");
+  } else {
+    uart.printf("\r\n  DEBUG: NO");
+  }
+  if (TRACEPRINT) {
+    uart.printf("\r\n  TRACEPRINT: YES");
+  } else {
+    uart.printf("\r\n  TRACEPRINT: NO");
+  }
+  if (BUFFMEASURES) {
+    uart.printf("\r\n  BUFFMEASURES: YES");
+    uart.printf("\r\n    buffer size: %d\n", BUFFERSIZE);
+  } else {
+    uart.printf("\r\n  BUFFMEASURES: NO");
+  }
+
+  uart.printf("\r\nDelay for FET switching: %d us", wait_mbbb);
+  uart.printf("\r\nDelay for HIGH current sensor switching: %d us", wait_high);
+  uart.printf("\r\nDelay for MID current sensor switching: %d us", wait_low1);
+  uart.printf("\r\nDelay for LOW current sensor switching: %d us", wait_low2);
+  uart.printf("\r\nDelay for voltage sensor switching: %d us", wait_vrail);
+
+
+  // turn on pull ups for option resistors, since resistors pull down pins
+  C_RANGE.mode(PullUp);
+  V_RANGE0.mode(PullUp);
+  V_RANGE1.mode(PullUp);
+  // change calculation multipliers according to option resistors:
+  i = V_RANGE1*2 + V_RANGE0;
+  if (i==1) vref = 6.6;
+  if (i==2) vref = 12.0;
+  if (C_RANGE==0) {
+    factor_H  = vref / 2.0;
+    factor_L1 = vref / (0.15 * 1000);
+    factor_L2 = vref / (15 * 1000);
+  }
+
+  uart.printf("\r\n\nFactor_H: %f", factor_H);
+  uart.printf("\r\nFactor_L1: %f", factor_L1);
+  uart.printf("\r\nFactor_L2: %f", factor_L2);
+
+
+//VB to debug the latency to compensate the FET peak current
+#if 0
+    float tempI=0;
+
+    enableHighRange();  // this should already be the case, but do it anyway...
+    #if (USEI2CNOTUART == 0)
+    current[0] = 0;
+    current[1] = 0;
+    current[2] = 0;
+    #endif
+    tempI = measureHigh(1);
+    #if (USEI2CNOTUART == 0)
+    current[0] = tempI;
+    #endif
+    status = 1;
+    // if current is below this threshold, use LOW1 to measure... 
+    if (tempI < 0.060) {
+      enableLow1Range();
+      tempI = measureLow1(false, 1); // call function 
+      #if (USEI2CNOTUART == 0)
+      current[1] = tempI;
+      #endif
+      status = 2;
+      // if current is below this threshold, use LOW2 to measure...
+      if (tempI < 0.0009){
+        while (1) {
+          timer.reset();
+          timer.start();
+          volt = measureRailV(n_meas);
+          enableLow2Range();  // change FETs to enable LOW2 measurement...
+          for (int idx_meas = 0; idx_meas < BUFFERSIZE; idx_meas++) {
+            enableLow2Range();
+            wait_us(100);
+            tempI = factor_L2 * LOW2_ADC;
+            //wait_us(500);
+            enableHighRange();
+            timestamp = timer.read();
+            buffer[idx_meas][0] = timestamp;
+            buffer[idx_meas][1] = volt;
+            buffer[idx_meas][2] = tempI;
+          }
+          for (int idx_meas = 0; idx_meas < BUFFERSIZE; idx_meas++) {
+            uart.printf("\r\n%d %f %f %f", idx_meas, buffer[idx_meas][0], buffer[idx_meas][1], buffer[idx_meas][2]);
+          }
+        }
+      }
+    }
+#else
+//End of VB
+
+  #if (DEBUG == 1)
+    #if (TRACEPRINT == 0)
+    uart.printf("\r\n\nMeasuresDuration(us)(V,I) sensor timestamp(s) Voltage(V) Current(A) HighSensor(A) MidSensor(A) LowSensor(A)");
+    #else
+    uart.printf("\r\n\nMeasuresDuration(us)(V,I) sensor timestamp(s) Voltage(V) Current(A) HighSensor(A) MidSensor(A) LowSensor(A) UartPrintDuration(us)");
+    #endif
+  #elif (BUFFMEASURES == 1)
+    uart.printf("\r\n\nidx timestamp(s) Voltage(V) Current(A)");
+  #else
+    #if (TRACEPRINT == 0)
+    uart.printf("\r\n\ntimestamp(s) Voltage(V) Current(A)");
+    #else
+    uart.printf("\r\n\ntimestamp(s) Voltage(V) Current(A) UartPrintDuration(us)");
+    #endif
+  #endif
   
+  #if (BUFFMEASURES == 0)
   timer.reset();
   timer.start();
-  
-   buf[0] = 0;
-
-#if (USEI2CNOTUART == 0)
-   uart.baud(115200);
-   uart.printf("Hello World!\r\n");  
-
-   uart.printf("\r\n\n........FROM SENSOR.......\n\n");
-   
-
-   // turn on pull ups for option resistors, since resistors pull down pins
-   C_RANGE.mode(PullUp);
-   V_RANGE0.mode(PullUp);
-   V_RANGE1.mode(PullUp);
-   // change calculation multipliers according to option resistors:
-   i = V_RANGE1*2 + V_RANGE0;
-   if (i==1) vref = 6.6;
-   if (i==2) vref = 12.0;
-   if (C_RANGE==0) {
-        factor_H  = vref / 2.0;
-        factor_L1 = vref / (0.15 * 1000);
-        factor_L2 = vref / (15 * 1000);
-   }
-   
-   uart.printf("\r\nfactor_H: %f", factor_H);
-   uart.printf("\r\nfactor_L1: %f", factor_L1);
-   uart.printf("\r\nfactor_L2: %f", factor_L2);
+  #endif
 
   while (1) {
-//    // configure the trigger interrupt...
-//    uart.printf("\ntrigger irq...");
-//    trigger.rise(&triggerIn);
-////    uart.printf("\r\nCalling measureAutoI...");
-////    uart.printf("\nmeasureAutoI:%f", measureAutoI());
 
-int nb_samples = 1;
-//    for(int nb_samples=1; nb_samples <=25; nb_samples++) {
-
-//        t.reset();
-//        t.start();
-        begin = timer.read_us();
-        volt = measureRailV_uart(nb_samples);
-        curr_sensor = measureAutoI_uart(nb_samples);
-        end = timer.read_us();
-//        uart.printf("\r\nTotal Measure Time = %d us", end-begin);
-        uart.printf("\r\n%d %d %f %f %f %f %f %f", end-begin, sensor, timestamp, volt, curr_sensor, current[0], current[1], current[2]);
-//        t.stop();
-//        uart.printf("\r\nTotal Measure Time = %f s", t.read());
-//        uart.printf("\r\nTotal Measure Time = %f ms", t.read_ms());
-//        uart.printf("\r\nTotal Measure Time = %f us", t.read_us());
-//        wait_us(100);
-//    }
+    #if (DEBUG == 1)
+    timeStart = timer.read_us();
+    #endif
+    #if (BUFFMEASURES == 1)
+    timer.reset();
+    timer.start();
+    for (int idx_meas = 0; idx_meas < BUFFERSIZE; idx_meas++) {
+      volt = measureRailV(n_meas);
+      curr_sensor = measureAutoI(n_meas);
+      buffer[idx_meas][0] = timestamp;
+      buffer[idx_meas][1] = volt;
+      buffer[idx_meas][2] = curr_sensor;
+    }
+    #else
+    volt = measureRailV(n_meas);
+    curr_sensor = measureAutoI(n_meas);
+    #endif
+    #if (DEBUG == 1)
+    timeEnd = timer.read_us();
+    #endif
+    #if (TRACEPRINT == 1)
+    before_printf = timer.read();
+    #endif
+    #if (DEBUG == 1)
+    uart.printf("\r\n%d %d %f %f %f %f %f %f", timeEnd-timeStart, sensor, timestamp, volt, curr_sensor, current[0], current[1], current[2]);
+    #elif (BUFFMEASURES == 1)
+    for (int idx_meas = 0; idx_meas < BUFFERSIZE; idx_meas++) {
+      uart.printf("\r\n%d %f %f %f", idx_meas, buffer[idx_meas][0], buffer[idx_meas][1], buffer[idx_meas][2]);
+    }
+    #else
+     uart.printf("\r\n%f %f %f", timestamp, volt, curr_sensor);
+    #endif
+    #if (TRACEPRINT == 1)
+    after_printf = timer.read();
+    uart.printf(" %f", after_printf - before_printf);
+    #endif
   }
-
-   
- #else  
+#endif
+#else  
    
    wait_us(200);   // wait before reassigning SWD pin so as to not get locked out...
    DigitalIn my_select(PTA2); // this is the individual line to each sensor...