Deep standby mode
GR-PEACHでディープスタンバイする際のメモ。
復帰条件はRTCのアラーム割り込み。5秒間隔でディープスタンバイから復帰する。
NV_DATA1は保持RAM領域。保持RAMを使用する際はリンクファイル(GCCの場合は後述のRZA1H.ld)も変更する必要がある。
main.cpp
#include "mbed.h" #include "rza_io_regrw.h" #include "rtc_api.h" // On-Chip Data Retention RAM static int wake_up_cnt __attribute((section("NV_DATA1"))); void Deep_standby_mode() { volatile uint32_t dummy_32; volatile uint16_t dummy_16; volatile uint8_t dummy_8; // 1. Set the standby_mode_en bit of the power control register in the PL310 to 1. L2C.REG15_POWER_CTRL = 0x00000001uL; dummy_32 = L2C.REG15_POWER_CTRL; // 2. Set the RRAMKP3 to RRAMKP0 bits in RRAMKP for the corresponding on-chip data-retention RAM area // that must be retained. Transfer the programs to be retained to the specified areas of the on-chip // data-retention RAM. CPG.RRAMKP = CPG_RRAMKP_RRAMKP1 | CPG_RRAMKP_RRAMKP2 | CPG_RRAMKP_RRAMKP3; dummy_8 = CPG.RRAMKP; // 3. Set the RAMBOOT and EBUSKEEPE bits in DSCTR to specify the activation method for returning from // deep standby mode and to select whether the external memory control pin status is retained or not. CPG.DSCTR = 0; // Activation Method : External memory dummy_8 = CPG.DSCTR; // 4. When canceling deep standby mode by an interrupt, set the corresponding bit in DSSSR to select // the pin or source to cancel deep standby mode. In this case, specify the input signal detection // mode for the selected pin with the corresponding bit in DSESR. CPG.DSSSR = CPG_DSSSR_RTCAR; // Deep standby mode is canceled by a realtime clock alarm interrupt. dummy_16 = CPG.DSSSR; CPG.DSESR = 0; dummy_16 = CPG.DSESR; // 5. Execute read and write of an arbitrary but the same address for each page in the on-chip data- // retention RAM area. When this is not executed, data last written may not be written to the on-chip // data-retention RAM. If there is a write to the on-chip data-retention RAM after this time, execute // this processing after the last write to the on-chip dataretention RAM. L1C_CleanInvalidateDCacheAll(); // Clean the whole data cache. // On-Chip Data Retention RAM Page 1 of bank 0 dummy_32 = *((uint32_t *)0x20004000); // Read *((uint32_t *)0x20004000) = dummy_32; // Write // On-Chip Data Retention RAM Page 2 of bank 0 dummy_32 = *((uint32_t *)0x20008000); // Read *((uint32_t *)0x20008000) = dummy_32; // Write // On-Chip Data Retention RAM Page 3 of bank 0 dummy_32 = *((uint32_t *)0x20010000); // Read *((uint32_t *)0x20010000) = dummy_32; // Write L1C_CleanDCacheAll(); // Clean the whole data cache. // 6. Set the STBY and DEEP bits in the STBCR1 register to 1, and then read this register. CPG.STBCR1 = CPG_STBCR1_DEEP | CPG_STBCR1_STBY; // deep standby mode dummy_8 = CPG.STBCR1; // 7. Clear the flag in the DSFR register. CPG.DSFR = 0; dummy_16 = CPG.DSFR; // 8. Set the CPU interface control register (ICCICR) of the interrupt controller to 0 so that the CPU // is not notified of interrupts other than NMIs. Then, read the ICCICR register. INTC.ICCICR = 0; dummy_32 = INTC.ICCICR; // Compiler warning measures (void)dummy_32; (void)dummy_16; (void)dummy_8; // Execute the WFI instruction while (1) { __WFI(); } } static void int_alarm(void) { RTC.RSECAR &= ~0x80; RTC.RMINAR &= ~0x80; RTC.RHRAR &= ~0x80; RTC.RDAYAR &= ~0x80; RTC.RMONAR &= ~0x80; RTC.RCR1 &= ~0x01u; // AF = 0 } static uint8_t hex8_to_dec(uint8_t hex_val) { uint32_t calc_data; calc_data = hex_val / 10 * 0x10; calc_data += hex_val % 10; if (calc_data > 0x99) { calc_data = 0; } return (uint8_t)calc_data; } static uint16_t hex16_to_dec(uint16_t hex_val) { uint32_t calc_data; calc_data = hex_val / 1000 * 0x1000; calc_data += ((hex_val / 100) % 10) * 0x100; calc_data += ((hex_val / 10) % 10) * 0x10; calc_data += hex_val % 10; if (calc_data > 0x9999) { calc_data = 0; } return (uint16_t)calc_data; } void set_alarm(time_t seconds) { struct tm *t = localtime(&seconds); RTC.RCR1 &= ~0x08u; // AIE = 0 GIC_DisableIRQ(ARM_IRQn); InterruptHandlerRegister(ARM_IRQn, &int_alarm); GIC_SetPriority(ARM_IRQn, 5); GIC_SetConfiguration(ARM_IRQn, 1); GIC_EnableIRQ(ARM_IRQn); RTC.RSECAR = 0x80 + hex8_to_dec(t->tm_sec); RTC.RMINAR = 0x80 + hex8_to_dec(t->tm_min); RTC.RHRAR = 0x80 + hex8_to_dec(t->tm_hour); RTC.RDAYAR = 0x80 + hex8_to_dec(t->tm_mday); RTC.RMONAR = 0x80 + hex8_to_dec(t->tm_mon + 1); RTC.RYRAR = hex16_to_dec(t->tm_year + 1900); RTC.RCR1 &= ~0x01u; // AF = 0 RTC.RCR1 |= 0x08u; // AIE = 1 } int main() { time_t seconds; uint16_t dsfr = CPG.DSFR; if (dsfr == 0x0000) { // initialization of On-Chip Data Retention RAM wake_up_cnt = 0; printf("Reset start\r\n"); rtc_init(); rtc_write(0); // Set RTC time : 01/01/1970 00:00:00 } else { wake_up_cnt++; printf("Wake up %d\r\n", wake_up_cnt); rtc_init(); } // RTC time seconds = rtc_read(); struct tm *t = localtime(&seconds); printf("RTC : %02d/%02d/%04d %02d:%02d:%02d\r\n", t->tm_mon + 1, t->tm_mday, t->tm_year + 1900, t->tm_hour, t->tm_min, t->tm_sec); // Set alarm interrupt set_alarm(seconds + 5); // 5 seconds later // Deep standby Deep_standby_mode(); }
RZA1H.ld
/* Linker script for mbed RZ_A1H */ == omit == MEMORY { ROM (rx) : ORIGIN = 0x00000000, LENGTH = 0x02000000 BOOT_LOADER (rx) : ORIGIN = BOOT_LOADER_ADDR, LENGTH = BOOT_LOADER_SIZE SFLASH (rx) : ORIGIN = SFLASH_ADDR, LENGTH = SFLASH_SIZE L_TTB (rw) : ORIGIN = 0x20000000, LENGTH = 0x00004000 RAM_NV1 (rwx) : ORIGIN = 0x20004000, LENGTH = 0x00004000 /* add */ RAM_NV2 (rwx) : ORIGIN = 0x20008000, LENGTH = 0x00008000 /* add */ RAM_NV3 (rwx) : ORIGIN = 0x20010000, LENGTH = 0x00010000 /* add */ RAM (rwx) : ORIGIN = 0x20020000, LENGTH = 0x008E0000 RAM_NC (rwx) : ORIGIN = 0x20900000, LENGTH = 0x00100000 } == omit == SECTIONS { == omit == .nv_data1 (NOLOAD) : { *(NV_DATA1) } > RAM_NV1 .nv_data2 (NOLOAD) : { *(NV_DATA2) } > RAM_NV2 .nv_data3 (NOLOAD) : { *(NV_DATA3) } > RAM_NV3 }
実行するとターミナル上に以下のように出力されます。
Reset start RTC : 01/01/1970 00:00:00 Wake up 1 RTC : 01/01/1970 00:00:05 Wake up 2 RTC : 01/01/1970 00:00:10 Wake up 3 RTC : 01/01/1970 00:00:15
Please log in to post comments.