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

Dependencies:   IAP 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 "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 01 15:27:34 2017 +0000
Revision:
0:697a3b20c1d1
first version of Hibernus Library. V1.0

Who changed what in which revision?

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