Calendar RTOS Driver

This Calendar RTOS driver provides an interface to set and get current date and time, and also alarm functionality used in a Real-Time operating system.

Refer Calendar Drivers for more detailed calendar basics.

Summary of the API's Functional Features

The API provides functions to:
  • Initialize and deinitialize the driver and associated hardware

  • Set time, date and base year

  • Get current date, and time

  • Set the software alarm timer with callback handler on the alarm event happen

Summary of Configuration Options

Below is the main Calendar parameters that can be configured in START. These parameters are used by the calendar_os_init function when initializing the driver and underlying hardware.
  • The clock source and the prescaler of counter hardware used by the calendar

Driver Implementation Description

The calendar driver implementation is based on a hardware counter which is configured to increase with one every second. The hardware may be RTC (Real-Time Counter) or RTT (Real-time Timer) depend on the device.

To use the software alarm, the alarm task API (calendar_os_task) should be called as an RTOS task or in the user while-loop thread.

The alarm task functions use semaphore to block the current task or thread until an alarm occurs. So the alarm task functions do not work without RTOS, and must be called in an RTOS task or thread.

Limitations

  • Only years divisible by 4 are leap year. This gives a correct result between the years 1901 to 2099

  • The task API (calendar_os_task) should be called in a user while-loop thread

Example of Usage

The following shows a simple example of using the Calendar. The calendar must have been initialized by calendar_os_init. This initialization will configure the operation of the underlying hardware counter.

The example creates the calendar example task. In the task, it first sets the given date and time, then it sets two alarm timers on specific second match with a callback function. Finally, the calendar_os_task is called in the while-loop thread.

Tip:
Take for example SAM D21. The RTC peripheral is used in counter mode and is to be increased by one every second. Correct RTC clock settings can be configured in START:
  • Clock
    • Select OSCULP32K source as generic clock generator 1 input

    • Enable generic clock generator 1 with division 32 to get 1kHz output

  • Calendar driver (RTC)
    • Select generic clock generator 1 as RTC clock input

    • Set prescaler to 1024, then RTC get a 1Hz clock input

          static struct calendar_os_alarm alarm1, alarm2;
          /**
           * Example of using CALENDAR_0.
           */
          static void alarm_cb(struct calendar_os_descriptor *const descr)
          {
              /* Handle alarm event */
          }
          /**
           * The alarm task function(calendar_os_task) should be called
           * in user while-loop thread, so that the soft alarm could be processed and
           * the alarm_cb function could be called.
           */
          void CALENDAR_0_example_task(void)
          {
              struct calendar_date_time dt;
              dt.date.year  = 2000;
              dt.date.month = 12;
              dt.date.day   = 31;
              dt.time.hour = 12;
              dt.time.min  = 59;
              dt.time.sec  = 59;
              calendar_os_set_date_time(&CALENDAR_0, &dt);
              alarm1.cal_alarm.datetime.time.sec = 20;
              alarm1.cal_alarm.option            = CALENDAR_ALARM_MATCH_SEC;
              alarm1.cal_alarm.mode              = ONESHOT;
              calendar_os_set_alarm(&CALENDAR_0, &alarm1, alarm_cb);
              alarm2.cal_alarm.datetime.time.sec = 40;
              alarm2.cal_alarm.option            = CALENDAR_ALARM_MATCH_SEC;
              alarm2.cal_alarm.mode              = REPEAT;
              calendar_os_set_alarm(&CALENDAR_0, &alarm2, alarm_cb);
              while(1) {
                  calendar_os_task(&CALENDAR_0);
              }
          }
          #define TASK_EXAMPLE_STACK_SIZE (256 / sizeof(portSTACK_TYPE))
          #define TASK_EXAMPLE_STACK_PRIORITY (tskIDLE_PRIORITY + 1)
          static TaskHandle_t      xCreatedExampleTask;
          int main(void)
          {
              /* Initializes MCU, drivers and middleware */
              atmel_start_init();
              if (xTaskCreate(
                      CALENDAR_0_example_task, "Example", TASK_EXAMPLE_STACK_SIZE, NULL,
                      TASK_EXAMPLE_STACK_PRIORITY, xCreatedExampleTask) != pdPASS) {
                  while (1) {
                      ;
                  }
              }
              vTaskStartScheduler();
              /* Replace with your application code */
              while (1) {
              }
          }
        

Dependencies

  • This driver expects a counter to be increased by one every second to count date and time correctly

  • Each instance of the driver requires a separate hardware timer

  • RTOS