The EFM32 microcontrollers include a
self-contained, ultra-low power LCD driver with internal bias voltage circuit
and boost converter to minimize external components. The LCD driver also
supports autonomous animation and blinking in deep sleep without software
intervention. The design and implementation for LCD has been explained in below
sections
Basic theory of EFM32 LCD
Segmented LCD displays are a common way to
display information. The extreme low-power LCD driver in the EFM32 enables a
lot of applications to utilize an LCD display even in energy critical systems.
In this project we are using a passive LCD
display. These displays are usually constructed by sandwiching the liquid
crystal between two glass plates. By using the voltage dependent, polarizing
properties of the liquid crystal material, light transmission through the LCD
glass can be controlled. The display is usually built up by segments that can
either block light or let it pass through depending on the voltage applied over
the liquid crystal within that segment.
By having a reflective coating on one side
of the glass, ambient light can either be reflected back to the user or blocked
by the polarizer closest to the reflective layer. This blocking of light occurs
because the liquid crystal in one state will change the polarization of the
light to allow it to pass both polarizers. In the other state it will not
affect the polarization, and the light is then blocked because the two
polarizers are orthogonally oriented with respect to each other. The segment is
"on" when it is blocking light and "off" when light can
pass through.
The EFM32 has two LEUART which needs only
32.768 KHz clock source to allow UART communication up to 9600 baud/s. So the
EFM32 hardware is designed for operating in deep sleep mode called EM2 and it
can wait for an incoming UART frame while consuming extremely little energy.
When the voltage is applied, the liquid
crystal does not change the polarization direction of the light, this causes it
to be blocked by the second polarizer which is oriented at an orthogonal angle
to the first polarizer. If no voltage is applied, the liquid crystal will
change the polarization of the light so that it can pass through both
polarizers.
Driving a Display Segment
Segment
LCD displays do
not have any
internal driving circuitry,
all the display
pins are directly connected to each side of the
corresponding segment. Just applying a constant voltage across the segment to
turn it on would work, but not for a long time. The problem is that after a
short time the LCD segment will be affected by the DC-current passing through
it, mainly through electrolysis effects on the liquid crystal and electrodes.
The solution is to drive the segment with a waveform that has an average 0 DC
value. As long as the voltage is switched fast enough (30-100 Hz) it will
mainly be the RMS-value of the voltage that affects the amount of polarization.
The simplest way of driving a "one
segment" LCD with the correct zero DC bias would be to apply two identical
and optionally phase shifted, square waveforms. By shifting the phase of one
signal with respect to the other by 180 degrees, the apparent RMS-voltage
across the segment goes from 0 to two times the voltage of the two waveforms.
Driving many LCD segments
With the static driving approach with one
segment line for each segment, large displays with many segments would need a
large number of the microcontroller pins just to drive the display. By
multiplexing several common and segment lines, fewer pins can be used to drive
more segments. The total number of segments that can be driven is the product
of the number of common lines and segment lines. Usually the maximum contrast
goes down, while the current consumption goes up with higher number of common
lines.
It is the amplitude of the apparent RMS
voltage across a segment that determines if it is on or off. A segment with a
low RMS voltage amplitude applied, seems to be off even if the voltage is
non-zero. The relationship between apparent RMS voltage across the segment, and
the visual properties is nonlinear. This non-linear property is utilized when
multiplexing several segments on the same driving pins. A segment does not need
to see zero RMS voltage to be perceived as completely off by the user. Each
common line and segment line is driven with waveforms consisting of more than
two voltage levels as in the static driving case. The number of voltage levels
are known as "bias"-levels. By carefully selecting the waveform of
each segment line and common line, it is possible to make some segments
"see" a low RMS-voltage, while others "see" a high RMS
voltage, even if the segments share either their common or segment electrode
with other segments. See Figure
Clock Sources
As like EFM32 timer clock section, LCD can
be driven from three different clock sources
·
the Low Frequency RF Oscillator
(LFRCO)
·
the Low Frequency Crystal
Oscillator (LFXO)
·
High Frequency RC Oscillator
(HFRCO)
·
High Frequency Crystal
Oscillator (HFXO)
In this program we have used Low
Frequency RF Oscillator (LFRCO) as clock source
EFM32 LCD configuration
Prior to start using of EFM32 LCD some
configurations must be performed to ensure that it works as expected. In order
to facilitate that the below parameters must be configured
•
Set HFCLK clock
•
Enable clock for core
•
Enable LFRCO as LFACLK
•
Set LCD Controller clock
Prescaler
•
Set frame rate
•
Enable clock to LCD module
Software Example
The EFM32 LCD program is implemented and
tested on EFM32 Giant Gecko starter kit. The numerical and Alfa-numerical
character segments of LCD display on EFM32 Giant Gecko starter kit are used to
display a numerical value and a string
LCD controller set up
The LED controller in EFM32 Giant Gecko
microcontroller is configured to work in following setup:
MUX setting : Octaplex (1/8 Duty cycle)
Bias setting: 1/4 Bias
Wave type: Low power
VLCD Voltage Source: VLCD Powered by VDD
Program
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "efm32gg990f1024.h"
#define STK3700 ;
#define EFM_DISPLAY_DEF {\
.Text = {\
{ /* 1 */\
.com[0] = 1, .com[1] = 1, .com[2] = 5, .com[3] = 7,\
.bit[0] = 13, .bit[1] = 14, .bit[2] = 14, .bit[3] = 14,\
.com[4] = 7, .com[5] = 3, .com[6] = 4, .com[7] = 2,\
.bit[4] = 13, .bit[5] = 13, .bit[6] = 13, .bit[7] = 13,\
.com[8] = 3, .com[9] = 2, .com[10] = 4, .com[11] = 6,\
.bit[8] = 14, .bit[9] = 14, .bit[10] = 14, .bit[11] = 14,\
.com[12] = 5, .com[13] = 6,\
.bit[12] = 13, .bit[13] = 13\
},\
{ /* 2 */\
.com[0] = 1, .com[1] = 1, .com[2] = 5, .com[3] = 7,\
.bit[0] = 15, .bit[1] = 16, .bit[2] = 16, .bit[3] = 16,\
.com[4] = 7, .com[5] = 3, .com[6] = 4, .com[7] = 2,\
.bit[4] = 15, .bit[5] = 15, .bit[6] = 15, .bit[7] = 15,\
.com[8] = 3, .com[9] = 2, .com[10] = 4, .com[11] = 6,\
.bit[8] = 16, .bit[9] = 16, .bit[10] = 16, .bit[11] = 16,\
.com[12] = 5, .com[13] = 6,\
.bit[12] = 15, .bit[13] = 15\
},\
{ /* 3 */\
.com[0] = 1, .com[1] = 1, .com[2] = 5, .com[3] = 7,\
.bit[0] = 17, .bit[1] = 18, .bit[2] = 18, .bit[3] = 18,\
.com[4] = 7, .com[5] = 3, .com[6] = 4, .com[7] = 2,\
.bit[4] = 17, .bit[5] = 17, .bit[6] = 17, .bit[7] = 17,\
.com[8] = 3, .com[9] = 2, .com[10] = 4, .com[11] = 6,\
.bit[8] = 18, .bit[9] = 18, .bit[10] = 18, .bit[11] = 18,\
.com[12] = 5, .com[13] = 6,\
.bit[12] = 17, .bit[13] = 17\
},\
{ /* 4 */\
.com[0] = 1, .com[1] = 1, .com[2] = 5, .com[3] = 7,\
.bit[0] = 19, .bit[1] = 28, .bit[2] = 28, .bit[3] = 28,\
.com[4] = 7, .com[5] = 3, .com[6] = 4, .com[7] = 2,\
.bit[4] = 19, .bit[5] = 19, .bit[6] = 19, .bit[7] = 19,\
.com[8] = 3, .com[9] = 2, .com[10] = 4, .com[11] = 6,\
.bit[8] = 28, .bit[9] = 28, .bit[10] = 28, .bit[11] = 28,\
.com[12] = 5, .com[13] = 6,\
.bit[12] = 19, .bit[13] = 19\
},\
{ /* 5 */\
.com[0] = 0, .com[1] = 1, .com[2] = 5, .com[3] = 7,\
.bit[0] = 29, .bit[1] = 30, .bit[2] = 30, .bit[3] = 30,\
.com[4] = 6, .com[5] = 2, .com[6] = 3, .com[7] = 1,\
.bit[4] = 29, .bit[5] = 29, .bit[6] = 29, .bit[7] = 29,\
.com[8] = 3, .com[9] = 2, .com[10] = 4, .com[11] = 6,\
.bit[8] = 30, .bit[9] = 30, .bit[10] = 30, .bit[11] = 30,\
.com[12] = 4, .com[13] = 5,\
.bit[12] = 29, .bit[13] = 29\
},\
{ /* 6 */\
.com[0] = 0, .com[1] = 1, .com[2] = 5, .com[3] = 7,\
.bit[0] = 31, .bit[1] = 32, .bit[2] = 32, .bit[3] = 32,\
.com[4] = 6, .com[5] = 2, .com[6] = 3, .com[7] = 1,\
.bit[4] = 31, .bit[5] = 31, .bit[6] = 31, .bit[7] = 31,\
.com[8] = 3, .com[9] = 2, .com[10] = 4, .com[11] = 6,\
.bit[8] = 32, .bit[9] = 32, .bit[10] = 32, .bit[11] = 32,\
.com[12] = 4, .com[13] = 5,\
.bit[12] = 31, .bit[13] = 31\
},\
{ /* 7 */\
.com[0] = 1, .com[1] = 1, .com[2] = 5, .com[3] = 7,\
.bit[0] = 33, .bit[1] = 34, .bit[2] = 34, .bit[3] = 34,\
.com[4] = 7, .com[5] = 3, .com[6] = 4, .com[7] = 2,\
.bit[4] = 33, .bit[5] = 33, .bit[6] = 33, .bit[7] = 33,\
.com[8] = 3, .com[9] = 2, .com[10] = 4, .com[11] = 6,\
.bit[8] = 34, .bit[9] = 34, .bit[10] = 34, .bit[11] = 34,\
.com[12] = 5, .com[13] = 6,\
.bit[12] = 33, .bit[13] = 33\
},\
},\
.Number = {\
{\
.com[0] = 7, .com[1] = 5, .com[2] = 2, .com[3] = 1,\
.bit[0] = 35, .bit[1] = 35, .bit[2] = 35, .bit[3] = 35,\
.com[4] = 3, .com[5] = 6, .com[6] = 4,\
.bit[4] = 35, .bit[5] = 35, .bit[6] = 35,\
},\
{\
.com[0] = 7, .com[1] = 5, .com[2] = 2, .com[3] = 1,\
.bit[0] = 36, .bit[1] = 36, .bit[2] = 36, .bit[3] = 36,\
.com[4] = 3, .com[5] = 6, .com[6] = 4,\
.bit[4] = 36, .bit[5] = 36, .bit[6] = 36,\
},\
{\
.com[0] = 7, .com[1] = 5, .com[2] = 2, .com[3] = 1,\
.bit[0] = 37, .bit[1] = 37, .bit[2] = 37, .bit[3] = 37,\
.com[4] = 3, .com[5] = 6, .com[6] = 4,\
.bit[4] = 37, .bit[5] = 37, .bit[6] = 37,\
},\
{\
.com[0] = 7, .com[1] = 5, .com[2] = 2, .com[3] = 1,\
.bit[0] = 38, .bit[1] = 38, .bit[2] = 38, .bit[3] = 38,\
.com[4] = 3, .com[5] = 6, .com[6] = 4,\
.bit[4] = 38, .bit[5] = 38, .bit[6] = 38,\
},\
},\
.EMode = {\
.com[0] = 0, .bit[0] = 39,\
.com[1] = 1, .bit[1] = 39,\
.com[2] = 7, .bit[2] = 39,\
.com[3] = 2, .bit[3] = 39,\
.com[4] = 6, .bit[4] = 39,\
},\
.ARing = {\
.com[0] = 0, .bit[0] = 19,\
.com[1] = 0, .bit[1] = 18,\
.com[2] = 0, .bit[2] = 17,\
.com[3] = 0, .bit[3] = 16,\
.com[4] = 0, .bit[4] = 15,\
.com[5] = 0, .bit[5] = 14,\
.com[6] = 0, .bit[6] = 13,\
.com[7] = 0, .bit[7] = 12,\
},\
.Battery = {\
.com[0] = 0, .bit[0] = 33,\
.com[1] = 0, .bit[1] = 37,\
.com[2] = 0, .bit[2] = 36,\
.com[3] = 0, .bit[3] = 38,\
},\
.TopBlocks = {\
{ /* 1 */\
.com[0] = 1, .com[1] = 1, .com[2] = 3, .com[3] = 4,\
.bit[0] = 13, .bit[1] = 14, .bit[2] = 13, .bit[3] = 13,\
.com[4] = 4, .com[5] = 2, .com[6] = 3, .com[7] = 2,\
.bit[4] = 14, .bit[5] = 13, .bit[6] = 14, .bit[7] = 14\
},\
{ /* 2 */\
.com[0] = 1, .com[1] = 1, .com[2] = 3, .com[3] = 4,\
.bit[0] = 15, .bit[1] = 16, .bit[2] = 15, .bit[3] = 15,\
.com[4] = 4, .com[5] = 2, .com[6] = 3, .com[7] = 2,\
.bit[4] = 16, .bit[5] = 15, .bit[6] = 16, .bit[7] = 16\
},\
{ /* 3 */\
.com[0] = 1, .com[1] = 1, .com[2] = 3, .com[3] = 4,\
.bit[0] = 17, .bit[1] = 18, .bit[2] = 17, .bit[3] = 17,\
.com[4] = 4, .com[5] = 2, .com[6] = 3, .com[7] = 2,\
.bit[4] = 18, .bit[5] = 17, .bit[6] = 18, .bit[7] = 18\
},\
{ /* 4 */\
.com[0] = 1, .com[1] = 1, .com[2] = 3, .com[3] = 4,\
.bit[0] = 19, .bit[1] = 28, .bit[2] = 19, .bit[3] = 19,\
.com[4] = 4, .com[5] = 2, .com[6] = 3, .com[7] = 2,\
.bit[4] = 28, .bit[5] = 19, .bit[6] = 28, .bit[7] = 28\
},\
{ /* 5 */\
.com[0] = 0, .com[1] = 1, .com[2] = 2, .com[3] = 3,\
.bit[0] = 29, .bit[1] = 30, .bit[2] = 29, .bit[3] = 29,\
.com[4] = 4, .com[5] = 1, .com[6] = 3, .com[7] = 2,\
.bit[4] = 30, .bit[5] = 29, .bit[6] = 30, .bit[7] = 30\
},\
{ /* 6 */\
.com[0] = 0, .com[1] = 1, .com[2] = 2, .com[3] = 3,\
.bit[0] = 31, .bit[1] = 32, .bit[2] = 31, .bit[3] = 31,\
.com[4] = 4, .com[5] = 1, .com[6] = 3, .com[7] = 2,\
.bit[4] = 32, .bit[5] = 31, .bit[6] = 32, .bit[7] = 32\
},\
{ /* 7 */\
.com[0] = 1, .com[1] = 1, .com[2] = 3, .com[3] = 4,\
.bit[0] = 33, .bit[1] = 34, .bit[2] = 33, .bit[3] = 33,\
.com[4] = 4, .com[5] = 2, .com[6] = 3, .com[7] = 2,\
.bit[4] = 34, .bit[5] = 33, .bit[6] = 34, .bit[7] = 34\
},\
},\
.BotBlocks = {\
{ /* 1 */\
.com[0] = 5, .com[1] = 7, .com[2] = 7, .com[3] = 4,\
.bit[0] = 14, .bit[1] = 14, .bit[2] = 13, .bit[3] = 13,\
.com[4] = 4, .com[5] = 6, .com[6] = 5, .com[7] = 6,\
.bit[4] = 14, .bit[5] = 14, .bit[6] = 13, .bit[7] = 13\
},\
{ /* 2 */\
.com[0] = 5, .com[1] = 7, .com[2] = 7, .com[3] = 4,\
.bit[0] = 16, .bit[1] = 16, .bit[2] = 15, .bit[3] = 15,\
.com[4] = 4, .com[5] = 6, .com[6] = 5, .com[7] = 6,\
.bit[4] = 16, .bit[5] = 16, .bit[6] = 15, .bit[7] = 15\
},\
{ /* 3 */\
.com[0] = 5, .com[1] = 7, .com[2] = 7, .com[3] = 4,\
.bit[0] = 18, .bit[1] = 18, .bit[2] = 17, .bit[3] = 17,\
.com[4] = 4, .com[5] = 6, .com[6] = 5, .com[7] = 6,\
.bit[4] = 18, .bit[5] = 18, .bit[6] = 17, .bit[7] = 17\
},\
{ /* 4 */\
.com[0] = 5, .com[1] = 7, .com[2] = 7, .com[3] = 4,\
.bit[0] = 28, .bit[1] = 28, .bit[2] = 19, .bit[3] = 19,\
.com[4] = 4, .com[5] = 6, .com[6] = 5, .com[7] = 6,\
.bit[4] = 28, .bit[5] = 28, .bit[6] = 19, .bit[7] = 19\
},\
{ /* 5 */\
.com[0] = 5, .com[1] = 7, .com[2] = 6, .com[3] = 3,\
.bit[0] = 30, .bit[1] = 30, .bit[2] = 29, .bit[3] = 29,\
.com[4] = 4, .com[5] = 6, .com[6] = 4, .com[7] = 5,\
.bit[4] = 30, .bit[5] = 30, .bit[6] = 29, .bit[7] = 29\
},\
{ /* 6 */\
.com[0] = 5, .com[1] = 7, .com[2] = 6, .com[3] = 3,\
.bit[0] = 32, .bit[1] = 32, .bit[2] = 31, .bit[3] = 31,\
.com[4] = 4, .com[5] = 6, .com[6] = 4, .com[7] = 5,\
.bit[4] = 32, .bit[5] = 32, .bit[6] = 31, .bit[7] = 31\
},\
{ /* 7 */\
.com[0] = 5, .com[1] = 7, .com[2] = 7, .com[3] = 4,\
.bit[0] = 34, .bit[1] = 34, .bit[2] = 33, .bit[3] = 33,\
.com[4] = 4, .com[5] = 6, .com[6] = 5, .com[7] = 6,\
.bit[4] = 34, .bit[5] = 34, .bit[6] = 33, .bit[7] = 33\
},\
}\
}
const uint16_t EFM_Alphabet[] = {
0x0000, /* space */
0x1100, /* ! */
0x0280, /* " */
0x0000, /* # */
0x0000, /* $ */
0x0602, /* % */
0x0000, /* & */
0x0020, /* ' */
0x0039, /* ( */
0x000f, /* ) */
0x0000, /* * */
0x1540, /* + */
0x2000, /* , */
0x0440, /* - */
0x1000, /* . */
0x2200, /* / */
0x003f, /* 0 */
0x0006, /* 1 */
0x045b, /* 2 */
0x044f, /* 3 */
0x0466, /* 4 */
0x046d, /* 5 */
0x047d, /* 6 */
0x0007, /* 7 */
0x047f, /* 8 */
0x046f, /* 9 */
0x0000, /* : */
0x0000, /* ; */
0x0a00, /* < */
0x0000, /* = */
0x2080, /* > */
0x0000, /* ? */
0xffff, /* @ */
0x0477, /* A */
0x0a79, /* B */
0x0039, /* C */
0x20b0, /* D */
0x0079, /* E */
0x0071, /* F */
0x047d, /* G */
0x0476, /* H */
0x0006, /* I */
0x000e, /* J */
0x0a70, /* K */
0x0038, /* L */
0x02b6, /* M */
0x08b6, /* N */
0x003f, /* O */
0x0473, /* P */
0x083f, /* Q */
0x0c73, /* R */
0x046d, /* S */
0x1101, /* T */
0x003e, /* U */
0x2230, /* V */
0x2836, /* W */
0x2a80, /* X */
0x046e, /* Y */
0x2209, /* Z */
0x0039, /* [ */
0x0880, /* backslash */
0x000f, /* ] */
0x0001, /* ^ */
0x0008, /* _ */
0x0100, /* ` */
0x1058, /* a */
0x047c, /* b */
0x0058, /* c */
0x045e, /* d */
0x2058, /* e */
0x0471, /* f */
0x0c0c, /* g */
0x0474, /* h */
0x0004, /* i */
0x000e, /* j */
0x0c70, /* k */
0x0038, /* l */
0x1454, /* m */
0x0454, /* n */
0x045c, /* o */
0x0473, /* p */
0x0467, /* q */
0x0450, /* r */
0x0c08, /* s */
0x0078, /* t */
0x001c, /* u */
0x2010, /* v */
0x2814, /* w */
0x2a80, /* x */
0x080c, /* y */
0x2048, /* z */
0x0000,
};
const uint16_t EFM_Numbers[] = {
0x003f, /* 0 */
0x0006, /* 1 */
0x005b, /* 2 */
0x004f, /* 3 */
0x0066, /* 4 */
0x006d, /* 5 */
0x007d, /* 6 */
0x0007, /* 7 */
0x007f, /* 8 */
0x006f, /* 9 */
0x0077, /* A */
0x007c, /* b */
0x0039, /* C */
0x005e, /* d */
0x0079, /* E */
0x0071, /* F */
0x0040 /* - */
};
typedef struct
{
uint8_t com[14]; /**< LCD COM line (for multiplexing) */
uint8_t bit[14]; /**< LCD bit number */
} CHAR_TypeDef;
/**************************************************************************//**
* @brief Defines segment COM and BIT fields numeric display
*****************************************************************************/
typedef struct
{
uint8_t com[7]; /**< LCD COM line (for multiplexing) */
uint8_t bit[7]; /**< LCD bit number */
} NUMBER_TypeDef;
/**************************************************************************//**
* @brief Defines segment COM and BIT fields for Energy Modes on display
*****************************************************************************/
typedef struct
{
uint8_t com[5]; /**< LCD COM line (for multiplexing) */
uint8_t bit[5]; /**< LCD bit number */
} EM_TypeDef;
/**************************************************************************//**
* @brief Defines segment COM and BIT fields for A-wheel (suited for Anim)
*****************************************************************************/
typedef struct
{
uint8_t com[8]; /**< LCD COM line (for multiplexing) */
uint8_t bit[8]; /**< LCD bit number */
} ARING_TypeDef;
/**************************************************************************//**
* @brief Defines segment COM and BIT fields for Battery (suited for Anim)
*****************************************************************************/
typedef struct
{
uint8_t com[4]; /**< LCD COM line (for multiplexing) */
uint8_t bit[4]; /**< LCD bit number */
} BATTERY_TypeDef;
typedef struct
{
uint8_t com[8]; /**< LCD COM line (for multiplexing) */
uint8_t bit[8]; /**< LCD bit number */
} Block_TypeDef;
typedef struct
{
CHAR_TypeDef Text[7]; /**< Text on display */
NUMBER_TypeDef Number[4]; /**< Numbers on display */
EM_TypeDef EMode; /**< Display energy mode */
ARING_TypeDef ARing; /**< Display ring */
BATTERY_TypeDef Battery; /**< Display battery */
Block_TypeDef TopBlocks[7]; /**< Display top blocks */
Block_TypeDef BotBlocks[7]; /**< Display bottom blocks */
} MCU_DISPLAY;
const MCU_DISPLAY EFM_Display = EFM_DISPLAY_DEF;
volatile uint32_t msTicks; /* counts 1ms timeTicks */
void Delay(uint32_t dlyTicks);
/**************************************************************************//**
* @brief SysTick_Handler
* Interrupt Service Routine for system tick counter
*****************************************************************************/
void SysTick_Handler(void)
{
msTicks++; /* increment counter necessary in Delay()*/
}
/**************************************************************************//**
* @brief Delays number of msTick Systicks (typically 1 ms)
* @param dlyTicks Number of ticks to delay
*****************************************************************************/
void Delay(uint32_t dlyTicks)
{
uint32_t curTicks;
curTicks = msTicks;
while ((msTicks - curTicks) < dlyTicks) ;
}
void LCD_Print(const char *string);
void SegmentSet(int com, int bit, bool enable);
void BUS_RegBitWrite(volatile uint32_t *addr,unsigned int bit,unsigned int val);
/**************************************************************************//**
* @brief Main function
*****************************************************************************/
int main(){
/*Setup SysTick Timer for 1 msec interrupts*/
if (SysTick_Config(48000000 / 1000)) while (1) ; // Systick is used to create delay function
/* Initialize LCD controller without boost. */
//SegmentLCD_Init(false);
/* Ensure LE modules are accessible */
CMU->HFCORECLKEN0|=1<<4; //Set to enable the clock for low energy modules. Interface used for bus access to Low Energy peripherals.
/*To use LCD module, the LE interface clock must be enabled in CMU_HFCORECLKEN0, in addition to
the module clock*/
/* Enable LFRCO as LFACLK in CMU (will also enable oscillator if not enabled) */
CMU->OSCENCMD=1 << 6; // Set LFRCOEN bit to Enables the low frequency RC oscillator (LFRCO)
//Refer referance module section '11.5.9 CMU_OSCENCMD - Oscillator Enable/Disable Command Register' for more details
while (!(CMU->STATUS& 1<<7 )); //Wait until LFRCO is enabled and start-up time has exceeded
// LFBCLK is the selected clock for the Low Energy A Peripherals
CMU->LFCLKSEL=0; //Make all bits CMU_LFCLKSEL - Low Frequency Clock Select Register as 0, because reset value of some of it's bits (LFB & LFA) are 1
CMU->LFCLKSEL&=~(1<<16); //Cleared- LFRCO selected as LFACLK
CMU->LFCLKSEL|=1<<0; //LFRCO selected as LFACLK as per details given in section 11.5.11 of reference manual
/* Enable clock to LCD module */
CMU->LFACLKEN0|=1<<3; //Liquid Crystal Display Controller Clock Enable Set to enable the clock for LCD.
//Refer RM section 11.5.21 for more details
/* Disable interrupts */
LCD->IEN = 0UL; // Cleared to disable interrupt on frame counter interrupt flag.
/* Disable controller before reconfiguration */
LCD->CTRL &= ~1UL; //clear LCD_CTRL_EN bit. Refer RM 33.5.1
/* Configure controller according to initialization structure */
/** Octaplex / 1/6 Duty cycle (segments can be multiplexed with LCD_COM[0:5]) */
LCD->DISPCTRL|= 3UL<<0; //Quadruplex. Uses com lines LCD_COM0-LCD_COM3, These bits set the multiplexing mode for the LCD Driver, The field is dependent on MUXE field
LCD->DISPCTRL|= 1<<22; //This bit redefines the meaning of the MUX field,Mux extended mode. Extends the meaning of the MUX field.
LCD->DISPCTRL|= 3UL<<2; //These bits set the bias mode for the LCD Driver into 1/4th
LCD->DISPCTRL&= ~(1UL<<4); //This bit configures the output waveform to Low power waveform
LCD->DISPCTRL&= ~(1UL<<16); //This bit controls which Voltage source that is connected to VLCD, to VDD
LCD->DISPCTRL&= ~(1UL<<15) ; //This bit selects whether the contrast adjustment is done relative to VLCDor Ground.
/* Enable controller by setting LCD_CTRL_EN bit*/
LCD->CTRL |= (1);
/* Enable all display segments by setting corresponding bits in LCD_SEGEN - Segment Enable (Refer RM section 33.5.3)*/
//Enable all display segments 12_15;
LCD->SEGEN |= 1<<3;
//Enable all display segments 16_19
LCD->SEGEN |= 1<<4;
//Enable all display segments 28_31
LCD->SEGEN |= 1<<7;
//Enable all display segments 32_35
LCD->SEGEN |= 1<<8;
//Enable all display segments 36_39
LCD->SEGEN |= 1<<9;
/* Enable boost converter. To save energy, first try to adjust framerate */
/* and contrast to maximum, in many cases this is enough to account for lower supply voltage. */
/* Set Vboost level, for lowest current consumption, set as low as possible. */
/* Reconfigure Voltage Boost */
LCD->DISPCTRL |= 3UL<<18; //lcdVBoostLevel3
LCD->DISPCTRL|= 1<<16; //This bit controls which Voltage source that is connected to VLCD, set to select Voltage Booster/External VDD
/*Adjusting contast */
LCD->DISPCTRL|= 0<<8; /* 0=Minimum, 31=maximum*/
/*Enable Vboost*/
CMU->LCDCTRL |= 1<<3; //This bit enables/disables the VBOOST function.
CMU->LCDCTRL |= 3<<4; //Voltage Boost update Frequency = LFACLK/8.
while (LCD->SYNCBUSY & 0xFFFFFFFF); //Polls LCD SYNCBUSY flags, until flag has been cleared
while (1){
/* Write something to text field on LCD display. */
LCD_print("NAME");
Delay(2000);
LCD_print("ID NUM");
Delay(2000);
/* Stay in this loop forever at end of program.*/
}
}
void LCD_print(const char *string)
{
int data, length, index;
uint16_t bitfield;
uint32_t com, bit;
int i;
length = strlen(string);
index = 0;
/* If an update is in progress we must block, or there might be tearing */
/*Polls LCD SYNCBUSY flags, until flag has been cleared*/
//LCD_SyncBusyDelay(0xFFFFFFFF);
while (LCD->SYNCBUSY & 0xFFFFFFFF);
/* Freeze LCD to avoid partial updates */
//LCD_FreezeEnable(true);segData = LCD->SEGD0L;
LCD->FREEZE = 1UL;
/* Turn all segments off */
/* Turn all segments on alpha characters in display off*/
LCD->SEGD7L &= ~(0x500FE000);
LCD->SEGD6L &= ~(0xF00FE000);
LCD->SEGD5L &= ~(0xF00FE000);
LCD->SEGD4L &= ~(0xF00FE000);
LCD->SEGD3L &= ~(0xF00FE000);
LCD->SEGD2L &= ~(0xF00FE000);
LCD->SEGD1L &= ~(0xF00FE000);
LCD->SEGD0L &= ~(0xA000000);
LCD->SEGD7H&= ~(0x00000007);
LCD->SEGD6H&= ~(0x00000007);
LCD->SEGD5H&= ~(0x00000007);
LCD->SEGD4H&= ~(0x00000007);
LCD->SEGD3H&= ~(0x00000007);
LCD->SEGD2H&= ~(0x00000007);
LCD->SEGD1H&= ~(0x00000007);
/* Fill out all characters on display */
for (index = 0; index < 7; index++)
{
if (index < length)
{
data = (int) *string;
}
else /* Padding with space */
{
data = 0x20; /* SPACE */
}
/* Defined letters currently starts at "SPACE" - ASCII 0x20; */
data = data - 0x20;
/* Get font for this letter */
bitfield = EFM_Alphabet[data];
for (i = 0; i < 14; i++)
{
bit = EFM_Display.Text[index].bit[i];
com = EFM_Display.Text[index].com[i];
if (bitfield & (1 << i))
{
/* Turn on segment */
SegmentSet(com, bit, true);
}
}
string++;
}
/* Enable update */
LCD->FREEZE = 0;
//When set, LCD registers will not be updated until cleared,
//LCD_FreezeEnable(false);
}
void SegmentSet(int com, int bit, bool enable)
{
/* Use bitband access for atomic bit set/clear of segment */
switch (com)
{
case 0:
if (bit < 32)
{
BUS_RegBitWrite(&(LCD->SEGD0L), bit, enable);
}
else
{
bit -= 32;
BUS_RegBitWrite(&(LCD->SEGD0H), bit, enable);
}
break;
case 1:
if (bit < 32)
{
BUS_RegBitWrite(&(LCD->SEGD1L), bit, enable);
}
else
{
bit -= 32;
BUS_RegBitWrite(&(LCD->SEGD1H), bit, enable);
}
break;
case 2:
if (bit < 32)
{
BUS_RegBitWrite(&(LCD->SEGD2L), bit, enable);
}
else
{
bit -= 32;
BUS_RegBitWrite(&(LCD->SEGD2H), bit, enable);
}
break;
case 3:
if (bit < 32)
{
BUS_RegBitWrite(&(LCD->SEGD3L), bit, enable);
}
else
{
bit -= 32;
BUS_RegBitWrite(&(LCD->SEGD3H), bit, enable);
}
break;
case 4:
if (bit < 32)
{
BUS_RegBitWrite(&(LCD->SEGD4L), bit, enable);
}
else
{
bit -= 32;
BUS_RegBitWrite(&(LCD->SEGD4H), bit, enable);
}
break;
case 5:
if (bit < 32)
{
BUS_RegBitWrite(&(LCD->SEGD5L), bit, enable);
}
else
{
bit -= 32;
BUS_RegBitWrite(&(LCD->SEGD5H), bit, enable);
}
break;
case 6:
if (bit < 32)
{
BUS_RegBitWrite(&(LCD->SEGD6L), bit, enable);
}
else
{
bit -= 32;
BUS_RegBitWrite(&(LCD->SEGD6H), bit, enable);
}
break;
case 7:
if (bit < 32)
{
BUS_RegBitWrite(&(LCD->SEGD7L), bit, enable);
}
else
{
bit -= 32;
BUS_RegBitWrite(&(LCD->SEGD7H), bit, enable);
}
break;
}
}
void BUS_RegBitWrite(volatile uint32_t *addr,
unsigned int bit,
unsigned int val)
{
uint32_t aliasAddr =
BITBAND_PER_BASE + (((uint32_t)addr - PER_MEM_BASE) * 32) + (bit * 4);
*(volatile uint32_t *)aliasAddr = (uint32_t)val;
}
0 comments:
Post a Comment