feat(rtc-service): служба RTC с резервированным backup-томом

Перенесена из k1921vk028/1921vk028/lib/rtc_service.

Ядро rtc_service_core.c зависит только от stddef, string и собственных
заголовков; доступ к часам и backup-памяти вынесен в rtc_service_port.h.
Порт для K1921VK028 идёт в комплекте и служит образцом для следующего МК.
This commit is contained in:
2026-08-23 01:15:36 +03:00
parent 3dc636e012
commit 34cbd92808
9 changed files with 774 additions and 0 deletions

View File

@@ -0,0 +1,127 @@
/**
****************************************************************************
* @file rtc_service_port_k1921vk028.c
* @brief Порт RTC Service для семейства K1921VK028 (plib028).
****************************************************************************
*/
#include "rtc_service_port.h"
#include "rtc_service_types.h"
#include "plib028_bflash.h"
#include "plib028_rtc.h"
#include "plib028_rcu.h"
#include <stddef.h>
#include <stdint.h>
/* Вывод: в данном HAL API явного выбора источника LSE/LSI на уровне C API нет,
поэтому конфигурирование делается как AUTO с флагом активного источника AUTO. */
RtcService_PortResult RtcService_Port_InitClock(RtcService_ClockSource preferred_source,
RtcService_ClockSource* actual_source)
{
if (actual_source != NULL) {
*actual_source = RTC_SERVICE_CLOCK_SOURCE_AUTO;
}
if (preferred_source != RTC_SERVICE_CLOCK_SOURCE_AUTO) {
/* На текущей ревизии драйвер NIIЭТ не предоставляет стабильных API для ручного
* выбора LSE/LSI через публичные функции. Рекомендуется использовать AUTO. */
return RTC_SERVICE_PORT_RESULT_UNSUPPORTED_CLOCK;
}
/* Включение тактирования RTC в RCC */
RCU_APBClk0Cmd(RCU_APBClk0_RTC, ENABLE);
return RTC_SERVICE_PORT_OK;
}
void RtcService_Port_EnableRtcClock(void)
{
/* На K1921VK028 дополнительной явной подготовки источника после включения тактирования
* RTC/APB-блока, как правило, не требуется. Реализация оставлена явной для port API. */
(void)0;
}
uint8_t RtcService_Port_IsPowerOnReset(void)
{
/* TODO: при наличии отдельного API/регистра статуса сброса заменить на реальную проверку.
* Безопасная дефолтная стратегия — считать, что это не cold reset. */
return 0U;
}
RtcService_PortResult RtcService_Port_ReadRtc(RtcService_DateTime* dt)
{
if (dt == NULL)
return RTC_SERVICE_PORT_RESULT_HW_ERROR;
RTC_Time_TypeDef t = {0};
RTC_Date_TypeDef d = {0};
RTC_GetTime(RTC_Format_BIN, &t);
RTC_GetDate(RTC_Format_BIN, &d);
dt->year = (uint16_t)d.Year;
dt->month = (uint16_t)d.Month;
dt->day = (uint16_t)d.Day;
dt->weekday = (uint16_t)d.Weekday;
dt->hour = (uint16_t)t.Hour;
dt->minute = (uint16_t)t.Minute;
dt->second = (uint16_t)t.Second;
return RTC_SERVICE_PORT_OK;
}
RtcService_PortResult RtcService_Port_WriteRtc(const RtcService_DateTime* dt)
{
RTC_Time_TypeDef t = {0};
RTC_Date_TypeDef d = {0};
if (dt == NULL)
return RTC_SERVICE_PORT_RESULT_HW_ERROR;
t.PSecond = 0U;
t.Hour = dt->hour;
t.Minute = dt->minute;
t.Second = dt->second;
d.Year = dt->year;
d.Month = dt->month;
d.Day = dt->day;
d.Weekday = (RTC_Weekday_TypeDef)dt->weekday;
RTC_SetTime(RTC_Format_BIN, &t);
RTC_SetDate(RTC_Format_BIN, &d);
RTC_ShadowCmd(DISABLE);
RTC_ShadowCmd(ENABLE);
return RTC_SERVICE_PORT_OK;
}
RtcService_PortResult RtcService_Port_ReadBackup(uint32_t* buffer, size_t words)
{
if ((buffer == NULL) || (words == 0U))
return RTC_SERVICE_PORT_RESULT_HW_ERROR;
for (size_t i = 0U; i < words; ++i) {
BFLASH_ReadData((uint32_t)i, &buffer[i], BFLASH_Region_NVR);
}
return RTC_SERVICE_PORT_OK;
}
RtcService_PortResult RtcService_Port_WriteBackup(const uint32_t* buffer, size_t words)
{
if ((buffer == NULL) || (words == 0U))
return RTC_SERVICE_PORT_RESULT_HW_ERROR;
for (size_t i = 0U; i < words; ++i) {
BFLASH_WriteData((uint32_t)i, (uint32_t*)&buffer[i], BFLASH_Region_NVR);
}
return RTC_SERVICE_PORT_OK;
}
RtcService_PortResult RtcService_Port_EraseBackup(void)
{
BFLASH_ErasePage(0UL, BFLASH_Region_NVR);
return RTC_SERVICE_PORT_OK;
}