RTC とバックアップドメインの概要
RTC(Real-Time Clock)は、システムメイン電源が遮断された場合でも動作を継続できる独立したタイモジュールです。STM32 マイクロコントローラでは、RTC とバックアップレジスタ(BKP)はバックアップドメインに属しており、システムリセットが発生してもデータが保持されます。
VDD 電源(2.0V〜3.6V)が失われた場合でも、VBAT ピン(1.8V〜3.6V)から予備電源を供給することで、時計機能およびバックアップレジスタのデータ保存を維持することが可能です。この機能を利用することで、電源断後も正確な時刻情報や重要な設定データを保持するシステムを構築できます。
ハードウェア抽象化レイヤの初期化
RTC を使用するには、まずバックアップドメインへのアクセス権限を有効化し、低速外部クロック(LSE)を安定させる必要があります。以下のコードでは、バックアップレジスタにマジックナンバーを書き込むことで、初回起動かどうかを判定し、必要に応じて RTC クロックソースの設定を行います。
void RTC_System_Init(void)
{
/* バックアップドメインおよび電源インターフェースのクロックを有効化 */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
/* バックアップレジスタへの書き込みを許可 */
PWR_BackupAccessCmd(ENABLE);
/* バックアップレジスタ DR1 の値を確認し、初期設定済みか判定 */
if (BKP_ReadBackupRegister(BKP_DR1) != 0x5AA5)
{
/* バックアップドメインをリセット */
RCC_BackupResetCmd(ENABLE);
RCC_BackupResetCmd(DISABLE);
/* 低速外部クロック(LSE)を有効化 */
RCC_LSEConfig(RCC_LSE_ON);
/* LSE の準備完了を待機 */
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
/* RTC クロックソースとして LSE を選択 */
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
/* RTC クロックを有効化 */
RCC_RTCCLKCmd(ENABLE);
/* RTC レジスタへの書き込み同期を待機 */
RTC_WaitForSynchro();
RTC_WaitForLastTask();
/* プリスケーラを設定(32.768kHz / 32768 = 1Hz) */
RTC_SetPrescaler(32768 - 1);
RTC_WaitForLastTask();
/* 初期時刻を設定 */
RTC_WriteTimestamp();
/* 設定完了を示すマジックナンバーを記録 */
BKP_WriteBackupRegister(BKP_DR1, 0x5AA5);
}
else
{
/* 設定済みの場合、同期のみ待機 */
RTC_WaitForSynchro();
RTC_WaitForLastTask();
}
}
時刻データの書き込み処理
標準 C ライブラリ<time.h>の機能を利用し、人間が読みやすい形式(年、月、日など)から UNIX タイムスタンプへ変換を行い、RTC のカウンタレジスタに書き込みます。タイムゾーンオフセットを考慮することで、地域に適した時刻管理が可能になります。
#define TIMEZONE_OFFSET (8 * 3600) /* 例:UTC+8 の場合 */
/* グローバル時刻バッファ [年,月,日,時,分,秒] */
extern uint16_t g_time_data[6];
void RTC_WriteTimestamp(void)
{
time_t unix_timestamp;
struct tm time_structure;
/* 構造体に各時刻要素を格納 */
time_structure.tm_year = g_time_data[0] - 1900;
time_structure.tm_mon = g_time_data[1] - 1;
time_structure.tm_mday = g_time_data[2];
time_structure.tm_hour = g_time_data[3];
time_structure.tm_min = g_time_data[4];
time_structure.tm_sec = g_time_data[5];
time_structure.tm_isdst = 0;
/* 日時を秒単位のタイムスタンプに変換 */
unix_timestamp = mktime(&time_structure);
/* タイムゾーン調整を行い RTC カウンタに設定 */
RTC_SetCounter(unix_timestamp - TIMEZONE_OFFSET);
RTC_WaitForLastTask();
}
時刻データの読み出し処理
RTC カウンタから現在の秒数を取得し、再度<time.h>の関数を用いて構造体形式へ変換します。これにより、アプリケーション層で容易に時刻情報を参照・表示できるようになります。ポインタ経由で構造体メンバーにアクセスし、グローバルバッファへ格納する実装例を示します。
void RTC_ReadTimestamp(void)
{
time_t current_count;
struct tm *time_info;
/* RTC カウンタから秒数を取得し、タイムゾーンを補正 */
current_count = RTC_GetCounter() + TIMEZONE_OFFSET;
/* タイムスタンプを分解して構造体ポインタを取得 */
time_info = localtime(¤t_count);
/* 各要素をグローバルバッファへ格納 */
g_time_data[0] = time_info->tm_year + 1900;
g_time_data[1] = time_info->tm_mon + 1;
g_time_data[2] = time_info->tm_mday;
g_time_data[3] = time_info->tm_hour;
g_time_data[4] = time_info->tm_min;
g_time_data[5] = time_info->tm_sec;
}