Allows easy usage of the LPC1768 RTC interrupts

Dependents:   Mini_DK_clk MakerBotServer GT-ACQUAPLUS_Consumo GT-ACQUAPLUS_Eficiencia ... more

The RTC library allows easy access to the LPC1768s interrupt sources on its RTC. There are two different interrupt sources: periodic interrupts, for example every new second, hour, etc, and an alarm, which is called at a specified time.

Time initialization

This library only allows easy usage of the RTC interrupts. You have to initialize the time functions (so the RTC) the normal way specified here: http://mbed.org/handbook/Time?action=view&revision=11592

Hello World!

#include "mbed.h"
#include "RTC.h"

DigitalOut led(LED1);

void ledFunction( void )
{
    led = 1;
    RTC::detach(RTC::Second);
}

void displayFunction( void )
{
    time_t seconds = time(NULL);
    printf("%s", ctime(&seconds));
}

void alarmFunction( void )
{
    error("Not most useful alarm function");
}

int main()
{
    set_time(1256729737); // Set time to Wed, 28 Oct 2009 11:35:37

    tm t = RTC::getDefaultTM();
    t.tm_sec = 5;
    t.tm_min = 36;

    RTC::alarm(&alarmFunction, t);
    RTC::attach(&displayFunction, RTC::Second);
    RTC::attach(&ledFunction, RTC::Minute);

    while(1);
}

Periodic interrupts

Periodic interrups can be attached by using:

RTC::attach([function], [TimeUnit]);

The TimeUnit specifies which unit should increase for the function to be called. This function is useful if you are making for example a clock: You can simply connect the display update to an RTC interrupt. Of course you can do something similar by using timer objects, but they aren't timed exactly correct, and it is nicer to do it directly on the RTC.

Alarm function

The LPC1768's RTC also allows for one alarm to be activated. The alarm goes off the first time there is a compare match on a specified time and the current time. All fields of the normal C tm structure are supported (http://www.cplusplus.com/reference/ctime/tm/), set a field at -1 for it to be ignored. The RTC::getDefaultTM() function helps with that, it returns a tm structure with every field initialized to -1, so don't care.

So if you want to make an alarm that gets called every monday, every 5 minutes and 30 seconds after the hour, you would use:

tm t = RTC::getDefaultTM();
t.tm_sec = 30;     //30 seconds
t.tm_min = 5;      //5 minute
t.tm_wday = 1;     //monday
RTC::alarm([yourFunction], t);

Attaching member functions

For compactness of the documentation attaching member functions of objects isn't included. However it works exactly the same as for example attaching one to a Ticker object: http://mbed.org/users/mbed_official/code/mbed/docs/63cdd78b2dc1/classmbed_1_1Ticker.html#af92f41ff11906b1f96fa6bbe0b17aa29

Disclaimer

Believe it or not, but I didn't test every possible combination of alarm settings / interrupts. So especially for the larger timescales there is an increased chance on bugs.

