µTasker Forum

µTasker Forum => NXPTM M522XX, KINETIS and i.MX RT => Topic started by: mark on August 12, 2007, 09:51:55 PM

Title: RTC in M5223X
Post by: mark on August 12, 2007, 09:51:55 PM
Hi All

On the one hand the RTC (Real Time Clock) in the M5223X is a bit disappointing - normally one thinks of a battery backed up device with 32kHz crystal, time of day, week day, day, month, year and automatic months and leap year adjustments - but on the other hand it could well come in handy in certain applications.

The RTC is clocked by a 1Hz clock which is derived from the local crystal (25MHz typically) and is only operational when the CPU is powered. It is not designed for keeping the time but rather counting elapsed time - however it can be set to a known time, for example from the information from a Time Server.

So it was time that it became supported in the uTasker project. Here is a brief of how the new interface can be used and how it can be tested in the demo project. The new support will be included in the next service pack or is available on demand (in development version) before then. The simulator has also be updated to include the RTC.

Features

These are more or less the capabilities of the RTC in the M5223X so the driver allows each to be simply configured. All of the events are interrupt events and any combination can be used at the same time - for example an alarm can be set, the stopwatch can be running and any of the other periodic interrupts can also be used [like seconds and hours]. Each event is dispatched to its own interrupt handler.

The easiest way to see how to use the interface is to try out the following demo code.

1. Add the define  SUPPORT_RTC to app_hw_m5223x.h
2. Enable define RTC_TEST in application.c

The following subroutine will be called to start the test.

Code: [Select]
static void fnTestRTC(void)
{
    RTC_SETUP rtc_setup;

    CONFIG_TIMER_TEST_LEDS();                                            // drive some LEDs for visibility
    TIMER_TEST_LED_ON();
    TIMER_TEST_LED2_ON();

    rtc_setup.command = RTC_TIME_SETTING;                                // set the present time to the RTC (this could be collected from a timer server and is a fixed value here)
    rtc_setup.usDays    = 5;
    rtc_setup.hours     = 3;
    rtc_setup.ucMinutes = 23;
    rtc_setup.ucSeconds = 53;

    fnConfigureRTC((void *)&rtc_setup);                                  // set the time

    rtc_setup.command = RTC_TICK_MIN;                                    // configure periodic interrupts - once a minute
    rtc_setup.int_handler = test_minute_tick;
    fnConfigureRTC((void *)&rtc_setup);                                  // set a minute interrupt rate (first expected after 7 seconds)

    rtc_setup.command = RTC_ALARM_TIME;                                  // set an alarm time
    rtc_setup.int_handler = test_alarm;
    rtc_setup.ucMinutes = 24;
    rtc_setup.ucSeconds = 14;
    fnConfigureRTC((void *)&rtc_setup);                                  // set an alarm interrupt rate (expected after 21 seconds)

    rtc_setup.command = RTC_STOPWATCH_GO;                                // set a stop watch time (minutes to nearest minute)
    rtc_setup.int_handler = test_stopwatch;
    rtc_setup.ucMinutes = 2;                                             
    fnConfigureRTC((void *)&rtc_setup);                                  // set 2 minute stop watch (expected after 67 seconds)   
}

Each event is given an interrupt handler which is called from the corresponding interrupt dispatched when the event occurs. For example test_minute_tick() is set to be called when the minute interrupt occurs.

Code: [Select]
// Interrupt once a minute
//
static void test_minute_tick(void)
{
    static int iBlick = 0;

    RTC_SETUP rtc_setup;
    rtc_setup.command = RTC_GET_TIME;

    fnConfigureRTC((void *)&rtc_setup);                                  // get the present time

    if (iBlick == 0) {
        iBlick = 1;
        TIMER_TEST_LED_OFF();
    }
    else {
        iBlick = 0;
        TIMER_TEST_LED_ON();
    }
}

When an alarm time occurs:

Code: [Select]
// Interrupt at alarm time
//
static void test_alarm(void)
{
    RTC_SETUP rtc_setup;
    rtc_setup.command = RTC_GET_TIME;

    fnConfigureRTC((void *)&rtc_setup);                                  // get the present time

    TIMER_TEST_LED_ON();
    TIMER_TEST_LED2_OFF();
}

and when the stopwatch counts down:

Code: [Select]
// Interrupt at stopwatch count down
//
static void test_stopwatch(void)
{
    RTC_SETUP rtc_setup;
    rtc_setup.command = (RTC_TICK_MIN | RTC_DISABLE);

    fnConfigureRTC((void *)&rtc_setup);                                  // disable further minute TICKs

    rtc_setup.command = RTC_TICK_SEC;                                    // change to second TICKs
    rtc_setup.int_handler = test_minute_tick;                            // re-use this interrupt routine
   
    fnConfigureRTC((void *)&rtc_setup);

    TIMER_TEST_LED2_ON();
}

The interrupt dispatcher is also so constructed that the Stopwatch and Alarm events are true single shot events so the user doesn't need to undertake any thing to ensure that there will not be multiple events generated over time.

Two LEDs are used to visualise the test process. The test works in the simulator or on the target boards and this is what it does - as defined by the configuration code and the interrupt handling as above:

1. The time is set to Day 5: Hour 3: Minute 23: Second 53 [5:3:23:53]
2. A minute interrupt is configured - the first is expected after just 7 seconds, when the minute counter overflows from 59 to 0.
3. An alarm time is set for 5:3:24:14. Therefore the alarm interrupt is expected 14s after the first minute interrupt.
4. A 2 minute stopwatch is started. Since the stop watch has a minute resolution it will count down the first time after only 7s and then will fire on the second minute - 46s after the alarm interrupt.
5. The stopwatch interrupt disables further minute interrupts, so only one minute interrupt is expected.
6. All interrups (excluding the stopwatch) read the present time (using the debugger the present time can be checked).
7. The stopwatch interrupt also enable a second interrupt (using the same handling code as the minute interrupt) so afterwards an interrupt once a second is expected.

The LEDs make this visible and so they do the following:

5:3:23:53 - LED 4:3 = ON:ON
5:3:24:00 - LED 4:3 = ON:OFF  (Minute interrupt)
5:3:24:14 - LED 4:3 = OFF:ON  (Alarm interrupt)
5:3:25:00 - LED 4:3 = ON:ON  (Stopwatch interrupt - clears minute interrupt and starts second interrupt
5:3:25:01 - LED 4:3 = ON:OFF (Second interrupt)
5:3:25:02 - LED 4:3 = ON:ON (Second Interrupt)
5:3:25:03 - LED 4:3 = ON:OFF (Second interrupt)
5:3:25:04 - LED 4:3 = ON:ON (Second Interrupt)
... etc. LED 1 will toggle every second.

Summary of commands used with fnConfigureRTC():
RTC_TIME_SETTING - pass the time to be set
RTC_TICK_SEC - enable seconds interrupt
RTC_TICK_MIN - enable minutes interrupt
RTC_TICK_HOUR - enable hours interrupt
RTC_TICK_DAY - enable days interrupt
RTC_ALARM_TIME - pass an alarm time and enable alarm interrupt
RTC_STOPWATCH_GO - pass stopwatch count down time (minutes) and enable stopwatch interrupt
RTC_GET_TIME - collect the present time
RTC_DISABLE - set together with other command to disable rather than enable interrupst (eg. RTC_ALARM_TIME  | RTC_DISABLE will disable the Alarm before it goes off)

Expect the support in the M5223X SP5 which will be available quite shortly.

Regards

Mark