分享到plurk 分享到twitter 分享到facebook

版本 e799add4fe9490df619302191043ad96bbf44403

embedded/RTC

Changes from e799add4fe9490df619302191043ad96bbf44403 to d0d4b6514efafe29573387ca04a5f830af3f3d20

Introduction
==============

Real-Time Clock(RTC)是負責記錄時間的元件,出現在需要長期使用時鐘的電子設備中。例如學校定時關閉冷氣的裝置,以及手機上的鬧鈴功能。

System Overview
----------------- 

基本上RTC(Real-time clock)本身就是一個真正的時鐘,利用原本STM本身所內建的振盪器再利用Prescaler降成1Hz讓RTC使用。利用硬體達成的binary-coded decimal (BCD) format,可以把下列與時間有關的資訊儲存,而且不需要任何軟體轉換,因為硬體就已經把資料轉成一般的日期格式。

- sub-seconds 
- seconds
- minutes
- hours in 12-hour or 24-hour format
- day of the week (day)
- day of the month (date)
- month
- year

可用的功能

- Alarm A & Alarm B
- Auto wakeup
- Timestamp
- Tamper detection


Block Diagram  
--------------------

.. image:: /rtc_block.png





Functional Description
============================
Clock Source 
--------------------

.. image:: /clocksource2.png

**STM32的 Clock 有分成「SYSCLK」和「RTCCLK」:**

SYSCLK為系統的clock有三種來源:

1. **HSI**  (High-Speed Internal) :16MHz,RC電路
2. **HSE** (Low-Speed External):4-26MHz (一般選用8MHz),石英震盪
3. Main **PLL** clock

RTCCLK為設備的clock有兩種來源:

1. **LSI**  (Low-Speed Internal)  :40kHz,RC電路震盪
2. **LSE** (High-Speed External):32.768kHz,石英震盪

----> RTC 主要是使用 **HSE** , **LSI**  , **LSE** 三種來源

*參閱reference manual p.150*

-----------------------------------------------

**比較 「HSE」, 「LSI」 , 「LSE」三種輸入來源:** 


- HSE  -  較為耗能, 可以處理像是USB或TV訊號的clock,需要和和另一個clock穩定同步。
- LSI  -  是一個低功耗的clock,可以再停機或待機模式下保持運行,用在auto-wakeup(簡稱AWU)與 watchdog看門狗(簡稱IMDG)。
- LSE  -  它是一個低功耗且"精準"的clock,適合用在時間的精確計算。

Prescaler 
--------------------

.. image:: /stm32 RTC prescaler.png

``ck_spre``一般而言要降為1Hz的頻率,因為省電的因素STM設計了兩個Prescaler。7 bit非同步prescaler(``PREDIV_A``)和15 bit同步的prescaler(``PREDIV_S``)。這兩個prescaler要在RTC_PRER的暫存器設定。*ST在Reference有說明當兩個Prescaler都使用時,建議讓非同步的Prescaler讓他有較大的值,以讓系統更省電*

所以``ck_spre``與兩個prescaler的關係為:

.. image:: /ck_spre2.png


例如:

LSE: 32.768kHz / (**127**+1) / (**255**+1) = 1Hz

LSI: 32kHz / (**127**+1) /(**249**+1) =1Hz

Alternate Function RTC Outputs
--------------------------------------

Alternate function 可以將RTC某些功能對應到輸出的接腳(GPIO Pin),這些輸出可以被選擇成**tamp event** 或 **time stamp event**,

甚至RTC Calibration 的訊號都可以藉由這個功能輸出。

可以選擇兩個輸出:

輸出接腳 **RTC_AF1(PC13)** : 

- RTC_ALARM output:    1. RTC Alarm A       2. RTC Alarm B       3. RTC Wakeup

- RTC_CALIB output

- RTC_TAMP1

- RTC_TS

輸出接腳 **RTC_AF2 (PI8)** :

- RTC_TAMP1

- RTC_TAMP2

- RTC_TS

*Reference Manual p.277*

*PI8接腳參考: datasheet p.10*

RTC Calendar 
--------------------


.. image:: /RTC_calendar.png


**讀取Calendar:**

當在讀取Calendar時其實並不是真正直接讀取calendar register,其實是在讀shadow register,如果想要直接讀取calendar必須

要設BYPSHAD控制位元為1(在RTC_C Rregister)才能繞過shadow register而直接讀取calender register。

**Shadow Register:**

- 通常初始化和讀取的動作採用Shadow Register。

- 每兩個RTCCLK時間週期,RTC的calendar register (RTC_SSR, RTC_TR, and RTC_DR)的值會被自動更新到Shadow Register。

-----------------------------

Calibration
-----------------------------

