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 "config.h"
BogdanL 0:697a3b20c1d1 12 #include "hibernus.h"
BogdanL 0:697a3b20c1d1 13
BogdanL 0:697a3b20c1d1 14 IAP iap;
BogdanL 0:697a3b20c1d1 15 Serial pc1(USBTX, USBRX);
BogdanL 0:697a3b20c1d1 16
BogdanL 0:697a3b20c1d1 17 void Enter_LLS(){
BogdanL 0:697a3b20c1d1 18 configure_VR_gpio_interrupt();
BogdanL 0:697a3b20c1d1 19
BogdanL 0:697a3b20c1d1 20 LPC_PMU->PCON |= 0x1;
BogdanL 0:697a3b20c1d1 21 LPC_SYSCON->PINTSEL[0] = 0x02; //configure pin P0_2 as interupt source
BogdanL 0:697a3b20c1d1 22 LPC_SYSCON->PDRUNCFG &= ~(1<<1);
BogdanL 0:697a3b20c1d1 23 LPC_SYSCON->STARTERP0 |= (1<<0); //Config chanel as wake up interrupt
BogdanL 0:697a3b20c1d1 24 LPC_SYSCON->PDAWAKECFG &= ~((1<<0)|(1<<1)|(1<<2)|(1<<5)|(1<<7)); //wake up all needed modules after recovering from deepslep mode
BogdanL 0:697a3b20c1d1 25 NVIC_SetPriority(FLEX_INT0_IRQn,0);
BogdanL 0:697a3b20c1d1 26 NVIC_EnableIRQ(FLEX_INT0_IRQn);
BogdanL 0:697a3b20c1d1 27 NVIC_SetPriority(FLEX_INT0_IRQn,0);
BogdanL 0:697a3b20c1d1 28
BogdanL 0:697a3b20c1d1 29 //Go to deep Sleep mode ---->
BogdanL 0:697a3b20c1d1 30 SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk; //choose Deep Sleep as power mode
BogdanL 0:697a3b20c1d1 31 __WFI(); // Stop executing instructions and enter Deep Sleep mode
BogdanL 0:697a3b20c1d1 32 }
BogdanL 0:697a3b20c1d1 33
BogdanL 0:697a3b20c1d1 34 //if there is no internal Coomparator define 2 GPIO interrupts to wake up and sleep
BogdanL 0:697a3b20c1d1 35
BogdanL 0:697a3b20c1d1 36 void configure_VR_gpio_interrupt(){
BogdanL 0:697a3b20c1d1 37 LPC_GPIO->DIR[0] |= 1<<2; //set pin P0_2 as input //generate interrupt for VR
BogdanL 0:697a3b20c1d1 38
BogdanL 0:697a3b20c1d1 39 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6);
BogdanL 0:697a3b20c1d1 40 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<16);
BogdanL 0:697a3b20c1d1 41 LPC_IOCON->PIO0_2 = (0x0|(0x2<<3)); //enable pullup
BogdanL 0:697a3b20c1d1 42 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<19); //System enable peripheral clock
BogdanL 0:697a3b20c1d1 43 LPC_SYSCON->PINTSEL[0] = 0x2; //configure interrupt chanel for the GPIO pin is syscon block
BogdanL 0:697a3b20c1d1 44
BogdanL 0:697a3b20c1d1 45 LPC_GPIO_PIN_INT->ISEL &= ~(1<<0); //set the interrupt mode for the pin0 to be Level Sensitive
BogdanL 0:697a3b20c1d1 46 LPC_GPIO_PIN_INT->IENF |= (1<<0); //enable the level sensitive interrupt on pin P0_2
BogdanL 0:697a3b20c1d1 47
BogdanL 0:697a3b20c1d1 48 LPC_SYSCON->STARTERP0 |= (1<<0); //config chanel as wake up interrupt is Syscon block
BogdanL 0:697a3b20c1d1 49
BogdanL 0:697a3b20c1d1 50 __enable_irq();
BogdanL 0:697a3b20c1d1 51 NVIC_EnableIRQ(FLEX_INT0_IRQn);
BogdanL 0:697a3b20c1d1 52 NVIC_SetPriority(FLEX_INT0_IRQn,0); //Set a higher prioroty for wake up interrupt, to be able to interrupt the sleep interrupt
BogdanL 0:697a3b20c1d1 53 }
BogdanL 0:697a3b20c1d1 54
BogdanL 0:697a3b20c1d1 55 void configure_VH_gpio_interrupt(){
BogdanL 0:697a3b20c1d1 56 LPC_GPIO->DIR[0] |= 1<<8; //set pin P0_8 as input //generate interrupt for VH
BogdanL 0:697a3b20c1d1 57
BogdanL 0:697a3b20c1d1 58 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<6);
BogdanL 0:697a3b20c1d1 59 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<16);
BogdanL 0:697a3b20c1d1 60 LPC_IOCON->PIO0_8 = (0x0|(0x2<<3)); //choose first pin function and enable pullup
BogdanL 0:697a3b20c1d1 61 LPC_SYSCON->SYSAHBCLKCTRL |= (1<<19); //System enable peripheral clock
BogdanL 0:697a3b20c1d1 62 LPC_SYSCON->PINTSEL[1] = (uint32_t)8; //configure interrupt chanel for the GPIO pin is syscon block
BogdanL 0:697a3b20c1d1 63
BogdanL 0:697a3b20c1d1 64 LPC_GPIO_PIN_INT->ISEL &= ~(1<<1); //set the interrupt mode for the pin1 to be Level Sensitive
BogdanL 0:697a3b20c1d1 65 LPC_GPIO_PIN_INT->IENF |= (1<<1); //enable the level sensitive interrupt on pin P0_8
BogdanL 0:697a3b20c1d1 66
BogdanL 0:697a3b20c1d1 67 __enable_irq();
BogdanL 0:697a3b20c1d1 68 NVIC_EnableIRQ(FLEX_INT1_IRQn);
BogdanL 0:697a3b20c1d1 69 NVIC_SetPriority(FLEX_INT1_IRQn,2); //Set a lower priority for the sleep interrupt, in order to be possible for the wake up interrupt to interrupt it
BogdanL 0:697a3b20c1d1 70 }
BogdanL 0:697a3b20c1d1 71
BogdanL 0:697a3b20c1d1 72 //the interrupt triggered by the GPIO/INternal Comparator where the snapshot is saved
BogdanL 0:697a3b20c1d1 73 extern "C" void FLEX_INT1_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:697a3b20c1d1 74 pc1.printf(" ",isFlagSet(getFlag_1()),isFlagSet(getFlag_2()),isFlagSet(getFlag_3()),isFlagSet(getFlag_4()));
BogdanL 0:697a3b20c1d1 75
BogdanL 0:697a3b20c1d1 76 if(isFlagSet(getFlag_2())&& isFlagSet(getFlag_3()) && isFlagSet(getFlag_4())) // Enter this only after complete shut down
BogdanL 0:697a3b20c1d1 77 {
BogdanL 0:697a3b20c1d1 78 erase_flags_memory();
BogdanL 0:697a3b20c1d1 79 setFlag(getFlag_1());
BogdanL 0:697a3b20c1d1 80 setFlag(getFlag_4());
BogdanL 0:697a3b20c1d1 81 }
BogdanL 0:697a3b20c1d1 82 if(isFlagSet(getFlag_2()))
BogdanL 0:697a3b20c1d1 83 { // Hibernate procedure
BogdanL 0:697a3b20c1d1 84 __disable_irq();
BogdanL 0:697a3b20c1d1 85
BogdanL 0:697a3b20c1d1 86 unsigned int regs = *(unsigned int*)(_SP+0x1C);
BogdanL 0:697a3b20c1d1 87 volatile unsigned int sp1=(_SP+0x40), lr1= *(unsigned int*)(_SP+0x34), pc1=*(unsigned int*)(_SP+0x38);
BogdanL 0:697a3b20c1d1 88 // Save previous SP value from main // 0x40 for hibernate function 38 otherwsie
BogdanL 0:697a3b20c1d1 89 *getCore_SP() = sp1;
BogdanL 0:697a3b20c1d1 90
BogdanL 0:697a3b20c1d1 91 // Save previous LR value from main// 34 for hibernate function 2C otherwise
BogdanL 0:697a3b20c1d1 92 *getCore_LR() = lr1;
BogdanL 0:697a3b20c1d1 93
BogdanL 0:697a3b20c1d1 94 // Save previous PC value from main // 38 for hibernate function 30 otherwise
BogdanL 0:697a3b20c1d1 95 *getCore_PC() = pc1;
BogdanL 0:697a3b20c1d1 96
BogdanL 0:697a3b20c1d1 97 setFlag(getFlag_3());
BogdanL 0:697a3b20c1d1 98 setFlag(getFlag_4());
BogdanL 0:697a3b20c1d1 99
BogdanL 0:697a3b20c1d1 100 Save_RAM_Regs();
BogdanL 0:697a3b20c1d1 101
BogdanL 0:697a3b20c1d1 102 configure_VR_gpio_interrupt();
BogdanL 0:697a3b20c1d1 103
BogdanL 0:697a3b20c1d1 104 __enable_irq();
BogdanL 0:697a3b20c1d1 105
BogdanL 0:697a3b20c1d1 106 Enter_LLS(); // Enter LLS mode
BogdanL 0:697a3b20c1d1 107 }
BogdanL 0:697a3b20c1d1 108
BogdanL 0:697a3b20c1d1 109 //clear interupt status register
BogdanL 0:697a3b20c1d1 110 LPC_GPIO_PIN_INT->IST |=((1<<0)|(1<<1));
BogdanL 0:697a3b20c1d1 111 //delete any sleep interupts that came during the sleep
BogdanL 0:697a3b20c1d1 112 NVIC_ClearPendingIRQ(FLEX_INT1_IRQn);
BogdanL 0:697a3b20c1d1 113 }
BogdanL 0:697a3b20c1d1 114
BogdanL 0:697a3b20c1d1 115 //ISR for wakeing up the core and seting the interrupt for Hibernate procedure
BogdanL 0:697a3b20c1d1 116 extern "C" void FLEX_INT0_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:697a3b20c1d1 117 NVIC_ClearPendingIRQ(FLEX_INT0_IRQn);
BogdanL 0:697a3b20c1d1 118 if(isFlagSet(getFlag_3())) // Enter after hibernation with no power loss
BogdanL 0:697a3b20c1d1 119 {
BogdanL 0:697a3b20c1d1 120 configure_VH_gpio_interrupt();
BogdanL 0:697a3b20c1d1 121 erase_flags_memory();
BogdanL 0:697a3b20c1d1 122 setFlag(getFlag_2());
BogdanL 0:697a3b20c1d1 123 __enable_irq(); // Enable interrupts
BogdanL 0:697a3b20c1d1 124 }
BogdanL 0:697a3b20c1d1 125
BogdanL 0:697a3b20c1d1 126 //clear interupt status register
BogdanL 0:697a3b20c1d1 127 LPC_GPIO_PIN_INT->IST |= (1<<0);
BogdanL 0:697a3b20c1d1 128 }
BogdanL 0:697a3b20c1d1 129
BogdanL 0:697a3b20c1d1 130 //used to restore the flags values from Flash to RAM
BogdanL 0:697a3b20c1d1 131 void restore_flags(){
BogdanL 0:697a3b20c1d1 132 if(!SaveFlagsInFlash){
BogdanL 0:697a3b20c1d1 133 *getFlag_1() = *(unsigned int*)(flash_ramSection_start+Fixed_Add_Vars_Offset);
BogdanL 0:697a3b20c1d1 134 *getFlag_2() = *(unsigned int*)(flash_ramSection_start+Fixed_Add_Vars_Offset+0x4);
BogdanL 0:697a3b20c1d1 135 *getFlag_3() = *(unsigned int*)(flash_ramSection_start+Fixed_Add_Vars_Offset+0x8);
BogdanL 0:697a3b20c1d1 136 *getFlag_4() = *(unsigned int*)(flash_ramSection_start+Fixed_Add_Vars_Offset+0xC);
BogdanL 0:697a3b20c1d1 137 }
BogdanL 0:697a3b20c1d1 138 }
BogdanL 0:697a3b20c1d1 139
BogdanL 0:697a3b20c1d1 140 //copy the whole content of RAM into the flash
BogdanL 0:697a3b20c1d1 141 void copyRamToFlash(){
BogdanL 0:697a3b20c1d1 142 // Erase flash sectors o save the RAM content
BogdanL 0:697a3b20c1d1 143 int g3=iap.prepare(6,7);
BogdanL 0:697a3b20c1d1 144 int g4=iap.erase(6,7);
BogdanL 0:697a3b20c1d1 145
BogdanL 0:697a3b20c1d1 146 // Copy all the RAM to flash
BogdanL 0:697a3b20c1d1 147 int g0 = iap.prepare(6,7);
BogdanL 0:697a3b20c1d1 148 int g1=iap.write((char*)RAM_1_Address,(char*)flash_ramSection_start,RAM_Size/2);
BogdanL 0:697a3b20c1d1 149 g1+=iap.write((char*)RAM_1_Address+(RAM_Size/2),(char*)flash_ramSection_start+(RAM_Size/2),(RAM_Size/2));
BogdanL 0:697a3b20c1d1 150 }
BogdanL 0:697a3b20c1d1 151
BogdanL 0:697a3b20c1d1 152 //Clear the memory area where the flags are saved
BogdanL 0:697a3b20c1d1 153 void erase_flags_memory(){
BogdanL 0:697a3b20c1d1 154 if(!SaveFlagsInFlash) {
BogdanL 0:697a3b20c1d1 155 *getFlag_1() = Flag_erase;
BogdanL 0:697a3b20c1d1 156 *getFlag_2() = Flag_erase;
BogdanL 0:697a3b20c1d1 157 *getFlag_3() = Flag_erase;
BogdanL 0:697a3b20c1d1 158 *getFlag_4() = Flag_erase;
BogdanL 0:697a3b20c1d1 159 }
BogdanL 0:697a3b20c1d1 160 }
BogdanL 0:697a3b20c1d1 161
BogdanL 0:697a3b20c1d1 162 //mark a flag as "SET"
BogdanL 0:697a3b20c1d1 163 void setFlag(volatile unsigned int* add){
BogdanL 0:697a3b20c1d1 164 *add = Flag_set;
BogdanL 0:697a3b20c1d1 165 }
BogdanL 0:697a3b20c1d1 166
BogdanL 0:697a3b20c1d1 167 //check if a flag is SET or CLEAR
BogdanL 0:697a3b20c1d1 168 bool isFlagSet(volatile unsigned int* add){
BogdanL 0:697a3b20c1d1 169 if(*add == Flag_set ) return true;
BogdanL 0:697a3b20c1d1 170 return false;
BogdanL 0:697a3b20c1d1 171 }
BogdanL 0:697a3b20c1d1 172