From 2372d8b59fb31e5a7c8a5e91fdae49d93a256e3b Mon Sep 17 00:00:00 2001 From: Nikolay Merinov Date: Sun, 2 Mar 2014 23:10:07 +0600 Subject: [PATCH] stm32/l1: lcd: example using the LCD --- .../l1/stm32l-discovery/lcd-display/Makefile | 25 +++ .../l1/stm32l-discovery/lcd-display/README | 7 + .../stm32l-discovery/lcd-display/lcd-hello.c | 201 ++++++++++++++++++ 3 files changed, 233 insertions(+) create mode 100644 examples/stm32/l1/stm32l-discovery/lcd-display/Makefile create mode 100644 examples/stm32/l1/stm32l-discovery/lcd-display/README create mode 100644 examples/stm32/l1/stm32l-discovery/lcd-display/lcd-hello.c diff --git a/examples/stm32/l1/stm32l-discovery/lcd-display/Makefile b/examples/stm32/l1/stm32l-discovery/lcd-display/Makefile new file mode 100644 index 0000000..c2c988a --- /dev/null +++ b/examples/stm32/l1/stm32l-discovery/lcd-display/Makefile @@ -0,0 +1,25 @@ +## +## This file is part of the libopencm3 project. +## +## Copyright (C) 2014 Nikolay Merinov +## +## 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 . +## + +BINARY = lcd-hello + +LDSCRIPT = $(OPENCM3_DIR)/lib/stm32/l1/stm32l15xxb.ld + +include ../../Makefile.include + diff --git a/examples/stm32/l1/stm32l-discovery/lcd-display/README b/examples/stm32/l1/stm32l-discovery/lcd-display/README new file mode 100644 index 0000000..79b6bfe --- /dev/null +++ b/examples/stm32/l1/stm32l-discovery/lcd-display/README @@ -0,0 +1,7 @@ +------------------------------------------------------------------------------ +README +------------------------------------------------------------------------------ + +This example program display word *HELLO on default LCD screen of +STM32L-DISCOVERY board. + diff --git a/examples/stm32/l1/stm32l-discovery/lcd-display/lcd-hello.c b/examples/stm32/l1/stm32l-discovery/lcd-display/lcd-hello.c new file mode 100644 index 0000000..6daa918 --- /dev/null +++ b/examples/stm32/l1/stm32l-discovery/lcd-display/lcd-hello.c @@ -0,0 +1,201 @@ +/* + * This file is part of the libopencm3 project. + * + * Copyright (C) 2014 Nikolay Merinov + * + * 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 . + */ + +#include +#include +#include + +static void lcd_init(void) +{ + /* Move all needed GPIO pins to LCD alternative mode */ + rcc_peripheral_enable_clock (&RCC_AHBENR, RCC_AHBENR_GPIOAEN + | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN); + rcc_peripheral_enable_clock (&RCC_AHBLPENR, RCC_AHBLPENR_GPIOALPEN + | RCC_AHBLPENR_GPIOBLPEN | RCC_AHBLPENR_GPIOCLPEN); + gpio_mode_setup(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO1 | GPIO2 + | GPIO3 | GPIO8 | GPIO9 | GPIO10 | GPIO15); + gpio_mode_setup(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, + GPIO3 | GPIO4 | GPIO5 | GPIO8 | GPIO9 | GPIO10 | GPIO11 + | GPIO12 | GPIO13 | GPIO14 | GPIO15); + gpio_mode_setup(GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO0 | GPIO1 + | GPIO2 | GPIO3 | GPIO6 | GPIO7 | GPIO8 | GPIO9 + | GPIO10 | GPIO11); + + gpio_set_af (GPIOA, GPIO_AF11, GPIO1 | GPIO2 | GPIO3 | GPIO8 | GPIO9 + | GPIO10 | GPIO15); + gpio_set_af (GPIOB, GPIO_AF11, GPIO3 | GPIO4 | GPIO5 | GPIO8 | GPIO9 + | GPIO10 | GPIO11 | GPIO12 | GPIO13 | GPIO14 | GPIO15); + gpio_set_af (GPIOC, GPIO_AF11, GPIO0 | GPIO1 | GPIO2 | GPIO3 | GPIO6 + | GPIO7 | GPIO8 | GPIO9 | GPIO10 | GPIO11); + + /* Enable LCD and use LSE clock as RTC/LCD clock. */ + rcc_peripheral_enable_clock (&RCC_APB1ENR, RCC_APB1ENR_PWREN | RCC_APB1ENR_LCDEN); + pwr_disable_backup_domain_write_protect (); + rcc_osc_on (LSE); + rcc_wait_for_osc_ready (LSE); + rcc_rtc_select_clock (RCC_CSR_RTCSEL_LSE); + RCC_CSR |= RCC_CSR_RTCEN; /* Enable RTC clock */ + pwr_enable_backup_domain_write_protect (); + + /* Map SEG[43:40] to SEG[31:28], use 4 LCD commons, use 3 voltage levels + when driving LCD display */ + lcd_enable_segment_multiplexing (); + lcd_set_duty (LCD_CR_DUTY_1_4); + lcd_set_bias (LCD_CR_BIAS_1_3); + + /* Set screen redraw frequency to 100Hz */ + lcd_set_refresh_frequency (100); + /* And increase contrast */ + lcd_set_contrast (LCD_FCR_CC_5); + + lcd_enable (); + do {} while (!lcd_is_enabled ()); + do {} while (!lcd_is_step_up_ready ()); +} + +static void clear_lcd_ram(void) +{ + LCD_RAM_COM0 = 0; + LCD_RAM_COM1 = 0; + LCD_RAM_COM2 = 0; + LCD_RAM_COM3 = 0; +} + +/* LCD MAPPING: + A + _ ---------- +COL |_| |\ |J /| + F| H | K |B + _ | \ | / | +COL |_| --G-- --M-- + | /| \ | + E| Q | N |C + _ | / |P \| +DP |_| ----------- + D + +`mask' corresponds to bits in lexicographic order: mask & 1 == A, mask & 2 == B, +and so on. + */ +static void write_mask_to_lcd_ram (int position, uint16_t mask, int clear_before) +{ + /* Every pixel of character at position can be accessed + as LCD_RAM_COMx & (1 << Px) */ + int P1,P2,P3,P4; + if (position < 2) P1 = 2*position; + else P1 = 2*position+4; + + if (position == 1) P2 = P1+5; + else P2 = P1+1; + + if (position < 3) P3 = (23-2*position)+6; + else P3 = (23-2*position)+4; + + if (position == 5) { + P4 = P3; + P3 -= 1; + } else { + P4 = P3 - 1; + } + + uint32_t COM0,COM1,COM2,COM3; + COM0 = LCD_RAM_COM0; + COM1 = LCD_RAM_COM1; + COM2 = LCD_RAM_COM2; + COM3 = LCD_RAM_COM3; + + if (clear_before) { + COM0&= ~(1<> 0x1) & 1) << P4 | ((mask >> 0x4) & 1) << P1 + | ((mask >> 0x6) & 1) << P3 | ((mask >> 0xA) & 1) << P2; + COM1 |= ((mask >> 0x0) & 1) << P4 | ((mask >> 0x2) & 1) << P2 + | ((mask >> 0x3) & 1) << P1 | ((mask >> 0x5) & 1) << P3; + COM3 |= ((mask >> 0x7) & 1) << P3 | ((mask >> 0x8) & 1) << P4 + | ((mask >> 0xB) & 1) << P1 | ((mask >> 0xE) & 1) << P2; + COM2 |= ((mask >> 0x9) & 1) << P4 | ((mask >> 0xC) & 1) << P1 + | ((mask >> 0xD) & 1) << P3 | ((mask >> 0xF) & 1) << P2; + + LCD_RAM_COM0 = COM0; + LCD_RAM_COM1 = COM1; + LCD_RAM_COM2 = COM2; + LCD_RAM_COM3 = COM3; +} + +static void write_char_to_lcd_ram (int position, uint8_t symbol, bool clear_before) +{ + uint16_t from_ascii[0x60] = { + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* ! " # $ % & ' */ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* ( ) * + , - . / */ + 0x0000, 0x0000, 0x3FC0, 0x1540, 0x0000, 0x0440, 0x4000, 0x2200, + /* 0 1 2 3 4 5 6 7 */ + 0x003F, 0x0006, 0x045B, 0x044F, 0x0466, 0x046D, 0x047D, 0x2201, + /* 8 9 : ; < = > ? */ + 0x047F, 0x046F, 0x8000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + /* @ A B C D E F G */ + 0x0000, 0x0477, 0x047C, 0x0039, 0x045E, 0x0479, 0x0471, 0x043D, + /* H I J K L M N O */ + 0x0476, 0x1109, 0x001E, 0x1B00, 0x0038, 0x02B6, 0x08B6, 0x003F, + /* P Q R S T U V W */ + 0x0473, 0x0467, 0x0C73, 0x046D, 0x1101, 0x003E, 0x0886, 0x2836, + /* X Y Z [ \ ] ^ _ */ + 0x2A80, 0x1280, 0x2209, 0x0000, 0x0880, 0x0000, 0x0000, 0x0008 + }; + if (symbol > 0x60) return; // masks not defined. Nothing to display + + write_mask_to_lcd_ram (position, from_ascii[symbol], clear_before); +} + + +static void lcd_display_hello (void) +{ + do {} while (!lcd_is_for_update_ready ()); + clear_lcd_ram (); /* all segments off */ + write_char_to_lcd_ram (0, '*', true); + write_char_to_lcd_ram (1, 'H', true); + write_char_to_lcd_ram (2, 'E', true); + write_char_to_lcd_ram (3, 'L', true); + write_char_to_lcd_ram (4, 'L', true); + write_char_to_lcd_ram (5, 'O', true); + + lcd_update (); +} + +int main(void) +{ + int i; + lcd_init (); + + lcd_display_hello (); + + for (i = 0; i < 1000000; i++) { /* Wait a bit. */ + __asm__("nop"); + } + + return 0; +}