* @note This macro can be used to activate a power saving mode.\r
*/\r
#define CH_CFG_IDLE_ENTER_HOOK() { \\r
- RCC->ICSCR = (RCC->ICSCR & ~RCC_ICSCR_MSIRANGE_Msk); \\r
- while (!(RCC->CR & RCC_CR_MSIRDY)); \\r
- PWR->CR &= ~PWR_CR_LPRUN; \\r
- PWR->CR |= PWR_CR_LPRUN; \\r
}\r
+// RCC->ICSCR = (RCC->ICSCR & ~RCC_ICSCR_MSIRANGE_Msk);\r
+// while (!(RCC->CR & RCC_CR_MSIRDY));\r
+// PWR->CR &= ~PWR_CR_LPRUN;\r
+// PWR->CR |= PWR_CR_LPRUN;\r
\r
/**\r
* @brief Idle thread leave hook.\r
* @note This macro can be used to deactivate a power saving mode.\r
*/\r
#define CH_CFG_IDLE_LEAVE_HOOK() { \\r
- RCC->ICSCR |= 6 << RCC_ICSCR_MSIRANGE_Pos; \\r
- while (!(RCC->CR & RCC_CR_MSIRDY)); \\r
- PWR->CR &= ~PWR_CR_LPRUN; \\r
}\r
+// RCC->ICSCR |= 6 << RCC_ICSCR_MSIRANGE_Pos;\r
+// while (!(RCC->CR & RCC_CR_MSIRDY));\r
+// PWR->CR &= ~PWR_CR_LPRUN;\r
\r
/**\r
* @brief System halt hook.\r
* @brief Enables the RTC subsystem.\r
*/\r
#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)\r
-#define HAL_USE_RTC FALSE\r
+#define HAL_USE_RTC TRUE\r
#endif\r
\r
/**\r
#define STM32_PLS STM32_PLS_LEV4\r
#define STM32_HSI16_ENABLED TRUE\r
#define STM32_HSI16_DIVIDER_ENABLED FALSE\r
-#define STM32_LSI_ENABLED FALSE\r
+#define STM32_LSI_ENABLED TRUE\r
#define STM32_HSE_ENABLED FALSE\r
#define STM32_LSE_ENABLED FALSE\r
#define STM32_ADC_CLOCK_ENABLED TRUE\r
#define STM32_MSIRANGE STM32_MSIRANGE_4M\r
#define STM32_SW STM32_SW_MSI\r
-#define STM32_PLLSRC STM32_PLLSRC_HSI16\r
-#define STM32_PLLMUL_VALUE 3\r
-#define STM32_PLLDIV_VALUE 4\r
+#define STM32_PLLSRC STM32_PLLSRC_NONE\r
+#define STM32_PLLMUL_VALUE 1\r
+#define STM32_PLLDIV_VALUE 8\r
#define STM32_HPRE STM32_HPRE_DIV1\r
#define STM32_PPRE1 STM32_PPRE1_DIV1\r
#define STM32_PPRE2 STM32_PPRE2_DIV1\r
#define STM32_MCOSEL STM32_MCOSEL_NOCLOCK\r
#define STM32_MCOPRE STM32_MCOPRE_DIV1\r
-#define STM32_RTCSEL STM32_RTCSEL_NOCLOCK\r
-#define STM32_RTCPRE STM32_RTCPRE_DIV2\r
+#define STM32_RTCSEL STM32_RTCSEL_LSI // ~37kHz\r
+#define STM32_RTCPRE STM32_RTCPRE_DIV2 // HSE only!\r
#define STM32_USART2SEL STM32_USART2SEL_APB\r
#define STM32_LPUART1SEL STM32_LPUART1SEL_APB\r
#define STM32_I2C1SEL STM32_I2C1SEL_APB\r
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)
{
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)
{
void dogs_init_display()
{
+ SET_CMD;
CS_LOW;
dogs_reset();
CS_HIGH;
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;
*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;
}
* - 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)
{
.chselr = ADC_CHSELR_CHSEL17 /* CHSELR */
};
-static int readVddmv()
+int readVddmv()
{
adcsample_t reading = 0;
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);
-}
-
-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