smart sensor code initial version

Dependencies:   mbed-src-KL05Z-smart-sensor

Committer:
vincenxp
Date:
Tue Mar 26 10:37:02 2019 +0000
Revision:
0:10bf1bb6d2b5
Child:
1:587e0346abca
initial version

Who changed what in which revision?

UserRevisionLine numberNew contents of line
vincenxp 0:10bf1bb6d2b5 1 /****************************************************************************************
vincenxp 0:10bf1bb6d2b5 2 *
vincenxp 0:10bf1bb6d2b5 3 * MIT License (https://spdx.org/licenses/MIT.html)
vincenxp 0:10bf1bb6d2b5 4 * Copyright 2018 NXP
vincenxp 0:10bf1bb6d2b5 5 *
vincenxp 0:10bf1bb6d2b5 6 * MBED code for KL05Z-based "smart" current sensor, which measures current in
vincenxp 0:10bf1bb6d2b5 7 * three ranges. Intended to be used with an aggregator board which triggers sensors
vincenxp 0:10bf1bb6d2b5 8 * on all instrumented rails and then sequentially reads the data from each out over I2C.
vincenxp 0:10bf1bb6d2b5 9 *
vincenxp 0:10bf1bb6d2b5 10 * Because there is no crystal on the board, need to edit source mbed-dev library
vincenxp 0:10bf1bb6d2b5 11 * to use internal oscillator with pound-define:
vincenxp 0:10bf1bb6d2b5 12 * change to "#define CLOCK_SETUP 0" in file:
vincenxp 0:10bf1bb6d2b5 13 * mbed-dev/targets/TARGET_Freescale/TARGET_KLXX/TARGET_KL05Z/device/system_MKL05Z4.c
vincenxp 0:10bf1bb6d2b5 14 *
vincenxp 0:10bf1bb6d2b5 15 ****************************************************************************************/
vincenxp 0:10bf1bb6d2b5 16
vincenxp 0:10bf1bb6d2b5 17 #include <mbed.h>
vincenxp 0:10bf1bb6d2b5 18
vincenxp 0:10bf1bb6d2b5 19 #define USEI2CNOTUART 0
vincenxp 0:10bf1bb6d2b5 20
vincenxp 0:10bf1bb6d2b5 21 // set things up...
vincenxp 0:10bf1bb6d2b5 22 #if (USEI2CNOTUART == 1)
vincenxp 0:10bf1bb6d2b5 23 I2CSlave slave(PTB4, PTB3);
vincenxp 0:10bf1bb6d2b5 24 #else
vincenxp 0:10bf1bb6d2b5 25 Serial uart(PTB3, PTB4); // tx, rx
vincenxp 0:10bf1bb6d2b5 26 #endif
vincenxp 0:10bf1bb6d2b5 27
vincenxp 0:10bf1bb6d2b5 28 // These will be used for identifying smart sensor build options:
vincenxp 0:10bf1bb6d2b5 29 // voltage range (0-3.3V, 0-6.6V, and 12V), and
vincenxp 0:10bf1bb6d2b5 30 // current range (high: 4A max, and low: 1.65A max)
vincenxp 0:10bf1bb6d2b5 31 // (default pin pulls are pull up...)
vincenxp 0:10bf1bb6d2b5 32 // But this still needs to be implemented per schematic...
vincenxp 0:10bf1bb6d2b5 33 DigitalIn gpio0(PTA3); // R8
vincenxp 0:10bf1bb6d2b5 34 DigitalIn C_RANGE(PTA4); // R9
vincenxp 0:10bf1bb6d2b5 35 DigitalIn V_RANGE0(PTA5); // R10
vincenxp 0:10bf1bb6d2b5 36 DigitalIn V_RANGE1(PTA6); // R11
vincenxp 0:10bf1bb6d2b5 37
vincenxp 0:10bf1bb6d2b5 38 // configure pins for measurements...
vincenxp 0:10bf1bb6d2b5 39 // analog inputs from sense amps and rail voltage (divider)...
vincenxp 0:10bf1bb6d2b5 40 AnalogIn HIGH_ADC(PTB10);
vincenxp 0:10bf1bb6d2b5 41 AnalogIn VRAIL_ADC(PTB11);
vincenxp 0:10bf1bb6d2b5 42 AnalogIn LOW1_ADC(PTA9);
vincenxp 0:10bf1bb6d2b5 43 AnalogIn LOW2_ADC(PTA8);
vincenxp 0:10bf1bb6d2b5 44 // outputs which control switching FETs...
vincenxp 0:10bf1bb6d2b5 45 DigitalOut VRAIL_MEAS(PTA7); // turns on Q7, connecting voltage divider
vincenxp 0:10bf1bb6d2b5 46 DigitalOut LOW_ENABLE(PTB0); // turns on Q4, turning off Q1, enabling low measurement
vincenxp 0:10bf1bb6d2b5 47 DigitalOut LOW1(PTB2); // turns on Q5, turning off Q2, disconnecting shunt R1
vincenxp 0:10bf1bb6d2b5 48 DigitalOut LOW2(PTB1); // turns on Q6, turning off Q3, disconnecting shunt R2
vincenxp 0:10bf1bb6d2b5 49
vincenxp 0:10bf1bb6d2b5 50
vincenxp 0:10bf1bb6d2b5 51
vincenxp 0:10bf1bb6d2b5 52 // set initial, default I2C listening address...
vincenxp 0:10bf1bb6d2b5 53 // same one for all sensors so we don't need to individually program each one...
vincenxp 0:10bf1bb6d2b5 54 int address = 0x48 << 1;
vincenxp 0:10bf1bb6d2b5 55 // buffers for I2C communication
vincenxp 0:10bf1bb6d2b5 56 char buf[15], inbuf[10];
vincenxp 0:10bf1bb6d2b5 57 char obuf[10], cbuf[10]; // another buf for compressed output...
vincenxp 0:10bf1bb6d2b5 58
vincenxp 0:10bf1bb6d2b5 59 // variables...
vincenxp 0:10bf1bb6d2b5 60 int i, j, n=0;
vincenxp 0:10bf1bb6d2b5 61 bool waiting;
vincenxp 0:10bf1bb6d2b5 62 bool big_data = false; // flag to save time during ISR
vincenxp 0:10bf1bb6d2b5 63 // only process uncompressed data if explicitly called for...
vincenxp 0:10bf1bb6d2b5 64
vincenxp 0:10bf1bb6d2b5 65 // these unions enable converting float val to bytes for transmission over I2C...
vincenxp 0:10bf1bb6d2b5 66 union u_tag {
vincenxp 0:10bf1bb6d2b5 67 char b[4];
vincenxp 0:10bf1bb6d2b5 68 float fval;
vincenxp 0:10bf1bb6d2b5 69 int ival;
vincenxp 0:10bf1bb6d2b5 70 } u, v;
vincenxp 0:10bf1bb6d2b5 71
vincenxp 0:10bf1bb6d2b5 72 //union u_current {
vincenxp 0:10bf1bb6d2b5 73 // float high;
vincenxp 0:10bf1bb6d2b5 74 // float mid;
vincenxp 0:10bf1bb6d2b5 75 // float low;
vincenxp 0:10bf1bb6d2b5 76 //} current;
vincenxp 0:10bf1bb6d2b5 77 float current[3];
vincenxp 0:10bf1bb6d2b5 78
vincenxp 0:10bf1bb6d2b5 79 // define measurement result and status variables...
vincenxp 0:10bf1bb6d2b5 80 float measurement1;
vincenxp 0:10bf1bb6d2b5 81 float measurement2;
vincenxp 0:10bf1bb6d2b5 82 char status=0;
vincenxp 0:10bf1bb6d2b5 83 //int n_meas=25; // number of averages when measuring...
vincenxp 0:10bf1bb6d2b5 84 int n_meas=1; // number of averages when measuring...
vincenxp 0:10bf1bb6d2b5 85 float vref =3.3;
vincenxp 0:10bf1bb6d2b5 86 float factor_H = vref / 0.8;
vincenxp 0:10bf1bb6d2b5 87 float factor_L1 = vref / (0.05 * 1000);
vincenxp 0:10bf1bb6d2b5 88 float factor_L2 = vref / (2 * 1000);
vincenxp 0:10bf1bb6d2b5 89
vincenxp 0:10bf1bb6d2b5 90 int wait_mbbb = 5;
vincenxp 0:10bf1bb6d2b5 91 int wait_high = 250;
vincenxp 0:10bf1bb6d2b5 92 int wait_low1 = 250;
vincenxp 0:10bf1bb6d2b5 93 int wait_low2 = 500;
vincenxp 0:10bf1bb6d2b5 94 int wait_vrail = 200;
vincenxp 0:10bf1bb6d2b5 95
vincenxp 0:10bf1bb6d2b5 96 Timer timer;
vincenxp 0:10bf1bb6d2b5 97 float timestamp;
vincenxp 0:10bf1bb6d2b5 98
vincenxp 0:10bf1bb6d2b5 99 /***********************************************************************************
vincenxp 0:10bf1bb6d2b5 100 *
vincenxp 0:10bf1bb6d2b5 101 * FUNCTIONS FOR MEASURING CURRENT AND VOLTAGE
vincenxp 0:10bf1bb6d2b5 102 *
vincenxp 0:10bf1bb6d2b5 103 ************************************************************************************/
vincenxp 0:10bf1bb6d2b5 104
vincenxp 0:10bf1bb6d2b5 105 void enableHighRange(){
vincenxp 0:10bf1bb6d2b5 106 LOW_ENABLE = 0; // short both low current shunts, close Q1
vincenxp 0:10bf1bb6d2b5 107 wait_us(wait_mbbb); // delay for FET to settle... (make before break)
vincenxp 0:10bf1bb6d2b5 108 LOW1 = 0; LOW2 = 0; // connect both shunts to make lower series resistance
vincenxp 0:10bf1bb6d2b5 109 VRAIL_MEAS = 0; // disconnect rail voltage divider
vincenxp 0:10bf1bb6d2b5 110 wait_us(wait_high); // wait for B2902A settling...
vincenxp 0:10bf1bb6d2b5 111 }
vincenxp 0:10bf1bb6d2b5 112
vincenxp 0:10bf1bb6d2b5 113 void enableLow1Range(){
vincenxp 0:10bf1bb6d2b5 114 LOW1 = 0; LOW2 = 1; // disconnect LOW2 shunt so LOW1 can measure
vincenxp 0:10bf1bb6d2b5 115 wait_us(wait_mbbb); // delay for FET to settle... (make before break)
vincenxp 0:10bf1bb6d2b5 116 LOW_ENABLE = 1; // unshort low current shunts, open Q1
vincenxp 0:10bf1bb6d2b5 117 VRAIL_MEAS = 0; // disconnect rail voltage divider
vincenxp 0:10bf1bb6d2b5 118 wait_us(wait_low1); // wait for B2902A settling...
vincenxp 0:10bf1bb6d2b5 119 }
vincenxp 0:10bf1bb6d2b5 120
vincenxp 0:10bf1bb6d2b5 121 void enableLow2Range(){
vincenxp 0:10bf1bb6d2b5 122 LOW1 = 1; LOW2 = 0; // disconnect LOW1 shunt so LOW2 can measure
vincenxp 0:10bf1bb6d2b5 123 wait_us(wait_mbbb); // delay for FET to settle... (make before break)
vincenxp 0:10bf1bb6d2b5 124 LOW_ENABLE = 1; // unshort low current shunts, open Q1
vincenxp 0:10bf1bb6d2b5 125 VRAIL_MEAS = 0; // disconnect rail voltage divider
vincenxp 0:10bf1bb6d2b5 126 wait_us(wait_low2); // wait for B2902A settling...
vincenxp 0:10bf1bb6d2b5 127 }
vincenxp 0:10bf1bb6d2b5 128
vincenxp 0:10bf1bb6d2b5 129 void enableRailV(){
vincenxp 0:10bf1bb6d2b5 130 VRAIL_MEAS = 1; // turn on Q7, to enable R3-R4 voltage divider
vincenxp 0:10bf1bb6d2b5 131 wait_us(wait_vrail); // wait for divider to settle...
vincenxp 0:10bf1bb6d2b5 132 // Compensation cap can be used to make
vincenxp 0:10bf1bb6d2b5 133 // voltage at ADC a "square wave" but it is
vincenxp 0:10bf1bb6d2b5 134 // rail voltage and FET dependent. Cap will
vincenxp 0:10bf1bb6d2b5 135 // need tuning if this wait time is to be
vincenxp 0:10bf1bb6d2b5 136 // removed/reduced.
vincenxp 0:10bf1bb6d2b5 137 //
vincenxp 0:10bf1bb6d2b5 138 // So, as it turns out, this settling time and
vincenxp 0:10bf1bb6d2b5 139 // compensation capacitance are voltage dependent
vincenxp 0:10bf1bb6d2b5 140 // because of the depletion region changes in the
vincenxp 0:10bf1bb6d2b5 141 // FET. Reminiscent of grad school and DLTS.
vincenxp 0:10bf1bb6d2b5 142 // Gotta love device physics...
vincenxp 0:10bf1bb6d2b5 143 }
vincenxp 0:10bf1bb6d2b5 144
vincenxp 0:10bf1bb6d2b5 145 // when a divider is present, turn it off to remove the current it draws...
vincenxp 0:10bf1bb6d2b5 146 void disableRailV(){
vincenxp 0:10bf1bb6d2b5 147 VRAIL_MEAS = 0; // turn off Q7, disabling R3-R4 voltage divider
vincenxp 0:10bf1bb6d2b5 148 }
vincenxp 0:10bf1bb6d2b5 149
vincenxp 0:10bf1bb6d2b5 150 // measure high range current...
vincenxp 0:10bf1bb6d2b5 151 float measureHigh(int nbMeas){
vincenxp 0:10bf1bb6d2b5 152 float highI=0;
vincenxp 0:10bf1bb6d2b5 153 enableHighRange();
vincenxp 0:10bf1bb6d2b5 154 for (i = 0; i < nbMeas; i++){
vincenxp 0:10bf1bb6d2b5 155 highI += HIGH_ADC;
vincenxp 0:10bf1bb6d2b5 156 }
vincenxp 0:10bf1bb6d2b5 157 highI = factor_H * highI/nbMeas;
vincenxp 0:10bf1bb6d2b5 158 timestamp = timer.read();
vincenxp 0:10bf1bb6d2b5 159 return highI;
vincenxp 0:10bf1bb6d2b5 160 }
vincenxp 0:10bf1bb6d2b5 161
vincenxp 0:10bf1bb6d2b5 162 // mesaure mid range current...
vincenxp 0:10bf1bb6d2b5 163 float measureLow1(bool autorange, int nbMeas){
vincenxp 0:10bf1bb6d2b5 164 float low1I=0;
vincenxp 0:10bf1bb6d2b5 165 if (!autorange) enableLow1Range();
vincenxp 0:10bf1bb6d2b5 166 for (i = 0; i < nbMeas; i++){
vincenxp 0:10bf1bb6d2b5 167 low1I += LOW1_ADC;
vincenxp 0:10bf1bb6d2b5 168 }
vincenxp 0:10bf1bb6d2b5 169 if (!autorange) enableHighRange();
vincenxp 0:10bf1bb6d2b5 170 low1I = factor_L1 * low1I/nbMeas;
vincenxp 0:10bf1bb6d2b5 171 timestamp = timer.read();
vincenxp 0:10bf1bb6d2b5 172 return low1I;
vincenxp 0:10bf1bb6d2b5 173 }
vincenxp 0:10bf1bb6d2b5 174
vincenxp 0:10bf1bb6d2b5 175 // measure low range current...
vincenxp 0:10bf1bb6d2b5 176 float measureLow2(bool autorange, int nbMeas){
vincenxp 0:10bf1bb6d2b5 177 float low2I=0;
vincenxp 0:10bf1bb6d2b5 178 if (!autorange) enableLow2Range();
vincenxp 0:10bf1bb6d2b5 179 for (i = 0; i < nbMeas; i++){
vincenxp 0:10bf1bb6d2b5 180 low2I += LOW2_ADC;
vincenxp 0:10bf1bb6d2b5 181 }
vincenxp 0:10bf1bb6d2b5 182 if (!autorange) enableHighRange();
vincenxp 0:10bf1bb6d2b5 183 low2I = factor_L2 * low2I/nbMeas;
vincenxp 0:10bf1bb6d2b5 184 timestamp = timer.read();
vincenxp 0:10bf1bb6d2b5 185 return low2I;
vincenxp 0:10bf1bb6d2b5 186 }
vincenxp 0:10bf1bb6d2b5 187
vincenxp 0:10bf1bb6d2b5 188 // this function measures current, autoranging as necessary
vincenxp 0:10bf1bb6d2b5 189 // to get the best measurement...
vincenxp 0:10bf1bb6d2b5 190 // hard coded values for switching ranges needs to be made
vincenxp 0:10bf1bb6d2b5 191 // dynamic so 4.125A/1.65A ranges can be used...
vincenxp 0:10bf1bb6d2b5 192 #if (USEI2CNOTUART == 1)
vincenxp 0:10bf1bb6d2b5 193 float measureAutoI(){
vincenxp 0:10bf1bb6d2b5 194 float tempI;
vincenxp 0:10bf1bb6d2b5 195 enableHighRange(); // this should already be the case, but do it anyway...
vincenxp 0:10bf1bb6d2b5 196 tempI = measureHigh();
vincenxp 0:10bf1bb6d2b5 197 status = 1;
vincenxp 0:10bf1bb6d2b5 198 // if current is below this threshold, use LOW1 to measure...
vincenxp 0:10bf1bb6d2b5 199 if (tempI < 0.060) {
vincenxp 0:10bf1bb6d2b5 200 enableLow1Range();
vincenxp 0:10bf1bb6d2b5 201 tempI = measureLow1(false); // call function
vincenxp 0:10bf1bb6d2b5 202 status = 2;
vincenxp 0:10bf1bb6d2b5 203 // if current is below this threshold, use LOW2 to measure...
vincenxp 0:10bf1bb6d2b5 204 if (tempI < 0.0009){
vincenxp 0:10bf1bb6d2b5 205 enableLow2Range(); // change FETs to enable LOW2 measurement...
vincenxp 0:10bf1bb6d2b5 206 tempI = measureLow2(false);
vincenxp 0:10bf1bb6d2b5 207 status = 3;
vincenxp 0:10bf1bb6d2b5 208 }
vincenxp 0:10bf1bb6d2b5 209 enableHighRange();
vincenxp 0:10bf1bb6d2b5 210 }
vincenxp 0:10bf1bb6d2b5 211 return tempI;
vincenxp 0:10bf1bb6d2b5 212 }
vincenxp 0:10bf1bb6d2b5 213 #else
vincenxp 0:10bf1bb6d2b5 214 float measureAutoI_uart(int nbMeas){
vincenxp 0:10bf1bb6d2b5 215 //void measureAutoI_uart(int nbMeas){
vincenxp 0:10bf1bb6d2b5 216 float tempI;
vincenxp 0:10bf1bb6d2b5 217
vincenxp 0:10bf1bb6d2b5 218 enableHighRange(); // this should already be the case, but do it anyway...
vincenxp 0:10bf1bb6d2b5 219 current[0] = 0;
vincenxp 0:10bf1bb6d2b5 220 current[1] = 0;
vincenxp 0:10bf1bb6d2b5 221 current[2] = 0;
vincenxp 0:10bf1bb6d2b5 222 tempI = measureHigh(nbMeas);
vincenxp 0:10bf1bb6d2b5 223 // uart.printf("\r\nnb samples: %d - measureHigh:%f A", nbMeas, tempI);
vincenxp 0:10bf1bb6d2b5 224 current[0] = tempI;
vincenxp 0:10bf1bb6d2b5 225 status = 1;
vincenxp 0:10bf1bb6d2b5 226 // if current is below this threshold, use LOW1 to measure...
vincenxp 0:10bf1bb6d2b5 227 if (tempI < 0.060) {
vincenxp 0:10bf1bb6d2b5 228 enableLow1Range();
vincenxp 0:10bf1bb6d2b5 229 tempI = measureLow1(false, nbMeas); // call function
vincenxp 0:10bf1bb6d2b5 230 // uart.printf("\r\nnb samples: %d - measureLow1:%f A", nbMeas, tempI);
vincenxp 0:10bf1bb6d2b5 231 current[1] = tempI;
vincenxp 0:10bf1bb6d2b5 232 status = 2;
vincenxp 0:10bf1bb6d2b5 233 // if current is below this threshold, use LOW2 to measure...
vincenxp 0:10bf1bb6d2b5 234 if (tempI < 0.0009){
vincenxp 0:10bf1bb6d2b5 235 enableLow2Range(); // change FETs to enable LOW2 measurement...
vincenxp 0:10bf1bb6d2b5 236 tempI = measureLow2(false, nbMeas);
vincenxp 0:10bf1bb6d2b5 237 // uart.printf("\r\nnb samples: %d - measureLow2:%f A", nbMeas, tempI);
vincenxp 0:10bf1bb6d2b5 238 current[2] = tempI;
vincenxp 0:10bf1bb6d2b5 239 status = 3;
vincenxp 0:10bf1bb6d2b5 240 }
vincenxp 0:10bf1bb6d2b5 241 enableHighRange();
vincenxp 0:10bf1bb6d2b5 242 }
vincenxp 0:10bf1bb6d2b5 243 return tempI;
vincenxp 0:10bf1bb6d2b5 244 }
vincenxp 0:10bf1bb6d2b5 245 #endif
vincenxp 0:10bf1bb6d2b5 246
vincenxp 0:10bf1bb6d2b5 247
vincenxp 0:10bf1bb6d2b5 248 // measure the rail voltage, default being with
vincenxp 0:10bf1bb6d2b5 249 // need to add logic for 5V/12V/arbitraryV range...
vincenxp 0:10bf1bb6d2b5 250 #if (USEI2CNOTUART == 1)
vincenxp 0:10bf1bb6d2b5 251 float measureRailV(){
vincenxp 0:10bf1bb6d2b5 252 float railv=0;
vincenxp 0:10bf1bb6d2b5 253 enableRailV(); // switch FETs so divider is connected...
vincenxp 0:10bf1bb6d2b5 254 for (i = 0; i < n_meas; i++){
vincenxp 0:10bf1bb6d2b5 255 railv += VRAIL_ADC; // read voltage at divider output...
vincenxp 0:10bf1bb6d2b5 256 }
vincenxp 0:10bf1bb6d2b5 257 disableRailV(); // now disconnect the voltage divider
vincenxp 0:10bf1bb6d2b5 258 railv = vref * (railv/n_meas); // compute average
vincenxp 0:10bf1bb6d2b5 259 // Convert to voltage by multiplying by "mult"
vincenxp 0:10bf1bb6d2b5 260 timestamp = timer.read();
vincenxp 0:10bf1bb6d2b5 261 if (vref==12.0) railv = railv * 0.24770642201;
vincenxp 0:10bf1bb6d2b5 262 return railv;
vincenxp 0:10bf1bb6d2b5 263 }
vincenxp 0:10bf1bb6d2b5 264 #else
vincenxp 0:10bf1bb6d2b5 265 float measureRailV_uart(int nbMeas){
vincenxp 0:10bf1bb6d2b5 266 float railv=0;
vincenxp 0:10bf1bb6d2b5 267 enableRailV(); // switch FETs so divider is connected...
vincenxp 0:10bf1bb6d2b5 268 for (i = 0; i < nbMeas; i++){
vincenxp 0:10bf1bb6d2b5 269 railv += VRAIL_ADC; // read voltage at divider output...
vincenxp 0:10bf1bb6d2b5 270 }
vincenxp 0:10bf1bb6d2b5 271 disableRailV(); // now disconnect the voltage divider
vincenxp 0:10bf1bb6d2b5 272 railv = vref * (railv/nbMeas); // compute average
vincenxp 0:10bf1bb6d2b5 273 // Convert to voltage by multiplying by "mult"
vincenxp 0:10bf1bb6d2b5 274 if (vref==12.0) railv = railv * 0.24770642201;
vincenxp 0:10bf1bb6d2b5 275 // uart.printf("\r\nnb samples: %d - measureRailV:%f V\n", nbMeas, railv);
vincenxp 0:10bf1bb6d2b5 276 return railv;
vincenxp 0:10bf1bb6d2b5 277 }
vincenxp 0:10bf1bb6d2b5 278 #endif
vincenxp 0:10bf1bb6d2b5 279 /***********************************************************************************
vincenxp 0:10bf1bb6d2b5 280 *
vincenxp 0:10bf1bb6d2b5 281 * INTERRUPT SERVICE ROUTINE
vincenxp 0:10bf1bb6d2b5 282 *
vincenxp 0:10bf1bb6d2b5 283 ************************************************************************************/
vincenxp 0:10bf1bb6d2b5 284 #if (USEI2CNOTUART == 1)
vincenxp 0:10bf1bb6d2b5 285 // measurements are only taken during ISR, triggered by aggregator on IRQ line...
vincenxp 0:10bf1bb6d2b5 286 // this could have been implemented differently, but this was simple...
vincenxp 0:10bf1bb6d2b5 287 // If coulomb counting is desired, this code would probably need to change...
vincenxp 0:10bf1bb6d2b5 288 void interrupt_service(){
vincenxp 0:10bf1bb6d2b5 289 // make measurement... (this is currently just a placeholder...)
vincenxp 0:10bf1bb6d2b5 290 status = 0; // clear status byte.. allow measurement functions to modify...
vincenxp 0:10bf1bb6d2b5 291 measurement1 = measureAutoI();
vincenxp 0:10bf1bb6d2b5 292 measurement2 = measureRailV();
vincenxp 0:10bf1bb6d2b5 293 n += 10; //increment interrupt counter...
vincenxp 0:10bf1bb6d2b5 294
vincenxp 0:10bf1bb6d2b5 295 // prepare data for transport, in the event that aggregator asks for short format...
vincenxp 0:10bf1bb6d2b5 296
vincenxp 0:10bf1bb6d2b5 297 // compressed data format, 4 bytes total, with a status nibble
vincenxp 0:10bf1bb6d2b5 298 // Each byte has form: (s*128) + (digit1*10) + (digit2), which fits into 8 bits
vincenxp 0:10bf1bb6d2b5 299 // Each value is composed of two bytes with form above, first three digits are
vincenxp 0:10bf1bb6d2b5 300 // the mantissa and the last digit is the exponent. Two values is four bytes, so
vincenxp 0:10bf1bb6d2b5 301 // that allows four status bits to be included.
vincenxp 0:10bf1bb6d2b5 302 sprintf(buf, "%4.2e", measurement1);
vincenxp 0:10bf1bb6d2b5 303 buf[10] = (buf[0]-48)*10 + (buf[2]-48); // no decimal, we use fixed point...
vincenxp 0:10bf1bb6d2b5 304 buf[11] = (buf[3]-48)*10 + (buf[7]-48); // no 'e', and no exp sign, since we know that's negative...
vincenxp 0:10bf1bb6d2b5 305 sprintf(buf, "%4.2e", measurement2);
vincenxp 0:10bf1bb6d2b5 306 buf[12] = (buf[0]-48)*10 + (buf[2]-48); // no decimal, we use fixed point...
vincenxp 0:10bf1bb6d2b5 307 buf[13] = (buf[3]-48)*10 + (buf[7]-48); // no 'e', and no exp sign, since we know that's negative...
vincenxp 0:10bf1bb6d2b5 308
vincenxp 0:10bf1bb6d2b5 309 // add in the four status bits...
vincenxp 0:10bf1bb6d2b5 310 buf[10] = buf[10] | (status & 1<<3)<<4;
vincenxp 0:10bf1bb6d2b5 311 buf[11] = buf[11] | (status & 1<<2)<<5;
vincenxp 0:10bf1bb6d2b5 312 buf[12] = buf[12] | (status & 1<<1)<<6;
vincenxp 0:10bf1bb6d2b5 313 buf[13] = buf[13] | (status & 1<<0)<<7;
vincenxp 0:10bf1bb6d2b5 314
vincenxp 0:10bf1bb6d2b5 315 // Convert each 32-bit floating point measurement value into 4 bytes
vincenxp 0:10bf1bb6d2b5 316 // using union, so we can send bytes over I2C...
vincenxp 0:10bf1bb6d2b5 317 u.fval = measurement1;
vincenxp 0:10bf1bb6d2b5 318 v.fval = measurement2;
vincenxp 0:10bf1bb6d2b5 319
vincenxp 0:10bf1bb6d2b5 320 // now fill the buffers with the stuff generated above so it can be sent over I2C:
vincenxp 0:10bf1bb6d2b5 321
vincenxp 0:10bf1bb6d2b5 322 // stuff latest measurement float values into bytes of buf for next transmission...
vincenxp 0:10bf1bb6d2b5 323 // buffer format: 4 bytes = (float) V, 4 bytes = (float) I, 1 byte status
vincenxp 0:10bf1bb6d2b5 324 for (j=0; j<4; j++) buf[j] = u.b[j]; // voltage
vincenxp 0:10bf1bb6d2b5 325 for (j=0; j<4; j++) buf[j+4] = v.b[j]; // current
vincenxp 0:10bf1bb6d2b5 326 buf[8] = status;
vincenxp 0:10bf1bb6d2b5 327
vincenxp 0:10bf1bb6d2b5 328 // transfer compressed measurement data to output buffers...
vincenxp 0:10bf1bb6d2b5 329 // for (j=0; j<9; j++) obuf[j] = buf[j];
vincenxp 0:10bf1bb6d2b5 330 // for (j=0; j<4; j++) cbuf[j] = buf[j+10];
vincenxp 0:10bf1bb6d2b5 331 for (j=0; j<9; j++) obuf[j] = j*10;
vincenxp 0:10bf1bb6d2b5 332 for (j=0; j<4; j++) cbuf[j] = j*10+10;
vincenxp 0:10bf1bb6d2b5 333
vincenxp 0:10bf1bb6d2b5 334 } //ISR
vincenxp 0:10bf1bb6d2b5 335 #endif
vincenxp 0:10bf1bb6d2b5 336 #if (USEI2CNOTUART == 0)
vincenxp 0:10bf1bb6d2b5 337 // input used for triggering measurement...
vincenxp 0:10bf1bb6d2b5 338 // will eventually need to be set up as an interrupt so it minimizes delay before measurement
vincenxp 0:10bf1bb6d2b5 339 InterruptIn trigger(PTA0); // use as a trigger to make measurement...
vincenxp 0:10bf1bb6d2b5 340
vincenxp 0:10bf1bb6d2b5 341 // test function to see if trigger pin is being hit...
vincenxp 0:10bf1bb6d2b5 342 // intended for use later to do timed triggering of measurements...
vincenxp 0:10bf1bb6d2b5 343 void triggerIn(){
vincenxp 0:10bf1bb6d2b5 344 uart.printf("You're triggering me! \r\n");
vincenxp 0:10bf1bb6d2b5 345 //measureAll();
vincenxp 0:10bf1bb6d2b5 346 }
vincenxp 0:10bf1bb6d2b5 347 #endif
vincenxp 0:10bf1bb6d2b5 348
vincenxp 0:10bf1bb6d2b5 349 /***********************************************************************************
vincenxp 0:10bf1bb6d2b5 350 *
vincenxp 0:10bf1bb6d2b5 351 * MAIN CODE
vincenxp 0:10bf1bb6d2b5 352 *
vincenxp 0:10bf1bb6d2b5 353 ************************************************************************************/
vincenxp 0:10bf1bb6d2b5 354
vincenxp 0:10bf1bb6d2b5 355 // main...
vincenxp 0:10bf1bb6d2b5 356 int main() {
vincenxp 0:10bf1bb6d2b5 357
vincenxp 0:10bf1bb6d2b5 358 int sensor = 0;
vincenxp 0:10bf1bb6d2b5 359 float volt = 0;
vincenxp 0:10bf1bb6d2b5 360 float curr_sensor = 0;
vincenxp 0:10bf1bb6d2b5 361 int begin=0, end=0;
vincenxp 0:10bf1bb6d2b5 362
vincenxp 0:10bf1bb6d2b5 363 timer.reset();
vincenxp 0:10bf1bb6d2b5 364 timer.start();
vincenxp 0:10bf1bb6d2b5 365
vincenxp 0:10bf1bb6d2b5 366 buf[0] = 0;
vincenxp 0:10bf1bb6d2b5 367
vincenxp 0:10bf1bb6d2b5 368 #if (USEI2CNOTUART == 0)
vincenxp 0:10bf1bb6d2b5 369 uart.baud(115200);
vincenxp 0:10bf1bb6d2b5 370 uart.printf("Hello World!\r\n");
vincenxp 0:10bf1bb6d2b5 371
vincenxp 0:10bf1bb6d2b5 372 uart.printf("\r\n\n........FROM SENSOR.......\n\n");
vincenxp 0:10bf1bb6d2b5 373
vincenxp 0:10bf1bb6d2b5 374
vincenxp 0:10bf1bb6d2b5 375 // turn on pull ups for option resistors, since resistors pull down pins
vincenxp 0:10bf1bb6d2b5 376 C_RANGE.mode(PullUp);
vincenxp 0:10bf1bb6d2b5 377 V_RANGE0.mode(PullUp);
vincenxp 0:10bf1bb6d2b5 378 V_RANGE1.mode(PullUp);
vincenxp 0:10bf1bb6d2b5 379 // change calculation multipliers according to option resistors:
vincenxp 0:10bf1bb6d2b5 380 i = V_RANGE1*2 + V_RANGE0;
vincenxp 0:10bf1bb6d2b5 381 if (i==1) vref = 6.6;
vincenxp 0:10bf1bb6d2b5 382 if (i==2) vref = 12.0;
vincenxp 0:10bf1bb6d2b5 383 if (C_RANGE==0) {
vincenxp 0:10bf1bb6d2b5 384 factor_H = vref / 2.0;
vincenxp 0:10bf1bb6d2b5 385 factor_L1 = vref / (0.15 * 1000);
vincenxp 0:10bf1bb6d2b5 386 factor_L2 = vref / (15 * 1000);
vincenxp 0:10bf1bb6d2b5 387 }
vincenxp 0:10bf1bb6d2b5 388
vincenxp 0:10bf1bb6d2b5 389 uart.printf("\r\nfactor_H: %f", factor_H);
vincenxp 0:10bf1bb6d2b5 390 uart.printf("\r\nfactor_L1: %f", factor_L1);
vincenxp 0:10bf1bb6d2b5 391 uart.printf("\r\nfactor_L2: %f", factor_L2);
vincenxp 0:10bf1bb6d2b5 392
vincenxp 0:10bf1bb6d2b5 393 while (1) {
vincenxp 0:10bf1bb6d2b5 394 // // configure the trigger interrupt...
vincenxp 0:10bf1bb6d2b5 395 // uart.printf("\ntrigger irq...");
vincenxp 0:10bf1bb6d2b5 396 // trigger.rise(&triggerIn);
vincenxp 0:10bf1bb6d2b5 397 //// uart.printf("\r\nCalling measureAutoI...");
vincenxp 0:10bf1bb6d2b5 398 //// uart.printf("\nmeasureAutoI:%f", measureAutoI());
vincenxp 0:10bf1bb6d2b5 399
vincenxp 0:10bf1bb6d2b5 400 int nb_samples = 1;
vincenxp 0:10bf1bb6d2b5 401 // for(int nb_samples=1; nb_samples <=25; nb_samples++) {
vincenxp 0:10bf1bb6d2b5 402
vincenxp 0:10bf1bb6d2b5 403 // t.reset();
vincenxp 0:10bf1bb6d2b5 404 // t.start();
vincenxp 0:10bf1bb6d2b5 405 begin = timer.read_us();
vincenxp 0:10bf1bb6d2b5 406 volt = measureRailV_uart(nb_samples);
vincenxp 0:10bf1bb6d2b5 407 curr_sensor = measureAutoI_uart(nb_samples);
vincenxp 0:10bf1bb6d2b5 408 end = timer.read_us();
vincenxp 0:10bf1bb6d2b5 409 // uart.printf("\r\nTotal Measure Time = %d us", end-begin);
vincenxp 0:10bf1bb6d2b5 410 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]);
vincenxp 0:10bf1bb6d2b5 411 // t.stop();
vincenxp 0:10bf1bb6d2b5 412 // uart.printf("\r\nTotal Measure Time = %f s", t.read());
vincenxp 0:10bf1bb6d2b5 413 // uart.printf("\r\nTotal Measure Time = %f ms", t.read_ms());
vincenxp 0:10bf1bb6d2b5 414 // uart.printf("\r\nTotal Measure Time = %f us", t.read_us());
vincenxp 0:10bf1bb6d2b5 415 // wait_us(100);
vincenxp 0:10bf1bb6d2b5 416 // }
vincenxp 0:10bf1bb6d2b5 417 }
vincenxp 0:10bf1bb6d2b5 418
vincenxp 0:10bf1bb6d2b5 419
vincenxp 0:10bf1bb6d2b5 420 #else
vincenxp 0:10bf1bb6d2b5 421
vincenxp 0:10bf1bb6d2b5 422 wait_us(200); // wait before reassigning SWD pin so as to not get locked out...
vincenxp 0:10bf1bb6d2b5 423 DigitalIn my_select(PTA2); // this is the individual line to each sensor...
vincenxp 0:10bf1bb6d2b5 424
vincenxp 0:10bf1bb6d2b5 425
vincenxp 0:10bf1bb6d2b5 426 while (my_select) {
vincenxp 0:10bf1bb6d2b5 427 // wait here until aggregator signals us for address reassignment...
vincenxp 0:10bf1bb6d2b5 428 } // end while
vincenxp 0:10bf1bb6d2b5 429
vincenxp 0:10bf1bb6d2b5 430 // Need to wait to set up I2C until after we've come out of wait loop above...
vincenxp 0:10bf1bb6d2b5 431 // Setting up the I2C earlier starts it listening on the bus even if it's not
vincenxp 0:10bf1bb6d2b5 432 // being polled, which means that multiple sensors will respond, hanging the bus...
vincenxp 0:10bf1bb6d2b5 433 slave.frequency(400000); // go as fast as possible...
vincenxp 0:10bf1bb6d2b5 434 slave.address(address); // listen on the default address...
vincenxp 0:10bf1bb6d2b5 435
vincenxp 0:10bf1bb6d2b5 436 while (!my_select) {
vincenxp 0:10bf1bb6d2b5 437 // listen for new address, then repeat it back aggregator...
vincenxp 0:10bf1bb6d2b5 438 waiting = true;
vincenxp 0:10bf1bb6d2b5 439 while (waiting && !my_select){
vincenxp 0:10bf1bb6d2b5 440 int i = slave.receive();
vincenxp 0:10bf1bb6d2b5 441 switch (i) {
vincenxp 0:10bf1bb6d2b5 442 case I2CSlave::WriteAddressed:
vincenxp 0:10bf1bb6d2b5 443 slave.read(buf, 1);
vincenxp 0:10bf1bb6d2b5 444 // we just got our new address, provided my_select subsequently changes...
vincenxp 0:10bf1bb6d2b5 445 waiting = false;
vincenxp 0:10bf1bb6d2b5 446 break;
vincenxp 0:10bf1bb6d2b5 447 case I2CSlave::ReadAddressed:
vincenxp 0:10bf1bb6d2b5 448 slave.write(buf, 1);
vincenxp 0:10bf1bb6d2b5 449 // write back our new address to confirm we go it...
vincenxp 0:10bf1bb6d2b5 450 waiting = false;
vincenxp 0:10bf1bb6d2b5 451 break;
vincenxp 0:10bf1bb6d2b5 452 }
vincenxp 0:10bf1bb6d2b5 453 }
vincenxp 0:10bf1bb6d2b5 454 } // end while, waiting for address reassignment...
vincenxp 0:10bf1bb6d2b5 455
vincenxp 0:10bf1bb6d2b5 456 // we fell out of loop above, so now change our I2C address to the newly assigned one...
vincenxp 0:10bf1bb6d2b5 457 // this newly assigned address will not change until we're reset...
vincenxp 0:10bf1bb6d2b5 458 slave.address(buf[0]);
vincenxp 0:10bf1bb6d2b5 459
vincenxp 0:10bf1bb6d2b5 460 // enable interrupts, need to wait until after getting new I2C address,
vincenxp 0:10bf1bb6d2b5 461 // since we cannot respond until we have our new address...
vincenxp 0:10bf1bb6d2b5 462 InterruptIn triggerIRQ(PTA0); // this is the ganged interrupt signal to all sensors
vincenxp 0:10bf1bb6d2b5 463 triggerIRQ.rise(&interrupt_service); // attach the service routine...
vincenxp 0:10bf1bb6d2b5 464
vincenxp 0:10bf1bb6d2b5 465 // make sure we can receive at the new address...
vincenxp 0:10bf1bb6d2b5 466 // this isn't absolutely necessary, but it's a good check...
vincenxp 0:10bf1bb6d2b5 467 // if this is removed, the corresponding write in the aggregator code needs to go, too
vincenxp 0:10bf1bb6d2b5 468 waiting = true;
vincenxp 0:10bf1bb6d2b5 469 while (waiting){
vincenxp 0:10bf1bb6d2b5 470 i = slave.receive();
vincenxp 0:10bf1bb6d2b5 471 switch (i) {
vincenxp 0:10bf1bb6d2b5 472 case I2CSlave::ReadAddressed:
vincenxp 0:10bf1bb6d2b5 473 slave.write(buf, 1);
vincenxp 0:10bf1bb6d2b5 474 waiting = false;
vincenxp 0:10bf1bb6d2b5 475 break;
vincenxp 0:10bf1bb6d2b5 476 case I2CSlave::WriteAddressed:
vincenxp 0:10bf1bb6d2b5 477 slave.read(buf, 1);
vincenxp 0:10bf1bb6d2b5 478 waiting = false;
vincenxp 0:10bf1bb6d2b5 479 break;
vincenxp 0:10bf1bb6d2b5 480 }
vincenxp 0:10bf1bb6d2b5 481 }
vincenxp 0:10bf1bb6d2b5 482
vincenxp 0:10bf1bb6d2b5 483
vincenxp 0:10bf1bb6d2b5 484 /******************************************************************************/
vincenxp 0:10bf1bb6d2b5 485 // this is the main loop:
vincenxp 0:10bf1bb6d2b5 486 // We just sit here and wait for I2C commands and triggers on IRQ line...
vincenxp 0:10bf1bb6d2b5 487 //
vincenxp 0:10bf1bb6d2b5 488 // A triggerIRQ causes measurements in ISR, aggregator must wait at least
vincenxp 0:10bf1bb6d2b5 489 // long enough for it to finish before reading back the result(s).
vincenxp 0:10bf1bb6d2b5 490 //
vincenxp 0:10bf1bb6d2b5 491 // results are sent in 9 byte packets: 4 for voltage, 4 for current, and one status,
vincenxp 0:10bf1bb6d2b5 492 // where voltage and current are floats in units of V and A. Status byte will be
vincenxp 0:10bf1bb6d2b5 493 // packed with something later, yet to be defined.
vincenxp 0:10bf1bb6d2b5 494 //
vincenxp 0:10bf1bb6d2b5 495 // What should be implemented are additional things like setting and reading
vincenxp 0:10bf1bb6d2b5 496 // back the delays in the GPIO control functions, turning on and off averaging
vincenxp 0:10bf1bb6d2b5 497 // so we can see what the min and max values are (which also helps tell if we
vincenxp 0:10bf1bb6d2b5 498 // don't have enough delay in the GPIO functions), and possibly other stuff
vincenxp 0:10bf1bb6d2b5 499 // not thought of yet... Definitely not an exercise for this pasta programmer...
vincenxp 0:10bf1bb6d2b5 500 //
vincenxp 0:10bf1bb6d2b5 501 while (1) {
vincenxp 0:10bf1bb6d2b5 502 i = slave.receive();
vincenxp 0:10bf1bb6d2b5 503 switch (i) {
vincenxp 0:10bf1bb6d2b5 504 case I2CSlave::ReadAddressed:
vincenxp 0:10bf1bb6d2b5 505 if (my_select){ // if high, send uncompressed format...
vincenxp 0:10bf1bb6d2b5 506 slave.write(obuf, 9);
vincenxp 0:10bf1bb6d2b5 507 waiting = false;
vincenxp 0:10bf1bb6d2b5 508 } else { // if low, send compressed format...
vincenxp 0:10bf1bb6d2b5 509 slave.write(cbuf, 4);
vincenxp 0:10bf1bb6d2b5 510 waiting = false;
vincenxp 0:10bf1bb6d2b5 511 }
vincenxp 0:10bf1bb6d2b5 512 break;
vincenxp 0:10bf1bb6d2b5 513 case I2CSlave::WriteAddressed:
vincenxp 0:10bf1bb6d2b5 514 // slave.read(inbuf, 1);
vincenxp 0:10bf1bb6d2b5 515 // waiting = false;
vincenxp 0:10bf1bb6d2b5 516 // break;
vincenxp 0:10bf1bb6d2b5 517 if (my_select){ // if high, receive two bytes...
vincenxp 0:10bf1bb6d2b5 518 slave.read(inbuf, 2);
vincenxp 0:10bf1bb6d2b5 519 waiting = false;
vincenxp 0:10bf1bb6d2b5 520 // if we're here, we've recieved two words, so we update the
vincenxp 0:10bf1bb6d2b5 521 // appropriate parameter.
vincenxp 0:10bf1bb6d2b5 522 switch (inbuf[0]) {
vincenxp 0:10bf1bb6d2b5 523 case 0:
vincenxp 0:10bf1bb6d2b5 524 wait_mbbb = inbuf[1];
vincenxp 0:10bf1bb6d2b5 525 break;
vincenxp 0:10bf1bb6d2b5 526 case 1:
vincenxp 0:10bf1bb6d2b5 527 wait_high = inbuf[1]*8;
vincenxp 0:10bf1bb6d2b5 528 break;
vincenxp 0:10bf1bb6d2b5 529 case 2:
vincenxp 0:10bf1bb6d2b5 530 wait_low1 = inbuf[1]*8;
vincenxp 0:10bf1bb6d2b5 531 break;
vincenxp 0:10bf1bb6d2b5 532 case 3:
vincenxp 0:10bf1bb6d2b5 533 wait_low2 = inbuf[1]*8;
vincenxp 0:10bf1bb6d2b5 534 break;
vincenxp 0:10bf1bb6d2b5 535 case 4:
vincenxp 0:10bf1bb6d2b5 536 wait_vrail = inbuf[1]*8;
vincenxp 0:10bf1bb6d2b5 537 break;
vincenxp 0:10bf1bb6d2b5 538 case 5:
vincenxp 0:10bf1bb6d2b5 539 n_meas = inbuf[1];
vincenxp 0:10bf1bb6d2b5 540 break;
vincenxp 0:10bf1bb6d2b5 541 } // switch
vincenxp 0:10bf1bb6d2b5 542 // and since we're still here, place the new values
vincenxp 0:10bf1bb6d2b5 543 // in obuf so we can read back all paramters values
vincenxp 0:10bf1bb6d2b5 544 obuf[0] = wait_mbbb;
vincenxp 0:10bf1bb6d2b5 545 obuf[1] = wait_high/8;
vincenxp 0:10bf1bb6d2b5 546 obuf[2] = wait_low1/8;
vincenxp 0:10bf1bb6d2b5 547 obuf[3] = wait_low2/8;
vincenxp 0:10bf1bb6d2b5 548 obuf[4] = wait_vrail/8;
vincenxp 0:10bf1bb6d2b5 549 obuf[5] = n_meas;
vincenxp 0:10bf1bb6d2b5 550 obuf[6] = 0;
vincenxp 0:10bf1bb6d2b5 551 obuf[7] = 0;
vincenxp 0:10bf1bb6d2b5 552 obuf[8] = 0;
vincenxp 0:10bf1bb6d2b5 553 } else { ;// if low, receive one byte...
vincenxp 0:10bf1bb6d2b5 554 slave.read(inbuf, 1);
vincenxp 0:10bf1bb6d2b5 555 waiting = false;
vincenxp 0:10bf1bb6d2b5 556 }
vincenxp 0:10bf1bb6d2b5 557 } // switch
vincenxp 0:10bf1bb6d2b5 558 } // while(1)
vincenxp 0:10bf1bb6d2b5 559 #endif
vincenxp 0:10bf1bb6d2b5 560
vincenxp 0:10bf1bb6d2b5 561 }