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.

Dependencies:   FreescaleIAP mbed

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 "FreescaleIAP" library, in order to write the required data to the flash nonvolatile memory. This library works and can be easily used in order to access the flash memory of all Freescale boards that suport Mbed

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 01 14:37:15 2017 +0000
Revision:
0:57ca0bfdc2d8
First version of the Hibernus Library. V1.0

Who changed what in which revision?

UserRevisionLine numberNew contents of line
BogdanL 0:57ca0bfdc2d8 1 /** Hibernus Library
BogdanL 0:57ca0bfdc2d8 2 * University of Southampton 2017
BogdanL 0:57ca0bfdc2d8 3 *
BogdanL 0:57ca0bfdc2d8 4 * Open-source liberary that enable any of your Mbed project work with transient enegy sources.
BogdanL 0:57ca0bfdc2d8 5 * In order to use this library include the "hibernus.h" header file, and use the "Hibernus()" method at the beginning of you main funtion.
BogdanL 0:57ca0bfdc2d8 6 * For more details and example see the "main.cpp" exampe file, and the attached documnetation
BogdanL 0:57ca0bfdc2d8 7 *
BogdanL 0:57ca0bfdc2d8 8 *
BogdanL 0:57ca0bfdc2d8 9 * Released under the MIT License: http://mbed.org/license/mit
BogdanL 0:57ca0bfdc2d8 10 */
BogdanL 0:57ca0bfdc2d8 11
BogdanL 0:57ca0bfdc2d8 12 #include "hibernus.h"
BogdanL 0:57ca0bfdc2d8 13 #include "mbed.h"
BogdanL 0:57ca0bfdc2d8 14 #include "config.h"
BogdanL 0:57ca0bfdc2d8 15
BogdanL 0:57ca0bfdc2d8 16 //11 variables stored at fixed addresses at the beginning of the RAM
BogdanL 0:57ca0bfdc2d8 17 volatile unsigned int FLAG_1 __attribute__((at(RAM_1_Address+Fixed_Add_Vars_Offset))) = Flash_Flags_Sector_Start;
BogdanL 0:57ca0bfdc2d8 18 volatile unsigned int FLAG_2 __attribute__((at(RAM_1_Address+Fixed_Add_Vars_Offset+ 0x4))) = Flash_Flags_Sector_Start + 0x4;
BogdanL 0:57ca0bfdc2d8 19 volatile unsigned int FLAG_3 __attribute__((at(RAM_1_Address+Fixed_Add_Vars_Offset+ 0x8))) = Flash_Flags_Sector_Start + 0x8;
BogdanL 0:57ca0bfdc2d8 20 volatile unsigned int FLAG_4 __attribute__((at(RAM_1_Address+Fixed_Add_Vars_Offset+ 0xC))) = Flash_Flags_Sector_Start + 0xC;
BogdanL 0:57ca0bfdc2d8 21
BogdanL 0:57ca0bfdc2d8 22 volatile unsigned int CoreReg_SP __attribute__((at(RAM_1_Address+Fixed_Add_Vars_Offset+0x10)));
BogdanL 0:57ca0bfdc2d8 23 volatile unsigned int CoreReg_LR __attribute__((at(RAM_1_Address+Fixed_Add_Vars_Offset+0x14)));
BogdanL 0:57ca0bfdc2d8 24 volatile unsigned int CoreReg_PC __attribute__((at(RAM_1_Address+Fixed_Add_Vars_Offset+0x18)));
BogdanL 0:57ca0bfdc2d8 25 volatile unsigned int n __attribute__((at(RAM_1_Address+Fixed_Add_Vars_Offset+0x1C))); // Variable used for counting in loops (4 bytes) stored at RAM address (RamStart+0x54)
BogdanL 0:57ca0bfdc2d8 26 volatile unsigned char i __attribute__((at(RAM_1_Address+Fixed_Add_Vars_Offset+0x20))); // Variable used for counting in loops (1 byte) stored at RAM address (RamStart+0x58)
BogdanL 0:57ca0bfdc2d8 27
BogdanL 0:57ca0bfdc2d8 28 volatile unsigned int *FLASH_ptr_4B __attribute__((at(RAM_1_Address+Fixed_Add_Vars_Offset+0x24))); // Pointer that points to flash (4 bytes) stored at RAM address (RamStart+0x5C)
BogdanL 0:57ca0bfdc2d8 29 volatile unsigned int *RAM_ptr __attribute__((at(RAM_1_Address+Fixed_Add_Vars_Offset+0x28))); // Pointer that points to RAM (4 bytes) stored at RAM address (RamStart+0x60)
BogdanL 0:57ca0bfdc2d8 30
BogdanL 0:57ca0bfdc2d8 31 // Arrays used to store the contents of the peripheral registers
BogdanL 0:57ca0bfdc2d8 32 volatile unsigned int REG_Array_4B[No_Of_4B_Peripheral_Reg] __attribute__((at(RAM_1_Address+Fixed_Add_Vars_Offset+0x2C)));;
BogdanL 0:57ca0bfdc2d8 33 volatile unsigned char REG_Array_1B[No_Of_1B_Peripheral_Reg] __attribute__((at(RAM_1_Address+Fixed_Add_Vars_Offset+0x2C+4*No_Of_4B_Peripheral_Reg)));;
BogdanL 0:57ca0bfdc2d8 34
BogdanL 0:57ca0bfdc2d8 35 Serial pc1(USBTX, USBRX);
BogdanL 0:57ca0bfdc2d8 36 void Hibernus(){
BogdanL 0:57ca0bfdc2d8 37 #if SaveFlagsInFlash == 0
BogdanL 0:57ca0bfdc2d8 38 restore_flags();
BogdanL 0:57ca0bfdc2d8 39 #endif
BogdanL 0:57ca0bfdc2d8 40
BogdanL 0:57ca0bfdc2d8 41 if( isFlagSet(&FLAG_2) && isFlagSet(&FLAG_3) && isFlagSet(&FLAG_4)) // Enter this only after complete shut down
BogdanL 0:57ca0bfdc2d8 42 {
BogdanL 0:57ca0bfdc2d8 43 erase_flags_memory();
BogdanL 0:57ca0bfdc2d8 44 setFlag(&FLAG_1);
BogdanL 0:57ca0bfdc2d8 45 setFlag(&FLAG_4);
BogdanL 0:57ca0bfdc2d8 46 }
BogdanL 0:57ca0bfdc2d8 47
BogdanL 0:57ca0bfdc2d8 48 if(isFlagSet(&FLAG_1)||isFlagSet(&FLAG_2)||isFlagSet(&FLAG_3)||isFlagSet(&FLAG_4))
BogdanL 0:57ca0bfdc2d8 49 {
BogdanL 0:57ca0bfdc2d8 50 __enable_irq(); // Enable interrupts
BogdanL 0:57ca0bfdc2d8 51 Enter_LLS(); // Enter LLS mode
BogdanL 0:57ca0bfdc2d8 52 }
BogdanL 0:57ca0bfdc2d8 53
BogdanL 0:57ca0bfdc2d8 54 if(!isFlagSet(&FLAG_1)) // If *FLAG_1 is not already set (first time waking up)
BogdanL 0:57ca0bfdc2d8 55 {
BogdanL 0:57ca0bfdc2d8 56 erase_flags_memory();
BogdanL 0:57ca0bfdc2d8 57 setFlag(&FLAG_2);
BogdanL 0:57ca0bfdc2d8 58
BogdanL 0:57ca0bfdc2d8 59 #if HasInternalComparator == 1
BogdanL 0:57ca0bfdc2d8 60 configure_VH_comparator_interrupt();
BogdanL 0:57ca0bfdc2d8 61 #else
BogdanL 0:57ca0bfdc2d8 62 configure_VH_gpio_interrupt();
BogdanL 0:57ca0bfdc2d8 63 #endif
BogdanL 0:57ca0bfdc2d8 64 __enable_irq(); // Enable interrupts
BogdanL 0:57ca0bfdc2d8 65 }
BogdanL 0:57ca0bfdc2d8 66 else{
BogdanL 0:57ca0bfdc2d8 67 if(isFlagSet(&FLAG_4))
BogdanL 0:57ca0bfdc2d8 68 {
BogdanL 0:57ca0bfdc2d8 69 #if HasInternalComparator == 1
BogdanL 0:57ca0bfdc2d8 70 configure_VH_comparator_interrupt();
BogdanL 0:57ca0bfdc2d8 71 #else
BogdanL 0:57ca0bfdc2d8 72 configure_VH_gpio_interrupt();
BogdanL 0:57ca0bfdc2d8 73 #endif
BogdanL 0:57ca0bfdc2d8 74
BogdanL 0:57ca0bfdc2d8 75 erase_flags_memory();
BogdanL 0:57ca0bfdc2d8 76 setFlag(&FLAG_2);
BogdanL 0:57ca0bfdc2d8 77 restore();
BogdanL 0:57ca0bfdc2d8 78 }
BogdanL 0:57ca0bfdc2d8 79 }
BogdanL 0:57ca0bfdc2d8 80 }
BogdanL 0:57ca0bfdc2d8 81
BogdanL 0:57ca0bfdc2d8 82 void Save_RAM_Regs(){
BogdanL 0:57ca0bfdc2d8 83 //Copy the peripheral registers to RAM
BogdanL 0:57ca0bfdc2d8 84 for(n=0; n<No_Of_4B_Peripheral_Reg;n++){
BogdanL 0:57ca0bfdc2d8 85 REG_Array_4B[n] = *(unsigned int*)REG_Addresses_4B[n];
BogdanL 0:57ca0bfdc2d8 86 }
BogdanL 0:57ca0bfdc2d8 87 for(n=0; n<No_Of_1B_Peripheral_Reg;n++){
BogdanL 0:57ca0bfdc2d8 88 REG_Array_1B[n] = *(unsigned int*)REG_Addresses_1B[n];
BogdanL 0:57ca0bfdc2d8 89 }
BogdanL 0:57ca0bfdc2d8 90
BogdanL 0:57ca0bfdc2d8 91 //copy all the ram to flash
BogdanL 0:57ca0bfdc2d8 92 copyRamToFlash();
BogdanL 0:57ca0bfdc2d8 93 }
BogdanL 0:57ca0bfdc2d8 94
BogdanL 0:57ca0bfdc2d8 95 void Restore_Regs(){
BogdanL 0:57ca0bfdc2d8 96 //Restore peripheral registers from RAM, After the ram content was copied back from flash, after a restore
BogdanL 0:57ca0bfdc2d8 97 for(n=0; n<No_Of_4B_Peripheral_Reg; n++){
BogdanL 0:57ca0bfdc2d8 98 *(unsigned int*) REG_Addresses_4B[n] = REG_Array_4B[n];
BogdanL 0:57ca0bfdc2d8 99 }
BogdanL 0:57ca0bfdc2d8 100
BogdanL 0:57ca0bfdc2d8 101 for(i=0; i<No_Of_1B_Peripheral_Reg; i++){
BogdanL 0:57ca0bfdc2d8 102 *(unsigned char*) REG_Addresses_1B[i] = REG_Array_1B[i];
BogdanL 0:57ca0bfdc2d8 103 }
BogdanL 0:57ca0bfdc2d8 104 }
BogdanL 0:57ca0bfdc2d8 105
BogdanL 0:57ca0bfdc2d8 106 void restore(){
BogdanL 0:57ca0bfdc2d8 107 // Restore procedure
BogdanL 0:57ca0bfdc2d8 108 __disable_irq(); // Disable interrupts
BogdanL 0:57ca0bfdc2d8 109
BogdanL 0:57ca0bfdc2d8 110 erase_flags_memory();
BogdanL 0:57ca0bfdc2d8 111 setFlag(&FLAG_2);
BogdanL 0:57ca0bfdc2d8 112
BogdanL 0:57ca0bfdc2d8 113 //Restore peripheral registers
BogdanL 0:57ca0bfdc2d8 114 Restore_Regs();
BogdanL 0:57ca0bfdc2d8 115
BogdanL 0:57ca0bfdc2d8 116 //Restore RAM
BogdanL 0:57ca0bfdc2d8 117 FLASH_ptr_4B = (unsigned int*) (flash_ramSection_start);
BogdanL 0:57ca0bfdc2d8 118 RAM_ptr = (unsigned int*) (RAM_1_Address);
BogdanL 0:57ca0bfdc2d8 119
BogdanL 0:57ca0bfdc2d8 120 //Copy RAM until where the pointers and loop variables are stored
BogdanL 0:57ca0bfdc2d8 121 //divide it by 4 because the copy is done word by word but byte by byte
BogdanL 0:57ca0bfdc2d8 122 for(n=0; n<(Fixed_Add_Vars_Offset/4); n++){
BogdanL 0:57ca0bfdc2d8 123 *(RAM_ptr + n) = *(FLASH_ptr_4B + n);
BogdanL 0:57ca0bfdc2d8 124 }
BogdanL 0:57ca0bfdc2d8 125
BogdanL 0:57ca0bfdc2d8 126 //skip the Core reg and fixed address variables
BogdanL 0:57ca0bfdc2d8 127 FLASH_ptr_4B = (unsigned int*)(flash_ramSection_start +Fixed_Add_Vars_Offset+ Fixed_Add_Vars_Size);
BogdanL 0:57ca0bfdc2d8 128 RAM_ptr = (unsigned int*)(RAM_1_Address +Fixed_Add_Vars_Offset+ Fixed_Add_Vars_Size);
BogdanL 0:57ca0bfdc2d8 129
BogdanL 0:57ca0bfdc2d8 130 //copy the rest of the RAM
BogdanL 0:57ca0bfdc2d8 131 //(RAM_Size-Fixed_Add_Vars_Offset-Fixed_Add_Vars_Size) is the siz eof the rest of the ram that have to be copied
BogdanL 0:57ca0bfdc2d8 132 //divide it by 4 because the copy is done word by word but byte by byte
BogdanL 0:57ca0bfdc2d8 133 for(n=0; n<(RAM_Size-Fixed_Add_Vars_Offset-Fixed_Add_Vars_Size)/4; n++){
BogdanL 0:57ca0bfdc2d8 134 *(RAM_ptr + n) = *(FLASH_ptr_4B + n);
BogdanL 0:57ca0bfdc2d8 135 }
BogdanL 0:57ca0bfdc2d8 136
BogdanL 0:57ca0bfdc2d8 137 //copy the 3 core registers from flash o ram
BogdanL 0:57ca0bfdc2d8 138 CoreReg_SP=*(unsigned int*)(flash_ramSection_start+Fixed_Add_Vars_Offset+0x10);
BogdanL 0:57ca0bfdc2d8 139 CoreReg_LR=*(unsigned int*)(flash_ramSection_start+Fixed_Add_Vars_Offset+0x14);
BogdanL 0:57ca0bfdc2d8 140 CoreReg_PC=*(unsigned int*)(flash_ramSection_start+Fixed_Add_Vars_Offset+0x18);
BogdanL 0:57ca0bfdc2d8 141
BogdanL 0:57ca0bfdc2d8 142 //Configure the iterrupt for VH/Hibernate
BogdanL 0:57ca0bfdc2d8 143 #if HasInternalComparator == 1
BogdanL 0:57ca0bfdc2d8 144 configure_VH_comparator_interrupt();
BogdanL 0:57ca0bfdc2d8 145 #else
BogdanL 0:57ca0bfdc2d8 146 configure_VH_gpio_interrupt();
BogdanL 0:57ca0bfdc2d8 147 #endif
BogdanL 0:57ca0bfdc2d8 148
BogdanL 0:57ca0bfdc2d8 149 __enable_irq(); // Enable interrupts
BogdanL 0:57ca0bfdc2d8 150
BogdanL 0:57ca0bfdc2d8 151 asm_restore(); // Restore the value of SP
BogdanL 0:57ca0bfdc2d8 152 _LR = CoreReg_LR; // Restore the value of LR
BogdanL 0:57ca0bfdc2d8 153 _PC = CoreReg_PC; // Restore the value of PC
BogdanL 0:57ca0bfdc2d8 154 }
BogdanL 0:57ca0bfdc2d8 155
BogdanL 0:57ca0bfdc2d8 156 extern "C" volatile unsigned int* getFlag_1(){
BogdanL 0:57ca0bfdc2d8 157 return &FLAG_1;
BogdanL 0:57ca0bfdc2d8 158 }
BogdanL 0:57ca0bfdc2d8 159
BogdanL 0:57ca0bfdc2d8 160 extern "C" volatile unsigned int* getFlag_2(){
BogdanL 0:57ca0bfdc2d8 161 return &FLAG_2;
BogdanL 0:57ca0bfdc2d8 162 }
BogdanL 0:57ca0bfdc2d8 163
BogdanL 0:57ca0bfdc2d8 164 extern "C" volatile unsigned int* getFlag_3(){
BogdanL 0:57ca0bfdc2d8 165 return &FLAG_3;
BogdanL 0:57ca0bfdc2d8 166 }
BogdanL 0:57ca0bfdc2d8 167
BogdanL 0:57ca0bfdc2d8 168 extern "C" volatile unsigned int* getFlag_4(){
BogdanL 0:57ca0bfdc2d8 169 return &FLAG_4;
BogdanL 0:57ca0bfdc2d8 170 }
BogdanL 0:57ca0bfdc2d8 171
BogdanL 0:57ca0bfdc2d8 172 extern "C" volatile unsigned int* getCore_SP(){
BogdanL 0:57ca0bfdc2d8 173 return &CoreReg_SP;
BogdanL 0:57ca0bfdc2d8 174 }
BogdanL 0:57ca0bfdc2d8 175
BogdanL 0:57ca0bfdc2d8 176 extern "C" volatile unsigned int* getCore_PC(){
BogdanL 0:57ca0bfdc2d8 177 return &CoreReg_PC;
BogdanL 0:57ca0bfdc2d8 178 }
BogdanL 0:57ca0bfdc2d8 179
BogdanL 0:57ca0bfdc2d8 180 extern "C" volatile unsigned int* getCore_LR(){
BogdanL 0:57ca0bfdc2d8 181 return &CoreReg_LR;
BogdanL 0:57ca0bfdc2d8 182 }