/* * Copyright (c) 2016 Open-RnD Sp. z o.o. * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #include #include ///// LED /* Change this if you have an LED connected to a custom port */ #ifndef LED0_GPIO_CONTROLLER #define LED0_GPIO_CONTROLLER LED0_GPIO_PORT #endif #define LED_PORT LED0_GPIO_CONTROLLER /* Change this if you have an LED connected to a custom pin */ #define LED LED0_GPIO_PIN ///// BUTTON /* change this to use another GPIO port */ #ifndef SW0_GPIO_CONTROLLER #ifdef SW0_GPIO_NAME #define SW0_GPIO_CONTROLLER SW0_GPIO_NAME #else #error SW0_GPIO_NAME or SW0_GPIO_CONTROLLER needs to be set in board.h #endif #endif #define PORT SW0_GPIO_CONTROLLER /* change this to use another GPIO pin */ #ifdef SW0_GPIO_PIN #define PIN SW0_GPIO_PIN #else #error SW0_GPIO_PIN needs to be set in board.h #endif /* change to use another GPIO pin interrupt config */ #ifdef SW0_GPIO_INT_CONF #define EDGE SW0_GPIO_INT_CONF #else /* * If SW0_GPIO_INT_CONF not defined used default EDGE value. * Change this to use a different interrupt trigger */ #define EDGE (GPIO_INT_EDGE | GPIO_INT_ACTIVE_LOW) #endif /* change this to enable pull-up/pull-down */ #ifdef SW0_GPIO_PIN_PUD #define PULL_UP SW0_GPIO_PIN_PUD #else #define PULL_UP 0 #endif /* Sleep time */ #define DELAY_TIME 100 #define STOP_TIMEOUT 5 #define __HAL_RCC_PWR_CLK_ENABLE() do { \ __IO uint32_t tmpreg; \ SET_BIT(RCC->APB1ENR, RCC_APB1ENR_PWREN);\ /* Delay after an RCC peripheral clock enabling */\ tmpreg = READ_BIT(RCC->APB1ENR, RCC_APB1ENR_PWREN);\ UNUSED(tmpreg); \ } while(0U) struct device *led; /* Comment from zephyr/ext/hal/st/stm32cube/stm32f0xx/drivers/src/stm32f0xx_hal_pwr.c *** Stop mode *** ================= [..] In Stop mode, all clocks in the 1.8V domain are stopped, the PLL, the HSI, and the HSE RC oscillators are disabled. Internal SRAM and register contents are preserved. The voltage regulator can be configured either in normal or low-power mode. To minimize the consumption. (+) Entry: The Stop mode is entered using the HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI ) function with: (++) Main regulator ON. (++) Low Power regulator ON. (++) PWR_STOPENTRY_WFI: enter STOP mode with WFI instruction (++) PWR_STOPENTRY_WFE: enter STOP mode with WFE instruction (+) Exit: (++) Any EXTI Line (Internal or External) configured in Interrupt/Event mode. (++) Some specific communication peripherals (CEC, USART, I2C) interrupts, when programmed in wakeup mode (the peripheral must be programmed in wakeup mode and the corresponding interrupt vector must be enabled in the NVIC) */ void stop_mode(void) { /** * Select the regulator state in STOP mode * * The following block is a pretty verbose method of updating * The LPDS bit. This was implemented during debugging, but the * same goal could be achieved with the following function: * LL_PWR_SetPowerMode(LL_PWR_MODE_STOP_LPREGU); */ uint32_t tmpreg = 0; tmpreg = PWR->CR; /* Set LPDS bit according to Regulator value */ tmpreg &= (uint32_t)~(PWR_CR_PDDS | PWR_CR_LPDS); tmpreg |= LL_PWR_MODE_STOP_LPREGU; PWR->CR = tmpreg; /* DONE configuring regulator */ /* Set SLEEPDEEP bit of Cortex System Control Register */ SCB->SCR |= SCB_SCR_SEVONPEND_Msk | SCB_SCR_SLEEPDEEP_Msk; printk("going to sleep now\n"); /* DEBUG: set and clear event notification */ __SEV(); __WFE(); printk("okay... NOW going to sleep\n"); /* wait for interrupts: could be generated by HW interrupts or EXTI signals */ /* Different from __WFI */ __WFE(); /** * Waking up! Time to re-configure clocks * * I currently see a bunch of garbage characters (�����) after * pressing the button while in STOP mode. So something seems to * wake up, but it seems like the clocks aren't configured anymore. */ /* Several attempts to initialize clocks, none worked */ //LL_RCC_DeInit(); //LL_RCC_HSI48_Enable(); //SystemInit(); //SystemCoreClockUpdate(); printk("Waking up!\n"); /* Clear SLEEPDEEP bit of Cortex System Control Register */ SCB->SCR &= (uint32_t)~((uint32_t)SCB_SCR_SLEEPDEEP_Msk); } static int cycle_count = 0; static struct gpio_callback gpio_cb; void button_pressed(struct device *gpiob, struct gpio_callback *cb, u32_t pins) { printk("Button pressed at %d\n", k_cycle_get_32()); cycle_count = 0; /* DEBUG: manually send an event */ __SEV(); gpio_pin_write(led, LED, 0); } void main(void) { struct device *gpiob; led = device_get_binding(LED_PORT); /* Set LED pin as output */ gpio_pin_configure(led, LED, GPIO_DIR_OUT); gpiob = device_get_binding(PORT); if (!gpiob) { printk("Unable to get button GPIO device\n"); return; } gpio_pin_configure(gpiob, PIN, GPIO_DIR_IN | GPIO_INT | PULL_UP | EDGE); gpio_init_callback(&gpio_cb, button_pressed, BIT(PIN)); gpio_add_callback(gpiob, &gpio_cb); gpio_pin_enable_callback(gpiob, PIN); printk("Press the user defined button on the board\n"); while (1) { cycle_count++; printk("Cycle %d\n", cycle_count); gpio_pin_write(led, LED, 1); if (cycle_count >= STOP_TIMEOUT) { stop_mode(); } gpio_pin_write(led, LED, 1); k_sleep(DELAY_TIME); gpio_pin_write(led, LED, 0); k_sleep(DELAY_TIME); gpio_pin_write(led, LED, 1); k_sleep(DELAY_TIME); gpio_pin_write(led, LED, 0); k_sleep(DELAY_TIME); } }