Configuración de RTC y Sleep en CH572
Para el modelo CH572, se recomienda el uso del modo TRIG (Disparo) en lugar del modo TMR (Temporizador). Al utilizar el modo TRIG, el sistema obtiene el valor del reloj al encenderse y lo carga directamente, lo que minmiiza el error acumulado en comparación con los múltiplos fijos de 32768 que utiliza el modo TMR.
#include "CH57x_common.h"
volatile uint32_t freq_LSI = 0;
void ConfigurarDebug(void) {
GPIOA_SetBits(GPIO_Pin_10);
GPIOA_ModeCfg(GPIO_Pin_10, GPIO_ModeOut_PP_5mA);
UART_Remap(ENABLE, UART_TX_REMAP_PA10, UART_RX_REMAP_PA11);
UART_DefInit();
}
int main() {
// Deshabilitar depuración de dos hilos para ahorrar energía
R16_PIN_ALTERNATE &= ~RB_PIN_DEBUG_EN;
HSECFG_Capacitance(HSECap_18p);
SetSysClock(CLK_SOURCE_HSE_PLL_100MHz);
GPIOA_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);
ConfigurarDebug();
UART_BaudRateCfg(921600);
PRINT("Chip ID detectado: %02x\n", R8_CHIP_ID);
DelayMs(200);
/* Fuente de despertar: GPIO PA5 */
GPIOA_ModeCfg(GPIO_Pin_5, GPIO_ModeIN_PU);
GPIOA_ITModeCfg(GPIO_Pin_5, GPIO_ITMode_FallEdge);
PFIC_EnableIRQ(GPIO_A_IRQn);
PWR_PeriphWakeUpCfg(ENABLE, RB_SLP_GPIO_WAKE, Fsys_Delay_4096);
/* Inicialización del RTC */
sys_safe_access_enable();
R8_LSI_CONFIG |= RB_CLK_LSI_PON;
sys_safe_access_disable();
freq_LSI = RTC_InitClock(Count_1024);
PRINT("Frecuencia LSI: %d\n", freq_LSI);
RTC_InitTime(2026, 4, 10, 1, 50, 0);
RTC_TRIGFunCfg(freq_LSI);
PFIC_EnableIRQ(RTC_IRQn);
PWR_PeriphWakeUpCfg(ENABLE, RB_SLP_RTC_WAKE, Fsys_Delay_4096);
PRINT("Entrando en modo Sleep...\n");
DelayMs(2);
while(1) {
LowPower_Sleep(RB_PWR_RAM12K | RB_PWR_EXTEND);
}
}
__INTERRUPT
__HIGH_CODE
void RTC_IRQHandler(void) {
SetSysClock(CLK_SOURCE_HSE_PLL_100MHz);
mDelaymS(5);
uint16_t a, m, d, hh, mm, ss;
RTC_GetTime(&a, &m, &d, &hh, &mm, &ss);
if (RTC_GetITFlag(RTC_TRIG_EVENT)) {
PRINT("Evento TRIG: %04d-%02d-%02d %02d:%02d:%02d\r\n", a, m, d, hh, mm, ss);
RTC_ClearITFlag(RTC_TRIG_EVENT);
RTC_TRIGFunCfg(freq_LSI); // Re-armar el trigger
}
}
__INTERRUPT
__HIGH_CODE
void GPIOA_IRQHandler(void) {
GPIOA_ClearITFlagBit(GPIO_Pin_5);
}
Gestión de Energía y RTC en CH573
El CH573 permite una gestión avanzada de la memoria RAM durante el modo de bajo consumo. En este ejemplo, se configura el sistema para despertar mediante RTC o un flanco de bajada en el puerto GPIO, manteniendo solo la alimentación esnecial en la SRAM.
#include "CH57x_common.h"
void InicializarUART(void) {
GPIOA_SetBits(GPIO_Pin_9);
GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA);
UART1_DefInit();
}
int main() {
SetSysClock(CLK_SOURCE_PLL_60MHz);
GPIOA_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PD);
GPIOB_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PD);
InicializarUART();
PRINT("Iniciando CH573 ID: %02x\n", R8_CHIP_ID);
DelayMs(200);
LClk32K_Select(Clk32K_LSI);
R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG1;
R8_SAFE_ACCESS_SIG = SAFE_ACCESS_SIG2;
R8_CK32K_CONFIG &= ~RB_CLK_XT32K_PON;
R8_SAFE_ACCESS_SIG = 0;
RTC_InitTime(2024, 1, 1, 0, 0, 0);
RTC_TRIGFunCfg(32768 * 2); // Disparo cada 2 segundos
PFIC_EnableIRQ(RTC_IRQn);
PWR_PeriphWakeUpCfg(ENABLE, RB_SLP_RTC_WAKE, Edge_LongDelay);
/* Despertar por GPIO PA10 */
GPIOA_ModeCfg(GPIO_Pin_10, GPIO_ModeIN_PU);
GPIOA_ITModeCfg(GPIO_Pin_10, GPIO_ITMode_FallEdge);
PFIC_EnableIRQ(GPIO_A_IRQn);
PWR_PeriphWakeUpCfg(ENABLE, RB_SLP_GPIO_WAKE, Edge_LongDelay);
while(1) {
PRINT("Durmiendo...\n");
DelayMs(2);
LowPower_Sleep(RB_PWR_RAM16K | RB_PWR_RAM2K | RB_PWR_EXTEND | RB_PWR_XROM);
HSECFG_Current(HSE_RCur_100);
DelayMs(2);
}
}
__attribute__((interrupt("WCH-Interrupt-fast")))
__attribute__((section(".highcode")))
void RTC_IRQHandler(void) {
SetSysClock(CLK_SOURCE_PLL_60MHz);
mDelaymS(3);
uint16_t y, mo, d, h, mi, s;
RTC_GetTime(&y, &mo, &d, &h, &mi, &s);
if (RTC_GetITFlag(RTC_TRIG_EVENT)) {
printf("RTC Wakeup: %d:%d:%d\n", h, mi, s);
RTC_ClearITFlag(RTC_TRIG_EVENT);
RTC_TRIGFunCfg(32768 * 2);
}
}
Modo Shutdown y Despertar en CH582
Es fundamental tener en cuenta que en el modo Shutdown del CH582, el microcontrolador realiza un reinicio completo tras el despertar. No se ejecuta el manejador de interrupciones inmediatamente después de despertar; en su lugar, el código comienza desde la función main y se debe verificar el registro de estado de reset.
#include "CH58x_common.h"
void SetupDebug(void) {
GPIOA_SetBits(GPIO_Pin_9);
GPIOA_ModeCfg(GPIO_Pin_9, GPIO_ModeOut_PP_5mA);
UART1_DefInit();
}
int main() {
uint16_t yr, mon, day, hr, min, sec;
uint8_t reset_reason;
SetSysClock(CLK_SOURCE_PLL_60MHz);
GPIOA_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);
GPIOB_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU);
SetupDebug();
reset_reason = R8_RESET_STATUS;
PRINT("Origen del Reset: %02x\n", reset_reason);
// Si es encendido inicial o reset por pin
if(((reset_reason & 0x07) == 0x01) || ((reset_reason & 0x07) == 0x03)) {
RTC_InitTime(2024, 1, 1, 0, 0, 0);
printf("RTC Inicializado\n");
}
if((reset_reason & 0x07) == 0x05) {
printf("Despertado desde Shutdown\n");
}
RTC_TMRFunCfg(Period_1_S);
PFIC_EnableIRQ(RTC_IRQn);
PWR_PeriphWakeUpCfg(ENABLE, RB_SLP_RTC_WAKE, Long_Delay);
RTC_GetTime(&yr, &mon, &day, &hr, &min, &sec);
printf("Hora actual: %02d:%02d:%02d\n", hr, min, sec);
PRINT("Entrando en Shutdown...\n");
DelayMs(5);
LowPower_Shutdown(0); // Apagado total, el despertar causará reset
// El código inferior no se alcanza normalmente
while(1);
}
__INTERRUPT
__HIGH_CODE
void RTC_IRQHandler(void) {
RTC_ClearITFlag(RTC_TRIG_EVENT);
RTC_ClearITFlag(RTC_TMR_EVENT);
}