1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2025-02-07 05:02:38 +00:00

feat(core): introduce RGB LED driver with low power TIM

[no changelog]
This commit is contained in:
tychovrahe 2025-01-24 15:57:45 +01:00 committed by TychoVrahe
parent c713ce23e9
commit 7f53b34b8e
5 changed files with 246 additions and 1 deletions

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifdef KERNEL_MODE
#include <trezor_bsp.h>
#include <trezor_model.h>
#include <trezor_rtl.h>
#include <io/rgb_led.h>
#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

View File

@ -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();

View File

@ -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 */

View File

@ -38,6 +38,10 @@
#include <io/haptic.h>
#endif
#ifdef USE_RGB_LED
#include <io/rgb_led.h>
#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

View File

@ -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",