Files
libopencm3/lib/stm32/l1/lcd.c
Karl Palsson a7902aa4d0 stm32l1: rcc/lcd: fix RTCSEL HSE definition
Wrong since original commit in 2013.

LCD code can't actually automatically determine clock speed if it's HSE,
as we don't know here whether what HSE is, nor what it's divided by.
For more fun, that old 2014 API doesn't have any way of flagging that it
failed either.  Hooray.
2020-11-28 22:13:25 +00:00

155 lines
3.2 KiB
C

/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2014 Nikolay Merinov <nikolay.merinov@member.fsf.org>
*
* This library is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libopencm3/stm32/l1/lcd.h>
#include <libopencm3/stm32/rcc.h>
void lcd_enable(void)
{
LCD_CR |= LCD_CR_LCDEN;
}
void lcd_update(void)
{
LCD_SR |= LCD_SR_UDR;
}
void lcd_wait_for_lcd_enabled(void)
{
while ((LCD_SR & LCD_SR_ENS) == 0);
}
void lcd_wait_for_step_up_ready(void)
{
while ((LCD_SR & LCD_SR_RDY) == 0);
}
void lcd_wait_for_update_ready(void)
{
while ((LCD_SR & LCD_SR_UDR) != 0);
}
int lcd_is_enabled(void)
{
return ((LCD_SR & LCD_SR_ENS) != 0);
}
int lcd_is_step_up_ready(void)
{
return ((LCD_SR & LCD_SR_RDY) != 0);
}
int lcd_is_for_update_ready(void)
{
return ((LCD_SR & LCD_SR_UDR) == 0);
}
void lcd_set_contrast(uint8_t contrast)
{
LCD_FCR &= ~(LCD_FCR_CC_MASK << LCD_FCR_CC_SHIFT);
LCD_FCR |= contrast << LCD_FCR_CC_SHIFT;
}
void lcd_set_bias(uint8_t bias)
{
LCD_CR &= ~(LCD_CR_BIAS_MASK << LCD_CR_BIAS_SHIFT);
LCD_CR |= bias << LCD_CR_BIAS_SHIFT;
}
void lcd_set_duty(uint8_t duty)
{
LCD_CR &= ~(LCD_CR_DUTY_MASK << LCD_CR_DUTY_SHIFT);
LCD_CR |= duty << LCD_CR_DUTY_SHIFT;
}
void lcd_set_prescaler(uint8_t ps)
{
LCD_FCR &= ~(LCD_FCR_PS_MASK << LCD_FCR_PS_SHIFT);
LCD_FCR |= ps << LCD_FCR_PS_SHIFT;
}
void lcd_set_divider(uint8_t div)
{
LCD_FCR &= ~(LCD_FCR_DIV_MASK << LCD_FCR_DIV_SHIFT);
LCD_FCR |= div << LCD_FCR_DIV_SHIFT;
}
void lcd_enable_segment_multiplexing(void)
{
LCD_CR |= LCD_CR_MUX_SEG;
}
void lcd_disable_segment_multiplexing(void)
{
LCD_CR &= ~LCD_CR_MUX_SEG;
}
void lcd_set_refresh_frequency(uint32_t frequency)
{
uint32_t duty, lcd_clock;
switch ((LCD_CR >> LCD_CR_DUTY_SHIFT) & LCD_CR_DUTY_MASK) {
case LCD_CR_DUTY_STATIC:
duty = 1;
break;
case LCD_CR_DUTY_1_2:
duty = 2;
break;
case LCD_CR_DUTY_1_3:
duty = 3;
break;
case LCD_CR_DUTY_1_4:
duty = 4;
break;
case LCD_CR_DUTY_1_8:
duty = 8;
break;
default:
/* Incorrect duty */
return;
}
switch ((RCC_CSR >> RCC_CSR_RTCSEL_SHIFT) & RCC_CSR_RTCSEL_MASK) {
case RCC_CSR_RTCSEL_LSE:
lcd_clock = 32786;
break;
case RCC_CSR_RTCSEL_LSI:
lcd_clock = 37000;
break;
case RCC_CSR_RTCSEL_HSE:
/* no current method of determining clock and divider! */
return;
default:
/* RCC Clock not selected */
return;
}
/* PS * DIV = lcd_clock/(duty * freq) */
uint32_t ps_mul_div = lcd_clock / (duty * frequency);
int div, ps = 0;
while (ps_mul_div > 32) {
ps_mul_div >>= 1;
ps++;
}
div = ps_mul_div - 16;
lcd_set_prescaler(ps);
lcd_set_divider(div);
}