RTC裡面有兩個校正功能,一個是coarse calibration另一個是smooth calibration。

這兩個校正不能同時被使用,而前者只能固定修正,後者則可以動態的校正。後者也可以較大範圍及更精準的校正。

**1、RTC coarse calibration :**

- 被使用在補償石英震盪器的校正。

- 在非同步分頻器(ck_apre)的輸出,藉由增加或減少時間的週期達到校正,最大範圍的校正為63ppm~126ppm。

- 只能在初始化Calendar時候修改,是一個非回授控制系統(opened loop control)。

- 可以利用AFO_CALIB去計算clock deviation。不能以圖中512Hz的訊號去確認coarse calibration的輸出結果,只能使用ck_spre確認校正的結果。

- reference clock calibration 和 coarse calibration 不能同時使用。

.. image:: /coarse cal.png

**2、RTC  smooth calibration:**

- 可以補償石英震盪器的偏差,此偏差可能是晶體老化或者溫度所造成。

- 利用每個RTCCLK pulse為單位做出小幅調整,來修正RTC的clock頻率。

- 最大範圍的校正為-487.1ppm~+488.5ppm。 

- 與coarse calibration不同,是一個閉迴路的控制系統(closed loop control)。

- 可以使用AFO_CALIB來計算時間偏差,而且可直接檢查512Hz和1Hz的校正輸出。 


.. image:: /smooth cal.png

**3、RTC reference clock detection:**

- 利用外部時鐘校正,其時鐘源必須要比LSE的時鐘還精準。


---------------------------------------------------

---------------------------------------------------


Interrupt Application
==========================

Alarm
---------------------------

- 有兩個時鐘Alarm A及Alarm B,可以當作鬧鐘使用。而且相關的register也都會有兩組。

- 可利用Mask達成不同時間的鬧鈴效果。


.. image:: /embedded/RTC/alarm_pass.png


-----------------------------------------------

.. image:: /Alarm3.png


**利用MSKx bits設定遮罩改變Alarm的行為:**

As an example, to configure the alarm time to 23:15:07 on Monday (預設MSK是0000)


.. image:: /MSK2.png


Application note p.10

---------------------------


Periodic Wakeup Unit
----------------------------

- 利用周期性的喚醒(wakeup)可以讓系統更省電。這個unit是一個downcounting且會auto-reload 的timer,當它的counter數到0的時候,一個flag和中斷會產生(如果在打開中斷的情況下)。

- 會有兩個因素影響wakeup unit的中斷觸發週期,一個是timer的value,一個是clock source

**設定wakeup period**

有三種組態:

Configuration 1:**short wakeup** periods

Configuration 2:**medium wakeup** periods

Configuration 3: **long wakeup** periods

**Configuration 1:**

Prescalers connected to the timebase/wakeup unit

.. image:: /wuck1.png

在這個設定中,wakeup unit,會接受由RTCCLK再經過Prescaler的clock。RTC_WUTR(RTC Wakeup Timer Register)為一個

auto-reload的down counting timer,這表示當使用者在初始化時設了一個值x,會在x數到0的時候觸發wakeup flag。

**EX:**當RTCCLK= 32768 Hz,代表著最小的timebase resolution為61.035μs(數一次的時間),最大則是488.28 μs。

- 所以這代表著最小可觸發wakeup flag時間為**(0x0001 + 1) x 61.035 μs = 122.07 μs**

- 最大可觸發wakeup flag時間為 **(0xFFFF+ 1) x 488.28 μs = 2 s**

*註:STM32禁止timer初始值設為0*

----------------------------------------------------------------------------

Prescalers connected to the wakeup unit for configurations 2 and 3

.. image:: /wuck2.png

2和3的clock source相同,都是用來計算calendar的ck_spre。

**Configuration 2:**

- The minimum timebase/wakeup period is **(0x0000 + 1) x 61.035 µs = 122.07 µs.**

- The maximum timebase/wakeup period is**(0xFFFF+ 1) x 32 s = 131072 s (more than 36 hours).**

**Configuration 3:**

其Clock Source與 Configuration 2 一樣,差在2最大可以從0xFFFF倒數至0x0000,3則是0x1FFFF至0x00000

- The minimum timebase/wakeup period is: **(0x10000 + 1) x 61.035 µs = 250.06 ms**

- The maximum timebase/wakeup period is: **(0x1FFFF+ 1) x 32 s = 4194304 s (more than 48 days).**



Min. and max. timebase/wakeup period when RTCCLK= 32768Hz


.. image:: /MaxMin.png

Time-stamp Function
--------------------------

實體世界裡有「郵戳為憑」來證明信件的時間,在網路世界裡如何來證明電子文件或交易的時間? 

利用Time-stamp function 可以為任何電子文件或電子交易提供準確的時間證明,並且驗證其內容自蓋上時戳後是否曾被人修改過。

Time-stamp function 提供自動幫你儲存日曆的功能

**RTC_TSDR register** : 會去讀取RTC_DR 裡面的年、月、日、周的資料並儲存

**RTC_TSTR register** : 會去讀取RTC_TR 裡面的秒、時、分的資料並儲存

**RTC_TSSR register** : 會去讀取RTC_SSR 裡面的Sub-second 的資料並儲存

.. image:: /timestamp.png

Tamper Detection Function
---------------------------------

tamper detection是一個可以檢測系統是否被破壞的功能,有20個backup register在tamper發生時,

全部自動reset,達到保護系統的作用。 

**Backup registers**

當tamper detection發生時,RTC_BKPxR(backup registers)會自己重設,在電源 VDD(1.8~3.6V) 關掉以後,

這個backup registers會動作在 VBAT (1.65~3.6V)的低功率電源( low power mode),所以它不會被系統重設,

它只會被tamper detection重設。


Example of code
========================

Initialize RTC
--------------------

.. code-block:: prettyprint
	
    RTC_InitTypeDef RTC_InitStructure;
	
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);   /* Enable the PWR clock */
    PWR_BackupAccessCmd(ENABLE);                          /* Allow access to RTC */

    RCC_LSICmd(ENABLE);                                   /* Enable the LSI OSC */
    while(RCC_GetFlagStatus(RCC_FLAG_LSIRDY) == RESET);   /* Wait till LSI is ready */  
    RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);               /* Select the RTC Clock Source */
	
    RCC_RTCCLKCmd(ENABLE);                                /* Enable the RTC Clock */
    RTC_WaitForSynchro();                                 /* Wait for RTC APB registers synchronisation */

    /* Configure the RTC data register and RTC prescaler */
    RTC_InitStructure.RTC_AsynchPrediv = 0x7F;
    RTC_InitStructure.RTC_SynchPrediv = 0xF9;
    RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
    RTC_Init(&RTC_InitStructure);

setting time
--------------------

.. code-block:: prettyprint

	/* set 8:29:55 */
	RTC_TimeTypeDef RTC_TimeStruct;
	RTC_TimeStruct.RTC_Hours = 8;
	RTC_TimeStruct.RTC_Minutes = 29;
	RTC_TimeStruct.RTC_Seconds = 55;
	
	RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);


initialize RTC alarm
--------------------

.. code-block:: prettyprint

	EXTI_InitTypeDef EXTI_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	/* EXTI configuration */
	EXTI_ClearITPendingBit(EXTI_Line17);
	EXTI_InitStructure.EXTI_Line = EXTI_Line17;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);

	/* Enable the RTC Alarm Interrupt */
	NVIC_InitStructure.NVIC_IRQChannel = RTC_Alarm_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);


setting alarm time
--------------------

.. code-block:: prettyprint

	RTC_AlarmTypeDef RTC_AlarmStructure;

	RTC_AlarmCmd(RTC_Alarm_A, DISABLE);   /* disable before setting or cann't write */

	/* set alarm time 8:30:0 everyday */
	RTC_AlarmStructure.RTC_AlarmTime.RTC_H12     = 0x00;
	RTC_AlarmStructure.RTC_AlarmTime.RTC_Hours   = 8;
	RTC_AlarmStructure.RTC_AlarmTime.RTC_Minutes = 30;
	RTC_AlarmStructure.RTC_AlarmTime.RTC_Seconds = 0;
	RTC_AlarmStructure.RTC_AlarmDateWeekDay = 0x31; // Nonspecific
	RTC_AlarmStructure.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_Date;
	RTC_AlarmStructure.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay; // Everyday 
	RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_A, &RTC_AlarmStructure);
	
	/* Enable Alarm */
	RTC_ITConfig(RTC_IT_ALRA, ENABLE);
	RTC_AlarmCmd(RTC_Alarm_A, ENABLE);
	RTC_ClearFlag(RTC_FLAG_ALRAF);



complete code
--------------------

.. code-block:: c

    git clone git@gitcafe.com:ctc8631/RTC-example.git
    cd RTC-example/
    make flash




Reference
================
`RTC application note<http://www.st.com/st-web-ui/static/active/cn/resource/technical/document/application_note/DM00025071.pdf>`_

`STM32F405xx/07xx, STM32F415xx/17xx, STM32F42xxx and STM32F43xxx Reference Manual
<http://www.st.com/st-web-ui/static/active/en/resource/technical/document/reference_manual/DM00031020.pdf>`_

`共筆<https://hackpad.com/STM32F74-RTCReal-Time-Clock-eclVxLGTj50>`_