added lcd example

the way text is generated is currently rather awkward, looking for a
better solution.
This commit is contained in:
chrysn 2012-04-04 19:59:45 +02:00
parent 48b3cd49fb
commit 0e62b15125
7 changed files with 450 additions and 16 deletions

View File

@ -0,0 +1,23 @@
##
## This file is part of the libopencm3 project.
##
## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
## Copyright (C) 2012 chrysn <chrysn@fsfe.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/>.
##
BINARY = lcd_demo
include ../Makefile.include

View File

@ -0,0 +1,8 @@
=========================================
EFM32-TG-STK3300 Examples LCD Demo README
=========================================
This is an example on how to use the LCD peripherial on Energy Micro Tiny Gecko
chips.
It's intended for the EFM32-TG-STK3300 eval board.

View File

@ -0,0 +1,76 @@
#!/usr/bin/env python
import yaml
class Font(dict):
def __init__(self, letterdict):
for (k, v) in letterdict.items():
self[k] = set(v.split())
class Display(object):
def __init__(self, data):
self.mapping = {}
for c, segs in enumerate(data['coms']):
for s, name in enumerate(segs):
self.mapping[name] = (c, s)
def render_text(self, text, symbols, font):
cursor = 1
segments = set()
for letter in text:
if letter == '.':
segments.add("a%s_dp"%(cursor-1))
elif letter == ':':
segments.add("a%s_colon"%(cursor-1))
elif letter in font:
for segment in font[letter]:
segments.add("a%s_%s"%(cursor, segment))
cursor += 1
for s in symbols:
segments.add(s)
coms = {}
for segment in segments:
com, seg = self.mapping[segment]
coms[com] = coms.get(com, 0) | (1<<seg)
return coms
def main():
data = yaml.load(open("lcd_mapping.yaml"))
d = Display(data)
text = "{FNORD}"
symbols = ['gecko']
f = Font({
'-': 'g1 g2',
'A': 'e f a b c g1 g2',
'C': 'a f e d',
'D': 'a b c d i l',
'E': 'a f g1 g2 e d',
'F': 'a f g1 g2 e',
'H': "f b g1 g2 e c",
'I': "i l a d",
'L': 'f e d',
'M': 'e f h j b c',
'N': 'e f h m c b',
'O': 'a f e d c b',
'R': 'a e f g1 j m',
'T': 'i l a',
'U': 'f e d c b',
'[': 'a d e f',
']': 'a b c d',
'{': 'a d k h g1',
'}': 'a j g2 m d',
})
for com, data in d.render_text(text, symbols, f).items():
print "set_bank(%d, %#08.0x);"%(com, data)
# with open('lcd_mapping.c', 'w') as outfile:
# for symbol in data['symbols']:
if __name__ == "__main__":
main()

View File

