This is the code used on my video series "Hybrid Supercapacitor Car Battery" for my own hardware monitoring system. THe videos can be found on madelectronengineering.com

Dependencies:   BurstSPI Fonts INA219 mbed LPC1114_WakeInterruptIn

Fork of SharpMemoryLCD by Paul Staron

Files at this revision

API Documentation at this revision

Comitter:
madelectroneng
Date:
Tue Dec 26 21:30:09 2017 +0000
Parent:
1:1bd2b42b305d
Commit message:
Inital setup

Changed in this revision

Device/LPC1114_WakeInterruptIn.lib Show annotated file Show diff for this revision Revisions of this file
Device/WakeUp_Freescale.cpp Show annotated file Show diff for this revision Revisions of this file
Device/WakeUp_LPC11XX.cpp Show annotated file Show diff for this revision Revisions of this file
Device/WakeUp_LPC11u24.cpp Show annotated file Show diff for this revision Revisions of this file
Device/WakeUp_LPC812.cpp Show annotated file Show diff for this revision Revisions of this file
Device/WakeUp_STM32_others.cpp Show annotated file Show diff for this revision Revisions of this file
Device/WakeUp_STM_RTC.cpp Show annotated file Show diff for this revision Revisions of this file
INA219.lib Show annotated file Show diff for this revision Revisions of this file
Images.lib Show diff for this revision Revisions of this file
SharpLCD.cpp Show annotated file Show diff for this revision Revisions of this file
SharpLCD.h Show annotated file Show diff for this revision Revisions of this file
WakeUp.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Device/LPC1114_WakeInterruptIn.lib	Tue Dec 26 21:30:09 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/Sissors/code/LPC1114_WakeInterruptIn/#128f3fe79240
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Device/WakeUp_Freescale.cpp	Tue Dec 26 21:30:09 2017 +0000
@@ -0,0 +1,135 @@
+#if defined(TARGET_Freescale)
+
+#include "WakeUp.h"
+#include "us_ticker_api.h"
+
+Callback<void()> WakeUp::callback;
+float WakeUp::cycles_per_ms = 1.0;
+
+static uint16_t remainder_count;
+static uint32_t oldvector;
+static uint8_t oldPSR;
+
+//See if we have a 32kHz crystal on the clock input
+//Check if the DMX32 bit is set, not perfect, but most cases will work
+static inline bool is32kXtal(void) {
+    return (MCG->C4 & MCG_C4_DMX32_MASK);
+}
+
+void restore(void);
+
+void WakeUp::set_ms(uint32_t ms)
+{
+    /* Clock the timer */
+    SIM->SCGC5 |= 0x1u;
+    
+    //Check if it is running, in that case, store current values
+    remainder_count = 0;
+    if (NVIC_GetVector(LPTimer_IRQn) != (uint32_t)WakeUp::irq_handler) {
+        oldvector = NVIC_GetVector(LPTimer_IRQn);
+        oldPSR = LPTMR0->PSR;
+        
+        if (LPTMR0->CSR & LPTMR_CSR_TIE_MASK) {
+            //Write first to sync value
+            LPTMR0->CNR = 0;
+            uint16_t countval = LPTMR0->CNR;
+            if (countval < LPTMR0->CMR)
+                remainder_count = countval - LPTMR0->CMR;
+        }
+    }
+    
+    LPTMR0->CSR = 0;
+
+    if (ms != 0) {
+        /* Set interrupt handler */
+        NVIC_SetVector(LPTimer_IRQn, (uint32_t)WakeUp::irq_handler);
+        NVIC_EnableIRQ(LPTimer_IRQn);
+        
+        uint32_t counts;
+        //Set clock
+        if (is32kXtal()) {
+            SIM->SOPT1 &= ~SIM_SOPT1_OSC32KSEL_MASK;    //Put RTC/LPTMR on 32kHz external. 
+            #ifdef OSC0
+            OSC0->CR |= OSC_CR_EREFSTEN_MASK;
+            #else
+            OSC->CR |= OSC_CR_EREFSTEN_MASK;
+            #endif
+            LPTMR0->PSR = LPTMR_PSR_PCS(2);
+            counts = (uint32_t)((float)ms * 32.768f);
+        } else {
+            //Clock from the 1kHz LPO
+            LPTMR0->PSR = LPTMR_PSR_PCS(1);
+            counts = (uint32_t)((float)ms * cycles_per_ms);
+        }
+        
+        //If no prescaler is needed
+        if (counts <= 0xFFFF) 
+            LPTMR0->PSR |= LPTMR_PSR_PBYP_MASK;
+        else {        //Otherwise increase prescaler until it fits
+            counts >>= 1;
+            uint32_t prescaler = 0;
+            while (counts > 0xFFFF) {
+                counts >>= 1;
+                prescaler++;
+            }
+            LPTMR0->PSR |= LPTMR_PSR_PRESCALE(prescaler);
+        }
+        LPTMR0->CMR = counts;        
+
+        LPTMR0->CSR = LPTMR_CSR_TIE_MASK;
+        LPTMR0->CSR |= LPTMR_CSR_TEN_MASK;
+    } else {
+        restore();
+    }
+
+}
+
+
+void WakeUp::irq_handler(void)
+{
+    // write 1 to TCF to clear the LPT timer compare flag
+    LPTMR0->CSR |= LPTMR_CSR_TCF_MASK;
+    restore();
+    callback.call();
+}
+
+void WakeUp::calibrate(void)
+{
+    if (!is32kXtal()) {
+        wait_us(1);     //Otherwise next wait might overwrite our settings
+        cycles_per_ms = 1.0;
+        set_ms(1100);
+        wait_ms(100);
+    
+        //Write first to sync value
+        LPTMR0->CNR = 0;
+        uint32_t ticks = LPTMR0->CNR;
+        cycles_per_ms = ticks / 100.0;
+        set_ms(0);
+    }
+}
+
+void restore(void){
+    /* Reset */
+    LPTMR0->CSR = 0;
+    
+    /* Set interrupt handler */
+    NVIC_SetVector(LPTimer_IRQn, oldvector);
+    NVIC_EnableIRQ(LPTimer_IRQn);
+    
+    /* Clock at (1)MHz -> (1)tick/us */
+    LPTMR0->PSR = oldPSR;
+
+    if (remainder_count) {  
+        /* Set the compare register */
+        LPTMR0->CMR = remainder_count;
+        
+        /* Enable interrupt */
+        LPTMR0->CSR |= LPTMR_CSR_TIE_MASK;
+        
+        /* Start the timer */
+        LPTMR0->CSR |= LPTMR_CSR_TEN_MASK;
+    }
+}
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Device/WakeUp_LPC11XX.cpp	Tue Dec 26 21:30:09 2017 +0000
@@ -0,0 +1,165 @@
+/**
+See homepage of this lib for LPC11xx special treatment
+**/
+
+#ifdef TARGET_LPC11XX_11CXX
+
+#include "WakeUp.h"
+#include "WakeInterruptIn.h"
+#include "pinmap.h"
+#include "toolchain.h"
+
+//Pin used, allowed pins = P0_1 (dp24, default), P0_8 (dp1) and P0_9 (dp2)
+//By defining WakeUpPin in for example your main.cpp this can be overridden
+WEAK PinName WakeUpPin = dp24;
+extern PinName WakeUpPin;
+
+WakeInterruptIn IRQ_in(WakeUpPin);
+PwmOut pulse_out(WakeUpPin);
+
+Callback<void()> WakeUp::callback;
+float WakeUp::cycles_per_ms = 20.0;
+
+static uint32_t old_clk_sel = ~0;
+static uint32_t SYSAHBCLKCTRL;
+static uint32_t TCR, PR, MR3;
+static LPC_TMR_TypeDef *WakeUpTimer;
+static uint32_t SYSAHBCLKCTRL_Sleep;
+static uint8_t WakeUpTimer_Match;
+
+static inline void restore(void);
+
+
+void WakeUp::set_ms(uint32_t ms)
+{
+    if (old_clk_sel == ~0) {                                //Only during first run
+        old_clk_sel = LPC_SYSCON->MAINCLKSEL;
+        SYSAHBCLKCTRL = LPC_SYSCON->SYSAHBCLKCTRL;
+        
+        switch(WakeUpPin) {
+            case dp24:
+                WakeUpTimer = LPC_TMR32B0;
+                SYSAHBCLKCTRL_Sleep = 0x15 | (1<<9);
+                WakeUpTimer_Match = 2;
+                break;
+            case dp1:
+                WakeUpTimer = LPC_TMR16B0;
+                SYSAHBCLKCTRL_Sleep = 0x15 | (1<<7);
+                WakeUpTimer_Match = 0;
+                break;
+            case dp2:
+                WakeUpTimer = LPC_TMR16B0;
+                SYSAHBCLKCTRL_Sleep = 0x15 | (1<<7);
+                WakeUpTimer_Match = 1;
+                break;
+            default:
+                error("Invalid WakeUp pin, choose dp1, dp2 or dp24");
+        }            
+    }
+        
+    if (ms != 0) {        
+        if (LPC_SYSCON->SYSAHBCLKCTRL != SYSAHBCLKCTRL_Sleep)    //Always when it is different from sleep settings
+            SYSAHBCLKCTRL = LPC_SYSCON->SYSAHBCLKCTRL;
+
+        LPC_SYSCON->PDRUNCFG &= ~PDRUNCFG_WDTOSC_PD;
+        LPC_SYSCON->PDSLEEPCFG = 0x000018B7 | (LPC_SYSCON->PDRUNCFG & (PDRUNCFG_WDTOSC_PD | PDRUNCFG_BOD_PD)); 
+        
+        //Set oscillator for 20kHz
+        LPC_SYSCON->WDTOSCCTRL = 14 | (1<<5);
+        
+        //Store old PWM
+        TCR = WakeUpTimer->TCR;
+        PR = WakeUpTimer->PR;
+        MR3 = WakeUpTimer->MR3;
+        
+        //Setup PWM
+        WakeUpTimer->TCR = TMR16B0TCR_CRST;
+        uint32_t ticks = (float)ms * cycles_per_ms;
+        
+        //whatever timer it is, we treat it as 16-bit (with PR that is 32-bit still, do the math, it is enough for this)
+        WakeUpTimer->PR = ticks >> 16;
+        WakeUpTimer->MR[WakeUpTimer_Match] = ticks / ((ticks >> 16) + 1);
+        WakeUpTimer->MR3 = 0xFFFF;
+                
+        IRQ_in.rise(irq_handler);
+        
+        //Disable most peripherals
+        LPC_SYSCON->SYSAHBCLKCTRL = SYSAHBCLKCTRL_Sleep;
+        
+        //Switch clock to WD OSC
+        LPC_SYSCON->MAINCLKSEL = 0x2;
+        LPC_SYSCON->MAINCLKUEN = 0;
+        LPC_SYSCON->MAINCLKUEN = MAINCLKUEN_ENA;
+        
+        //Enable PWM:
+        WakeUpTimer->TCR = TMR16B0TCR_CEN;
+    } else {
+        //Else restore normal settings
+        restore();
+    }
+    
+}
+
+void WakeUp::irq_handler(void)
+{    
+    restore();    
+    callback.call();
+}
+
+void WakeUp::calibrate(void)
+{
+    //Save current pin function
+    __IO uint32_t *reg = (__IO uint32_t*)(LPC_IOCON_BASE + (dp24 & 0xFF));
+    uint32_t old_pinfun = *reg;
+    
+    //Set oscillator for 20kHz
+    LPC_SYSCON->PDRUNCFG &= ~PDRUNCFG_WDTOSC_PD;
+    LPC_SYSCON->WDTOSCCTRL = 14 | (1<<5);
+    
+    //Direct WDT to the CLKOUT pin (dp24), sample it back
+    DigitalIn din(dp24);
+    Timer timer;
+    
+    LPC_SYSCON->CLKOUTDIV = 1;
+    LPC_SYSCON->CLKOUTCLKSEL = 0x2;
+    LPC_SYSCON->CLKOUTUEN = 0;
+    LPC_SYSCON->CLKOUTUEN = CLKOUTUEN_ENA;
+    pin_function(dp24, 1);
+    
+    int count = 0;
+    timer.start();
+    while (timer.read_ms() < 100) {
+        while (din.read() == 0);
+        while (din.read() == 1);
+        count++;
+    }
+    cycles_per_ms = (float)count / 100.0f;
+    
+    //Set old pin function back, disable CLKOUT
+    *reg = old_pinfun;
+    LPC_SYSCON->CLKOUTDIV = 0;
+}
+
+static inline void restore(void) {
+        
+    WakeUpTimer->MR[WakeUpTimer_Match] = 0xFFFFFFFF;
+
+    if (old_clk_sel == 3)                           //Was running on PLL
+        while(LPC_SYSCON->SYSPLLSTAT != SYSPLLSTAT_LOCK);
+    
+    if (old_clk_sel < 4) {  //If valid setting
+        LPC_SYSCON->MAINCLKSEL = old_clk_sel;
+        LPC_SYSCON->MAINCLKUEN = 0;
+        LPC_SYSCON->MAINCLKUEN = MAINCLKUEN_ENA;
+    }
+    
+    IRQ_in.rise(NULL);
+    
+    LPC_SYSCON->SYSAHBCLKCTRL = SYSAHBCLKCTRL; 
+    
+    WakeUpTimer->MR3 = MR3;
+    WakeUpTimer->PR = PR;
+    WakeUpTimer->TCR = TCR;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Device/WakeUp_LPC11u24.cpp	Tue Dec 26 21:30:09 2017 +0000
@@ -0,0 +1,63 @@
+/**
+Due to lack of another option for the LPC11u24 the watchdog timer is used as wakeup source.
+Since if the reset on watchdog event bit is set, I cannot remove it again, this means if you also got watchdog code running
+the most likely result is that it just resets your board.
+**/
+
+
+#ifdef TARGET_LPC11U24
+
+#include "WakeUp.h"
+
+Callback<void()> WakeUp::callback;
+float WakeUp::cycles_per_ms = 5.0;
+
+void WakeUp::set_ms(uint32_t ms)
+{
+    if (ms != 0) {
+        LPC_SYSCON->SYSAHBCLKCTRL |= 0x8000;
+        LPC_SYSCON->PDRUNCFG &= ~(1<<6);
+        LPC_SYSCON->PDSLEEPCFG &= ~(1<<6);
+        LPC_SYSCON->STARTERP1 |= 1<<12;
+        
+        //Set oscillator for 20kHz = 5kHz after divide by 4 in WDT
+        LPC_SYSCON->WDTOSCCTRL = 14 | (1<<5);
+        
+        LPC_WWDT->MOD = 1;      //Enable WDT
+        LPC_WWDT->TC = (uint32_t)((float)ms * cycles_per_ms);
+        LPC_WWDT->CLKSEL = 1;   //WDTOSC
+        LPC_WWDT->WARNINT = 0;
+        
+        NVIC_SetVector(WDT_IRQn, (uint32_t)WakeUp::irq_handler);
+        
+        //Feeeeeed me
+        LPC_WWDT->FEED = 0xAA;
+        LPC_WWDT->FEED = 0x55;
+        
+        NVIC_EnableIRQ(WDT_IRQn);
+    } else
+        NVIC_DisableIRQ(WDT_IRQn);
+    
+}
+
+void WakeUp::irq_handler(void)
+{
+    LPC_WWDT->MOD = 1<<3;
+    callback.call();
+}
+
+void WakeUp::calibrate(void)
+{
+    cycles_per_ms = 5.0;
+    set_ms(1100);
+    wait_ms(10);    //Give time to sync
+    uint32_t count1 = LPC_WWDT->TV;
+    wait_ms(100);
+    uint32_t count2 = LPC_WWDT->TV;
+    set_ms(0);
+    count1 = count1 - count2;
+    
+    cycles_per_ms = count1 / 100.0;
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Device/WakeUp_LPC812.cpp	Tue Dec 26 21:30:09 2017 +0000
@@ -0,0 +1,74 @@
+#ifdef TARGET_LPC812
+
+#include "WakeUp.h"
+
+Callback<void()> WakeUp::callback;
+float WakeUp::cycles_per_ms = 10.0;
+
+void WakeUp::set_ms(uint32_t ms)
+{
+    //Enable clock to register interface:
+    LPC_SYSCON->SYSAHBCLKCTRL |= 1<<9;
+
+    //Clear the counter:
+    LPC_WKT->CTRL |= 1<<2;
+    if (ms != 0) {
+        //Enable clock to register interface:
+        LPC_SYSCON->SYSAHBCLKCTRL |= 1<<9;
+
+        //Set 10kHz timer as source, and just to be sure clear status bit
+        LPC_WKT->CTRL = 3;
+
+        //Enable the 10kHz timer
+        LPC_PMU->DPDCTRL |= (1<<2) | (1<<3);
+
+        //Set interrupts
+        NVIC_SetVector(WKT_IRQn, (uint32_t)WakeUp::irq_handler);
+        NVIC_EnableIRQ(WKT_IRQn);
+
+        //Load the timer
+        LPC_WKT->COUNT = (uint32_t)((float)ms * cycles_per_ms);
+
+    } else {
+        //Disable clock to register interface:
+        LPC_SYSCON->SYSAHBCLKCTRL &= ~(1<<9);
+
+        //Disable the 10kHz timer
+        LPC_PMU->DPDCTRL &= ~((1<<2) | (1<<3));
+    }
+}
+
+void WakeUp::irq_handler(void)
+{
+    //Clear status
+    LPC_WKT->CTRL |= 2;
+
+    //Disable clock to register interface:
+    LPC_SYSCON->SYSAHBCLKCTRL &= ~(1<<9);
+
+    //Disable the 10kHz timer
+    LPC_PMU->DPDCTRL &= ~((1<<2) | (1<<3));
+
+    callback.call();
+}
+
+void WakeUp::calibrate(void)
+{
+    cycles_per_ms = 10.0;
+    set_ms(1100);
+    wait_ms(100);
+
+    uint32_t prevread = LPC_WKT->COUNT;
+    uint32_t read = LPC_WKT->COUNT;
+    while( read != prevread) {
+        prevread = read;
+        read = LPC_WKT->COUNT;
+    }
+
+    uint32_t ticks = 11000 - read;
+
+    cycles_per_ms = ticks / 100.0;
+    set_ms(0);
+}
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Device/WakeUp_STM32_others.cpp	Tue Dec 26 21:30:09 2017 +0000
@@ -0,0 +1,188 @@
+// Created new file only for STM32/Nucleo boards which I have own it
+//  by JH1PJL       2017-9-21
+
+#if defined(TARGET_NUCLEO_F446RE) || defined(TARGET_NUCLEO_F411RE)\
+ || defined(TARGET_NUCLEO_F401RE)\
+ || defined(TARGET_NUCLEO_L152RE) || defined(TARGET_NUCLEO_L073RZ)\
+ || defined(TARGET_NUCLEO_L053R8)
+
+#include "WakeUp.h"
+#include "rtc_api.h"
+
+//#define DEBUG
+
+extern Serial pc;
+
+#if 0
+#define DBG(...)   pc.printf(__VA_ARGS__)
+#else
+#define DBG(...)   {;}
+#endif
+
+#if 0
+#define DBGP(...)   pc.printf(__VA_ARGS__)
+#else
+#define DBGP(...)   {;}
+#endif
+
+#define BYTE2BCD(byte)  ((byte % 10) | ((byte / 10) << 4))
+
+//Most things are pretty similar between the different STM targets.
+//Only the IRQ number the alarm is connected to differs. Any errors
+//with RTC_IRQn/RTC_Alarm_IRQn in them are related to this
+#if defined(TARGET_M4) || defined(TARGET_M3)
+#define RTC_IRQ     RTC_Alarm_IRQn               
+#else
+#define RTC_IRQ     RTC_IRQn
+#endif
+
+// Some things to handle Disco L476VG (and similar ones)
+#if defined(TARGET_STM32L4)
+#define IMR     IMR1
+#define EMR     EMR1
+#define RTSR    RTSR1
+#define FTSR    FTSR2
+#define PR      PR1
+#endif
+
+Callback<void()> WakeUp::callback;
+bool WakeUp::use_reset = false;
+
+
+void WakeUp::set_ms(uint32_t ms)
+{
+    if (ms == 0) {              //Just disable alarm
+        return;
+    }
+    
+    if (!rtc_isenabled()) {     //Make sure RTC is running
+        rtc_init();
+        wait_us(250);           //The f401 seems to want a delay after init
+    }
+
+    PWR->CR |= PWR_CR_DBP;      //Enable power domain
+    RTC->WPR = 0xCA;            //Disable RTC write protection
+    RTC->WPR = 0x53;
+
+    //Alarm must be disabled to change anything
+    RTC->CR &= ~RTC_CR_ALRAE;
+    RTC->CR &= 0x00ff00ff;
+    while(!(RTC->ISR & RTC_ISR_ALRAWF));
+
+    DBG("Step(%u)\r\n", __LINE__);
+
+    //RTC prescaler + calculate how many sub-seconds should be added
+    uint32_t prescaler = (RTC->PRER & 0x7FFF) + 1;
+    uint32_t subsecsadd = ((ms % 1000) * prescaler) / 1000;
+
+    if ((ms < 1000) && (subsecsadd < 2))
+        subsecsadd = 2;//At least 5 subsecs delay to be sure interrupt is called
+
+    __disable_irq();   //At this point we don't want IRQs anymore
+
+    //Get current time
+    uint32_t subsecs = RTC->SSR;
+    time_t secs = rtc_read(); 
+    DBG("Step(%u),secs:%d,subsecs:%d\r\n", __LINE__, secs, subsecs);
+
+    //Calculate alarm values
+    //Subseconds is countdown,
+    //    so substract the 'added' sub-seconds and prevent underflow
+    if (subsecs < subsecsadd) {
+        subsecs += prescaler;
+        secs++;
+    }
+    subsecs -= subsecsadd;
+
+    //Set seconds correctly
+    secs += ms / 1000;
+    struct tm *timeinfo = localtime(&secs);
+    DBG("Step(%u),secs:%d\r\n", __LINE__, secs);
+ 
+    //Enable rising edge EXTI interrupt of the RTC
+    EXTI->IMR |= RTC_EXTI_LINE_ALARM_EVENT;     // enable it
+    EXTI->EMR &= ~RTC_EXTI_LINE_ALARM_EVENT;    // disable event
+    EXTI->RTSR |= RTC_EXTI_LINE_ALARM_EVENT;    // enable rising edge
+    EXTI->FTSR &= ~RTC_EXTI_LINE_ALARM_EVENT;   // disable falling edge
+
+    //Calculate alarm register values
+    uint32_t alarmreg = 0;
+    alarmreg |= BYTE2BCD(timeinfo->tm_sec)  << 0;
+    alarmreg |= BYTE2BCD(timeinfo->tm_min)  << 8;
+    alarmreg |= BYTE2BCD(timeinfo->tm_hour) << 16;
+    alarmreg |= BYTE2BCD(timeinfo->tm_mday) << 24;
+    alarmreg &= 0x3f3f7f7f; // All MSKx & WDSEL = 0
+
+    //Enable RTC interrupt (use Alarm-A)
+    DBG("Step(%u),alarmreg:0x%08x\r\n", __LINE__, alarmreg);
+    DBG("Step(%u),RTC->ISR:0x%08x\r\n", __LINE__, RTC->ISR); 
+    RTC->ALRMAR = alarmreg;
+    RTC->ALRMASSR = subsecs | RTC_ALRMASSR_MASKSS;      //Mask no subseconds
+    DBG("Step(%u),alarmreg(reg):0x%08x\r\n", __LINE__, RTC->ALRMAR);
+    RTC->CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE;            //Enable Alarm-A  
+    DBG("Step(%u),RTC->CR:0x%08x\r\n", __LINE__, RTC->CR); 
+
+    RTC->WPR = 0xFF;        //Enable RTC write protection
+    PWR->CR &= ~PWR_CR_DBP; //Disable power domain
+
+    __enable_irq();         //Alarm is set, so irqs can be enabled again
+
+    //Enable everything else
+    NVIC_SetVector(RTC_IRQ, (uint32_t)WakeUp::irq_handler);
+    NVIC_EnableIRQ(RTC_IRQ);
+    use_reset = false;
+    //---- Only for Debug purpose
+    DBGP("PWR->CR     0x%08x:0x%08x\r\n",&PWR->CR, PWR->CR);
+    DBGP("PWR->CSR    0x%08x:0x%08x\r\n",&PWR->CSR, PWR->CSR);
+    DBGP("SCB->SCR    0x%08x:0x%08x\r\n",&SCB->SCR, SCB->SCR);
+    DBGP("SCB->AIRCR  0x%08x:0x%08x\r\n",&SCB->AIRCR, SCB->AIRCR);
+    DBGP("EXTI->IMR   0x%08x:0x%08x\r\n",&EXTI->IMR, EXTI->IMR);
+    DBGP("EXTI->EMR   0x%08x:0x%08x\r\n",&EXTI->EMR, EXTI->EMR);
+    DBGP("EXTI->RTSR  0x%08x:0x%08x\r\n",&EXTI->RTSR, EXTI->RTSR);
+    DBGP("EXTI->FTSR  0x%08x:0x%08x\r\n",&EXTI->FTSR, EXTI->FTSR);
+    DBGP("RTC->TR     0x%08x:0x%08x\r\n",&RTC->TR,RTC->TR);
+    DBGP("RTC->DR     0x%08x:0x%08x\r\n",&RTC->DR,RTC->DR);
+    DBGP("RTC->CR     0x%08x:0x%08x\r\n",&RTC->CR,RTC->CR);
+    DBGP("RTC->ISR    0x%08x:0x%08x\r\n",&RTC->ISR,RTC->ISR);
+    DBGP("RTC->ALRMAR 0x%08x:0x%08x\r\n",&RTC->ALRMAR,RTC->ALRMAR);
+}
+
+void WakeUp::standby_then_reset(uint32_t ms)
+{
+    DBG("Step(%u),ms:%d\r\n", __LINE__, ms);
+    if (ms == 0){   // just go to Reset
+        __NVIC_SystemReset();
+    } 
+    set_ms(ms);
+    use_reset = true;
+    PWR->CR |= PWR_CR_CWUF;
+    HAL_PWR_EnterSTANDBYMode();
+}
+
+void WakeUp::irq_handler(void)
+{
+    //Clear RTC + EXTI interrupt flags
+    PWR->CR |= PWR_CR_DBP;      // Enable power domain
+    RTC->ISR &= ~RTC_ISR_ALRAF;
+    RTC->CR &= 0x00ff00ff;      // just in case
+    RTC->WPR = 0xCA;            // Disable RTC write protection
+    RTC->WPR = 0x53;
+    RTC->CR &= ~(RTC_CR_ALRAE | RTC_CR_ALRAIE); //DisEnable Alarm-A  
+    RTC->WPR = 0xFF;            // Enable RTC write protection
+    EXTI->PR = RTC_EXTI_LINE_ALARM_EVENT;  
+    PWR->CR &= ~PWR_CR_DBP;     // Disable power domain
+    if (use_reset == true){
+        NVIC_SystemReset();
+    } else {
+        if (callback){
+            callback.call();
+        }
+    }
+}
+
+void WakeUp::calibrate(void)
+{
+    //RTC, we assume it is accurate enough without calibration
+}
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Device/WakeUp_STM_RTC.cpp	Tue Dec 26 21:30:09 2017 +0000
@@ -0,0 +1,133 @@
+#ifdef TARGET_STM
+// added by JH1PJL 2017-9-21
+#if defined(TARGET_NUCLEO_F446RE) || defined(TARGET_NUCLEO_F411RE)\
+ || defined(TARGET_NUCLEO_F401RE)\
+ || defined(TARGET_NUCLEO_L152RE) || defined(TARGET_NUCLEO_L073RZ)\
+ || defined(TARGET_NUCLEO_L053R8)
+        // use WakeUp_STM32_others.cpp
+#else
+
+#include "WakeUp.h"
+#include "rtc_api.h"
+
+#define BYTE2BCD(byte)      ((byte % 10) | ((byte / 10) << 4))
+
+//Most things are pretty similar between the different STM targets.
+//Only the IRQ number the alarm is connected to differs. Any errors
+//with RTC_IRQn/RTC_Alarm_IRQn in them are related to this
+#if defined(TARGET_M4) || defined(TARGET_M3)
+#define RTC_IRQ     RTC_Alarm_IRQn           
+#else
+#define RTC_IRQ     RTC_IRQn
+#endif
+
+// Some things to handle Disco L476VG (and similar ones)
+#if defined(TARGET_STM32L4)
+#define IMR     IMR1
+#define EMR     EMR1
+#define RTSR    RTSR1
+#define FTSR    FTSR2
+#define PR      PR1
+#endif
+
+//Disabling the Backup Powerdomain does not seem to work nicely anymore if you want to use other RTC functions afterwards.
+//For now I have disabled it in code, if you find WakeUp increases your powerconsumption, try enabling it again (code is still there, just commented)
+
+Callback<void()> WakeUp::callback;
+
+void WakeUp::set_ms(uint32_t ms)
+{        
+    if (!rtc_isenabled()) {      //Make sure RTC is running
+        rtc_init();
+        wait_us(250);            //The f401 seems to want a delay after init
+    }
+    
+    //PWR->CR |= PWR_CR_DBP;      //Enable power domain
+    RTC->WPR = 0xCA;            //Disable RTC write protection
+    RTC->WPR = 0x53;
+    
+    //Alarm must be disabled to change anything
+    RTC->CR &= ~RTC_CR_ALRAE;
+    while(!(RTC->ISR & RTC_ISR_ALRAWF));
+    
+    if (ms == 0) {              //Just disable alarm
+        //PWR->CR &= ~PWR_CR_DBP; //Disable power domain
+        RTC->WPR = 0xFF;        //Enable RTC write protection
+        return;
+    }
+    
+    //RTC prescaler + calculate how many sub-seconds should be added
+    uint32_t prescaler = (RTC->PRER & 0x7FFF) + 1;
+    uint32_t subsecsadd = ((ms % 1000) * prescaler) / 1000;
+    
+    if ((ms < 1000) && (subsecsadd < 2))
+        subsecsadd = 2;                             //At least 2 subsecs delay to be sure interrupt is called
+    
+    __disable_irq();                                //At this point we don't want IRQs anymore
+    
+    //Get current time
+    uint32_t subsecs = RTC->SSR;
+    time_t secs = rtc_read();
+    
+    //Calculate alarm values
+    //Subseconds is countdown, so substract the 'added' sub-seconds and prevent underflow
+    if (subsecs < subsecsadd) {
+        subsecs += prescaler;
+        secs++;
+    }
+    subsecs -= subsecsadd;
+    
+    //Set seconds correctly
+    secs += ms / 1000;
+    struct tm *timeinfo = localtime(&secs);
+    
+    //Enable rising edge EXTI interrupt of the RTC
+    EXTI->IMR |= RTC_EXTI_LINE_ALARM_EVENT;
+    EXTI->EMR &= ~RTC_EXTI_LINE_ALARM_EVENT;
+    EXTI->RTSR |= RTC_EXTI_LINE_ALARM_EVENT;
+    EXTI->FTSR &= ~RTC_EXTI_LINE_ALARM_EVENT;
+    
+    //Calculate alarm register values
+    uint32_t alarmreg = 0;
+    alarmreg |= BYTE2BCD(timeinfo->tm_sec)  << 0;
+    alarmreg |= BYTE2BCD(timeinfo->tm_min)  << 8;
+    alarmreg |= BYTE2BCD(timeinfo->tm_hour) << 16;
+    alarmreg |= BYTE2BCD(timeinfo->tm_mday) << 24;
+    
+    //Enable RTC interrupt
+    RTC->ALRMAR = alarmreg;
+    RTC->ALRMASSR = subsecs | RTC_ALRMASSR_MASKSS;      //Mask no subseconds
+    RTC->CR |= RTC_CR_ALRAE | RTC_CR_ALRAIE;            //Enable Alarm
+    
+    RTC->WPR = 0xFF;        //Enable RTC write protection
+    //PWR->CR &= ~PWR_CR_DBP; //Disable power domain
+    
+    __enable_irq();         //Alarm is set, so irqs can be enabled again
+    
+    //Enable everything else
+    NVIC_SetVector(RTC_IRQ, (uint32_t)WakeUp::irq_handler);  
+    NVIC_EnableIRQ(RTC_IRQ);    
+}
+
+
+void WakeUp::irq_handler(void)
+{
+    //Clear RTC + EXTI interrupt flags
+    //PWR->CR |= PWR_CR_DBP;      //Enable power domain
+    RTC->ISR &= ~RTC_ISR_ALRAF;
+    RTC->WPR = 0xCA;            //Disable RTC write protection
+    RTC->WPR = 0x53;
+    RTC->CR &= ~RTC_CR_ALRAE;
+    RTC->WPR = 0xFF;        //Enable RTC write protection
+    EXTI->PR = RTC_EXTI_LINE_ALARM_EVENT;
+    //PWR->CR &= ~PWR_CR_DBP;     //Disable power domain 
+    callback.call();
+}
+
+void WakeUp::calibrate(void)
+{
+    //RTC, we assume it is accurate enough without calibration
+}
+
+#endif  // TARGET_NUCLEO_F446RE (added by JH1PJL 2017-9-21)
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/INA219.lib	Tue Dec 26 21:30:09 2017 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/madelectroneng/code/INA219/#8ccc8e47e3d5
--- a/Images.lib	Tue Aug 25 21:15:06 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://developer.mbed.org/users/star297/code/Images/#cd5f51ea83f1
--- a/SharpLCD.cpp	Tue Aug 25 21:15:06 2015 +0000
+++ b/SharpLCD.cpp	Tue Dec 26 21:30:09 2017 +0000
@@ -112,7 +112,7 @@
          :  spi(mosi, miso, sclk), chipSelect(chipSelect), Enable(enable), ExtCom(extcom)
 {
 	//Initialize
-	spi.frequency(3500000);// Nominal speed is 1MHz, tested working at 3MHz
+	spi.frequency(1000000);// Nominal speed is 1MHz, tested working at 3MHz
 	lcdPolarity = 0;	
 	rowCount = 0;
 	memset((uint8_t*)pixelBuffer, White, sizeof(pixelBuffer));	// init full pixel buffer to White
@@ -141,6 +141,12 @@
     Enable = 0;
 }
 
+void SharpLCD::clearspace() {
+	// set pixel buffer to zero but do not blank screen
+	memset((void*)pixelBuffer, foreground, sizeof(pixelBuffer));
+	memset((void*)RowState, 0, sizeof(RowState));
+	}
+
 void SharpLCD::clearImmediate() {
 	// Clear out the pixel buffer
 	memset((void*)pixelBuffer, foreground, sizeof(pixelBuffer));
--- a/SharpLCD.h	Tue Aug 25 21:15:06 2015 +0000
+++ b/SharpLCD.h	Tue Dec 26 21:30:09 2017 +0000
@@ -12,9 +12,9 @@
 /// Set the display geometry depending on the resolution of the display used
 /// common types are 96x96, 128x128, 400x240
 /** MemoryLCD width in pixels */
-#define DISPLAY_WIDTH				(128)
+#define DISPLAY_WIDTH				(400)
 /** MemoryLCD height in pixels */
-#define DISPLAY_HEIGHT				(128)
+#define DISPLAY_HEIGHT				(240)
 
 /** Maximum length of a printf to the display */
 #define MAX_PRINTF_CHARS			40
@@ -224,6 +224,12 @@
 	 * Transfers pixel buffer to the display
 	 */	
 	void update();	
+
+	/**
+	 * set pixel buffer to zero but do not blank screen.
+	 */	
+	void clearspace();	
+
 	/**
 	 * Clear the display & set pixel buffer to zero.
 	 */	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WakeUp.h	Tue Dec 26 21:30:09 2017 +0000
@@ -0,0 +1,114 @@
+#include "mbed.h"
+
+/**
+ * Class to make wake up a microcontroller from deepsleep using a low-power timer. 
+ *
+ * @code
+ * // Depending on the LED connections either the LED is off the 2 seconds
+ * // the target spends in deepsleep(), and on for the other second. Or it is inverted 
+ * 
+ * #include "mbed.h"
+ * #include "WakeUp.h"
+ * 
+ * DigitalOut myled(LED1);
+ * 
+ * int main() {
+ *     wait(5);
+ *
+ *     //The low-power oscillator can be quite inaccurate on some targets
+ *     //this function calibrates it against the main clock
+ *     WakeUp::calibrate();
+ *    
+ *     while(1) {
+ *         //Set LED to zero
+ *         myled = 0;
+ *         
+ *         //Set wakeup time for 2 seconds
+ *         WakeUp::set_ms(2000);
+ *         
+ *         //Enter deepsleep, the program won't go beyond this point until it is woken up
+ *         deepsleep();
+ *         
+ *         //Set LED for 1 second to one
+ *         myled = 1;
+ *         wait(1);
+ *     }
+ * }
+ * @endcode
+ */
+class WakeUp
+{
+public:
+    /**
+    * Set the timeout
+    *
+    * @param s required time in seconds
+    */
+    static void set(uint32_t s) {
+        set_ms(1000 * s);
+    }
+    
+    /**
+    * Set the timeout
+    *
+    * @param ms required time in milliseconds
+    */
+    static void set_ms(uint32_t ms);
+    
+    /**
+    * Attach a function to be called after timeout
+    *
+    * This is optional, if you just want to wake up you 
+    * do not need to attach a function.
+    *
+    * Important: Many targets will run the wake-up routine
+    * at reduced clock speed, afterwards clock speed is restored.
+    * This means that clock speed dependent functions, such as printf
+    * might end up distorted.
+    *
+    * @code
+    * // Attaching regular function
+    * WakeUp::attach(&yourFunc);
+    * // Attaching member function inside another library    
+    * WakeUp::attach(callback(this, &YourLib::yourLibFunction));    
+    * @endcode
+    *
+    * It uses the new Callback system to attach functions.
+    *
+    * @param *function function to call
+    */
+    static void attach(Callback<void()> function) {
+        callback = function;
+    }
+    
+    /**
+    * Calibrate the timer
+    *
+    * Some of the low-power timers have very bad accuracy.
+    * This function calibrates it against the main timer.
+    *
+    * Warning: Blocks for 100ms!
+    */
+    static void calibrate(void);
+
+    /**
+    * Enter Standby mode then Reset
+    *  (available only for confirmed Nucleo boards)
+    *
+    * @param ms required time in milliseconds
+    */
+#if defined(TARGET_NUCLEO_F446RE) || defined(TARGET_NUCLEO_F411RE)\
+ || defined(TARGET_NUCLEO_F401RE)\
+ || defined(TARGET_NUCLEO_L152RE) || defined(TARGET_NUCLEO_L073RZ)\
+ || defined(TARGET_NUCLEO_L053R8)
+    // added by JH1PJL 2017-9-21
+    static void standby_then_reset(uint32_t ms);
+
+#endif
+
+private:
+    static Callback<void()> callback;
+    static void irq_handler(void);
+    static float cycles_per_ms;
+    static bool use_reset;          // added by JH1PJL 2017-9-21
+};
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Dec 26 21:30:09 2017 +0000
@@ -0,0 +1,159 @@
+/* This is a project for madelectronengineering.com
+ This code is used for a hardware monitoring system for the Hybrid Supercapacitor Car Battery to monitor the supercap voltage, the LiFeP04 voltage,
+current, and wattage, plus also monitor 3 seperate temperature points.
+
+Required hardware:
+    STM32 NUCLEO-L073RZ
+    TMP36 Temperature Sensors (x3)
+    INA219 Current & Voltage Breakout (modify by removing 0.1Ohm resistor and replacing with 0.01Ohm Resistor to measure up to 32Amps
+    ST NUCLEO Protoboard
+    30k & 7.5k resistors for voltage divider to measure supercap voltage
+    0.1Ohm 25W current limiting power resistor in between supercap array and LiFeP04 battery
+    Sharp Memory LCD 400x240
+    
+The INA219 measures the current and amperage on the battery side of the current limiting resistor to keep an eye on the LiFeP04 battery.
+voltage divider connects directly to + of supercap array
+
+Arduino equivelant connections:
+A0 - TMP36 #1
+A1 - TMP36 #2
+A2 - TMP36 #3
+A3 - Voltage divider Input
+A4&A5 - I2C for INA219
+
+Arduino equivelant connections for LCD Screen:
+D13 - SClk
+D11 - MOSI
+D10 - CD
+D9 - Enable
+D8 - Extcom
+
+*/
+#include "mbed.h"
+#include "SharpLCD.h"
+#include "INA219.hpp"
+#include "Neu44x36.h"
+#include "Neu31x26.h"
+#include "WakeUp.h"
+
+SharpLCD display(PA_7, NC, PA_5, PB_6, PC_7, PA_9); //mosi, miso(not used), sck, cs, enable, extcom
+INA219 ina219(PC_1, PC_0, 0x40, 400000, RES_12BITS);
+AnalogIn   ain1(PA_0); // connect A0 to Vout(Temp36)
+AnalogIn   ain2(PA_1); // connect A1 to Vout(Temp36)
+AnalogIn   ain3(PA_4); // connect A2 to Vout(Temp36)
+AnalogIn   ain4(PB_0); // Connect A3 to Voltage Divider
+
+int main()
+{        
+    display.enableDisplay();  //enable sharp memory lcd
+    display.clearImmediate();   //clear the screen buffer and screen
+    
+    display.set_font(Neu44x36);
+       
+       //only send graphics and text once to the screen during bootup
+       display.locate(17,0);
+       display.printf("Hybrid Supercap");
+       display.locate(75,35);
+       display.printf("Car Battery");
+       
+       display.rect(0,73,195,239, Black);
+       display.rect(205,73,399,239, Black);
+       display.fillrect(195,73,10,167, Black);
+       display.line(1,174,194,174, Black);
+       display.line(1,176,194,176, Black);
+       display.line(1,107,194,107, Black);
+       display.line(206,107,399,107, Black);
+       display.line(1,141,194,141, Black);
+       display.line(206,141,399,141, Black);
+       display.line(1,175,194,175, Black);
+       display.line(206,175,399,175, Black);
+       display.line(1,209,194,209, Black);
+       display.line(206,209,399,209, Black);
+       
+       display.set_font(Neu31x26);
+       display.locate(15,76);
+       display.printf("Supercaps");
+       display.locate(240,76);
+       display.printf("LiFePo4");
+       display.locate(30,179);
+       display.printf("Resistor");
+       
+       display.locate(360,110);
+       display.printf("V");
+       display.locate(360,143);
+       display.printf("A");
+       display.locate(360,177);
+       display.printf("W");
+       display.locate(155,212);
+       display.printf("'F");
+       display.locate(360,212);
+       display.printf("'F");
+       display.locate(155,143);
+       display.printf("'F");
+       display.locate(155,110);
+       display.printf("V");
+       
+  while(1) {    
+       
+       float volt;
+       float current_ma;
+       float power;
+                  
+       volt       = ina219.read_bus_voltage();
+       current_ma = ina219.read_current_mA() / 1000;
+       power      = volt * current_ma;
+       
+       float V1 = ain1.read() * 3.3; // connect Vs(Tmp36) to 3.3V        
+       float tempC1 = (V1-0.5) * 100; // calculate temperature C
+       float tempF1 = (tempC1 * 9 / 5) + 32.0; // calculate temperature F
+       
+       float V2 = ain2.read() * 3.3; // connect Vs(Tmp36) to 3.3V        
+       float tempC2 = (V2-0.5) * 100; // calculate temperature C
+       float tempF2 = (tempC2 * 9 / 5) + 32.0; // calculate temperature F
+       
+       float V3 = ain3.read() * 3.3; // connect Vs(Tmp36) to 3.3V        
+       float tempC3 = (V3-0.5) * 100; // calculate temperature C
+       float tempF3 = (tempC3 * 9 / 5) + 32.0; // calculate temperature F
+ 
+       float V4 = (ain4.read()) * 3.3; // Voltage divider for supercap voltage
+       float voltage = (V4 * 5);   // Voltage divider is 1 to 5 ratio
+   
+       display.set_font(Neu31x26);
+       display.locate(210,110);
+       display.printf("      ");
+       display.locate(210,110);
+       display.printf("%+05.2f", volt);      
+       display.locate(210,143);
+       display.printf("      "); 
+       display.locate(210,143);
+       display.printf("%+04.1f", current_ma);      
+       display.locate(210,177);
+       display.printf("      ");
+       display.locate(210,177);
+       display.printf("%+05.1f", power);      
+       display.locate(20,212);
+       display.printf("      ");
+       display.locate(20,212);
+       display.printf("%+03.0f", tempF1);      
+       display.locate(210,212);
+       display.printf("      ");
+       display.locate(210,212);
+       display.printf("%+03.0f", tempF2);      
+       display.locate(20,143);
+       display.printf("      ");
+       display.locate(20,143);
+       display.printf("%+03.0f", tempF3);      
+       display.locate(20,110);
+       display.printf("      ");
+       display.locate(20,110);
+       display.printf("%+05.2f", voltage);       
+
+       display.update();
+ 
+//Set wakeup time for 1 second
+//        WakeUp::set_ms(500);
+        
+        //Enter deepsleep, the program won't go beyond this point until it is woken up
+//        deepsleep();   
+}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Dec 26 21:30:09 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/e7ca05fa8600
\ No newline at end of file