00001 /* 00002 * Copyright (C) 2009 Libelium Comunicaciones Distribuidas S.L. 00003 * http://www.libelium.com 00004 * 00005 * This program is free software: you can redistribute it and/or modify 00006 * it under the terms of the GNU Lesser General Public License as published by 00007 * the Free Software Foundation, either version 2.1 of the License, or 00008 * (at your option) any later version. 00009 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU Lesser General Public License for more details. 00014 00015 * You should have received a copy of the GNU Lesser General Public License 00016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00017 * 00018 * Version: 0.6 00019 * Design: David Gascón 00020 * Implementation: Alberto Bielsa, David Cuartielles 00021 */ 00022 00023 #ifndef __WPROGRAM_H__ 00024 // #include <WProgram.h> 00025 #include <WaspClasses.h> 00026 #endif 00027 00028 00029 #ifndef cbi 00030 #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) 00031 #endif 00032 00033 #ifndef sbi 00034 #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) 00035 #endif 00036 00037 // Variables //////////////////////////////////////////////////////////////// 00038 00039 // these two variables have been moved to the general system 00040 uint8_t intIPRA = 0; 00041 uint8_t intIPRB = 0; 00042 00043 // Constructors //////////////////////////////////////////////////////////////// 00044 00045 WaspPWR::WaspPWR() 00046 { 00047 // nothing to do when constructing 00048 } 00049 00050 // Private Methods ///////////////////////////////////////////////////////////// 00051 00052 /* setIPF ( peripheral ) 00053 * - sets a certain internal peripheral on 00054 * - to control the pwr on the different internal peripherals it is 00055 * convenient to read MCU's manual on pgs. 56/57 00056 * FIXME: missing all the Timers and UART to reduce consumption 00057 */ 00058 void WaspPWR::setIPF(uint8_t peripheral) 00059 { 00060 setIPF_(peripheral); 00061 intIPRA = IPRA; 00062 } 00063 00064 /* resetIPR ( peripheral ) 00065 * - resets a certain internal peripheral to off 00066 * - to control the pwr on the different internal peripherals it is 00067 * convenient to read MCU's manual on pgs. 56/57 00068 * FIXME: missing all the Timers and UART to reduce consumption 00069 */ 00070 void WaspPWR::resetIPF(uint8_t peripheral) 00071 { 00072 resetIPF_(peripheral); 00073 intIPRA = IPRA; 00074 } 00075 00076 /* uint8_t getIPR ( ) 00077 * - answers with the whole IPR 00078 */ 00079 uint8_t WaspPWR::getIPF() 00080 { 00081 return intIPRA; 00082 } 00083 00084 /* sleepNow ( functionName ) 00085 * - call the sleepNow method with the wake up function sent as parameter 00086 */ 00087 /* 00088 void WaspPWR::sleepNow(void (*userFunc)(void), uint8_t mode) // here we put the Wasp to sleep 00089 { 00090 /* Now is the time to set the sleep mode. In the Atmega8 datasheet 00091 * http://www.atmel.com/dyn/resources/prod_documents/doc2486.pdf on page 35 00092 * there is a list of sleep modes which explains which clocks and 00093 * wake up sources are available in which sleep modus. 00094 * 00095 * In the avr/sleep.h file, the call names of these sleep modus are to be found: 00096 * 00097 * The 6 different modes are: 00098 * SLEEP_MODE_IDLE -the least power savings 00099 * SLEEP_MODE_ADC 00100 * SLEEP_MODE_PWR_SAVE 00101 * SLEEP_MODE_STANDBY 00102 * SLEEP_MODE_EXT_STANDBY 00103 * SLEEP_MODE_PWR_DOWN -the most power savings 00104 * 00105 * For now, we want as much power savings as possible, so we 00106 * choose the according 00107 * sleep modus: SLEEP_MODE_PWR_DOWN 00108 * 00109 */ 00110 /* 00111 cbi(ADCSRA,ADEN); // switch Analog to Digitalconverter OFF 00112 set_sleep_mode(mode); // sleep mode is set here 00113 00114 sleep_enable(); // enables the sleep bit in the mcucr register 00115 // so sleep is possible. just a safety pin 00116 00117 /* Now is time to enable a interrupt. we do it here so an 00118 * accidentally pushed interrupt button doesn't interrupt 00119 * our running program. if you want to be able to run 00120 * interrupt code besides the sleep function, place it in 00121 * setup() for example. 00122 * 00123 * In the function call attachInterrupt(A, B, C) 00124 * A can be either 0 or 1 for interrupts on pin 2 or 3. 00125 * 00126 * B Name of a function you want to execute at interrupt for A. 00127 * 00128 * C Trigger mode of the interrupt pin. can be: 00129 * LOW a low level triggers 00130 * CHANGE a change in level triggers 00131 * RISING a rising edge of a level triggers 00132 * FALLING a falling edge of a level triggers 00133 * 00134 * In all but the IDLE sleep modes only LOW can be used. 00135 */ 00136 /* 00137 attachInterrupt(7,userFunc, LOW); // use interrupt 7 (pin RST_RTC) and run function 00138 // blinkLEDs when pin E7 changes to LOW 00139 00140 sleep_mode(); // here the device is actually put to sleep!! 00141 // THE PROGRAM CONTINUES FROM HERE AFTER WAKING UP 00142 00143 sleep_disable(); // first thing after waking from sleep: 00144 // disable sleep... 00145 detachInterrupt(7); // disables interrupt 7 on pin E7 so the 00146 // blinkLEDs code will not be executed 00147 // during normal running time. 00148 sbi(ADCSRA,ADEN); // switch Analog to Digitalconverter ON 00149 } 00150 */ 00151 00152 00153 // Public Methods ////////////////////////////////////////////////////////////// 00154 00155 00156 00157 /* setSensorPower( type, mode) - set ON/OFF 3V3 or 5V switches 00158 * 00159 * It sets ON/OFF 3V3 or 5V switches 00160 */ 00161 void WaspPWR::setSensorPower(uint8_t type, uint8_t mode) 00162 { 00163 pinMode(SENS_PW_3V3,OUTPUT); 00164 pinMode(SENS_PW_5V,OUTPUT); 00165 00166 switch( type ) 00167 { 00168 case SENS_3V3: if(mode==SENS_ON) digitalWrite(SENS_PW_3V3,HIGH); 00169 else if(mode==SENS_OFF) digitalWrite(SENS_PW_3V3,LOW); 00170 break; 00171 case SENS_5V: if(mode==SENS_ON) digitalWrite(SENS_PW_5V,HIGH); 00172 else if(mode==SENS_OFF) digitalWrite(SENS_PW_5V,LOW); 00173 break; 00174 } 00175 } 00176 00177 00178 /* setWatchdog( mode, timer) - enables or disables watchdog interruption 00179 * 00180 * It enables or disables watchdog interruption. 00181 * 00182 * 'mode' --> if mode=WTD_ON, it enables watchdog interruption. If mode=WTD_OFF, it disables watchdog interruption. 00183 * 'timer' --> it specifies the time before the watchdog activates the interruption. Possible values are: 00184 * WTD_16MS 0 00185 * WTD_32MS 1 00186 * WTD_64MS 2 00187 * WTD_128MS 3 00188 * WTD_250MS 4 00189 * WTD_500MS 5 00190 * WTD_1S 6 00191 * WTD_2S 7 00192 * WTD_4S 8 00193 * WTD_8S 9 00194 * 00195 * It returns nothing 00196 */ 00197 void WaspPWR::setWatchdog(uint8_t mode, uint8_t timer) 00198 { 00199 if(mode==WTD_ON) 00200 { 00201 enableInterrupts(WTD_INT); 00202 setup_watchdog(timer); // set watchdog interrupt to wake up from Sleep Power Down Mode 00203 } 00204 00205 if(mode==WTD_OFF) 00206 { 00207 disableInterrupts(WTD_INT); 00208 off_watchdog(); 00209 } 00210 } 00211 00212 00213 /* switchesOFF() - switches off the Waspmote switches specified 00214 * 00215 * It switches off all Waspmote switches 00216 */ 00217 void WaspPWR::switchesOFF(uint8_t option) 00218 { 00219 cbi(ADCSRA,ADEN); // switch Analog to Digital Converter OFF 00220 pinMode(SERID_PW,OUTPUT); 00221 digitalWrite(SERID_PW,LOW); 00222 pinMode(MEM_PW,OUTPUT); 00223 digitalWrite(MEM_PW,LOW); 00224 00225 if( option & SENS_OFF ) 00226 { 00227 pinMode(SENS_PW_3V3,OUTPUT); 00228 digitalWrite(SENS_PW_3V3,LOW); 00229 pinMode(SENS_PW_5V,OUTPUT); 00230 digitalWrite(SENS_PW_5V,LOW); 00231 } 00232 00233 if( option & UART0_OFF ) 00234 { 00235 XBee.setMode(XBEE_OFF); 00236 } 00237 00238 if( option & UART1_OFF ) 00239 { 00240 closeSerial(1); 00241 pinMode(MUX_PW, OUTPUT); 00242 digitalWrite(MUX_PW, LOW); 00243 pinMode(GPS_PW, OUTPUT); 00244 digitalWrite(GPS_PW, LOW); 00245 00246 } 00247 00248 if( option & RTC_OFF ) 00249 { 00250 pinMode(RTC_PW,OUTPUT); 00251 digitalWrite(RTC_PW,LOW); 00252 00253 } 00254 00255 if( option & BAT_OFF ) 00256 { 00257 pinMode(BAT_MONITOR_PW,OUTPUT); 00258 digitalWrite(BAT_MONITOR_PW,LOW); 00259 } 00260 } 00261 00262 00263 /* switchesON() - switches on all Waspmote switches 00264 * 00265 * It switches on all Waspmote switches 00266 */ 00267 void WaspPWR::switchesON(uint8_t option) 00268 { 00269 sbi(ADCSRA,ADEN); // switch Analog to Digital Converter OFF 00270 /* 00271 digitalWrite(SERID_PW,HIGH); 00272 digitalWrite(MEM_PW,HIGH); 00273 00274 if( option & SENS_OFF ) 00275 { 00276 digitalWrite(SENS_PW_3V3,HIGH); 00277 digitalWrite(SENS_PW_5V,HIGH); 00278 } 00279 00280 if( option & RTC_OFF ) 00281 { 00282 digitalWrite(RTC_PW,HIGH); 00283 } 00284 00285 if( option & BAT_OFF ) 00286 { 00287 digitalWrite(BAT_MONITOR_PW,HIGH); 00288 } 00289 */ 00290 00291 } 00292 00293 00294 /* clearInts() - clears all captured interrupts to allow new interrupts on that modules 00295 * 00296 * It clears all captured interrupts to allow new interrupts on that modules 00297 */ 00298 void WaspPWR::clearInts() 00299 { 00300 if( intFlag & ACC_INT ) 00301 { 00302 ACC.setFF(); 00303 } 00304 if( intFlag & BAT_INT ) 00305 { 00306 } 00307 if( intFlag & RTC_INT ) // hay que mirar si está inicializado el I2C 00308 { 00309 RTC.clearAlarmFlag(); 00310 } 00311 if( intFlag & UART1_INT ) 00312 { 00313 enableInterrupts(UART1_INT); 00314 } 00315 if( intFlag & WTD_INT ) 00316 { 00317 } 00318 if( intFlag & SENS_INT ) 00319 { 00320 } 00321 } 00322 00323 /* sleep() - sets the microcontroller to the lowest consumption sleep mode 00324 * 00325 * It sets the microcontroller to the lowest consumption sleep mode. Before setting this state, some interruption 00326 * should be enabled to be able to wake up the microcontroller from this state. 00327 * 00328 * It switches off all the switches on the Waspmote board. 00329 * 00330 * It returns nothing. 00331 */ 00332 void WaspPWR::sleep(uint8_t option) 00333 { 00334 switchesOFF(option); 00335 set_sleep_mode(SLEEP_MODE_PWR_DOWN); 00336 sleep_enable(); 00337 delay(10); 00338 sleep_mode(); 00339 sleep_disable(); 00340 switchesON(option); 00341 } 00342 00343 00344 /* sleep(timer) - sets the microcontroller to the lowest consumption sleep mode 00345 * 00346 * It sets the microcontroller to the lowest consumption sleep mode. It enables watchdog interruption to be able to 00347 * wake up the microcontroller after 'timer' time. 00348 * 00349 * 'timer' --> it specifies the time before the watchdog activates the interruption. Possible values are: 00350 * WTD_16MS 0 00351 * WTD_32MS 1 00352 * WTD_64MS 2 00353 * WTD_128MS 3 00354 * WTD_250MS 4 00355 * WTD_500MS 5 00356 * WTD_1S 6 00357 * WTD_2S 7 00358 * WTD_4S 8 00359 * WTD_8S 9 00360 * 00361 * It switches off all the switches on the Waspmote board. 00362 * 00363 * It returns nothing. 00364 */ 00365 void WaspPWR::sleep(uint8_t timer, uint8_t option) 00366 { 00367 switchesOFF(option); 00368 set_sleep_mode(SLEEP_MODE_PWR_DOWN); 00369 sleep_enable(); 00370 00371 setWatchdog(WTD_ON,timer); 00372 sleep_mode(); 00373 sleep_disable(); 00374 switchesON(option); 00375 00376 } 00377 00378 00379 /* deepSleep(time2wake, offset, mode) - sets the microcontroller to the lowest consumption sleep mode 00380 * 00381 * It sets the microcontroller to the lowest consumption sleep mode. It enables RTC interruption to be able to 00382 * wake up the microcontroller when the RTC alarm is launched. 00383 * 00384 * 'time2wake' --> it specifies the time at which the RTC alarm will activate. It must follow the next format: 00385 * "DD:HH:MM:SS" 00386 * 'offset' --> it specifies if 'time2wake' is added to the actual time or if this time is set as the alarm 00387 * 'mode' --> it specifies the mode for RTC alarm 00388 * 00389 * It uses Alarm1 on the RTC due to this Alarm has more precision than Alarm2 00390 * 00391 * It switches off all the switches on the Waspmote board. 00392 * 00393 * It returns nothing. 00394 */ 00395 void WaspPWR::deepSleep(const char* time2wake, uint8_t offset, uint8_t mode, uint8_t option) 00396 { 00397 // Set RTC alarme to wake up from Sleep Power Down Mode 00398 RTC.setAlarm1(time2wake,offset,mode); 00399 RTC.close(); 00400 switchesOFF(option); 00401 set_sleep_mode(SLEEP_MODE_PWR_DOWN); 00402 sleep_enable(); 00403 sleep_mode(); 00404 sleep_disable(); 00405 switchesON(option); 00406 } 00407 00408 00409 /* hibernate(time2wake, offset, mode) - switches off the general switch and enables RTC interruption 00410 * 00411 * It switches off the general switch and enables RTC interruption. It enables RTC interruption to be able to 00412 * switch on the general switch. 00413 * 00414 * When this function is called, Waspmote has no power and when RTC alarm is activated, the power will return to 00415 * the board. This will cause the Waspmote inits again, restarting the code from the init. 00416 * 00417 * 'time2wake' --> it specifies the time at which the RTC alarm will activate. It must follow the next format: 00418 * "DD:HH:MM:SS" 00419 * 'offset' --> it specifies if 'time2wake' is added to the actual time or if this time is set as the alarm 00420 * 'mode' --> it specifies the mode for RTC alarm 00421 * 00422 * It uses Alarm1 on the RTC due to this Alarm has more precision than Alarm2 00423 * 00424 * It switches off all the switches on the Waspmote board. 00425 * 00426 * It returns nothing. 00427 */ 00428 void WaspPWR::hibernate(const char* time2wake, uint8_t offset, uint8_t mode) 00429 { 00430 // Set RTC alarme to wake up from Sleep Power Down Mode 00431 RTC.setAlarm1(time2wake,offset,mode); 00432 RTC.close(); 00433 RTC.setMode(RTC_OFF); 00434 00435 Utils.writeEEPROM(HIB_ADDR,HIB_VALUE); 00436 00437 pinMode(RTC_SLEEP,OUTPUT); 00438 digitalWrite(RTC_SLEEP,HIGH); 00439 delay(18); 00440 digitalWrite(RTC_SLEEP,LOW); 00441 00442 // To avoid executing any other function after calling hibernate 00443 while(1); 00444 } 00445 00446 00447 /* getBatteryLevel() - gets % of of remaining battery 00448 * 00449 * It gets the % of remaining battery. 00450 * 00451 * It gives a value of 1024 for +3V3 00452 * A resistor bridge is put to down max +4V2 battery level around +2V07 on 100% battery charge 00453 * Minimum value for good battery is +1V5, so with resistor bridge is set to +0V75 00454 * Values (in this case) are from 204 to 567 00455 */ 00456 uint8_t WaspPWR::getBatteryLevel() 00457 { 00458 float aux=0; 00459 uint8_t resul=0; 00460 pinMode(BAT_MONITOR_PW,OUTPUT); 00461 digitalWrite(BAT_MONITOR_PW,HIGH); 00462 aux=analogRead(0); 00463 // it gives a value 1024 for +3V3 00464 // a resistor bridge is put to down max +4V2 battery level around +2V07 on 100% battery charge 00465 // minimum value for good battery +1V5, so with resistor bridge is set to +0V75 00466 // values are from 204 to 567 00467 if(aux<BAT_MIN) aux=0; 00468 else aux=((aux-BAT_MIN)/(BAT_MAX-BAT_MIN))*100; 00469 resul=(uint8_t) aux; 00470 digitalWrite(BAT_MONITOR_PW,LOW); 00471 return resul; 00472 } 00473 00474 00475 /* closeI2C() - closes I2C, setting SDA and SCL to '0' 00476 * 00477 * This function closes I2C, setting SDA and SCL to '0' 00478 * 00479 * Returns nothing 00480 */ 00481 void WaspPWR::closeI2C() 00482 { 00483 pinMode(I2C_SDA,OUTPUT); 00484 pinMode(I2C_SCL,OUTPUT); 00485 Wire.close(); 00486 } 00487 00488 // inits the value of the digipot used in the battery detector 00489 void WaspPWR::setLowBatteryThreshold(float threshold) 00490 { 00491 uint8_t dig=0; 00492 uint8_t rpot=200; 00493 dig = uint8_t (rpot-(((threshold-1.15)*470/1.15)-806))*255/rpot; 00494 Wire.begin(); 00495 delay(200); 00496 Wire.beginTransmission(0x2d); // Address 00497 Wire.send(0x11); // Write command 00498 Wire.send(dig); // Data 00499 Wire.endTransmission(); 00500 closeI2C(); 00501 } 00502 00503 // checks if Hibernate has generated the reset 00504 void WaspPWR::ifHibernate() 00505 { 00506 if( digitalRead(RTC_INT_PIN_MON) && (Utils.readEEPROM(HIB_ADDR)==HIB_VALUE) ) 00507 { 00508 intFlag |= HIB_INT; 00509 } 00510 Utils.writeEEPROM(HIB_ADDR,0); 00511 if( !(intFlag & HIB_INT) ) 00512 { 00513 pinMode(RST_RTC, OUTPUT); 00514 digitalWrite(RST_RTC, HIGH); 00515 delay(10); 00516 digitalWrite(RST_RTC, LOW); 00517 } 00518 } 00519 00520 // Private Methods ///////////////////////////////////////////////////////////// 00521 00522 // Preinstantiate Objects ////////////////////////////////////////////////////// 00523 00524 WaspPWR PWR = WaspPWR(); 00525
1.5.6