diff --git a/core/embed/io/rgb_led/stm32u5/rgb_led_lp.c b/core/embed/io/rgb_led/stm32u5/rgb_led_lp.c new file mode 100644 index 0000000000..3465ffd1d1 --- /dev/null +++ b/core/embed/io/rgb_led/stm32u5/rgb_led_lp.c @@ -0,0 +1,231 @@ +/* + * This file is part of the Trezor project, https://trezor.io/ + * + * Copyright (c) SatoshiLabs + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifdef KERNEL_MODE + +#include +#include +#include + +#include + +#define LED_SWITCHING_FREQUENCY_HZ 20000 +#define TIMER_PERIOD (16000000 / LED_SWITCHING_FREQUENCY_HZ) + +#define RGB_LED_RED_PIN GPIO_PIN_2 +#define RGB_LED_RED_PORT GPIOB +#define RGB_LED_RED_CLK_ENA __HAL_RCC_GPIOB_CLK_ENABLE + +#define RGB_LED_GREEN_PIN GPIO_PIN_2 +#define RGB_LED_GREEN_PORT GPIOF +#define RGB_LED_GREEN_CLK_ENA __HAL_RCC_GPIOF_CLK_ENABLE + +#define RGB_LED_BLUE_PIN GPIO_PIN_0 +#define RGB_LED_BLUE_PORT GPIOB +#define RGB_LED_BLUE_CLK_ENA __HAL_RCC_GPIOB_CLK_ENABLE + +typedef struct { + LPTIM_HandleTypeDef tim_1; + LPTIM_HandleTypeDef tim_3; + bool initialized; +} rgb_led_t; + +static rgb_led_t g_rgb_led = {0}; + +static void rgb_led_set_default_pin_state(void) { + GPIO_InitTypeDef GPIO_InitStructure = {0}; + GPIO_InitStructure.Mode = GPIO_MODE_ANALOG; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + + GPIO_InitStructure.Pin = RGB_LED_RED_PIN; + HAL_GPIO_Init(RGB_LED_RED_PORT, &GPIO_InitStructure); + + GPIO_InitStructure.Pin = RGB_LED_GREEN_PIN; + HAL_GPIO_Init(RGB_LED_GREEN_PORT, &GPIO_InitStructure); + + GPIO_InitStructure.Pin = RGB_LED_BLUE_PIN; + HAL_GPIO_Init(RGB_LED_BLUE_PORT, &GPIO_InitStructure); +} + +void rgb_led_init(void) { + rgb_led_t* drv = &g_rgb_led; + if (drv->initialized) { + return; + } + + memset(drv, 0, sizeof(*drv)); + + rgb_led_set_default_pin_state(); + + // enable LSE clock + RCC_OscInitTypeDef RCC_OscInitStruct = {0}; + RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; + RCC_OscInitStruct.HSIState = RCC_HSI_ON; + RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; + HAL_RCC_OscConfig(&RCC_OscInitStruct); + + // select LSE as LPTIM clock source + RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; + PeriphClkInitStruct.PeriphClockSelection = + RCC_PERIPHCLK_LPTIM1 | RCC_PERIPHCLK_LPTIM34; + PeriphClkInitStruct.Lptim1ClockSelection = RCC_LPTIM1CLKSOURCE_HSI; + PeriphClkInitStruct.Lptim34ClockSelection = RCC_LPTIM34CLKSOURCE_HSI; + HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct); + + __HAL_RCC_LPTIM1_CLK_ENABLE(); + __HAL_RCC_LPTIM1_FORCE_RESET(); + __HAL_RCC_LPTIM1_RELEASE_RESET(); + + __HAL_RCC_LPTIM3_CLK_ENABLE(); + __HAL_RCC_LPTIM3_FORCE_RESET(); + __HAL_RCC_LPTIM3_RELEASE_RESET(); + + drv->tim_1.State = HAL_LPTIM_STATE_RESET; + drv->tim_1.Instance = LPTIM1; + drv->tim_1.Init.Period = TIMER_PERIOD; + drv->tim_1.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC; + drv->tim_1.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1; + drv->tim_1.Init.UltraLowPowerClock.Polarity = LPTIM_CLOCKPOLARITY_RISING; + drv->tim_1.Init.UltraLowPowerClock.SampleTime = + LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION; + drv->tim_1.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE; + HAL_LPTIM_Init(&drv->tim_1); + + drv->tim_3.State = HAL_LPTIM_STATE_RESET; + drv->tim_3.Instance = LPTIM3; + drv->tim_3.Init.Period = TIMER_PERIOD; + drv->tim_3.Init.Clock.Source = LPTIM_CLOCKSOURCE_APBCLOCK_LPOSC; + drv->tim_3.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1; + drv->tim_3.Init.UltraLowPowerClock.Polarity = LPTIM_CLOCKPOLARITY_RISING; + drv->tim_3.Init.UltraLowPowerClock.SampleTime = + LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION; + drv->tim_3.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE; + HAL_LPTIM_Init(&drv->tim_3); + + // OC initialization + LPTIM_OC_ConfigTypeDef OC_Init = {0}; + OC_Init.Pulse = 0; + OC_Init.OCPolarity = LPTIM_OCPOLARITY_LOW; + + HAL_LPTIM_OC_ConfigChannel(&drv->tim_1, &OC_Init, LPTIM_CHANNEL_1); + HAL_LPTIM_OC_ConfigChannel(&drv->tim_3, &OC_Init, LPTIM_CHANNEL_1); + HAL_LPTIM_OC_ConfigChannel(&drv->tim_3, &OC_Init, LPTIM_CHANNEL_2); + + HAL_LPTIM_Counter_Start(&drv->tim_1); + HAL_LPTIM_Counter_Start(&drv->tim_3); + + __HAL_LPTIM_COMPARE_SET(&drv->tim_1, LPTIM_CHANNEL_1, TIMER_PERIOD); + __HAL_LPTIM_COMPARE_SET(&drv->tim_3, LPTIM_CHANNEL_1, TIMER_PERIOD); + __HAL_LPTIM_COMPARE_SET(&drv->tim_3, LPTIM_CHANNEL_2, TIMER_PERIOD); + + // Enable the Peripheral + __HAL_LPTIM_ENABLE(&drv->tim_1); + __HAL_LPTIM_ENABLE(&drv->tim_3); + + // Start timer in continuous mode + __HAL_LPTIM_START_CONTINUOUS(&drv->tim_1); + __HAL_LPTIM_START_CONTINUOUS(&drv->tim_3); + + // Wait for reload before configuring the pins + __HAL_LPTIM_CLEAR_FLAG(&drv->tim_1, LPTIM_FLAG_UPDATE); + __HAL_LPTIM_CLEAR_FLAG(&drv->tim_3, LPTIM_FLAG_UPDATE); + while (__HAL_LPTIM_GET_FLAG(&drv->tim_1, LPTIM_FLAG_UPDATE) != true) { + } + while (__HAL_LPTIM_GET_FLAG(&drv->tim_3, LPTIM_FLAG_UPDATE) != true) { + } + + GPIO_InitTypeDef GPIO_InitStructure = {0}; + GPIO_InitStructure.Mode = GPIO_MODE_AF_OD; + GPIO_InitStructure.Pull = GPIO_NOPULL; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + + RGB_LED_RED_CLK_ENA(); + GPIO_InitStructure.Pin = RGB_LED_RED_PIN; + GPIO_InitStructure.Alternate = GPIO_AF1_LPTIM1; + HAL_GPIO_Init(RGB_LED_RED_PORT, &GPIO_InitStructure); + + RGB_LED_GREEN_CLK_ENA(); + GPIO_InitStructure.Pin = RGB_LED_GREEN_PIN; + GPIO_InitStructure.Alternate = GPIO_AF2_LPTIM3; + HAL_GPIO_Init(RGB_LED_GREEN_PORT, &GPIO_InitStructure); + + RGB_LED_BLUE_CLK_ENA(); + GPIO_InitStructure.Pin = RGB_LED_BLUE_PIN; + GPIO_InitStructure.Alternate = GPIO_AF4_LPTIM3; + HAL_GPIO_Init(RGB_LED_BLUE_PORT, &GPIO_InitStructure); + + drv->initialized = true; +} + +void rgb_led_deinit(void) { + rgb_led_t* drv = &g_rgb_led; + if (!drv->initialized) { + return; + } + + rgb_led_set_default_pin_state(); + + HAL_LPTIM_PWM_Stop(&drv->tim_1, LPTIM_CHANNEL_1); + HAL_LPTIM_PWM_Stop(&drv->tim_3, LPTIM_CHANNEL_1); + HAL_LPTIM_PWM_Stop(&drv->tim_3, LPTIM_CHANNEL_2); + + HAL_LPTIM_Counter_Stop(&drv->tim_1); + HAL_LPTIM_Counter_Stop(&drv->tim_3); + + memset(drv, 0, sizeof(*drv)); +} + +void rgb_led_set_color(uint32_t color) { + rgb_led_t* drv = &g_rgb_led; + if (!drv->initialized) { + return; + } + + uint32_t red = (color >> 16) & 0xFF; + uint32_t green = (color >> 8) & 0xFF; + uint32_t blue = color & 0xFF; + + if (red != 0) { + __HAL_LPTIM_CAPTURE_COMPARE_ENABLE(&drv->tim_1, LPTIM_CHANNEL_1); + } else { + __HAL_LPTIM_CAPTURE_COMPARE_DISABLE(&drv->tim_1, LPTIM_CHANNEL_1); + } + + if (green != 0) { + __HAL_LPTIM_CAPTURE_COMPARE_ENABLE(&drv->tim_3, LPTIM_CHANNEL_2); + } else { + __HAL_LPTIM_CAPTURE_COMPARE_DISABLE(&drv->tim_3, LPTIM_CHANNEL_2); + } + + if (blue != 0) { + __HAL_LPTIM_CAPTURE_COMPARE_ENABLE(&drv->tim_3, LPTIM_CHANNEL_1); + } else { + __HAL_LPTIM_CAPTURE_COMPARE_DISABLE(&drv->tim_3, LPTIM_CHANNEL_1); + } + + __HAL_LPTIM_COMPARE_SET(&drv->tim_1, LPTIM_CHANNEL_1, + TIMER_PERIOD - (red * (TIMER_PERIOD) / 255)); + __HAL_LPTIM_COMPARE_SET(&drv->tim_3, LPTIM_CHANNEL_2, + TIMER_PERIOD - (green * (TIMER_PERIOD) / 255)); + __HAL_LPTIM_COMPARE_SET(&drv->tim_3, LPTIM_CHANNEL_1, + TIMER_PERIOD - (blue * (TIMER_PERIOD) / 255)); +} + +#endif diff --git a/core/embed/projects/bootloader/main.c b/core/embed/projects/bootloader/main.c index 82ff4bf6cf..6878e926c4 100644 --- a/core/embed/projects/bootloader/main.c +++ b/core/embed/projects/bootloader/main.c @@ -136,6 +136,9 @@ static void drivers_deinit(void) { #ifdef USE_BUTTON button_deinit(); #endif +#ifdef USE_RGB_LED + rgb_led_deinit(); +#endif #endif display_deinit(DISPLAY_JUMP_BEHAVIOR); ensure_compatible_settings(); diff --git a/core/embed/sys/bsp/stm32u5/stm32u5xx_hal_conf.h b/core/embed/sys/bsp/stm32u5/stm32u5xx_hal_conf.h index e5b411bd0f..0b489baf77 100644 --- a/core/embed/sys/bsp/stm32u5/stm32u5xx_hal_conf.h +++ b/core/embed/sys/bsp/stm32u5/stm32u5xx_hal_conf.h @@ -63,7 +63,7 @@ extern "C" { /*#define HAL_IWDG_MODULE_ENABLED */ #define HAL_I2C_MODULE_ENABLED /*#define HAL_I2S_MODULE_ENABLED */ -/*#define HAL_LPTIM_MODULE_ENABLED */ +#define HAL_LPTIM_MODULE_ENABLED #define HAL_LTDC_MODULE_ENABLED /*#define HAL_NAND_MODULE_ENABLED */ /*#define HAL_NOR_MODULE_ENABLED */ diff --git a/core/embed/sys/powerctl/stm32u5/powerctl_suspend.c b/core/embed/sys/powerctl/stm32u5/powerctl_suspend.c index b5ed21cef4..6cace8e7c8 100644 --- a/core/embed/sys/powerctl/stm32u5/powerctl_suspend.c +++ b/core/embed/sys/powerctl/stm32u5/powerctl_suspend.c @@ -38,6 +38,10 @@ #include #endif +#ifdef USE_RGB_LED +#include +#endif + #ifdef KERNEL_MODE static void background_tasks_suspend(void) { @@ -68,6 +72,9 @@ void powerctl_suspend(void) { #ifdef USE_HAPTIC haptic_deinit(); #endif +#ifdef USE_RGB_LED + rgb_led_deinit(); +#endif #ifdef USE_TOUCH touch_deinit(); #endif @@ -135,6 +142,9 @@ void powerctl_suspend(void) { #ifdef USE_HAPTIC haptic_init(); #endif +#ifdef USE_RGB_LED + rgb_led_init(); +#endif #ifdef USE_USB usb_start(); #endif diff --git a/core/site_scons/models/stm32u5_common.py b/core/site_scons/models/stm32u5_common.py index b7faa19e9a..736d062696 100644 --- a/core/site_scons/models/stm32u5_common.py +++ b/core/site_scons/models/stm32u5_common.py @@ -58,6 +58,7 @@ def stm32u5_common_files(env, defines, sources, paths): "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_i2c.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_i2c_ex.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_icache.c", + "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_lptim.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_ltdc.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_ltdc_ex.c", "vendor/stm32u5xx_hal_driver/Src/stm32u5xx_hal_pcd.c",