From c61598fe95bb188ca28f1710dd8a42907bb797cb Mon Sep 17 00:00:00 2001 From: Clyne Sullivan Date: Fri, 17 Sep 2021 07:26:50 -0400 Subject: [PATCH] use rtc for timing --- cfg/chconf.h | 14 ++--- cfg/halconf.h | 2 +- cfg/mcuconf.h | 12 ++-- dogs.c | 50 +++++++++-------- main.c | 153 ++++++++++++++++++++++++++++---------------------- openocd.sh | 2 +- 6 files changed, 126 insertions(+), 107 deletions(-) diff --git a/cfg/chconf.h b/cfg/chconf.h index dc2ccc1..25d444a 100644 --- a/cfg/chconf.h +++ b/cfg/chconf.h @@ -451,11 +451,11 @@ * @note This macro can be used to activate a power saving mode. */ #define CH_CFG_IDLE_ENTER_HOOK() { \ - RCC->ICSCR = (RCC->ICSCR & ~RCC_ICSCR_MSIRANGE_Msk); \ - while (!(RCC->CR & RCC_CR_MSIRDY)); \ - PWR->CR &= ~PWR_CR_LPRUN; \ - PWR->CR |= PWR_CR_LPRUN; \ } +// RCC->ICSCR = (RCC->ICSCR & ~RCC_ICSCR_MSIRANGE_Msk); +// while (!(RCC->CR & RCC_CR_MSIRDY)); +// PWR->CR &= ~PWR_CR_LPRUN; +// PWR->CR |= PWR_CR_LPRUN; /** * @brief Idle thread leave hook. @@ -464,10 +464,10 @@ * @note This macro can be used to deactivate a power saving mode. */ #define CH_CFG_IDLE_LEAVE_HOOK() { \ - RCC->ICSCR |= 6 << RCC_ICSCR_MSIRANGE_Pos; \ - while (!(RCC->CR & RCC_CR_MSIRDY)); \ - PWR->CR &= ~PWR_CR_LPRUN; \ } +// RCC->ICSCR |= 6 << RCC_ICSCR_MSIRANGE_Pos; +// while (!(RCC->CR & RCC_CR_MSIRDY)); +// PWR->CR &= ~PWR_CR_LPRUN; /** * @brief System halt hook. diff --git a/cfg/halconf.h b/cfg/halconf.h index 5cdb5e0..6688b95 100644 --- a/cfg/halconf.h +++ b/cfg/halconf.h @@ -128,7 +128,7 @@ * @brief Enables the RTC subsystem. */ #if !defined(HAL_USE_RTC) || defined(__DOXYGEN__) -#define HAL_USE_RTC FALSE +#define HAL_USE_RTC TRUE #endif /** diff --git a/cfg/mcuconf.h b/cfg/mcuconf.h index 217d13f..96e9080 100644 --- a/cfg/mcuconf.h +++ b/cfg/mcuconf.h @@ -44,22 +44,22 @@ #define STM32_PLS STM32_PLS_LEV4 #define STM32_HSI16_ENABLED TRUE #define STM32_HSI16_DIVIDER_ENABLED FALSE -#define STM32_LSI_ENABLED FALSE +#define STM32_LSI_ENABLED TRUE #define STM32_HSE_ENABLED FALSE #define STM32_LSE_ENABLED FALSE #define STM32_ADC_CLOCK_ENABLED TRUE #define STM32_MSIRANGE STM32_MSIRANGE_4M #define STM32_SW STM32_SW_MSI -#define STM32_PLLSRC STM32_PLLSRC_HSI16 -#define STM32_PLLMUL_VALUE 3 -#define STM32_PLLDIV_VALUE 4 +#define STM32_PLLSRC STM32_PLLSRC_NONE +#define STM32_PLLMUL_VALUE 1 +#define STM32_PLLDIV_VALUE 8 #define STM32_HPRE STM32_HPRE_DIV1 #define STM32_PPRE1 STM32_PPRE1_DIV1 #define STM32_PPRE2 STM32_PPRE2_DIV1 #define STM32_MCOSEL STM32_MCOSEL_NOCLOCK #define STM32_MCOPRE STM32_MCOPRE_DIV1 -#define STM32_RTCSEL STM32_RTCSEL_NOCLOCK -#define STM32_RTCPRE STM32_RTCPRE_DIV2 +#define STM32_RTCSEL STM32_RTCSEL_LSI // ~37kHz +#define STM32_RTCPRE STM32_RTCPRE_DIV2 // HSE only! #define STM32_USART2SEL STM32_USART2SEL_APB #define STM32_LPUART1SEL STM32_LPUART1SEL_APB #define STM32_I2C1SEL STM32_I2C1SEL_APB diff --git a/dogs.c b/dogs.c index a29ee2c..7d32698 100644 --- a/dogs.c +++ b/dogs.c @@ -21,6 +21,17 @@ unsigned char dogs_buffer[DISP_WIDTH * DISP_HEIGHT / 8]; static volatile bool dogs_spi_done = false; +static void spi_send(unsigned char *data, unsigned int len) +{ + dogs_spi_done = false; + spiStartSend(&SPID1, len, data); + while (!dogs_spi_done) + asm("wfi"); + + //for (; len > 0; --len) + // spiPolledExchange(&SPID1, *data++); +} + static void dogs_init_display(); static void dogs_spi_callback(SPIDriver *spid) { @@ -54,27 +65,15 @@ void dogs_init() dogs_flush(); } -void dogs_write_data(unsigned char byte) -{ - SET_DATA; - dogs_spi_done = false; - spiStartSend(&SPID1, 1, &byte); - while (!dogs_spi_done); -} void dogs_write_cmd(unsigned char byte) { - SET_CMD; - dogs_spi_done = false; - spiStartSend(&SPID1, 1, &byte); - while (!dogs_spi_done); + spi_send(&byte, 1); } void dogs_set_column(unsigned int col) { - //if (col < DISP_WIDTH) { - dogs_write_cmd(0x10 | ((col >> 4) & 0xF)); - dogs_write_cmd(0x00 | (col & 0xF)); - //} + dogs_write_cmd(0x10 | ((col >> 4) & 0xF)); + dogs_write_cmd(0x00 | (col & 0xF)); } void dogs_set_power(unsigned int bits) { @@ -133,6 +132,7 @@ void dogs_set_advanced(unsigned int bits) void dogs_init_display() { + SET_CMD; CS_LOW; dogs_reset(); CS_HIGH; @@ -154,9 +154,10 @@ void dogs_init_display() void dogs_clear() { - unsigned char *ptr = dogs_buffer; - int count = sizeof(dogs_buffer); - for (; count > 8; count -= 8) { + uint32_t *ptr = (uint32_t *)dogs_buffer; + unsigned int count = sizeof(dogs_buffer) / sizeof(uint32_t) / 12; + + for (; count; --count) { *ptr++ = 0; *ptr++ = 0; *ptr++ = 0; @@ -165,24 +166,25 @@ void dogs_clear() *ptr++ = 0; *ptr++ = 0; *ptr++ = 0; - } - for (; --count >= 0;) *ptr++ = 0; + *ptr++ = 0; + *ptr++ = 0; + *ptr++ = 0; + } } void dogs_flush() { unsigned char *ptr = dogs_buffer; CS_LOW; - for (int page = 0; page < 8; page++) { + for (int page = 0; page < 8; ++page) { + SET_CMD; dogs_set_page(page); dogs_set_column(30); SET_DATA; - dogs_spi_done = false; - spiStartSend(&SPID1, 102, ptr); + spi_send(ptr, 102); ptr += 102; - while (!dogs_spi_done); } CS_HIGH; } diff --git a/main.c b/main.c index 5c963fc..37c1471 100644 --- a/main.c +++ b/main.c @@ -29,9 +29,93 @@ * - Run at 4MHz, drop to low-power run/sleep @ 64kHz for idle: 375uA (also lowered contrast) * - Sleep display for 'pause': ~240uA * + * - Use RTC for delay, Stop mode when idle: 348uA + * * - Flappy bird is going, 2048 next */ +static int readVddmv(); + +THD_WORKING_AREA(waThread2, 128); +THD_FUNCTION(Thread2, arg) +{ + (void)arg; + + dogs_init(); + flapbird_init(); +} +THD_TABLE_BEGIN + THD_TABLE_THREAD(0, "game", waThread2, Thread2, NULL) +THD_TABLE_END + +static void alarm_callback(RTCDriver *rtcp, rtcevent_t event) +{ + (void)rtcp; + (void)event; + + static bool sleep = false; + + bool sleep_button = (button_state & BUTTON_1) != 0; + if (sleep && !sleep_button) + return; + + RCC->ICSCR |= 6 << RCC_ICSCR_MSIRANGE_Pos; + dogs_set_sleep(false); + + if (sleep_button) { + sleep ^= true; + if (sleep) { + draw_number(DISP_WIDTH - 33, 0, + !(PWR->CSR & PWR_CSR_PVDO) ? readVddmv() : 1); + dogs_flush(); + } + } + + if (!sleep) + flapbird_loop(); + + dogs_set_sleep(true); +} + +int main(void) +{ + halInit(); + chSysInit(); + buttons_init(); + + static const RTCWakeup wakeupcfg = { + (0 << 16) | // wucksel (37k /16 = ~2k) + 240 // wut (hope for 10Hz) + }; + rtcSTM32SetPeriodicWakeup(&RTCD1, &wakeupcfg); + rtcSetCallback(&RTCD1, alarm_callback); + + RCC->CR &= ~RCC_CR_HSION; + PWR->CR |= PWR_CR_LPSDSR | PWR_CR_ULP; + PWR->CR |= PWR_CR_LPRUN; + SCB->SCR = 6; + FLASH->ACR |= FLASH_ACR_SLEEP_PD; + + // Below code for serial -- note that it cuts off debugging, and MUST be used in a thread + //chThdSleepMilliseconds(2000); + //palSetPadMode(GPIOA, 13, PAL_MODE_ALTERNATE(6)); + //palSetPadMode(GPIOA, 14, PAL_MODE_ALTERNATE(6)); + //sdStart(&LPSD1, NULL); + //chnWrite(&LPSD1, (const uint8_t *)"Hello World!\r\n", 14); + + /* This is now the idle thread loop, you may perform here a low priority + task but YOU MUST NEVER TRY TO SLEEP OR WAIT in this loop. Note that + this tasks runs at the lowest priority level so any instruction added + here will be executed after all other tasks have been started. */ + while (1) + asm("wfe"); +} + +void HardFault_Handler() +{ + while (1); +} + static volatile bool adc_is_complete = false; static void adc_callback(ADCDriver *adcd) { @@ -55,7 +139,7 @@ static const ADCConversionGroup adcgrpcfg = { .chselr = ADC_CHSELR_CHSEL17 /* CHSELR */ }; -static int readVddmv() +int readVddmv() { adcsample_t reading = 0; @@ -74,70 +158,3 @@ static int readVddmv() return 3000 * /* CAL */ *((adcsample_t *)0x1FF80078) / reading; } - -THD_WORKING_AREA(waThread2, 128); -THD_FUNCTION(Thread2, arg) -{ - (void)arg; - - dogs_init(); - - flapbird_init(); - - bool sleep = false; - while (1) { - if (button_state & BUTTON_1) { - sleep ^= true; - if (sleep) { - draw_number(DISP_WIDTH - 33, 0, - !(PWR->CSR & PWR_CSR_PVDO) ? readVddmv() : 1); - dogs_flush(); - } - dogs_set_sleep(sleep); - } - - int dtime = 100; - if (!sleep) { - dtime = flapbird_loop(); - } - - chThdSleepS(TIME_MS2I(dtime) / 64); - } -} - -THD_TABLE_BEGIN - THD_TABLE_THREAD(0, "game", waThread2, Thread2, NULL) -THD_TABLE_END - -int main(void) -{ - halInit(); - chSysInit(); - - RCC->CR &= ~RCC_CR_HSION; - PWR->CR |= PWR_CR_LPSDSR; - - buttons_init(); - - // Below code for serial -- note that it cuts off debugging, and MUST be used in a thread - //chThdSleepMilliseconds(2000); - //palSetPadMode(GPIOA, 13, PAL_MODE_ALTERNATE(6)); - //palSetPadMode(GPIOA, 14, PAL_MODE_ALTERNATE(6)); - //sdStart(&LPSD1, NULL); - //chnWrite(&LPSD1, (const uint8_t *)"Hello World!\r\n", 14); - - - - /* This is now the idle thread loop, you may perform here a low priority - task but YOU MUST NEVER TRY TO SLEEP OR WAIT in this loop. Note that - this tasks runs at the lowest priority level so any instruction added - here will be executed after all other tasks have been started. */ - while (1) - asm("wfi"); -} - -void HardFault_Handler() -{ - while (1); -} - diff --git a/openocd.sh b/openocd.sh index 6cf8e57..90d4052 100755 --- a/openocd.sh +++ b/openocd.sh @@ -1 +1 @@ -sudo openocd -f /usr/local/share/openocd/scripts/interface/cmsis-dap.cfg -f /usr/local/share/openocd/scripts/target/stm32l0.cfg +sudo openocd -f /usr/local/share/openocd/scripts/interface/stlink-v2.cfg -f /usr/local/share/openocd/scripts/target/stm32l0.cfg