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.
185 lines
5.0 KiB
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
|