@ -0,0 +1,130 @@
/*
* This file is part of the libopencm3 project.
*
* Copyright (C) 2012 chrysn <chrysn@fsfe.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/>.
*/
/** @file
* Demo of the LCD display aboard the EFM32-TG-STK330 eval board.
*/
#include <libopencm3/efm32/tinygecko/cmu.h>
#include <libopencm3/efm32/tinygecko/gpio.h>
#include <libopencm3/efm32/tinygecko/lcd.h>
#include "../lightswitch/lightswitch-common.c"
void led_toggle(void) { gpio_toggle(GPIO_PD, GPIO7); }
void delay(void)
{
int x;
/* Start up delay until we mess with clock stuff, so the debugger can catch up. */
for(x = 0; x < 10000000; ++x) led_on();
}
void lcd_init(void)
{
/* LCD is a LE module. We're constantly powered on for now, so using
* HFCORECLK/2 */
CMU_HFCORECLKEN0 |= CMU_HFCORECLKEN0_LE;
CMU_LFCLKSEL = (CMU_LFCLKSEL & ~CMU_LFCLKSEL_LFA_MASK) | CMU_LFCLKSEL_LFA_HFCORECLKLEDIV2;
/* We need to get this down to reasonable 100Hz from 14MHz, 7MHz at
* LFACLK, 70kHz after LFA prescaler, 10kHz after FDIV. Octaplexing
* brings us down to about 500Hz. */
CMU_LFAPRESC0 |= CMU_LFAPRESC0_LCD_DIV128;
CMU_LCDCTRL |= CMU_LCDCTRL_FDIV_MASK; /* factor 7+1 */
/* If we don't wait for the prescaler to become ready, the "Do it" step
* won't pass. */
while (CMU_SYNCBUSY & CMU_SYNCBUSY_LFAPRESC0);
CMU_LFACLKEN0 |= CMU_LFACLKEN0_LCD;
while (CMU_SYNCBUSY & CMU_SYNCBUSY_LFACLKEN0);
/* Voltage is around 3.3V anyway, we don't need voltage boosting,
* leaving it disabled. I don't fully understand the implications of
* biasing yet, but it seems like he more biased the better, and will
* just affect frame rate negatively. */
LCD_DISPCTRL = (LCD_DISPCTRL & ~(LCD_DISPCTRL_BIAS_MASK | LCD_DISPCTRL_MUX_MASK)) | LCD_DISPCTRL_BIAS_ONEFOURTH | LCD_DISPCTRL_MUX_OCTAPLEX;
/* Segments default to disabled, enable the 20 relevant ones */
LCD_SEGEN = ~(~0<<5);
/* Do it */
LCD_CTRL |= LCD_CTRL_EN;
while (LCD_SYNCBUSY & LCD_SYNCBUSY_CTRL) led_off();
led_on();
}
void set_bank(u8 com, u32 data)
{
switch(com)
{
case 0: LCD_SEGD0L = data; break;
case 1: LCD_SEGD1L = data; break;
case 2: LCD_SEGD2L = data; break;
case 3: LCD_SEGD3L = data; break;
case 4: LCD_SEGD4L = data; break;
case 5: LCD_SEGD5L = data; break;
case 6: LCD_SEGD6L = data; break;
case 7: LCD_SEGD7L = data; break;
}
}
int main(void)
{
u8 active_bit = 0;
u8 active_com = 0;
gpio_setup();
// delay();
lcd_init();
/* "{FNORD}" with a gecko as generated by current generate_lcd_mapping.py */
set_bank(0, 0x000a00);
set_bank(1, 0x0031cb);
set_bank(2, 0x004622);
set_bank(3, 0x0012a8);
set_bank(4, 0x00481a);
set_bank(5, 0x001140);
set_bank(6, 0x004642);
set_bank(7, 0x0051ac);
while(1)
{
if (pb0_get())
{
while(pb0_get());
set_bank(active_com, ~0);
active_bit = (active_bit + 1) % 21; /* one more to see where 0 is */
set_bank(active_com, ~(1<<active_bit));
}
if (pb1_get())
{
while(pb1_get());
set_bank(active_com, ~0);
active_com = (active_com + 1) % 9; /* one more to see where 0 is */
set_bank(active_com, ~(1<<active_bit));
}
led_toggle();
}
}

View File

