This library allows any user to use their Mbed project with a transient energy source( e.g. windturbine, solar power).

Dependencies:   mbed

Fork of Hibernus by Bogdan Lazarescu

This library allows any user to use their Mbed project with a transient energy source( e.g. windturbine, solar power). You can do this by simply import the "hibernus.h" header file, and call the "Hibernus()" method at the beginning of you main program. In case of a power loss the state of your programm will be saved to the nonvolatile memory and it will be resumed from the same point as soon as there is enough power for the board to run properly. If the power drops down, the internal capacitance of the system is used to save a snapshot of your program into the flash memory, and the board goes in a low power mode (sleep or deepsleep). In order to detect a power loss, the library uses an analog comparator which can be internal (eg Freescale KL 05Z has an internal comparator which can be used ), or external (on LPC11U24 there is no internal comparator) via a GPIO interrupt. For more details see the code comments and the attached example main.cpp file.

This library use "IAP" library, in order to write the required data to the flash nonvolatile memory.

The library can be easily adapted to work with other boards, from different manufactures, which have support for Mbed. In order to adapt this library and use it on your board, the write to flash methods have to be changed. Some changes listed below are required because of the platform dependent parameters of each board. All required changes have to be applied to the "config.h" and "config.cpp" files.

  • The "erase_flags_memory()", "copyRamToFlash()", "restore_flags()", "setFlag()" and " isFlagSet()" methods have to be modified in order to use the right Flash IAP of your board.
  • The wake up and hibernate interrupts have to be modified in order to be trigghered when the voltage drops down or rise. If you use an internal comparator, it should trigger and interrupt whenever the power drops(e.g see CMP0_IRQHandler() method writtend for KL05Z at https://developer.mbed.org/users/BogdanL/code/Hibernus-KL05Z/ ) . At that time a snapshot have to be saved and the board sent to sleep. Another interrupt have to be triggered when the power comes back(see "LLW_IRQHandler()" at https://developer.mbed.org/users/BogdanL/code/Hibernus-KL05Z ) . This have to wake up the board and resume de computation. In you use an external comparator two GPIO interrupts are used. One of them (for LPC11U24 see "FLEX_INT1_IRQHandler()" ) is used to save the snapshot when the power drops down, and the other one (for LPC11U24 see "FLEX_INT0_IRQHandler()" ) is used to wake up the board.
  • For each board, the right Sleep mode have to be chosen. Also the interrups and the comparator have to be properly set, in order to be triggered as desired. For a good example see "configure_VR_gpio_interrupt()" and "configure_VH_gpio_interrupt()" that are used to set up the Restore and Hibernate interrupts on LPC11U24 board, that uses an external comparator.
  • In the "config.h" file, the two arrays, "REG_Addresses_4B[]" and "REG_Addresses_4B[]" have to be populated with the addresses of the 1 Byte and 4Bytes peripheral registers that are used by your project. Different boards have different modules that use different peripheral registers. The addresses of the registers can be found in the Reference Manual of each board, and will be used in order to save and later restore the content of the registers. Also the number of used registers, "No_Of_4B_Peripheral_Reg", No_Of_1B_Peripheral_Reg, have to be updated with the correct number of used registers.
  • At the top of "config.h" header file, specific board parameters have to be fixed: RAM start address(RAM_1_Address), Flash start address(FLASH_Start), RAM size(RAM_Size), Flash size(flash_Size) and the flash sector size(sector_Size).
Committer:
BogdanL
Date:
Fri Sep 08 18:01:22 2017 +0000
Revision:
0:f9a13d4b41f3
First Version of Hibernus Library;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
BogdanL 0:f9a13d4b41f3 1 #include "config.h"
BogdanL 0:f9a13d4b41f3 2 #ifdef KL05Z
BogdanL 0:f9a13d4b41f3 3 #include "Driver_KL05Z.h"
BogdanL 0:f9a13d4b41f3 4 #include "hibernus.h"
BogdanL 0:f9a13d4b41f3 5 Serial pr(USBTX, USBRX);
BogdanL 0:f9a13d4b41f3 6 volatile unsigned int dummyread1; // Variable used for serialization
BogdanL 0:f9a13d4b41f3 7
BogdanL 0:f9a13d4b41f3 8 //inerrupt triggered by comparator whenever the power drops under the treshold value
BogdanL 0:f9a13d4b41f3 9 extern "C" void CMP0_IRQHandler() //To make sure the compiler sees handler, need to declare it as extern (https://developer.mbed.org/forum/mbed/topic/419/?page=1#comment-2126)
BogdanL 0:f9a13d4b41f3 10 {
BogdanL 0:f9a13d4b41f3 11 CMP0->SCR |= CMP_SCR_CFF_MASK | CMP_SCR_CFR_MASK; // Clear CMP0 flags
BogdanL 0:f9a13d4b41f3 12 dummyread1 = CMP0->SCR; // Read back for serialization
BogdanL 0:f9a13d4b41f3 13
BogdanL 0:f9a13d4b41f3 14 //call hibernate procedure directly with the three parameters (don't store them in a variable and then call the method with them,
BogdanL 0:f9a13d4b41f3 15 //the store procedure changes the stackpointer and the program counter)
BogdanL 0:f9a13d4b41f3 16 // pram1 = StackPointer = SP, param2 = LinkRegister = LR, param3 = ProgramCounter = PC
BogdanL 0:f9a13d4b41f3 17 // call hibernate(param1, param2, param3) then the voltage drops under the low(hibernate) treshold
BogdanL 0:f9a13d4b41f3 18 hibernate((_SP+0x28),*((unsigned int*)(_SP+0x1C)),*((unsigned int*)(_SP+0x20)));
BogdanL 0:f9a13d4b41f3 19
BogdanL 0:f9a13d4b41f3 20 }
BogdanL 0:f9a13d4b41f3 21
BogdanL 0:f9a13d4b41f3 22 extern "C" void LLW_IRQHandler(){ //interrupt triggered to wake up the board from sleep mode
BogdanL 0:f9a13d4b41f3 23
BogdanL 0:f9a13d4b41f3 24 CMP0->SCR |= CMP_SCR_CFF_MASK | CMP_SCR_CFR_MASK; // Clear CMP0 flags
BogdanL 0:f9a13d4b41f3 25 dummyread1 = CMP0->SCR; // Read back for serialization
BogdanL 0:f9a13d4b41f3 26 NVIC_ClearPendingIRQ(CMP0_IRQn); // Clear pending CMP0 interrupt so that the CMP_IRQ is not entered
BogdanL 0:f9a13d4b41f3 27
BogdanL 0:f9a13d4b41f3 28 recovery_no_power_loss(); //check if you are recovering after no power loss, and if so, configure VH interrupt
BogdanL 0:f9a13d4b41f3 29 }
BogdanL 0:f9a13d4b41f3 30
BogdanL 0:f9a13d4b41f3 31 void Comparator_Setup(){
BogdanL 0:f9a13d4b41f3 32
BogdanL 0:f9a13d4b41f3 33 NVIC_SetPriority(CMP0_IRQn, 1); // Lower the CMP0 interrupt priority from 0 to 1 (smaller number = higher priority)
BogdanL 0:f9a13d4b41f3 34 NVIC_EnableIRQ(CMP0_IRQn); // Enable CMP0 interrupts in NVIC
BogdanL 0:f9a13d4b41f3 35
BogdanL 0:f9a13d4b41f3 36 SIM->SCGC4 |= SIM_SCGC4_CMP_MASK; // Enable comparator module clock
BogdanL 0:f9a13d4b41f3 37 LLWU->ME |= LLWU_ME_WUME1_MASK; // Enable CMP0 as a LLWU source
BogdanL 0:f9a13d4b41f3 38 PMC->REGSC |= PMC_REGSC_BGEN_MASK | // Allow bangap buffer in low power operation
BogdanL 0:f9a13d4b41f3 39 PMC_REGSC_BGBE_MASK; // Enable bandgap buffer for +1V reference (CMP0_IN6)
BogdanL 0:f9a13d4b41f3 40
BogdanL 0:f9a13d4b41f3 41 // Comparator in sampled, filtered mode 4B
BogdanL 0:f9a13d4b41f3 42 CMP0->CR0 = 0x22; // Hysteresis level 2 (20mV) and 2 consecutive filter samples must agree
BogdanL 0:f9a13d4b41f3 43 CMP0->CR1 = 0x00; // Low-speed compare, non-inverted output, use filtered output and disable comparator output pin PTA2
BogdanL 0:f9a13d4b41f3 44 CMP0->FPR = 0x01; // Filter sample period = 1 bus clock cycle
BogdanL 0:f9a13d4b41f3 45 CMP0->SCR = 0x06; // Disable all interrupts and clear flags
BogdanL 0:f9a13d4b41f3 46 CMP0->DACCR = 0x40; // Disable DAC, Vdd is 6-bit reference, threshold set to zero
BogdanL 0:f9a13d4b41f3 47 CMP0->MUXCR = 0x3E; // CMP0_IN7 (DAC) to V+ channel and CMP0_IN6 (+1V bandgap) to V- 3E
BogdanL 0:f9a13d4b41f3 48 }
BogdanL 0:f9a13d4b41f3 49
BogdanL 0:f9a13d4b41f3 50 void Enter_LLS(){
BogdanL 0:f9a13d4b41f3 51
BogdanL 0:f9a13d4b41f3 52 Comparator_Setup();
BogdanL 0:f9a13d4b41f3 53 CMP0->DACCR = 0xDA; // Enable DAC, Vdd is 6-bit reference, threshold set to P3V3 = +2.37V (V_R)
BogdanL 0:f9a13d4b41f3 54 CMP0->SCR = 0x16; // Enable rising edge interrupt and clear flags
BogdanL 0:f9a13d4b41f3 55 CMP0->CR1 |= CMP_CR1_EN_MASK; // Enable comparator module
BogdanL 0:f9a13d4b41f3 56
BogdanL 0:f9a13d4b41f3 57 NVIC_EnableIRQ(LLW_IRQn); // Enable LLW interrupts in NVIC
BogdanL 0:f9a13d4b41f3 58 MCG->C6 &= ~(MCG_C6_CME_MASK); // DIsable all clock monitors
BogdanL 0:f9a13d4b41f3 59 SCB->SCR = 1<<SCB_SCR_SLEEPDEEP_Pos; // Set the SLEEPDEEP bit for stop mode
BogdanL 0:f9a13d4b41f3 60
BogdanL 0:f9a13d4b41f3 61 SMC->PMPROT = SMC_PMPROT_ALLS_MASK; // Allow LLS power modes
BogdanL 0:f9a13d4b41f3 62 SMC->PMCTRL &= ~(SMC_PMCTRL_STOPM_MASK); // Serialisation
BogdanL 0:f9a13d4b41f3 63 SMC->PMCTRL = SMC_PMCTRL_STOPM(0x3); // Select LLS as desired power mode
BogdanL 0:f9a13d4b41f3 64 dummyread1 = SMC->PMCTRL; // Read back for serialisation
BogdanL 0:f9a13d4b41f3 65
BogdanL 0:f9a13d4b41f3 66 __WFI(); // Stop executing instructions and enter LLS (wait for interrupt)
BogdanL 0:f9a13d4b41f3 67 }
BogdanL 0:f9a13d4b41f3 68
BogdanL 0:f9a13d4b41f3 69 void configure_VH_comparator_interrupt(){
BogdanL 0:f9a13d4b41f3 70 Comparator_Setup();
BogdanL 0:f9a13d4b41f3 71 CMP0->DACCR = 0xDC; // Enable DAC, Vdd is 6-bit reference, threshold set to P3V3 = +2.21V (V_H)
BogdanL 0:f9a13d4b41f3 72 CMP0->SCR = 0x0E; // Enable falling edge interrupt and clear flags
BogdanL 0:f9a13d4b41f3 73 CMP0->CR1 |= CMP_CR1_EN_MASK; // Enable comparator module
BogdanL 0:f9a13d4b41f3 74 }
BogdanL 0:f9a13d4b41f3 75
BogdanL 0:f9a13d4b41f3 76 void configure_VR_comparator_interrupt(){
BogdanL 0:f9a13d4b41f3 77 CMP0->DACCR = 0xDA; // Enable DAC, Vdd is 6-bit reference, threshold set to P3V3 = +2.37V (V_R)
BogdanL 0:f9a13d4b41f3 78 CMP0->SCR = 0x16; // Enable all interrupts and clear flags
BogdanL 0:f9a13d4b41f3 79 CMP0->CR1 |= CMP_CR1_EN_MASK; // Enable comparator module
BogdanL 0:f9a13d4b41f3 80 }
BogdanL 0:f9a13d4b41f3 81
BogdanL 0:f9a13d4b41f3 82 void setFlag(volatile unsigned int* add){
BogdanL 0:f9a13d4b41f3 83 const unsigned int set = Flag_set;
BogdanL 0:f9a13d4b41f3 84 program_flash(*add,(char*)&set,4); //if the flags are stored in flash, use this line
BogdanL 0:f9a13d4b41f3 85 }
BogdanL 0:f9a13d4b41f3 86
BogdanL 0:f9a13d4b41f3 87 bool isFlagSet(volatile unsigned int* add){
BogdanL 0:f9a13d4b41f3 88 if( *(unsigned int *)(*add) == Flag_set) return true;
BogdanL 0:f9a13d4b41f3 89 return false;
BogdanL 0:f9a13d4b41f3 90 }
BogdanL 0:f9a13d4b41f3 91
BogdanL 0:f9a13d4b41f3 92 void erase_flags_memory(){
BogdanL 0:f9a13d4b41f3 93 if(!SaveFlagsInFlash) { //if the flags are stored in RAM, their value have to be clanged to the "erased" value ("Flag_erase")
BogdanL 0:f9a13d4b41f3 94 *getFlag_1() = Flag_erase;
BogdanL 0:f9a13d4b41f3 95 *getFlag_2() = Flag_erase;
BogdanL 0:f9a13d4b41f3 96 *getFlag_3() = Flag_erase;
BogdanL 0:f9a13d4b41f3 97 *getFlag_4() = Flag_erase;
BogdanL 0:f9a13d4b41f3 98 }else{ //if the flags are stored in Flash, their secvtor have to be erased
BogdanL 0:f9a13d4b41f3 99 erase_sector(Flash_Flags_Sector_Start);
BogdanL 0:f9a13d4b41f3 100 }
BogdanL 0:f9a13d4b41f3 101 }
BogdanL 0:f9a13d4b41f3 102 //erase the flash memory needed to save the whole RAM content
BogdanL 0:f9a13d4b41f3 103 void erase_flash_secors_for_RAM(){
BogdanL 0:f9a13d4b41f3 104 int i;
BogdanL 0:f9a13d4b41f3 105 for(i = 2; i<= 2+ramToFlash_sectors_number; i++) //start the erase from the second last block, the first is used for flags
BogdanL 0:f9a13d4b41f3 106 erase_sector(flash_end-i*sector_Size);
BogdanL 0:f9a13d4b41f3 107 }
BogdanL 0:f9a13d4b41f3 108
BogdanL 0:f9a13d4b41f3 109 void copyRamToFlash(){
BogdanL 0:f9a13d4b41f3 110 // Erase flash sectors o save the RAM content
BogdanL 0:f9a13d4b41f3 111 erase_flash_secors_for_RAM();
BogdanL 0:f9a13d4b41f3 112 program_flash(flash_ramSection_start, (char*) RAM_Start, RAM_Size); // Copy all the RAM to flash
BogdanL 0:f9a13d4b41f3 113 }
BogdanL 0:f9a13d4b41f3 114 #endif