Logger to USB stick running on KL25Z

Dependencies:   F401RE-USBHost FastAnalogIn RTC mbed tsi_sensor2 mbed-rtos2

Fork of ReadSendData by Stuart Scott

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* low power data logger. [FRDM-KL25Z]
00002 
00003 Periodically read data from ADC and when present write it in JSON format to USB Stick
00004 
00005 Copyright  http://www.apache.org/licenses/LICENSE-2.0
00006 and all subsystems per their own licenses which are believed to be GPL 2.0
00007 
00008 [c]Record an analoge value to an internal buffer 
00009 [p]and when a USB stick is plugged in store the values on the USB stick in JSON format
00010    (currently requires USB stick at reset)
00011 [c]Debug output the events as they happen.
00012 [c]The ticker delay sets the sampling rate. 
00013 [F]Date is set when user sets it, 
00014 [c]or elapsed time used in the beginning 
00015 
00016 [F]If OpenSDA USB power supplied, then flash LEDs to indicate activity as follows
00017 [c]1) the Blue led when taking a sample
00018 [c]2) the green led when delivering samples to the USB stick
00019 [F]3)no led shall be on at same time for clear colours
00020 
00021 [F] when not doing anything else sleep to conserve power.
00022 
00023  To modify this for your application, assuming a ratiometric input to the Vref=3.3V
00024  1) Determine physical pins ADC performed on and type of conversion,
00025  1) Determine the "multiplier" from the incoming 16bit ADC wrt to 3.3V to your units.
00026  2) Write the output code changing the JSON headers to define your headers, dataConversion and units
00027  
00028 Thanks to other authors for setting up KL25z for 
00029 * FastAnalogIn Library  mbed.org/users/Sissors/code/FastAnalogIn/
00030 * USB Host mbed.org/users/va009039/code/F401RE-USBHost/
00031  
00032  [] 1st three character nomeclature.
00033 [x] indicates implemented state of feature 
00034 [c] - complete and unit tested
00035 [p] - partial in progress or not unit tested
00036 [f] - future idea
00037 
00038 Testing: Basic tests performed, see attached file logger_tests.docx
00039 
00040 Modifications to Hardware
00041 1) FRDM-KL25z add J21 and R8 per the instruction manual for USB host
00042 
00043 Issues: 
00044 1) FRDM-KL25z hardware not designed to switch the USB power so saving power on a connected USB device.
00045 Solution: Add switched 5V power.
00046 2) FRDM-KL25z Hardware not designed for low power accurate wall time clock - wastes power keeping the 8Mhz going.
00047 Solution: add an external low power 32KHz oscilator into hardware pin RTC_IN (An osc is the next step up from a raw Xtal)
00048 
00049 
00050 */
00051 
00052 #include "mbed.h"
00053 //#include "rtos.h"
00054 #include "rtc_api.h"
00055 #include "FastAnalogIn.h"
00056 #include "USBHostMSD.h"
00057 #include "board_cust.h"
00058 
00059 
00060 #if defined(TARGET_K20D50M)
00061 #define TsiActive 0
00062 
00063 #elif defined (TARGET_KL25Z) || defined (TARGET_KL46Z)
00064   #define TsiActive 1
00065   #include "tsi_sensor.h"
00066   //Cap Sensor B0=CH0, B1=CH6
00067   #define ELEC0 0
00068   #define ELEC1 6
00069   //FRDM_KL25x slider electrodes - TSI0_CH9=PTB16, CH10=B17
00070 //  #define ELEC0 9
00071 //  #define ELEC1 10
00072    TSIAnalogSlider tsi(ELEC0, ELEC1, 40);
00073    //TSIElectrode tsiElec0(ELEC0);
00074    //TSIElectrode tsiElec1(ELEC1);
00075    //#define TsiRead()  tsi.readDistance() - has problesm
00076    #define TsiRead()  tsi.readPercentage()
00077    
00078 #elif defined (TARGET_KL05Z)
00079   #define TsiActive 0
00080   #include "TSISensor.h"
00081 
00082   #define ELEC0 9
00083   #define ELEC1 8
00084     TSIAnalogSlider tsi(ELEC0, ELEC1, 40);
00085     //#define TsiRead(void)  tsi.Distance()
00086 #else
00087   #define TsiActive 0
00088   #error TARGET NOT DEFINED
00089 #endif
00090 
00091 
00092 //size of Customer ADC sample  buffer 
00093 #define BuffSize 16  //16 to test, upto kl25z spare ram of about xxxx?, !2000, linker warns if too large, but also fails
00094 #define SAMPLE_WIN 8 // Should be less than BuffSize
00095 #if BuffSize < SAMPLE_WIN
00096 #error Buffsize < SAMPLE_WIN
00097 #endif 
00098 //set the delay used by the ticker
00099 const int sysTockInit_sec = 1; //Test 1, Real life 15minutes or 900sec
00100 
00101 using namespace mbed;
00102 
00103 
00104 //Device Init - per FRDM-KL25Z
00105 DigitalOut ledRed(LED1); 
00106 //DigitalOut ledGrn(LED2); 
00107 PwmOut ledPwmGrn(LED2);
00108 DigitalOut ledBlue(LED3); 
00109 FastAnalogIn ainPinAA(PTC2); ///AnalogAin pin
00110 
00111 Serial pc(USBTX, USBRX);
00112 
00113 //Samples stored here - needs to be compact as can use a lot of internal ram
00114  unsigned short sample_u16[BuffSize]; //critical resource for number of samples
00115  unsigned short publish_u16[BuffSize]; //value published
00116  unsigned short sampleInst_raw, sampleAvg_raw;
00117 float tsiSlider_dist;
00118 uint32_t elec0p,electr[BuffSize];
00119 //uint32_t elec1p;
00120  unsigned int time_[BuffSize];
00121 
00122 
00123  
00124  bool UsbPresent=0;
00125  bool warmBoot = rtc_isenabled(); 
00126  long lp2i =0;
00127  bool sysEventA=0; //Local event
00128  unsigned int tmrE_evt; //Elapsed
00129  Ticker tock; //periodic tick
00130 
00131      
00132 #if defined(TARGET_K20D50M)
00133 const char meProc[] = "K20D50M";
00134 #elif defined(TARGET_KL25Z)
00135 const char meProc[]= "KL25Z";
00136 #else //#if defined(TARGET_KL46Z)||defined(TARGET_K64F) 
00137 #error Undef processor
00138 #endif //
00139 
00140 
00141  
00142 
00143 
00144 //--------------------------------------------------------------
00145 void tockEvent()
00146 {
00147     tmrE_evt++;
00148     sysEventA=1;
00149 }
00150 
00151 //--------------------------------------------------------------
00152 /* Process output Header to USB, 
00153 return !0 if valid USB present
00154 */
00155  bool outputHeaderUsb(FILE* fpUsb) {
00156     // JSON {"headings":{"time":{"elapsed":"seconds"},  "adcN":"normalized_to_1.0", "adcV":"Volts"}}
00157     
00158     if (!UsbPresent) 
00159     {
00160       if (1/*ToDo msd.connect()*/) //Attempt to find a device
00161       {//USB Event: newly connected so attempt write header
00162         if (NULL !=(fpUsb = fopen("/usbAa/test1.txt", "a"))) 
00163         {
00164             pc.printf("USB File test1.txt opened.\n\r");
00165             fprintf(fpUsb,"{\"headings\":{\"time\":{\"elapsed\":\"seconds\"},  \"adcN\":\"normalized_to_1.0\", \"adcV\":\"Volts\"}"
00166 #if TsiActive
00167              "\"tsi\":\"[0-40]\""
00168 #endif
00169             "}}\n");
00170             UsbPresent=1;
00171             fclose(fpUsb); fpUsb=NULL;
00172         } else {
00173             //Can't find a file for some reason. Could be USB full or failed software
00174             pc.printf(" Error: USB File not opened.\n\r");
00175             UsbPresent=0;
00176         }
00177       } //else //Can't find USB device
00178     } else {
00179         // UsbPresent and assume headers written
00180         if (1/*ToDo !msd.connected()*/) 
00181         {
00182           pc.printf("  USB Flash drive removed.\n\r");
00183           UsbPresent=0;
00184         }
00185     }
00186     
00187     return UsbPresent;
00188 }
00189 //--------------------------------------------------------------
00190  void outputHeaders(void) {
00191     //ToDo - outputHeaderUsb(*fp);
00192     pc.printf("  Time(S)   depthR(norm) Volts Idx %d\n\r",(unsigned int) rtc_read());
00193 }//outputHeaders
00194 
00195 
00196 
00197 //--------------------------------------------------------------
00198 /* Manage the write to USB stick
00199 [FUT] detect USB stick and if not present write it when inserted
00200 
00201 JSON output json.org
00202 {key:value, key:value, key:value}
00203 {time:[elapsed:<secs 0-2**32>, epoch2014:<secs 0-2**32>,wall:[date:<>,clock:<>],],
00204  adcNorm:<float number 0.0-1.0>, 
00205  adcV:<Volts 0-VRef>
00206  */
00207 bool manageUsbWrite(FILE* fpUsb) {
00208 #define ADC_NORMALIZE (1.0f/65535.0f)
00209 #define ADC_NORM_VREF 3.3
00210     float data_n=( ((float)sample_u16[lp2i]) * ADC_NORMALIZE);
00211     bool writeUsb=0;
00212     //Future redesign to use USBHALHost::wait_attach()
00213     if (outputHeaderUsb(fpUsb)) 
00214     {
00215       if (NULL !=(fpUsb = fopen("/usbAa/test1.txt", "a"))) 
00216       {  
00217 #if TsiActive
00218     //del pc.printf("%10d  %5.4f (%6.4fV) %i\n\r",time_[lp2i],data_n,(ADC_NORM_VREF*data_n),lp2i);
00219           fprintf(fpUsb, "{\"time\":{\"elapsed\":%10d},\"adcN\":  %5.4f, \"adcV\":%6.4f, \"e0\":%i }\n",time_[lp2i],
00220           data_n,(ADC_NORM_VREF*data_n), 
00221           elec0p);
00222 #else
00223            fprintf(fpUsb, "{\"time\":{\"elapsed\":%10d},\"adcN\":  %5.4f, \"adcV\":%6.4f}\n",time_[lp2i],data_n,(ADC_NORM_VREF*data_n));
00224 #endif
00225            fclose(fpUsb); fpUsb=NULL;
00226            writeUsb=1;
00227        } else {
00228            //Potential Error
00229            UsbPresent=0; //Can't say its dissappeared as will cause USB find problem.
00230            pc.printf("  Error: USB unexpected can't write!!\n\r");
00231            //writeUsb=0;
00232        }
00233     } 
00234     return writeUsb;
00235  } 
00236 //--------------------------------------------------------------
00237 /* Manage the sample
00238 - store it 
00239 - and write it to USB stick
00240 [FUT] detect USB stick and if not present write it when inserted
00241 
00242 JSON output json.org
00243 {key:value, key:value, key:value}
00244 {time:[elapsed:<secs 0-2**32>, epoch2014:<secs 0-2**32>,wall:[date:<>,clock:<>],],
00245  adcNorm:<float number 0.0-1.0>, 
00246  adcV:<Volts 0-VRef>}
00247 */
00248 void manageSample() {
00249     float data_n;
00250     int i_lp,idx;
00251     int publishInst_raw;
00252     bool noisey=0;
00253 
00254     /* WaterDepth eTape sensor is noisey - average input for noise and compare against changes by capactive sensor
00255     * Average published sensor and check if new reading changes by more than 1/300 of fsd if it does check against capacitive sensor and see if it is trending same direction
00256     */
00257     publishInst_raw = sample_u16[lp2i]; //over X previous
00258     sampleInst_raw  = sample_u16[lp2i]; //over X previous
00259     elec0p = electr[lp2i];
00260     for (i_lp =1; i_lp< SAMPLE_WIN; i_lp++) {
00261         idx = lp2i-i_lp;
00262         if (idx <0) idx+= BuffSize;
00263         publishInst_raw += publish_u16[i_lp]; //over X previous
00264         sampleInst_raw += sample_u16[i_lp]; //over X previous
00265         elec0p += electr[i_lp];
00266     }
00267     publishInst_raw /= SAMPLE_WIN;
00268     sampleInst_raw /= SAMPLE_WIN;
00269     elec0p /= SAMPLE_WIN;
00270 #if 0 //future
00271     #define SAMPLES_ABS_CNT 5
00272     if (SAMPLES_ABS_CNT < abs(sampleInst_raw - publishInst_raw) )  {
00273         //Need to check if this is noise
00274         //if ( abs(abs(elec0p) - electr[lp21]);
00275         noisey = 1;
00276         }
00277 #endif //0
00278     data_n=sampleInst_raw * ADC_NORMALIZE;
00279     pc.printf("\n\r%10d  %5.4f (%6.4fV) %i %i N%i %i",time_[lp2i],data_n,(ADC_NORM_VREF*data_n),
00280     electr[lp2i],elec0p, noisey,
00281     lp2i);
00282 
00283     //ledGrn = !(lp2i&0x01);//!ledGrn; syncs with blue led flashing    
00284     //ledPwmGrn = ((lp2i&0x01) ? (1.0-? ? ?) : 1.0 ); //LEDGrn=1 off, =0 On
00285     if (lp2i&0x01) {//Only write every two times
00286         if (1/*ToDo==manageUsbWrite(*fp)*/) {
00287             ledBlue = !ledBlue; //(lp2i&0x03);
00288         } else {ledBlue =1;}//off
00289     }
00290 
00291 }//end manageSample
00292 
00293 //--------------------------------------------------------------
00294 /* Manage the sample
00295 - take an ADC sample and 
00296 */
00297 void manageAdcIn(void){
00298     //Take samples and store in buffer
00299     if (++lp2i >= BuffSize) lp2i=0;
00300     sample_u16[lp2i]=ainPinAA.read_u16();
00301     time_[lp2i]=(unsigned int)tmrE_evt; //TODO - replace with wall time
00302 #if TsiActive
00303     tsiSlider_dist = TsiRead();
00304     electr[lp2i]= tsi.getDelta0();
00305 #endif //TsiActive
00306     
00307     //elec1p = tsi.getDelta1();    
00308     //tsiSlider_dist = (float)tsi.readPercentage(); 
00309        
00310  }//manageAdcIn
00311  
00312  //--------------------------------------------------------------
00313  void UsbHostMsd_task(void const *) {
00314      USBHostMSD  msd("usbAa"); //defines the file system access
00315     int i = 0;
00316     
00317     while(1) {
00318         
00319         // try to connect a MSD device
00320         while(!msd.connect()) {
00321             //Thread::wait(500);
00322         }
00323         
00324         // in a loop, append a file
00325         // if the device is disconnected, we try to connect it again
00326         while(1) {
00327             
00328             // append a file
00329             FILE * fp = fopen("/usb/test1.txt", "a");
00330         
00331             if (fp != NULL) {
00332                 fprintf(fp, "Hello fun SD Card World: %d!\r\n", i++);
00333                 printf("Goodbye World!\r\n");
00334                 fclose(fp);
00335             } else {
00336                 printf("FILE == NULL\r\n");
00337             }
00338             
00339             //Thread::wait(500);
00340         
00341             // if device disconnected, try to connect again
00342             if (!msd.connected())
00343                 break;
00344         }
00345             
00346     }
00347 }
00348 /* Input parser from usb - but how large is buffer
00349   char buffer[128];    
00350   pc.gets(buffer, 4);
00351   pc.printf("I got '%s'\n", buffer);  
00352 */
00353 //--------------------------------------------------------------
00354 int main() {
00355 
00356 //TODO: check RCM_SRS0 &RS1
00357     warmBoot = rtc_isenabled(); 
00358     if (!warmBoot) {
00359         //TODO figure out how to manage wall time
00360         rtc_init(); //Assumes external clock - TODO: options int32Khz  RTC_CLKIN ext32KhzXtal 
00361         rtc_write(0x0); //Init to some default;
00362     }
00363 
00364     ledRed =0;//ON
00365     //ledGrn =1; //off
00366     ledPwmGrn =1.0; //off
00367     ledBlue = 1; //on    
00368     
00369     //Thread msdTask(UsbHostMsd_task, NULL, osPriorityNormal, 1024 * 4);
00370     
00371     wait_ms(5000); 
00372     //Thread::wait(2000);
00373     ledRed =1;//Off
00374     //ledGrn =1; //off
00375     ledPwmGrn =1.0; //off
00376     ledBlue = 0; //on
00377     pc.baud(115200);//Opt 57600
00378 
00379     pc.printf("\n\r%s Logger v0.1 \n\r Sample [time=%dsec, size=%d] Clock=%d\n\r",meProc, sysTockInit_sec,BuffSize,SystemCoreClock);
00380 
00381     outputHeaders();
00382 
00383     tock.attach(&tockEvent,sysTockInit_sec); 
00384 
00385     while (true) {        
00386      if(sysEventA)
00387      {
00388        sysEventA=0;
00389        manageAdcIn();
00390        manageSample();
00391       }//else 
00392       // TODO go into power down till next event
00393     }
00394    
00395 }