@ -0,0 +1,192 @@
description:
LCD segment layout for the EFM32TG_STK3300 kit.
Determined by trial and error.
The digit display is called D1..D4 left to right, the alphanumerics
A1..A7.
The 7 segment display bars are labeled a..g from top cw with g being
the last in the center.
The 14 segment display bars are labelled a..f as with 7-segment, g1
and g2 the parts of 7-segment's g from left to right, and then h, i,
j left to right top parts, and k, l, m left to right bottom parts.
(Labelling according to the 7 segment display Wikipedia article; for 14,
found in German Wikipedia.)
Sectors start at the top, CCW.
Rings are numbered from the outside startin at 0, the dot in the middle
being 4.
symbols: [efm, antenna, celsius, fahrenheit]
coms:
-
- sector_0
- sector_1
- sector_2
- sector_3
- sector_4
- sector_5
- sector_6
- sector_7
- efm
- a5_a
- a4_colon
- a6_a
- antenna
- battery_outline
- celsius
- fahrenheit
- battery_1
- battery_0
- battery_2
- ring0
-
- gecko
- a1_a
- a1_b
- a2_a
- a2_b
- a3_a
- a3_b
- a4_a
- a4_b
- a5_h
- a5_b
- a6_h
- a6_b
- a7_a
- a7_b
- d4_d
- d3_d
- d2_d
- d1_d
- ring1
-
- lock_closed
- a1_h
- a1_j
- a2_h
- a2_j
- a3_h
- a3_j
- a4_h
- a4_j
- a5_f
- a5_j
- a6_f
- a6_j
- a7_h
- a7_j
- d4_c
- d3_c
- d2_c
- d1_c
- ring3
-
- a_minus
- a1_f
- a1_i
- a2_f
- a2_i
- a3_f
- a3_i
- a4_f
- a4_i
- a5_g1
- a5_i
- a6_g1
- a6_i
- a7_f
- a7_i
- d4_e
- d3_e
- d2_e
- d1_e
- lock_open
-
- a2_colon
- a1_g1
- a1_g2
- a2_g1
- a2_g2
- a3_g1
- a3_g2
- a4_g1
- a4_g2
- a5_l
- a5_g2
- a6_l
- a6_g2
- a7_g1
- a7_g2
- d4_g
- d3_g
- d2_g
- d1_g
- d2_dp
-
- a2_dp
- a1_l
- a1_c
- a2_l
- a2_c
- a3_l
- a3_c
- a4_l
- a4_c
- a5_k
- a5_c
- a6_k
- a6_c
- a7_l
- a7_c
- d4_b
- d3_b
- d2_b
- d1_b
- d2_dp
-
- a4_dp
- a1_k
- a1_m
- a2_k
- a2_m
- a3_k
- a3_m
- a4_k
- a4_m
- a5_e
- a5_m
- a6_e
- a6_m
- a7_k
- a7_m
- d4_f
- d3_f
- d2_f
- d1_f
- ring4
-
- a1_dp
- a1_e
- a1_d
- a2_e
- a2_d
- a3_e
- a3_d
- a4_e
- a4_d
- a4_dp
- a5_d
- a5_dp
- a6_d
- a7_e
- a7_d
- d4_a
- d3_a
- d2_a
- d1_a
- ring2

View File

