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 #include "config.h"
BogdanL 0:57ca0bfdc2d8 12 #include "hibernus.h"
BogdanL 0:57ca0bfdc2d8 13
BogdanL 0:57ca0bfdc2d8 14 volatile unsigned int dummyread; // Variable used for serialization
BogdanL 0:57ca0bfdc2d8 15 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:57ca0bfdc2d8 16 {
BogdanL 0:57ca0bfdc2d8 17
BogdanL 0:57ca0bfdc2d8 18 CMP0->SCR |= CMP_SCR_CFF_MASK | CMP_SCR_CFR_MASK; // Clear CMP0 flags
BogdanL 0:57ca0bfdc2d8 19 dummyread = CMP0->SCR; // Read back for serialization
BogdanL 0:57ca0bfdc2d8 20
BogdanL 0:57ca0bfdc2d8 21
BogdanL 0:57ca0bfdc2d8 22 if(isFlagSet(getFlag_2())&& isFlagSet(getFlag_3()) && isFlagSet(getFlag_4())){ // Enter this only after complete shut down
BogdanL 0:57ca0bfdc2d8 23 erase_flags_memory(); // Erase flash sector used to save the flags
BogdanL 0:57ca0bfdc2d8 24 setFlag(getFlag_1());
BogdanL 0:57ca0bfdc2d8 25 setFlag(getFlag_4());
BogdanL 0:57ca0bfdc2d8 26 }
BogdanL 0:57ca0bfdc2d8 27
BogdanL 0:57ca0bfdc2d8 28 if(isFlagSet(getFlag_2())){ // Hibernate procedure
BogdanL 0:57ca0bfdc2d8 29 __disable_irq(); // Disable interrupts
BogdanL 0:57ca0bfdc2d8 30
BogdanL 0:57ca0bfdc2d8 31 volatile unsigned int sp1=(_SP+0x28), lr1= *(unsigned int*)(_SP+0x1C), pc1=*(unsigned int*)(_SP+0x20);
BogdanL 0:57ca0bfdc2d8 32 // Save previous SP value from main // 0x40 for hibernate function 38 otherwsie
BogdanL 0:57ca0bfdc2d8 33 *getCore_SP() = sp1;
BogdanL 0:57ca0bfdc2d8 34
BogdanL 0:57ca0bfdc2d8 35 // Save previous LR value from main// 34 for hibernate function 2C otherwise
BogdanL 0:57ca0bfdc2d8 36 *getCore_LR() = lr1;
BogdanL 0:57ca0bfdc2d8 37
BogdanL 0:57ca0bfdc2d8 38 // Save previous PC value from main // 38 for hibernate function 30 otherwise
BogdanL 0:57ca0bfdc2d8 39 *getCore_PC() = pc1;
BogdanL 0:57ca0bfdc2d8 40
BogdanL 0:57ca0bfdc2d8 41 Save_RAM_Regs();
BogdanL 0:57ca0bfdc2d8 42
BogdanL 0:57ca0bfdc2d8 43 setFlag(getFlag_3());
BogdanL 0:57ca0bfdc2d8 44 setFlag(getFlag_4());
BogdanL 0:57ca0bfdc2d8 45
BogdanL 0:57ca0bfdc2d8 46 Comparator_Setup();
BogdanL 0:57ca0bfdc2d8 47 CMP0->DACCR = 0xDA; // Enable DAC, Vdd is 6-bit reference, threshold set to P3V3 = +2.37V (V_R)
BogdanL 0:57ca0bfdc2d8 48 CMP0->SCR = 0x16; // Enable all interrupts and clear flags
BogdanL 0:57ca0bfdc2d8 49 CMP0->CR1 |= CMP_CR1_EN_MASK; // Enable comparator module
BogdanL 0:57ca0bfdc2d8 50
BogdanL 0:57ca0bfdc2d8 51 __enable_irq(); // Enable interrupts
BogdanL 0:57ca0bfdc2d8 52
BogdanL 0:57ca0bfdc2d8 53 Enter_LLS(); // Enter LLS mode
BogdanL 0:57ca0bfdc2d8 54 }
BogdanL 0:57ca0bfdc2d8 55 }
BogdanL 0:57ca0bfdc2d8 56
BogdanL 0:57ca0bfdc2d8 57 extern "C" void LLW_IRQHandler(){
BogdanL 0:57ca0bfdc2d8 58
BogdanL 0:57ca0bfdc2d8 59 CMP0->SCR |= CMP_SCR_CFF_MASK | CMP_SCR_CFR_MASK; // Clear CMP0 flags
BogdanL 0:57ca0bfdc2d8 60 dummyread = CMP0->SCR; // Read back for serialization
BogdanL 0:57ca0bfdc2d8 61 NVIC_ClearPendingIRQ(CMP0_IRQn); // Clear pending CMP0 interrupt so that the CMP_IRQ is not entered
BogdanL 0:57ca0bfdc2d8 62
BogdanL 0:57ca0bfdc2d8 63 if(isFlagSet(getFlag_3())){ // Enter after hibernation with no power loss
BogdanL 0:57ca0bfdc2d8 64 Comparator_Setup();
BogdanL 0:57ca0bfdc2d8 65 CMP0->DACCR = 0xDC; // Enable DAC, Vdd is 6-bit reference, threshold set to P3V3 = +2.21V (V_H)
BogdanL 0:57ca0bfdc2d8 66 CMP0->SCR = 0x0E; // Enable falling edge interrupt and clear flags
BogdanL 0:57ca0bfdc2d8 67 CMP0->CR1 |= CMP_CR1_EN_MASK; // Enable comparator module
BogdanL 0:57ca0bfdc2d8 68
BogdanL 0:57ca0bfdc2d8 69 erase_flags_memory(); // Erase flash sector used to save the flags
BogdanL 0:57ca0bfdc2d8 70 setFlag(getFlag_2());
BogdanL 0:57ca0bfdc2d8 71
BogdanL 0:57ca0bfdc2d8 72 __enable_irq(); // Enable interrupts
BogdanL 0:57ca0bfdc2d8 73 }
BogdanL 0:57ca0bfdc2d8 74 }
BogdanL 0:57ca0bfdc2d8 75 void Comparator_Setup(){
BogdanL 0:57ca0bfdc2d8 76
BogdanL 0:57ca0bfdc2d8 77 NVIC_SetPriority(CMP0_IRQn, 1); // Lower the CMP0 interrupt priority from 0 to 1 (smaller number = higher priority)
BogdanL 0:57ca0bfdc2d8 78 NVIC_EnableIRQ(CMP0_IRQn); // Enable CMP0 interrupts in NVIC
BogdanL 0:57ca0bfdc2d8 79
BogdanL 0:57ca0bfdc2d8 80 SIM->SCGC4 |= SIM_SCGC4_CMP_MASK; // Enable comparator module clock
BogdanL 0:57ca0bfdc2d8 81 LLWU->ME |= LLWU_ME_WUME1_MASK; // Enable CMP0 as a LLWU source
BogdanL 0:57ca0bfdc2d8 82 PMC->REGSC |= PMC_REGSC_BGEN_MASK | // Allow bangap buffer in low power operation
BogdanL 0:57ca0bfdc2d8 83 PMC_REGSC_BGBE_MASK; // Enable bandgap buffer for +1V reference (CMP0_IN6)
BogdanL 0:57ca0bfdc2d8 84
BogdanL 0:57ca0bfdc2d8 85 // Comparator in sampled, filtered mode 4B
BogdanL 0:57ca0bfdc2d8 86 CMP0->CR0 = 0x22; // Hysteresis level 2 (20mV) and 2 consecutive filter samples must agree
BogdanL 0:57ca0bfdc2d8 87 CMP0->CR1 = 0x00; // Low-speed compare, non-inverted output, use filtered output and disable comparator output pin PTA2
BogdanL 0:57ca0bfdc2d8 88 CMP0->FPR = 0x01; // Filter sample period = 1 bus clock cycle
BogdanL 0:57ca0bfdc2d8 89 CMP0->SCR = 0x06; // Disable all interrupts and clear flags
BogdanL 0:57ca0bfdc2d8 90 CMP0->DACCR = 0x40; // Disable DAC, Vdd is 6-bit reference, threshold set to zero
BogdanL 0:57ca0bfdc2d8 91 CMP0->MUXCR = 0x3E; // CMP0_IN7 (DAC) to V+ channel and CMP0_IN6 (+1V bandgap) to V- 3E
BogdanL 0:57ca0bfdc2d8 92 }
BogdanL 0:57ca0bfdc2d8 93
BogdanL 0:57ca0bfdc2d8 94 void Enter_LLS(){
BogdanL 0:57ca0bfdc2d8 95
BogdanL 0:57ca0bfdc2d8 96 Comparator_Setup();
BogdanL 0:57ca0bfdc2d8 97 CMP0->DACCR = 0xDA; // Enable DAC, Vdd is 6-bit reference, threshold set to P3V3 = +2.37V (V_R)
BogdanL 0:57ca0bfdc2d8 98 CMP0->SCR = 0x16; // Enable rising edge interrupt and clear flags
BogdanL 0:57ca0bfdc2d8 99 CMP0->CR1 |= CMP_CR1_EN_MASK; // Enable comparator module
BogdanL 0:57ca0bfdc2d8 100
BogdanL 0:57ca0bfdc2d8 101 NVIC_EnableIRQ(LLW_IRQn); // Enable LLW interrupts in NVIC
BogdanL 0:57ca0bfdc2d8 102 MCG->C6 &= ~(MCG_C6_CME_MASK); // DIsable all clock monitors
BogdanL 0:57ca0bfdc2d8 103 SCB->SCR = 1<<SCB_SCR_SLEEPDEEP_Pos; // Set the SLEEPDEEP bit for stop mode
BogdanL 0:57ca0bfdc2d8 104
BogdanL 0:57ca0bfdc2d8 105 SMC->PMPROT = SMC_PMPROT_ALLS_MASK; // Allow LLS power modes
BogdanL 0:57ca0bfdc2d8 106 SMC->PMCTRL &= ~(SMC_PMCTRL_STOPM_MASK); // Serialisation
BogdanL 0:57ca0bfdc2d8 107 SMC->PMCTRL = SMC_PMCTRL_STOPM(0x3); // Select LLS as desired power mode
BogdanL 0:57ca0bfdc2d8 108 dummyread = SMC->PMCTRL; // Read back for serialisation
BogdanL 0:57ca0bfdc2d8 109
BogdanL 0:57ca0bfdc2d8 110 __WFI(); // Stop executing instructions and enter LLS (wait for interrupt)
BogdanL 0:57ca0bfdc2d8 111 }
BogdanL 0:57ca0bfdc2d8 112
BogdanL 0:57ca0bfdc2d8 113 void configure_VH_comparator_interrupt(){
BogdanL 0:57ca0bfdc2d8 114 Comparator_Setup();
BogdanL 0:57ca0bfdc2d8 115 CMP0->DACCR = 0xDC; // Enable DAC, Vdd is 6-bit reference, threshold set to P3V3 = +2.21V (V_H)
BogdanL 0:57ca0bfdc2d8 116 CMP0->SCR = 0x0E; // Enable falling edge interrupt and clear flags
BogdanL 0:57ca0bfdc2d8 117 CMP0->CR1 |= CMP_CR1_EN_MASK; // Enable comparator module
BogdanL 0:57ca0bfdc2d8 118 }
BogdanL 0:57ca0bfdc2d8 119
BogdanL 0:57ca0bfdc2d8 120 void setFlag(volatile unsigned int* add){
BogdanL 0:57ca0bfdc2d8 121 const unsigned int set = Flag_set;
BogdanL 0:57ca0bfdc2d8 122 program_flash(*add,(char*)&set,4); //if the flags are stored in flash, use this line
BogdanL 0:57ca0bfdc2d8 123 }
BogdanL 0:57ca0bfdc2d8 124
BogdanL 0:57ca0bfdc2d8 125 bool isFlagSet(volatile unsigned int* add){
BogdanL 0:57ca0bfdc2d8 126 if( *(unsigned int *)(*add) == Flag_set) return true;
BogdanL 0:57ca0bfdc2d8 127 return false;
BogdanL 0:57ca0bfdc2d8 128 }
BogdanL 0:57ca0bfdc2d8 129
BogdanL 0:57ca0bfdc2d8 130 void erase_flash_secors_for_RAM(){
BogdanL 0:57ca0bfdc2d8 131 int i;
BogdanL 0:57ca0bfdc2d8 132 for(i = 2; i<= 2+ramToFlash_sectors_number; i++) //start the erase from the 3rd last block, the first 2 are used for flags and peripheral registers
BogdanL 0:57ca0bfdc2d8 133 erase_sector(flash_end-i*sector_Size);
BogdanL 0:57ca0bfdc2d8 134 }
BogdanL 0:57ca0bfdc2d8 135
BogdanL 0:57ca0bfdc2d8 136 void erase_flags_memory(){
BogdanL 0:57ca0bfdc2d8 137 if(!SaveFlagsInFlash) {
BogdanL 0:57ca0bfdc2d8 138 *getFlag_1() = Flag_erase;
BogdanL 0:57ca0bfdc2d8 139 *getFlag_2() = Flag_erase;
BogdanL 0:57ca0bfdc2d8 140 *getFlag_3() = Flag_erase;
BogdanL 0:57ca0bfdc2d8 141 *getFlag_4() = Flag_erase;
BogdanL 0:57ca0bfdc2d8 142 }else{
BogdanL 0:57ca0bfdc2d8 143 erase_sector(Flash_Flags_Sector_Start);
BogdanL 0:57ca0bfdc2d8 144 }
BogdanL 0:57ca0bfdc2d8 145 }
BogdanL 0:57ca0bfdc2d8 146
BogdanL 0:57ca0bfdc2d8 147 void copyRamToFlash(){
BogdanL 0:57ca0bfdc2d8 148 // Erase flash sectors o save the RAM content
BogdanL 0:57ca0bfdc2d8 149 erase_flash_secors_for_RAM();
BogdanL 0:57ca0bfdc2d8 150 program_flash(flash_ramSection_start, (char*) RAM_1_Address, RAM_Size); // Copy all the RAM to flash
BogdanL 0:57ca0bfdc2d8 151 }