You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
trezor-firmware/core/embed/trezorhal/stm32f4/backlight_pwm.c

185 lines
5.0 KiB

#include "backlight_pwm.h"
#include STM32_HAL_H
#include TREZOR_BOARD
#define TIM_FREQ 1000000
#define LED_PWM_PRESCALER (SystemCoreClock / TIM_FREQ - 1) // 1 MHz
#define LED_PWM_TIM_PERIOD (TIM_FREQ / BACKLIGHT_PWM_FREQ)
static int BACKLIGHT = -1;
static int pwm_period = 0;
int backlight_pwm_set(int val) {
if (BACKLIGHT != val && val >= 0 && val <= 255) {
BACKLIGHT = val;
BACKLIGHT_PWM_TIM->CCR1 = (pwm_period * val) / 255;
}
return BACKLIGHT;
}
int backlight_pwm_get(void) { return BACKLIGHT; }
void backlight_pwm_init(void) {
// init peripherals
BACKLIGHT_PWM_PORT_CLK_EN();
BACKLIGHT_PWM_TIM_CLK_EN();
GPIO_InitTypeDef GPIO_InitStructure = {0};
// LCD_PWM (backlight control)
GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStructure.Alternate = BACKLIGHT_PWM_TIM_AF;
GPIO_InitStructure.Pin = BACKLIGHT_PWM_PIN;
HAL_GPIO_Init(BACKLIGHT_PWM_PORT, &GPIO_InitStructure);
uint32_t tmpcr1 = 0;
/* Select the Counter Mode */
tmpcr1 |= TIM_COUNTERMODE_UP;
/* Set the clock division */
tmpcr1 |= (uint32_t)TIM_CLOCKDIVISION_DIV1;
/* Set the auto-reload preload */
#ifdef STM32U5
tmpcr1 |= TIM_AUTORELOAD_PRELOAD_DISABLE;
#endif
BACKLIGHT_PWM_TIM->CR1 = tmpcr1;
/* Set the Autoreload value */
BACKLIGHT_PWM_TIM->ARR = (uint32_t)LED_PWM_TIM_PERIOD - 1;
/* Set the Prescaler value */
BACKLIGHT_PWM_TIM->PSC = LED_PWM_PRESCALER;
/* Set the Repetition Counter value */
BACKLIGHT_PWM_TIM->RCR = 0;
/* Generate an update event to reload the Prescaler
and the repetition counter (only for advanced timer) value immediately */
BACKLIGHT_PWM_TIM->EGR = TIM_EGR_UG;
pwm_period = LED_PWM_TIM_PERIOD;
/* Set the Preload enable bit for channel1 */
BACKLIGHT_PWM_TIM->CCMR1 |= TIM_CCMR1_OC1PE;
/* Configure the Output Fast mode */
BACKLIGHT_PWM_TIM->CCMR1 &= ~TIM_CCMR1_OC1FE;
BACKLIGHT_PWM_TIM->CCMR1 |= TIM_OCFAST_DISABLE;
uint32_t tmpccmrx;
uint32_t tmpccer;
uint32_t tmpcr2;
/* Get the TIMx CCER register value */
tmpccer = BACKLIGHT_PWM_TIM->CCER;
/* Disable the Channel 1: Reset the CC1E Bit */
BACKLIGHT_PWM_TIM->CCER &= ~TIM_CCER_CC1E;
tmpccer |= TIM_CCER_CC1E;
/* Get the TIMx CR2 register value */
tmpcr2 = BACKLIGHT_PWM_TIM->CR2;
/* Get the TIMx CCMR1 register value */
tmpccmrx = BACKLIGHT_PWM_TIM->CCMR1;
/* Reset the Output Compare Mode Bits */
tmpccmrx &= ~TIM_CCMR1_OC1M;
tmpccmrx &= ~TIM_CCMR1_CC1S;
/* Select the Output Compare Mode */
tmpccmrx |= BACKLIGHT_PWM_TIM_OCMODE;
/* Reset the Output Polarity level */
tmpccer &= ~TIM_CCER_CC1P;
/* Set the Output Compare Polarity */
tmpccer |= TIM_OCPOLARITY_HIGH;
if (IS_TIM_CCXN_INSTANCE(BACKLIGHT_PWM_TIM, TIM_CHANNEL_1)) {
/* Check parameters */
assert_param(IS_TIM_OCN_POLARITY(OC_Config->OCNPolarity));
/* Reset the Output N Polarity level */
tmpccer &= ~TIM_CCER_CC1NP;
/* Set the Output N Polarity */
tmpccer |= TIM_OCNPOLARITY_HIGH;
/* Set the Output N State */
tmpccer |= TIM_CCER_CC1NE;
}
if (IS_TIM_BREAK_INSTANCE(BACKLIGHT_PWM_TIM)) {
/* Check parameters */
assert_param(IS_TIM_OCNIDLE_STATE(OC_Config->OCNIdleState));
assert_param(IS_TIM_OCIDLE_STATE(OC_Config->OCIdleState));
/* Reset the Output Compare and Output Compare N IDLE State */
tmpcr2 &= ~TIM_CR2_OIS1;
tmpcr2 &= ~TIM_CR2_OIS1N;
/* Set the Output Idle state */
tmpcr2 |= TIM_OCIDLESTATE_SET;
/* Set the Output N Idle state */
tmpcr2 |= TIM_OCNIDLESTATE_SET;
}
/* Write to TIMx CR2 */
BACKLIGHT_PWM_TIM->CR2 = tmpcr2;
/* Write to TIMx CCMR1 */
BACKLIGHT_PWM_TIM->CCMR1 = tmpccmrx;
/* Set the Capture Compare Register value */
BACKLIGHT_PWM_TIM->CCR1 = 0;
/* Write to TIMx CCER */
BACKLIGHT_PWM_TIM->CCER = tmpccer;
backlight_pwm_set(0);
BACKLIGHT_PWM_TIM->BDTR |= TIM_BDTR_MOE;
BACKLIGHT_PWM_TIM->CR1 |= TIM_CR1_CEN;
}
void backlight_pwm_reinit(void) {
uint32_t prev_arr = BACKLIGHT_PWM_TIM->ARR;
uint32_t prev_ccr1 = BACKLIGHT_PWM_TIM->BACKLIGHT_PWM_TIM_CCR;
uint32_t prev_val = (prev_ccr1 * 255) / (prev_arr + 1);
prev_val = prev_val > 255 ? 255 : prev_val;
BACKLIGHT = prev_val;
pwm_period = LED_PWM_TIM_PERIOD;
BACKLIGHT_PWM_TIM->CR1 |= TIM_CR1_ARPE;
BACKLIGHT_PWM_TIM->CR2 |= TIM_CR2_CCPC;
BACKLIGHT_PWM_TIM->BACKLIGHT_PWM_TIM_CCR = (pwm_period * prev_val) / 255;
BACKLIGHT_PWM_TIM->ARR = LED_PWM_TIM_PERIOD - 1;
}
#ifdef TREZOR_MODEL_T
#define LED_PWM_SLOW_TIM_PERIOD \
(10000) // about 10Hz (with PSC = (SystemCoreClock / 1000000) - 1)
void backlight_pwm_set_slow(void) {
uint32_t prev_arr = BACKLIGHT_PWM_TIM->ARR;
uint32_t prev_ccr1 = BACKLIGHT_PWM_TIM->CCR1;
uint32_t prev_val = (prev_ccr1 * 255) / (prev_arr + 1);
prev_val = prev_val > 255 ? 255 : prev_val;
pwm_period = LED_PWM_SLOW_TIM_PERIOD;
BACKLIGHT_PWM_TIM->CR1 |= TIM_CR1_ARPE;
BACKLIGHT_PWM_TIM->CR2 |= TIM_CR2_CCPC;
BACKLIGHT_PWM_TIM->ARR = LED_PWM_SLOW_TIM_PERIOD - 1;
BACKLIGHT_PWM_TIM->BACKLIGHT_PWM_TIM_CCR = pwm_period * prev_val / 255;
}
#endif