smart sensor code initial version
Dependencies: mbed-src-KL05Z-smart-sensor
Diff: kl05-smart-sensor.cpp
- 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...