drive backlight using PWM
This commit is contained in:
parent
1e446cbb0b
commit
d37edd9e9d
41
main.c
41
main.c
|
@ -1,5 +1,5 @@
|
||||||
/* firmware to control LCD using HD44780 driver over I²C
|
/* firmware to control LCD using HD44780 driver over I²C
|
||||||
* Copyright (C) 2019-2020 King Kévin <kingkevin@cuvoodoo.info>
|
* Copyright (C) 2019-2022 King Kévin <kingkevin@cuvoodoo.info>
|
||||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
*/
|
*/
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -7,12 +7,9 @@
|
||||||
#include "stm8s.h"
|
#include "stm8s.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
||||||
// on-board LED pin in on PB5 (use as sink), same as SDA
|
// nMOS gate to drive backlight LED
|
||||||
#define LED_PORT GPIO_PA
|
#define BL_PORT GPIO_PA
|
||||||
#define LED_PIN PA3
|
#define BL_PIN PA3
|
||||||
#define led_on() {LED_PORT->ODR.reg &= ~LED_PIN;}
|
|
||||||
#define led_off() {LED_PORT->ODR.reg |= LED_PIN;}
|
|
||||||
#define led_toggle() {LED_PORT->ODR.reg ^= LED_PIN;}
|
|
||||||
|
|
||||||
/* usual HD44780 pinout:
|
/* usual HD44780 pinout:
|
||||||
* - 1 GND: ground
|
* - 1 GND: ground
|
||||||
|
@ -201,14 +198,9 @@ void main(void)
|
||||||
while (!(CLK_ICKR & CLK_ICKR_HSIRDY)); // wait for internal oscillator to be ready
|
while (!(CLK_ICKR & CLK_ICKR_HSIRDY)); // wait for internal oscillator to be ready
|
||||||
|
|
||||||
// save power by disabling unused peripheral
|
// save power by disabling unused peripheral
|
||||||
CLK_PCKENR1 = CLK_PCKENR1_I2C; // only keep I²C
|
CLK_PCKENR1 = CLK_PCKENR1_I2C | CLK_PCKENR1_TIM25; // only keep I²C and timer 2
|
||||||
CLK_PCKENR2 = CLK_PCKENR2_AWU; // only keep AWU
|
CLK_PCKENR2 = CLK_PCKENR2_AWU; // only keep AWU
|
||||||
|
|
||||||
// configure LED
|
|
||||||
LED_PORT->DDR.reg |= LED_PIN; // switch pin to output
|
|
||||||
LED_PORT->CR1.reg &= ~LED_PIN; // use in open-drain mode
|
|
||||||
led_off(); // start with LED off
|
|
||||||
|
|
||||||
// configure independent watchdog (very loose, just it case the firmware hangs)
|
// configure independent watchdog (very loose, just it case the firmware hangs)
|
||||||
IWDG_KR = IWDG_KR_KEY_REFRESH; // reset watchdog
|
IWDG_KR = IWDG_KR_KEY_REFRESH; // reset watchdog
|
||||||
IWDG_KR = IWDG_KR_KEY_ENABLE; // start watchdog
|
IWDG_KR = IWDG_KR_KEY_ENABLE; // start watchdog
|
||||||
|
@ -270,6 +262,21 @@ void main(void)
|
||||||
AWU->APR.fields.APR = 0x3e; // set time to 256 ms
|
AWU->APR.fields.APR = 0x3e; // set time to 256 ms
|
||||||
AWU_CSR |= AWU_CSR_AWUEN; // enable AWU (start only when entering wait or active halt mode)
|
AWU_CSR |= AWU_CSR_AWUEN; // enable AWU (start only when entering wait or active halt mode)
|
||||||
|
|
||||||
|
// configure PWM output for backlight
|
||||||
|
BL_PORT->DDR.reg |= BL_PIN; // switch pin to output
|
||||||
|
BL_PORT->CR1.reg |= BL_PIN; // use in push-pull mode
|
||||||
|
TIM2->CCMR3.output_fields.OC3M = 6; // PWM mode 1
|
||||||
|
TIM2->CCMR3.output_fields.CC3S = 0; // configure channel as output
|
||||||
|
TIM2->CCER2.fields.CC3P = 0; // active high
|
||||||
|
TIM2->CCER2.fields.CC3E = 1; // output enable
|
||||||
|
TIM2->ARRH.fields.ARR15_8 = 0; // set reload to 0xff
|
||||||
|
TIM2->ARRL.fields.ARR7_0 = 0xfe; // set reload to 0xff
|
||||||
|
TIM2->PSCR.fields.PSC = 6; // set frequency to 1 kHz
|
||||||
|
TIM2->CCR3H.fields.CCR3 = 0; // start with PWM off
|
||||||
|
TIM2->CCR3L.fields.CCR3 = 0; // start with PWM off
|
||||||
|
TIM2->EGR.fields.UG = 1; // force reload of values
|
||||||
|
TIM2->CR1.fields.CEN = 1; // enable timer
|
||||||
|
|
||||||
// configure display (as per datasheet)
|
// configure display (as per datasheet)
|
||||||
IWDG_KR = IWDG_KR_KEY_REFRESH; // reset watchdog
|
IWDG_KR = IWDG_KR_KEY_REFRESH; // reset watchdog
|
||||||
HD44780_RS_PORT->ODR.reg &= ~HD44780_RS_PIN; // set low for instruction
|
HD44780_RS_PORT->ODR.reg &= ~HD44780_RS_PIN; // set low for instruction
|
||||||
|
@ -292,10 +299,8 @@ void main(void)
|
||||||
|
|
||||||
rim(); // re-enable interrupts
|
rim(); // re-enable interrupts
|
||||||
|
|
||||||
led_on();
|
|
||||||
while (true) {
|
while (true) {
|
||||||
IWDG_KR = IWDG_KR_KEY_REFRESH; // reset watchdog
|
IWDG_KR = IWDG_KR_KEY_REFRESH; // reset watchdog
|
||||||
//led_toggle(); // indicate we re running
|
|
||||||
while (i2c_input_used) { // I²C data is available
|
while (i2c_input_used) { // I²C data is available
|
||||||
sim(); // disable interrupt while reading buffer to not corrupt indexes
|
sim(); // disable interrupt while reading buffer to not corrupt indexes
|
||||||
uint8_t input_data = i2c_input_buffer[i2c_input_i]; // get start buffered data
|
uint8_t input_data = i2c_input_buffer[i2c_input_i]; // get start buffered data
|
||||||
|
@ -356,11 +361,7 @@ void main(void)
|
||||||
hd44780_write_instruction(0x80 | (input_data & 0x3f));
|
hd44780_write_instruction(0x80 | (input_data & 0x3f));
|
||||||
break;
|
break;
|
||||||
case MODE_BRIGHTNESS:
|
case MODE_BRIGHTNESS:
|
||||||
if (input_data) {
|
TIM2->CCR3L.fields.CCR3 = input_data; // set duty cycle
|
||||||
led_on();
|
|
||||||
} else {
|
|
||||||
led_off();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default: // read values do not make sense
|
default: // read values do not make sense
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue