Files
uv-k1-k5v3-firmware-custom/App/driver/backlight.c
T

277 lines
7.1 KiB
C

/* Copyright 2025 muzkr https://github.com/muzkr
* Copyright 2023 Dual Tachyon
* https://github.com/DualTachyon
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "driver/backlight.h"
#include "py32f071_ll_system.h"
#include "py32f071_ll_dma.h"
#include "py32f071_ll_bus.h"
#include "py32f071_ll_tim.h"
#include "driver/gpio.h"
#include "driver/systick.h"
#include "settings.h"
#include "external/printf/printf.h"
#ifdef ENABLE_FEAT_F4HWN
#include "driver/system.h"
#include "audio.h"
#include "misc.h"
#endif
#define PWM_FREQ 4000
#define DUTY_CYCLE_LEVELS 64
#define DUTY_CYCLE_ON_VALUE GPIO_PIN_MASK(GPIO_PIN_BACKLIGHT)
#define DUTY_CYCLE_OFF_VALUE (DUTY_CYCLE_ON_VALUE << 16)
#define TIMx TIM7
#define DMA_CHANNEL LL_DMA_CHANNEL_7
static uint32_t dutyCycle[DUTY_CYCLE_LEVELS];
// this is decremented once every 500ms
uint16_t gBacklightCountdown_500ms = 0;
bool gUpdateBacklight = false;
bool backlightOn;
static uint8_t currentIndex = 0;
static int16_t currentBrightness = 0;
static int16_t targetBrightness = 0;
static int16_t fadeStep = 0;
#ifdef ENABLE_FEAT_F4HWN
const uint8_t value[] = {
0, // 0 off
8, // 1 visible in the dark
14, // 2
22, // 3
32, // 4
48, // 5
72, // 6
104, // 7
150, // 8
200, // 9
255 // 10 max
};
#endif
#ifdef ENABLE_FEAT_F4HWN_SLEEP
uint16_t gSleepModeCountdown_500ms = 0;
#endif
void BACKLIGHT_InitHardware()
{
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM7);
LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
LL_APB1_GRP1_ForceReset(LL_APB1_GRP1_PERIPH_TIM7);
LL_APB1_GRP1_ReleaseReset(LL_APB1_GRP1_PERIPH_TIM7);
// 48 MHz / ((1 + PSC) * (1 + ARR)) == PWM_freq * levels
LL_TIM_SetPrescaler(TIMx, 0);
LL_TIM_SetAutoReload(TIMx, SystemCoreClock / PWM_FREQ / DUTY_CYCLE_LEVELS - 1);
LL_TIM_EnableARRPreload(TIMx);
LL_TIM_EnableDMAReq_UPDATE(TIMx);
LL_TIM_EnableUpdateEvent(TIMx);
LL_DMA_DisableChannel(DMA1, DMA_CHANNEL) ;
LL_SYSCFG_SetDMARemap(DMA1, DMA_CHANNEL, LL_SYSCFG_DMA_MAP_TIM7_UP);
LL_DMA_ConfigTransfer(DMA1, DMA_CHANNEL, //
LL_DMA_DIRECTION_MEMORY_TO_PERIPH //
| LL_DMA_MODE_CIRCULAR //
| LL_DMA_PERIPH_NOINCREMENT //
| LL_DMA_MEMORY_INCREMENT //
| LL_DMA_PDATAALIGN_WORD //
| LL_DMA_MDATAALIGN_WORD //
| LL_DMA_PRIORITY_HIGH //
);
LL_DMA_SetMemoryAddress(DMA1, DMA_CHANNEL, (uint32_t)dutyCycle);
LL_DMA_SetPeriphAddress(DMA1, DMA_CHANNEL, (uint32_t)(&GPIO_PORT(GPIO_PIN_BACKLIGHT)->BSRR));
LL_DMA_SetDataLength(DMA1, DMA_CHANNEL, sizeof(dutyCycle) / sizeof(uint32_t));
}
static void BACKLIGHT_Sound(void)
{
if (gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_SOUND || gEeprom.POWER_ON_DISPLAY_MODE == POWER_ON_DISPLAY_MODE_ALL)
{
AUDIO_PlayBeep(BEEP_880HZ_60MS_TRIPLE_BEEP);
AUDIO_PlayBeep(BEEP_880HZ_60MS_TRIPLE_BEEP);
}
gK5startup = false;
}
void BACKLIGHT_UpdateTickless(void) {
while(gUpdateBacklight) {
BACKLIGHT_Update();
SYSTEM_DelayMs(10);
}
}
void BACKLIGHT_TurnOn(void)
{
#ifdef ENABLE_FEAT_F4HWN_SLEEP
gSleepModeCountdown_500ms = gSetting_set_off * 120;
#endif
#ifdef ENABLE_FEAT_F4HWN
gBacklightBrightnessOld = BACKLIGHT_GetBrightness();
#endif
if (gEeprom.BACKLIGHT_TIME == 0) {
BACKLIGHT_TurnOff();
#ifdef ENABLE_FEAT_F4HWN
if(gK5startup == true)
{
BACKLIGHT_Sound();
}
#endif
return;
}
backlightOn = true;
BACKLIGHT_SetBrightness(gEeprom.BACKLIGHT_MAX);
#ifdef ENABLE_FEAT_F4HWN
if(gK5startup == true)
#else
static bool startup = true;
if(startup)
#endif
{
BACKLIGHT_UpdateTickless();
#ifdef ENABLE_FEAT_F4HWN
BACKLIGHT_Sound();
#else
startup = false;
#endif
}
switch (gEeprom.BACKLIGHT_TIME) {
default:
case 1 ... 60: // 5 sec * value
gBacklightCountdown_500ms = 1 + (gEeprom.BACKLIGHT_TIME * 5) * 2;
break;
case 61: // always on
gBacklightCountdown_500ms = 0;
break;
}
}
void BACKLIGHT_TurnOff()
{
#ifdef ENABLE_BLMIN_TMP_OFF
register uint8_t tmp;
if (gEeprom.BACKLIGHT_MIN_STAT == BLMIN_STAT_ON)
tmp = gEeprom.BACKLIGHT_MIN;
else
tmp = 0;
BACKLIGHT_SetBrightness(tmp);
#else
BACKLIGHT_SetBrightness(gEeprom.BACKLIGHT_MIN);
#endif
gBacklightCountdown_500ms = 0;
backlightOn = false;
}
bool BACKLIGHT_IsOn()
{
return backlightOn;
}
static void BACKLIGHT_SetHardwareBrightness(uint8_t brightness)
{
// printf("BL: %d\n", brigtness);
if (0 == brightness)
{
LL_TIM_DisableCounter(TIMx);
LL_DMA_DisableChannel(DMA1, DMA_CHANNEL);
SYSTICK_DelayUs(1);
GPIO_TurnOffBacklight();
}
else
{
const uint32_t level = (uint32_t)(brightness) * DUTY_CYCLE_LEVELS / 255;
if (level >= DUTY_CYCLE_LEVELS)
{
LL_TIM_DisableCounter(TIMx);
LL_DMA_DisableChannel(DMA1, DMA_CHANNEL);
GPIO_TurnOnBacklight();
}
else
{
for (uint32_t i = 0; i < DUTY_CYCLE_LEVELS; i++)
{
dutyCycle[i] = i < level ? DUTY_CYCLE_ON_VALUE : DUTY_CYCLE_OFF_VALUE;
}
if (!LL_TIM_IsEnabledCounter(TIMx))
{
LL_DMA_EnableChannel(DMA1, DMA_CHANNEL);
LL_TIM_EnableCounter(TIMx);
}
}
}
}
void BACKLIGHT_Update(void)
{
if (gUpdateBacklight) {
currentBrightness += fadeStep;
if ((fadeStep > 0 && currentBrightness >= targetBrightness) ||
(fadeStep < 0 && currentBrightness <= targetBrightness)) {
currentBrightness = targetBrightness;
gUpdateBacklight = false;
}
BACKLIGHT_SetHardwareBrightness((uint8_t)currentBrightness);
}
}
void BACKLIGHT_SetBrightness(uint8_t targetIndex)
{
if (currentIndex == targetIndex) {
return;
}
currentIndex = targetIndex;
targetBrightness = value[targetIndex];
int16_t diff = targetBrightness - currentBrightness;
if (diff == 0) {
gUpdateBacklight = false;
return;
}
fadeStep = diff > 0 ? -(-diff >> 4) : diff >> 4;
gUpdateBacklight = true;
}
uint8_t BACKLIGHT_GetBrightness(void)
{
return currentIndex;
}