David DiCarlo
/
30848-KL25Z-AGGREGATOR
Code for a FRDM-KL25Z board with a 30848 aggregator plugged on top. For use with 30847 smart sensors.
aggregator-kl25z.cpp
- Committer:
- r14793
- Date:
- 2019-05-24
- Revision:
- 0:b33aadc7cfad
File content as of revision 0:b33aadc7cfad:
/******************************************************************************* * * MIT License (https://spdx.org/licenses/MIT.html) * Copyright 2018-2019 NXP * * MBED code for FRDM-KL25Z aggregator. Configures and triggers "smart" sensors. * Aggregates data and sends up the line to a host computer over USB serial. * Other FRDM boards (K64F or K66F) may be used for ethernet connection or for * more local memory or faster processing speed. * * * !!! 22Apr19: seems fixed again with latest (Feb19 mbed lib)... * !!! 3Dec18: This now appears to be fixed with current version of library... * !!! must use mbed-2 from 20 Mar 2018 or serial port won't work !!! * !!! do not update mbed library... !!! * ********************************************************************************/ #include "mbed.h" char version_info[] = "24 May 2019"; // date info... Serial uart(USBTX, USBRX); // standard FRDM board USBx // set up GPIO connections... DigitalOut reset(PTB0); // PTA1 on smart sensor board DigitalOut interrupt(PTB1); // PTA0 on smart sensor board const int sensors = 14; // total number of sensor available... DigitalOut select[sensors] = // PTA2 on smart sensor board { (PTD4), (PTA12), (PTA4), (PTA5), (PTC8), (PTC9), (PTA13), (PTD5), (PTD0), (PTD2), (PTD3), (PTD1), (PTB3), (PTB2)}; I2C i2c(PTE0, PTE1); int addr8bit = 0x48 << 1; // default start addr for communication with sensors // multipliers of ten used for decompressing data... // *note* this array fails when it's not a const. index 4 returns zero for some // reason... maybe mbed, not sure... seems to be mbed-2 related... const float pow10[14] = {1.0, 1.0e-1, 1.0e-2, 1.0e-3, 1.0e-4, 1.0e-5, 1.0e-6, 1.0e-7, 1.0e-8, 1.0e-9, 1.0e-10, 1.0e-11, 1.0e-12, 1.0e-13}; // some more variables... int n, i, j, k, status, temp; short int chan, range; int delay=500000; // starting delay for measurement updates... long int count=0; char cmd[200]; // buffer for Ggholding data sent to/from sensor boards char params[sensors][20];// array to keep sensor parameter data... bool deebug=false; // flag to print extra stuff for debug... float v1, v2, i1, i2; // for holding full float vs. compressed 3-sigfig measurements bool full = false; // boolean to control whether full binary numbers sent bool gui = true; // flag to print data out in compressed format bool bargraph = true; // flag for bar graph... bool logging = false; bool flag; // timer so we can time how long things take... Timer t, l; // set up various arrays related to smart sensors... bool present[sensors] = { false, false }; // whether or not a sensor is present bool continuous = true; // flag for making continuous vs. triggered measurements... // this array of addresses also needed to be made a const array or // some values would inexplicably change and cause I2C errors // (because the address in the array gets changed somehow)... const fixes... // this seems to be mbed-2 related... const short int address[sensors] = // assigned address for each sensor { 0x50<<1, 0x51<<1, 0x52<<1, 0x53<<1, 0x54<<1, 0x55<<1, 0x56<<1, 0x57<<1, 0x58<<1, 0x59<<1, 0x5a<<1, 0x5b<<1, 0x5c<<1, 0x5d<<1 }; // this union allows easily converting float value to bare bytes and back again... union u_tag { char b[4]; float fval; int bobo; // just in case we want to see it as an int... } volt[2], curr[2]; // voltage and current value from sensor // these arrays are used for keeping track of the range status of each sensor... int rangeStatus[sensors] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', }; char rangesAvail[4] = {' ', 'H', 'M', 'L'}; // function that sends measurement trigger pulse to all sensors, singalling // them to take a measurement which will be subsequently and sequentially read... void send_trigger(){ interrupt = 1; wait_us(50); interrupt = 0; } // main code starts here... int main() { // set things up... reset = 0; // place sensors in reset interrupt = 0; // place trigger line low for (k=0; k<sensors; k++) select[k] = 1; // set each sensor's select line high i2c.frequency(200000); // set I2C frequency uart.baud(115200); // set UART baud rate uart.printf("\r\n\r\n\e[2J%s\r\nI'm here...\r\n ", version_info); // signal that we're off and running... // where \e[2J clears the screen... // loop forever (although, as code has evolved, this loop never completes...) while(1) { reset = 0; // issue a global reset wait(0.01); // wait a bit reset = 1; // release reset count++; // overall iteration count uart.printf("\r\n\r\nReleased reset... %d\r\n", count); wait(0.0005); // wait a little bit... // iterate to identify and configure each connected sensor... for (k=0; k<sensors; k++){ // loop over all sensors present[k] = false; // set presence to false before looking for sensor... select[k] = 0; // smake sensor select line low to start address reassignment uart.printf("Asserted select[%X] line low... \r\n", k); wait(0.001); // wait a bit... // write the new address to sensor and then read it back to verify... cmd[0] = address[k]; n = i2c.write( addr8bit, cmd, 1); uart.printf("Wrote: %x error %d \r\n", cmd[0], n); if (n==0) present[k] = true; // a sensor IS connected on this select line, since it ACKed if (present[k]){ cmd[0] = 0; // clear cmd... wait(0.0001); n = i2c.read( addr8bit, cmd, 1); uart.printf(" ===> Read back: %x error %d\r\n", cmd[0], n); // here we're reading it back but we're not actually checking the value... // just assuming that since we were able to write, we'll read the same // value back... } else i2c.stop(); // not present, error condition... wait(0.0001); select[k] = 1; // set sensor's select line high, telling it to change its I2C addr uart.printf("Sending select[%X] back high to change address... \r\n", k); if (present[k]) { // now check that the address change was successful... // write to the new address, there is currently no error out // if sensor does not respond... wait(0.0001); cmd[0]=0xff; n = i2c.write( address[k], cmd, 1); if (n==0) { uart.printf("\r\nSensor %X configured... now to test... \r\n\r\n", k); } else present[k]=false; } // endif if (present[k]) { // read parameters from sensor // Need to do this sequence without a trigger, since that'll cause an interrupt // and clobber any pre-loaded paramter data... cmd[0] = 99; // make a dummy write in order to pre-load parameter buffer... n = i2c.write( address[k], cmd, 2 ); wait(0.001); // here's where we actually read the parameters: n = i2c.read( address[k], params[k], 9 ); // select is already high from above, so we don't need to do it again... uart.printf("\r\n params %d %d %d %d %d %d \r\n", params[k][0], params[k][1]*8, params[k][2]*8, params[k][3]*8, params[k][4]*8, params[k][5]); // now add one to each parameter to make sure we can write them all... // will see below if it worked... (we'll see it down below) for (i=0; i<6; i++){ cmd[0] = i; cmd[1] = params[k][i]+1; uart.printf(" %d, %d, %d %d \r\n", k, i, cmd[0], cmd[1]); n = i2c.write( address[k], cmd, 2 ); wait(0.01); } } } // for k wait(0.0005); // ****************************************************************** // read data from all connected sensors... // ****************************************************************** while (1) { if (!logging) { if (!gui) uart.printf("\r\nTriggering measurement... \r\n"); else { uart.printf("\e[2J"); // clear screen uart.printf("\033[H"); // go to upper left corner of window uart.printf("\r\n\033[0;36mRail (V) (A)\033[0;37m\r\n"); } } /* // testing curr_range indicators... uart.printf("\r\n"); for (i=0; i<sensors; i++){ //if (present[i]) uart.printf("%X: .%d. ", i, rangeStatus[i]); } uart.printf("\r\n"); */ t.start(); send_trigger(); // trigger tells all connected sensors to make the measurements wait_ms(8.75); // need to give enough time to make them... if (logging) uart.printf("%6.2f ", l.read()); // print timestamp if logging... for (k=0; k<sensors; k++){ // iterate over all sensors if (present[k]){ // if a sensor is present, read its data if (full){ // full floating point data tranfer... n = i2c.read( address[k], cmd, 9 ); if (deebug && !gui && !logging) uart.printf(" I2C adddr: 0x%X %X\r\n", address[k], k); // unstuff the bytes back into floating point values... for (j=0; j<4; j++) curr[0].b[j] = cmd[j]; for (j=0; j<4; j++) volt[0].b[j] = cmd[j+4]; v1 = volt[0].fval; i1 = curr[0].fval; if (!gui && !logging) uart.printf(" Sensor %X: ===> %4.2e %4.2e 0x%x err %d\r\n", k, volt[0].fval, curr[0].fval, cmd[8], n); } // if (full) // compressed data transfer with status nibble: 2 float values of 3 sig figs each + status nibble: // where each value is 3 digits, single digit exponent, and two status bits packed into 2 bytes // four bytes in total... select[k] = 0; // indicate that we want to read compressed data from sensor... n = i2c.read( address[k], cmd, 4 ); select[k] = 1; // pull out status bits from the four received bytes... status = (cmd[0]&(1<<7))>>4 | (cmd[1]&(1<<7))>>5 | (cmd[2]&(1<<7))>>6 | (cmd[3]&(1<<7))>>7 ; if (deebug && !gui && !logging) uart.printf(" %02d %02d %02d %02d %8.6f %d %8.6f %d\r\n", cmd[0]&0x7f, cmd[1]&0x7f, cmd[2]&0x7f, cmd[3]&0x7f, pow10[(int)(((cmd[1]&(0x7f)) % 10)+2)], (int) (((cmd[1]&(0x7f)) % 10)+2), pow10[(int)(((cmd[3]&(0x7f)) % 10)+2)], (int) (((cmd[3]&(0x7f)) % 10)+2)); // now reconstruct the two float values... curr[1].fval = (float) ( (cmd[0]&(0x7f))*10 + (cmd[1]&(0x7f))/10 ) * pow10[((cmd[1]&(0x7f)) % 10)+2]; volt[1].fval = (float) ( (cmd[2]&(0x7f))*10 + (cmd[3]&(0x7f))/10 ) * pow10[((cmd[3]&(0x7f)) % 10)+2]; v2 = volt[1].fval; i2 = curr[1].fval; if (!gui && !logging) uart.printf(" compd %X: ===> %4.2e V %4.2e A %d err %d\r\n", k, volt[1].fval, curr[1].fval, status, n); if (deebug && !gui) printf(" volt? %s current? %s \r\n", (abs(v1-v2)/v1 <0.05) ? "true" : "false", (abs(i1-i2)/i1 <0.05) ? "true" : "false"); // if we're in gui mode, this is the only line that'll print out for each attached sensor... if (!logging){ if (gui && full) { // uart.printf(" %X %4.2e %4.2e %4.2e %4.2e \r\n", k, v1, v2, i1, i2); uart.printf(" \033[33m#%X\033[37m %3.2f %4.2e %c ", k , v1, i1, rangeStatus[k]); if ((i1>=0.25) && (bargraph)) { for (j=0; j<13*i1; j++) uart.printf("\033[31mA"); } if ((i1<0.25) && (i1>=0.001) && (bargraph)) { for (j=0; j<208*i1; j++) uart.printf("\033[32mm"); } if ((i1<0.001) && (bargraph)) { for (j=0; j<52000*i1; j++) uart.printf("\033[35mu"); } uart.printf("\033[37m\r\n"); } else { uart.printf(" \033[33m#%X\033[37m %3.2f %4.2e %c ", k , v2, i2, rangeStatus[k]); if ((i2>=0.25) && (bargraph)) { for (j=0; j<13*i2; j++) uart.printf("\033[31mA"); } if ((i2<0.25) && (i2>=0.001) && (bargraph)) { for (j=0; j<208*i2; j++) uart.printf("\033[32mm"); } if ((i2<0.001) && (bargraph)) { for (j=0; j<52000*i2; j++) uart.printf("\033[35mu"); } uart.printf("\033[37m\r\n"); /* // testing curr_range indicators... uart.printf(" "); for (i=0; i<sensors; i++){ //if (present[i]) uart.printf("%X: .%d. ", i, rangeStatus[i]); } uart.printf("\r\n"); */ } // else } else { uart.printf(" %3.2e %4.2e", v2, i2); } // parameter readback from sensor // !! Smart Sensor's selelct line needs to be high while doing this !! // Need to do this sequence without a trigger, since that'll cause an interrupt // and clobber any pre-loaded paramter data... if (deebug && !gui && !logging) { cmd[0] = 99; // dummy write to pre-load parameter buffer... n = i2c.write( address[k], cmd, 2 ); n = i2c.read( address[k], params[k], 9 ); // select is already high from above, so we don't need to do it again... uart.printf(" params %d %d %d %d %d %d \r\n", params[k][0], params[k][1]*8, params[k][2]*8, params[k][3]*8, params[k][4]*8, params[k][5]); } } else{ //uart.printf(" !!! device %d missing... \r\n", k); } //endif } // for k if (logging) uart.printf("\r\n"); // wait_ms(250); while (t.read_us()<delay){ // wait until delay worth of time has elapsed... } t.stop(); t.reset(); if (!continuous) while (!uart.readable()); // wait here until we get text, if in triggered mode... while (uart.readable()){ temp = uart.getc(); if (deebug) printf ("%d\r\n", temp); if (temp== '+') { delay += 100000; if (delay > 2000000) delay = 2000000; } if (temp== '-') { delay -=100000; if (delay < 14300) delay = 14300; } if (temp== 't') { uart.printf ("\r\nDelay value = %d\r\n", delay); } if (temp== '_') { delay = 500000; } if (temp== 'c') { continuous = !continuous; } if (temp== 'd') { deebug = !deebug; } if (temp== 'g') { gui = false; } if (temp== 'G') { gui = true; } if (temp==(int) 'b') { bargraph = !bargraph; } if ((temp== 'l')||(temp== 'L')) { if (!logging) { uart.printf("Enable logfile and then hit any key when ready...\r\n"); while (!uart.readable()); // only pause if we're already logging... temp = uart.getc(); // capture last character so we don't do it again... } logging = !logging; // toggle logging flag... // print a header if we're just starting to log... uart.printf("Time_S"); for (j=0; k<sensors; k++){ if (logging && present[j]) uart.printf(" Volts_%d Amps_%d", j, j); } if (logging) uart.printf("\r\n"); l.reset(); l.start(); // for timestamping the output... } if (temp=='f') { full = !full; uart.printf("\r\n\r\n"); if (full) uart.printf("Full data over I2C"); else uart.printf("Compressed data over I2C"); wait(2); } if (temp=='h') { uart.printf("\r\n\r\n"); uart.printf("+/- add/remove update time\r\n"); uart.printf("_ half second update rate\r\n"); uart.printf("b toggle bar graph in gui mode\r\n"); uart.printf("c toggle continuous/single trigger\r\n"); uart.printf("t trigger and print current delay value\r\n"); uart.printf("d toggle debug flag\r\n"); uart.printf("f toggke full data over I2C\r\n"); uart.printf("g turn off gui mode\r\n"); uart.printf("G turn on gui mode\r\n"); uart.printf("h print this help\r\n"); uart.printf("l toggle logging output\r\n"); uart.printf("R/r enter range selection menu\r\n"); uart.printf("\r\n"); wait(5); } if (temp=='R' || temp=='r') { // present range changing stuff... uart.printf("\r\nCAUTION: Selecting fixed range can damage sensor!\r\n\r\n"); uart.printf("Select a valid channel:\r\n"); for (j=0; j<sensors; j++){ // iterate over all sensors if (present[j]) uart.printf("%X ", j); } uart.printf("\r\n"); // Select which channel to change range... flag = true; while (flag){ while (!uart.readable()); temp = uart.getc(); // capture last character so we don't do it again... // test input validity... if ((int) '0'<=temp && temp<= (int) '9') chan = temp - (int) '0'; else if ((int) 'a'<=temp && temp<=(int) 'd') chan = temp - (int) 'a' + 10; else if ((int) 'A'<=temp && temp<=(int) 'D') chan = temp - (int) 'A' + 10; // then test that input is actually a valid channel... for (i=0; i<sensors; i++){ // iterate over all sensors if (present[i] && chan==i) { flag = false; // turn off flag so we leave the while loop... break; // break out of the for loop... } } } // present range choices... uart.printf("\r\n Selected: %X \r\n", chan); uart.printf("Select Current Range:\r\n"); uart.printf("A = Autorange\r\n"); uart.printf("H = High only\r\n"); uart.printf("M = Middle only\r\n"); uart.printf("L = Low only\r\n"); uart.printf("X = Exit, no change\r\n"); // select which range to use... flag = true; while (flag){ while (!uart.readable()); temp = (int) uart.getc(); // capture last character so we don't do it again... if ('A'==temp || 'a'==temp) {flag = false; range = 0;} if ('H'==temp || 'h'==temp) {flag = false; range = 1;} if ('M'==temp || 'm'==temp) {flag = false; range = 2;} if ('L'==temp || 'l'==temp) {flag = false; range = 3;} if ('X'==temp || 'x'==temp) {flag = false; range = 4;} } uart.printf(" Range %d \r\n", range); if (range<4) { cmd[0] = 127; cmd[1] = range; uart.printf(" %d, %d, %d \r\n", chan, cmd[0], cmd[1]); n = i2c.write( address[chan], cmd, 2 ); wait_ms(10); n = i2c.read( address[chan], cmd, 9 ); // read back to make sure... rangeStatus[chan] = rangesAvail[ cmd[8] ]; uart.printf(" reported range = %d ('%c')\r\n", params[chan][8], rangeStatus[chan]); wait(1); } } // range changing block... } // while uart.readable... } // while read from sensors... // ***************************************************************** // end data read // ***************************************************************** } // while main, should never actually fall out to here... } // main