From 47b02df11e37d3088fb838fcd942772452926384 Mon Sep 17 00:00:00 2001 From: schneider <schneider@blinkenlichts.net> Date: Tue, 10 Aug 2021 13:00:24 +0200 Subject: [PATCH] change(backlight): Keep PWM stable when changing PCLK Timer frequency is now held close to a value which can be achieved both with a 48 MHz PCLK (96 MHz system clock) and a 7.5 MHz PCLK (15 MHz system clock). If even lower PCLKs should be supported, the frequency of the timer has to be changed as well. --- epicardium/drivers/display.c | 5 +++ epicardium/drivers/drivers.h | 1 + lib/gfx/GUI_DEV/DEV_Config.c | 68 ++++++++++++++++++++++++++++++++++-- lib/gfx/GUI_DEV/DEV_Config.h | 2 ++ lib/gfx/LCD/LCD_Driver.c | 8 +++++ lib/gfx/LCD/LCD_Driver.h | 1 + 6 files changed, 82 insertions(+), 3 deletions(-) diff --git a/epicardium/drivers/display.c b/epicardium/drivers/display.c index 05b0eaec1..7cf92c7a2 100644 --- a/epicardium/drivers/display.c +++ b/epicardium/drivers/display.c @@ -311,6 +311,11 @@ int epic_disp_close() } } +void disp_update_backlight_clock(void) +{ + LCD_UpdateBacklightClock(); +} + void disp_forcelock() { TaskHandle_t task = xTaskGetCurrentTaskHandle(); diff --git a/epicardium/drivers/drivers.h b/epicardium/drivers/drivers.h index 1f2f22fbb..047728b6c 100644 --- a/epicardium/drivers/drivers.h +++ b/epicardium/drivers/drivers.h @@ -61,6 +61,7 @@ int pmic_read_amux(enum pmic_amux_signal sig, float *result); /* ---------- Display ------------------------------------------------------ */ /* Forces an unlock of the display. Only to be used in Epicardium */ void disp_forcelock(); +void disp_update_backlight_clock(void); /* ---------- BHI160 ------------------------------------------------------- */ #define BHI160_FIFO_SIZE 128 diff --git a/lib/gfx/GUI_DEV/DEV_Config.c b/lib/gfx/GUI_DEV/DEV_Config.c index 67c73a142..68a5e5f10 100644 --- a/lib/gfx/GUI_DEV/DEV_Config.c +++ b/lib/gfx/GUI_DEV/DEV_Config.c @@ -70,7 +70,68 @@ void lcd_write(uint8_t *data, int size) #define PORT_PWM PORT_0 // port #define PIN_PWM PIN_28 // pin #define FREQ 1000 // (Hz) +#define TIMER_FREQ 6000000 // _Target_ timer frequncy (Hz) #define PWM_TIMER MXC_TMR4 // must change PORT_PWM and PIN_PWM if changed + +/* Find a prescaler which gives us at least TIMER_FREQ HZ base clock + * at the current PCLK setting. + * + * Maximum prescaler chosen is 128. + */ +static uint8_t timer_prescale_factor(void) +{ + uint32_t target_prescaler = PeripheralClock / TIMER_FREQ; + + if (target_prescaler == 0) { + printf("TIMER_FREQ to high for PeripheralClock\n"); + while (1) + ; + } + + uint8_t prescaler = 1; + for (int i = 0; i < 7; i++) { + uint8_t next_prescaler = prescaler << 1; + if (next_prescaler > target_prescaler) { + break; + } + prescaler = next_prescaler; + } + + return prescaler; +} + +/* Return the constant need for the timer prescaler register to + * reach a least TIMER_FREQ HZ base clock frequency at the + * current PCLK setting */ +static uint32_t timer_prescaler(void) +{ + switch (timer_prescale_factor()) { + case 1: + return MXC_S_TMR_CN_PRES_DIV1; + case 2: + return MXC_S_TMR_CN_PRES_DIV2; + case 4: + return MXC_S_TMR_CN_PRES_DIV4; + case 8: + return MXC_S_TMR_CN_PRES_DIV8; + case 16: + return MXC_S_TMR_CN_PRES_DIV16; + case 32: + return MXC_S_TMR_CN_PRES_DIV32; + case 64: + return MXC_S_TMR_CN_PRES_DIV64; + default: + return MXC_S_TMR_CN_PRES_DIV128; + } +} + +/* Update the timer prescaler to what ever PCLK currently requires */ +void DEV_Update_BL_Clock(void) +{ + PWM_TIMER->cn = + (PWM_TIMER->cn & ~(MXC_F_TMR_CN_PRES)) | timer_prescaler(); +} + void DEV_Set_BL(uint16_t _Value) { // Declare variables @@ -82,8 +143,9 @@ void DEV_Set_BL(uint16_t _Value) _Value = 100; } - unsigned int period_ticks = PeripheralClock / FREQ; - unsigned int duty_ticks = period_ticks * _Value / 100; + unsigned int period_ticks = + PeripheralClock / timer_prescale_factor() / FREQ; + unsigned int duty_ticks = period_ticks * _Value / 100; TMR_Disable(PWM_TIMER); @@ -95,7 +157,7 @@ void DEV_Set_BL(uint16_t _Value) gpio_pwm.pad = GPIO_PAD_PULL_DOWN; GPIO_Config(&gpio_pwm); - TMR_Init(PWM_TIMER, TMR_PRES_1, 0); + TMR_Init(PWM_TIMER, timer_prescaler(), 0); tmr.mode = TMR_MODE_PWM; tmr.cmp_cnt = period_ticks; diff --git a/lib/gfx/GUI_DEV/DEV_Config.h b/lib/gfx/GUI_DEV/DEV_Config.h index cbc4c5f65..321b6d9c9 100644 --- a/lib/gfx/GUI_DEV/DEV_Config.h +++ b/lib/gfx/GUI_DEV/DEV_Config.h @@ -74,6 +74,8 @@ void display_set_reset_pin(uint8_t state); //#define DEV_Set_BL(_Value) DEV_BL_PIN= _Value void DEV_Set_BL(uint16_t _Value); +void DEV_Update_BL(void); +void DEV_Update_BL_Clock(void); /*-----------------------------------------------------------------------------*/ #endif diff --git a/lib/gfx/LCD/LCD_Driver.c b/lib/gfx/LCD/LCD_Driver.c index 55c872a82..3ef962efa 100644 --- a/lib/gfx/LCD/LCD_Driver.c +++ b/lib/gfx/LCD/LCD_Driver.c @@ -56,6 +56,14 @@ void LCD_SetBacklight(UWORD Value) { DEV_Set_BL(Value); } +/******************************************************************************* +function: + Update backlight clock +*******************************************************************************/ +void LCD_UpdateBacklightClock(void) +{ + DEV_Update_BL_Clock(); +} /******************************************************************************* function: diff --git a/lib/gfx/LCD/LCD_Driver.h b/lib/gfx/LCD/LCD_Driver.h index 49358115b..ad6f29f24 100644 --- a/lib/gfx/LCD/LCD_Driver.h +++ b/lib/gfx/LCD/LCD_Driver.h @@ -46,6 +46,7 @@ void LCD_SetUWORD(UWORD x, UWORD y, UWORD Color); void LCD_Init(void); void LCD_SetBacklight(UWORD Value); +void LCD_UpdateBacklightClock(void); void LCD_Clear(UWORD Color); void LCD_ClearWindow(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD UWORD); uint8_t *LCD_Framebuffer(void); -- GitLab