Committer:
Sissors
Date:
Wed Dec 05 21:03:44 2012 +0000
Revision:
0:39767ffe05e6
Child:
1:be9d058ee5c7
Version 1, lacks comments, seems to work

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Sissors 0:39767ffe05e6 1 #include "RTC.h"
Sissors 0:39767ffe05e6 2
Sissors 0:39767ffe05e6 3 FunctionPointer RTC::attachCB[6];
Sissors 0:39767ffe05e6 4 FunctionPointer RTC::alarmCB;
Sissors 0:39767ffe05e6 5
Sissors 0:39767ffe05e6 6 bool RTC::initialRun = true;
Sissors 0:39767ffe05e6 7
Sissors 0:39767ffe05e6 8 void RTC::attach(void (*function)(void), TimeUnit interval)
Sissors 0:39767ffe05e6 9 {
Sissors 0:39767ffe05e6 10 //Disable IRQs, dont want them to happen while busy here
Sissors 0:39767ffe05e6 11 NVIC_DisableIRQ(RTC_IRQn);
Sissors 0:39767ffe05e6 12
Sissors 0:39767ffe05e6 13 //Set the IRQ vector
Sissors 0:39767ffe05e6 14 NVIC_SetVector(RTC_IRQn, (uint32_t)&RTC::IRQHandler);
Sissors 0:39767ffe05e6 15
Sissors 0:39767ffe05e6 16 //If this is the first time it is called, delete all interrupt sources
Sissors 0:39767ffe05e6 17 //We need to do this because RTC unit isnt affected by system resets apparently
Sissors 0:39767ffe05e6 18 if (initialRun) {
Sissors 0:39767ffe05e6 19 LPC_RTC->CIIR = 0;
Sissors 0:39767ffe05e6 20 LPC_RTC->AMR = 255;
Sissors 0:39767ffe05e6 21 initialRun = false;
Sissors 0:39767ffe05e6 22 LPC_RTC->ILR = 0x03;
Sissors 0:39767ffe05e6 23 }
Sissors 0:39767ffe05e6 24
Sissors 0:39767ffe05e6 25 //Set the function pointer
Sissors 0:39767ffe05e6 26 attachCB[interval].attach(function);
Sissors 0:39767ffe05e6 27
Sissors 0:39767ffe05e6 28
Sissors 0:39767ffe05e6 29 //Set/reset correct interrupt source
Sissors 0:39767ffe05e6 30 if (function == NULL) {
Sissors 0:39767ffe05e6 31 switch (interval) {
Sissors 0:39767ffe05e6 32 case Second:
Sissors 0:39767ffe05e6 33 LPC_RTC->CIIR &= ~1;
Sissors 0:39767ffe05e6 34 break;
Sissors 0:39767ffe05e6 35 case Minute:
Sissors 0:39767ffe05e6 36 LPC_RTC->CIIR &= ~2;
Sissors 0:39767ffe05e6 37 break;
Sissors 0:39767ffe05e6 38 case Hour:
Sissors 0:39767ffe05e6 39 LPC_RTC->CIIR &= ~4;
Sissors 0:39767ffe05e6 40 break;
Sissors 0:39767ffe05e6 41 case Day:
Sissors 0:39767ffe05e6 42 LPC_RTC->CIIR &= ~56;
Sissors 0:39767ffe05e6 43 break;
Sissors 0:39767ffe05e6 44 case Month:
Sissors 0:39767ffe05e6 45 LPC_RTC->CIIR &= ~64;
Sissors 0:39767ffe05e6 46 break;
Sissors 0:39767ffe05e6 47 case Year:
Sissors 0:39767ffe05e6 48 LPC_RTC->CIIR &= ~128;
Sissors 0:39767ffe05e6 49 break;
Sissors 0:39767ffe05e6 50 }
Sissors 0:39767ffe05e6 51 } else {
Sissors 0:39767ffe05e6 52 switch (interval) {
Sissors 0:39767ffe05e6 53 case Second:
Sissors 0:39767ffe05e6 54 LPC_RTC->CIIR |= 1;
Sissors 0:39767ffe05e6 55 break;
Sissors 0:39767ffe05e6 56 case Minute:
Sissors 0:39767ffe05e6 57 LPC_RTC->CIIR |= 2;
Sissors 0:39767ffe05e6 58 break;
Sissors 0:39767ffe05e6 59 case Hour:
Sissors 0:39767ffe05e6 60 LPC_RTC->CIIR |= 4;
Sissors 0:39767ffe05e6 61 break;
Sissors 0:39767ffe05e6 62 case Day:
Sissors 0:39767ffe05e6 63 LPC_RTC->CIIR |= 56;
Sissors 0:39767ffe05e6 64 break;
Sissors 0:39767ffe05e6 65 case Month:
Sissors 0:39767ffe05e6 66 LPC_RTC->CIIR |= 64;
Sissors 0:39767ffe05e6 67 break;
Sissors 0:39767ffe05e6 68 case Year:
Sissors 0:39767ffe05e6 69 LPC_RTC->CIIR |= 128;
Sissors 0:39767ffe05e6 70 break;
Sissors 0:39767ffe05e6 71 }
Sissors 0:39767ffe05e6 72 }
Sissors 0:39767ffe05e6 73
Sissors 0:39767ffe05e6 74 //We can always enable IRQs, since if all IRQs are disabled by the user the RTC hardware will never raise its IRQ flag anyway
Sissors 0:39767ffe05e6 75 NVIC_EnableIRQ(RTC_IRQn);
Sissors 0:39767ffe05e6 76 }
Sissors 0:39767ffe05e6 77
Sissors 0:39767ffe05e6 78
Sissors 0:39767ffe05e6 79 void RTC::alarm(void (*function)(void), tm time)
Sissors 0:39767ffe05e6 80 {
Sissors 0:39767ffe05e6 81 //Disable IRQs, dont want them to happen while busy here
Sissors 0:39767ffe05e6 82 NVIC_DisableIRQ(RTC_IRQn);
Sissors 0:39767ffe05e6 83
Sissors 0:39767ffe05e6 84 //Set the IRQ vector
Sissors 0:39767ffe05e6 85 NVIC_SetVector(RTC_IRQn, (uint32_t)&RTC::IRQHandler);
Sissors 0:39767ffe05e6 86
Sissors 0:39767ffe05e6 87 //If this is the first time it is called, delete all interrupt sources
Sissors 0:39767ffe05e6 88 //We need to do this because RTC unit isnt affected by system resets apparently
Sissors 0:39767ffe05e6 89 if (initialRun) {
Sissors 0:39767ffe05e6 90 LPC_RTC->CIIR = 0;
Sissors 0:39767ffe05e6 91 LPC_RTC->AMR = 255;
Sissors 0:39767ffe05e6 92 initialRun = false;
Sissors 0:39767ffe05e6 93 LPC_RTC->ILR = 0x03;
Sissors 0:39767ffe05e6 94 }
Sissors 0:39767ffe05e6 95
Sissors 0:39767ffe05e6 96 //Set the function pointer
Sissors 0:39767ffe05e6 97 alarmCB.attach(function);
Sissors 0:39767ffe05e6 98
Sissors 0:39767ffe05e6 99 //Set the alarm register
Sissors 0:39767ffe05e6 100 if ((time.tm_sec>=0) && (time.tm_sec<60)) {
Sissors 0:39767ffe05e6 101 LPC_RTC->ALSEC = time.tm_sec;
Sissors 0:39767ffe05e6 102 LPC_RTC->AMR &= ~1;
Sissors 0:39767ffe05e6 103 } else
Sissors 0:39767ffe05e6 104 LPC_RTC->AMR |= 1;
Sissors 0:39767ffe05e6 105
Sissors 0:39767ffe05e6 106 if ((time.tm_min>=0) && (time.tm_min<60)) {
Sissors 0:39767ffe05e6 107 LPC_RTC->ALMIN = time.tm_min;
Sissors 0:39767ffe05e6 108 LPC_RTC->AMR &= ~2;
Sissors 0:39767ffe05e6 109 } else
Sissors 0:39767ffe05e6 110 LPC_RTC->AMR |= 2;
Sissors 0:39767ffe05e6 111
Sissors 0:39767ffe05e6 112 if ((time.tm_hour>=0) && (time.tm_hour<24)) {
Sissors 0:39767ffe05e6 113 LPC_RTC->ALHOUR = time.tm_hour;
Sissors 0:39767ffe05e6 114 LPC_RTC->AMR &= ~4;
Sissors 0:39767ffe05e6 115 } else
Sissors 0:39767ffe05e6 116 LPC_RTC->AMR |= 4;
Sissors 0:39767ffe05e6 117
Sissors 0:39767ffe05e6 118 if ((time.tm_mday>=1) && (time.tm_mday<32)) {
Sissors 0:39767ffe05e6 119 LPC_RTC->ALDOM = time.tm_mday;
Sissors 0:39767ffe05e6 120 LPC_RTC->AMR &= ~8;
Sissors 0:39767ffe05e6 121 } else
Sissors 0:39767ffe05e6 122 LPC_RTC->AMR |= 8;
Sissors 0:39767ffe05e6 123
Sissors 0:39767ffe05e6 124 if ((time.tm_mon>=0) && (time.tm_mon<12)) {
Sissors 0:39767ffe05e6 125 LPC_RTC->ALMON = time.tm_mon + 1; //Different definitions
Sissors 0:39767ffe05e6 126 LPC_RTC->AMR &= ~64;
Sissors 0:39767ffe05e6 127 } else
Sissors 0:39767ffe05e6 128 LPC_RTC->AMR |= 64;
Sissors 0:39767ffe05e6 129
Sissors 0:39767ffe05e6 130 if ((time.tm_year>=0) && (time.tm_year<1000)) {
Sissors 0:39767ffe05e6 131 LPC_RTC->ALYEAR = time.tm_year + 1900; //Different definitions
Sissors 0:39767ffe05e6 132 LPC_RTC->AMR &= ~128;
Sissors 0:39767ffe05e6 133 } else
Sissors 0:39767ffe05e6 134 LPC_RTC->AMR |= 128;
Sissors 0:39767ffe05e6 135
Sissors 0:39767ffe05e6 136 //We can always enable IRQs, since if all IRQs are disabled by the user the RTC hardware will never raise its IRQ flag anyway
Sissors 0:39767ffe05e6 137 NVIC_EnableIRQ(RTC_IRQn);
Sissors 0:39767ffe05e6 138 }
Sissors 0:39767ffe05e6 139
Sissors 0:39767ffe05e6 140 void RTC::alarmOff( void ) {
Sissors 0:39767ffe05e6 141 LPC_RTC->AMR = 255;
Sissors 0:39767ffe05e6 142 }
Sissors 0:39767ffe05e6 143
Sissors 0:39767ffe05e6 144
Sissors 0:39767ffe05e6 145 void RTC::IRQHandler( void )
Sissors 0:39767ffe05e6 146 {
Sissors 0:39767ffe05e6 147 if ((LPC_RTC->ILR & 0x01) == 0x01) {
Sissors 0:39767ffe05e6 148 //Attach interrupt
Sissors 0:39767ffe05e6 149 attachCB[0].call();
Sissors 0:39767ffe05e6 150
Sissors 0:39767ffe05e6 151 //If seconds zero
Sissors 0:39767ffe05e6 152 if (LPC_RTC->SEC == 0) {
Sissors 0:39767ffe05e6 153 attachCB[1].call();
Sissors 0:39767ffe05e6 154
Sissors 0:39767ffe05e6 155 //If minutes zero
Sissors 0:39767ffe05e6 156 if (LPC_RTC->MIN == 0) {
Sissors 0:39767ffe05e6 157 attachCB[2].call();
Sissors 0:39767ffe05e6 158
Sissors 0:39767ffe05e6 159 //If hours zero
Sissors 0:39767ffe05e6 160 if (LPC_RTC->HOUR == 0) {
Sissors 0:39767ffe05e6 161 attachCB[3].call();
Sissors 0:39767ffe05e6 162
Sissors 0:39767ffe05e6 163 //If days zero
Sissors 0:39767ffe05e6 164 if (LPC_RTC->DOM == 0) {
Sissors 0:39767ffe05e6 165 attachCB[4].call();
Sissors 0:39767ffe05e6 166
Sissors 0:39767ffe05e6 167 //If month zero
Sissors 0:39767ffe05e6 168 if (LPC_RTC->MONTH == 0)
Sissors 0:39767ffe05e6 169 attachCB[5].call();
Sissors 0:39767ffe05e6 170 }
Sissors 0:39767ffe05e6 171 }
Sissors 0:39767ffe05e6 172 }
Sissors 0:39767ffe05e6 173 }
Sissors 0:39767ffe05e6 174 }
Sissors 0:39767ffe05e6 175
Sissors 0:39767ffe05e6 176 if ((LPC_RTC->ILR & 0x02) == 0x02)
Sissors 0:39767ffe05e6 177 alarmCB.call();
Sissors 0:39767ffe05e6 178
Sissors 0:39767ffe05e6 179
Sissors 0:39767ffe05e6 180
Sissors 0:39767ffe05e6 181 //Reset interrupt status
Sissors 0:39767ffe05e6 182 LPC_RTC->ILR = 0x03;
Sissors 0:39767ffe05e6 183 }