Smart sensor code for KL05Z, including fixed ranging as well as auto-ranging.

Dependencies:   mbed-src-KL05Z-smart-sensor

Committer:
r14793
Date:
Tue May 28 14:04:19 2019 +0000
Revision:
0:119db3edc934
first commit.

Who changed what in which revision?

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