@ -65,7 +65,7 @@
#define LCD_SEGD2L MMIO32(LCD_BASE + 0x048) /**< @see EFM32TG_LCD_SEG_bits */ #define LCD_SEGD2L MMIO32(LCD_BASE + 0x048) /**< @see EFM32TG_LCD_SEG_bits */
#define LCD_SEGD3L MMIO32(LCD_BASE + 0x04c) /**< @see EFM32TG_LCD_SEG_bits */ #define LCD_SEGD3L MMIO32(LCD_BASE + 0x04c) /**< @see EFM32TG_LCD_SEG_bits */
#define LCD_FREEZE MMIO32(LCD_BASE + 0x060) /**< @see EFM32TG_LCD_FREEZE_bits */ #define LCD_FREEZE MMIO32(LCD_BASE + 0x060) /**< @see EFM32TG_LCD_FREEZE_bits */
#define LCD_SYNGBUSY MMIO32(LCD_BASE + 0x064) /**< @see EFM32TG_LCD_SYNGBUSY_bits */ #define LCD_SYNCBUSY MMIO32(LCD_BASE + 0x064) /**< @see EFM32TG_LCD_SYNCBUSY_bits */
#define LCD_SEGD4L MMIO32(LCD_BASE + 0x0cc) /**< @see EFM32TG_LCD_SEG_bits */ #define LCD_SEGD4L MMIO32(LCD_BASE + 0x0cc) /**< @see EFM32TG_LCD_SEG_bits */
#define LCD_SEGD5L MMIO32(LCD_BASE + 0x0d0) /**< @see EFM32TG_LCD_SEG_bits */ #define LCD_SEGD5L MMIO32(LCD_BASE + 0x0d0) /**< @see EFM32TG_LCD_SEG_bits */
#define LCD_SEGD6L MMIO32(LCD_BASE + 0x0d4) /**< @see EFM32TG_LCD_SEG_bits */ #define LCD_SEGD6L MMIO32(LCD_BASE + 0x0d4) /**< @see EFM32TG_LCD_SEG_bits */
@ -116,6 +116,8 @@
/** By this parameter, the voltage V_LCD_OUT is interpolated linearly from /** By this parameter, the voltage V_LCD_OUT is interpolated linearly from
* 0.5V_LCD to V_LCD. * 0.5V_LCD to V_LCD.
*/ */
#define LCD_DISPCTRL_CONLEV_MIN (0<<8)
#define LCD_DISPCTRL_CONLEV_MAX (31<<8)
#define LCD_DISPCTRL_CONLEV_MASK (0x1f<<8) #define LCD_DISPCTRL_CONLEV_MASK (0x1f<<8)
#define LCD_DISPCTRL_WAVE_LOWPOWER (0<<4) #define LCD_DISPCTRL_WAVE_LOWPOWER (0<<4)
#define LCD_DISPCTRL_WAVE_NORMAL (1<<4) #define LCD_DISPCTRL_WAVE_NORMAL (1<<4)
@ -197,26 +199,26 @@
/** @} */ /** @} */
/** Bit states for the LCD_SYNGBUSY register /** Bit states for the LCD_SYNCBUSY register
* *
* See d0034_efm32tg_reference_manual.pdf section 29.5.17 for definitions. * See d0034_efm32tg_reference_manual.pdf section 29.5.17 for definitions.
* *
* @defgroup EFM32TG_LCD_SYNGBUSY_bits LCD SYNGBUSY bits * @defgroup EFM32TG_LCD_SYNCBUSY_bits LCD SYNCBUSY bits
* @{ * @{
*/ */
#define LCD_SYNGBUSY_SEGD7L (1<<19) #define LCD_SYNCBUSY_SEGD7L (1<<19)
#define LCD_SYNGBUSY_SEGD6L (1<<18) #define LCD_SYNCBUSY_SEGD6L (1<<18)
#define LCD_SYNGBUSY_SEGD5L (1<<17) #define LCD_SYNCBUSY_SEGD5L (1<<17)
#define LCD_SYNGBUSY_SEGD4L (1<<16) #define LCD_SYNCBUSY_SEGD4L (1<<16)
#define LCD_SYNGBUSY_SEGD3L (1<<7) #define LCD_SYNCBUSY_SEGD3L (1<<7)
#define LCD_SYNGBUSY_SEGD2L (1<<6) #define LCD_SYNCBUSY_SEGD2L (1<<6)
#define LCD_SYNGBUSY_SEGD1L (1<<5) #define LCD_SYNCBUSY_SEGD1L (1<<5)
#define LCD_SYNGBUSY_SEGD0L (1<<4) #define LCD_SYNCBUSY_SEGD0L (1<<4)
#define LCD_SYNGBUSY_AREGB (1<<3) #define LCD_SYNCBUSY_AREGB (1<<3)
#define LCD_SYNGBUSY_AREGA (1<<2) #define LCD_SYNCBUSY_AREGA (1<<2)
#define LCD_SYNGBUSY_BACTRL (1<<1) #define LCD_SYNCBUSY_BACTRL (1<<1)
#define LCD_SYNGBUSY_CTRL (1<<0) #define LCD_SYNCBUSY_CTRL (1<<0)
/** @} */ /** @} */

View File

@ -87,6 +87,9 @@ registers:
length: 5 length: 5
type: uint type: uint
doc: "By this parameter, the voltage V_LCD_OUT is interpolated linearly from 0.5V_LCD to V_LCD." doc: "By this parameter, the voltage V_LCD_OUT is interpolated linearly from 0.5V_LCD to V_LCD."
values:
- {value: 0, name: MIN}
- {value: 31, name: MAX}
- name: WAVE - name: WAVE
shift: 4 shift: 4
values: values:
@ -208,7 +211,7 @@ registers:
- {value: 0, name: UPDATE} - {value: 0, name: UPDATE}
- {value: 1, name: FREEZE} - {value: 1, name: FREEZE}
# FIXME: this seems to be a typical FREEZE register # FIXME: this seems to be a typical FREEZE register
- name: SYNGBUSY - name: SYNCBUSY
offset: 0x064 offset: 0x064
definition_baserefext: .5.17 definition_baserefext: .5.17
fields: fields: