Code for a FRDM-KL25Z board with a 30848 aggregator plugged on top. For use with 30847 smart sensors.

Dependencies:   mbed

Revision:
0:b33aadc7cfad
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/aggregator-kl25z.cpp	Fri May 24 15:37:43 2019 +0000
@@ -0,0 +1,452 @@
+/*******************************************************************************
+*
+*  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