You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
409 lines
11 KiB
409 lines
11 KiB
/** |
|
* |
|
* Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/ |
|
* |
|
* |
|
* Redistribution and use in source and binary forms, with or without |
|
* modification, are permitted provided that the following conditions |
|
* are met: |
|
* |
|
* Redistributions of source code must retain the above copyright |
|
* notice, this list of conditions and the following disclaimer. |
|
* |
|
* Redistributions in binary form must reproduce the above copyright |
|
* notice, this list of conditions and the following disclaimer in the |
|
* documentation and/or other materials provided with the |
|
* distribution. |
|
* |
|
* Neither the name of Texas Instruments Incorporated nor the names of |
|
* its contributors may be used to endorse or promote products derived |
|
* from this software without specific prior written permission. |
|
* |
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
* |
|
*/ |
|
|
|
/** |
|
* @ingroup chronos |
|
* @{ |
|
*/ |
|
|
|
/** |
|
* @file |
|
* @brief eZ430-chronos display driver |
|
* |
|
* @author Oliver Hahm <oliver.hahm@inria.fr> |
|
* @author Ludwig Knüpfer <ludwig.knuepfer@fu-berlin.de> |
|
* @author Kaspar Schleiser <kaspar@schleiser.de> |
|
* @author mikoff |
|
* |
|
*/ |
|
|
|
#include <string.h> |
|
#include <cc430f6137.h> |
|
|
|
#include "display.h" |
|
|
|
void write_lcd_mem(uint8_t *lcdmem, uint8_t bits, uint8_t bitmask, uint8_t state); |
|
void clear_line(uint8_t line); |
|
void display_symbol(uint8_t symbol, uint8_t mode); |
|
|
|
/** Display flags */ |
|
volatile s_display_flags_t display; |
|
|
|
/** Global return string for itoa function */ |
|
char itoa_str[8]; |
|
|
|
void lcd_init(void) |
|
{ |
|
/* Clear entire display memory */ |
|
LCDBMEMCTL |= LCDCLRBM + LCDCLRM; |
|
|
|
/* LCD_FREQ = ACLK/16/8 = 256Hz */ |
|
/* Frame frequency = 256Hz/4 = 64Hz, LCD mux 4, LCD on */ |
|
LCDBCTL0 = (LCDDIV0 + LCDDIV1 + LCDDIV2 + LCDDIV3) | (LCDPRE0 + LCDPRE1) | LCD4MUX | LCDON; |
|
|
|
/* LCB_BLK_FREQ = ACLK/8/4096 = 1Hz */ |
|
LCDBBLKCTL = LCDBLKPRE0 | LCDBLKPRE1 | LCDBLKDIV0 | LCDBLKDIV1 | LCDBLKDIV2 | LCDBLKMOD0; |
|
|
|
/* I/O to COM outputs */ |
|
P5SEL |= (BIT5 | BIT6 | BIT7); |
|
P5DIR |= (BIT5 | BIT6 | BIT7); |
|
|
|
/* Activate LCD output */ |
|
LCDBPCTL0 = 0xFFFF; /* Select LCD segments S0-S15 */ |
|
LCDBPCTL1 = 0x00FF; /* Select LCD segments S16-S22 */ |
|
|
|
#ifdef USE_LCD_CHARGE_PUMP |
|
/* Charge pump voltage generated internally, internal bias (V2-V4) generation */ |
|
LCDBVCTL = LCDCPEN | VLCD_2_72; |
|
#endif |
|
} |
|
|
|
void clear_display_all(void) |
|
{ |
|
// Clear generic content |
|
clear_line(LINE1); |
|
clear_line(LINE2); |
|
} |
|
|
|
void clear_display(void) |
|
{ |
|
clear_line(LINE1); |
|
clear_line(LINE2); |
|
} |
|
|
|
void clear_line(uint8_t line) |
|
{ |
|
display_chars(switch_seg(line, LCD_SEG_L1_3_0, LCD_SEG_L2_5_0), NULL, SEG_OFF); |
|
|
|
if (line == LINE1) { |
|
display_symbol(LCD_SEG_L1_DP1, SEG_OFF); |
|
display_symbol(LCD_SEG_L1_DP0, SEG_OFF); |
|
display_symbol(LCD_SEG_L1_COL, SEG_OFF); |
|
} |
|
/* line == LINE2 */ |
|
else { |
|
display_symbol(LCD_SEG_L2_DP, SEG_OFF); |
|
display_symbol(LCD_SEG_L2_COL1, SEG_OFF); |
|
display_symbol(LCD_SEG_L2_COL0, SEG_OFF); |
|
} |
|
} |
|
|
|
void write_lcd_mem(uint8_t *lcdmem, uint8_t bits, uint8_t bitmask, uint8_t state) |
|
{ |
|
if (state == SEG_ON) { |
|
/* Clear segments before writing */ |
|
*lcdmem = (uint8_t)(*lcdmem & ~bitmask); |
|
|
|
/* Set visible segments */ |
|
*lcdmem = (uint8_t)(*lcdmem | bits); |
|
} |
|
else if (state == SEG_OFF) { |
|
/* Clear segments */ |
|
*lcdmem = (uint8_t)(*lcdmem & ~bitmask); |
|
} |
|
else if (state == SEG_ON_BLINK_ON) { |
|
/* Clear visible / blink segments before writing */ |
|
*lcdmem = (uint8_t)(*lcdmem & ~bitmask); |
|
*(lcdmem + 0x20) = (uint8_t)(*(lcdmem + 0x20) & ~bitmask); |
|
|
|
/* Set visible / blink segments */ |
|
*lcdmem = (uint8_t)(*lcdmem | bits); |
|
*(lcdmem + 0x20) = (uint8_t)(*(lcdmem + 0x20) | bits); |
|
} |
|
else if (state == SEG_ON_BLINK_OFF) { |
|
/* Clear visible segments before writing */ |
|
*lcdmem = (uint8_t)(*lcdmem & ~bitmask); |
|
|
|
/* Set visible segments */ |
|
*lcdmem = (uint8_t)(*lcdmem | bits); |
|
|
|
/* Clear blink segments */ |
|
*(lcdmem + 0x20) = (uint8_t)(*(lcdmem + 0x20) & ~bitmask); |
|
} |
|
else if (state == SEG_OFF_BLINK_OFF) { |
|
/* Clear segments */ |
|
*lcdmem = (uint8_t)(*lcdmem & ~bitmask); |
|
|
|
/* Clear blink segments */ |
|
*(lcdmem + 0x20) = (uint8_t)(*(lcdmem + 0x20) & ~bitmask); |
|
} |
|
} |
|
|
|
char *itoa(uint32_t n, uint8_t digits, uint8_t blanks) |
|
{ |
|
uint8_t digits1 = digits; |
|
|
|
/* Preset result string */ |
|
memcpy(itoa_str, "0000000", 7); |
|
|
|
/* Return empty string if number of digits is invalid (valid range for digits: 1-7) */ |
|
if ((digits == 0) || (digits > 7)) { |
|
return (itoa_str); |
|
} |
|
|
|
/* Numbers 0 .. 180 can be copied from itoa_conversion_table without conversion */ |
|
if (n <= 180) { |
|
if (digits >= 3) { |
|
memcpy(itoa_str + (digits - 3), itoa_conversion_table[n], 3); |
|
} |
|
/* digits == 1 || 2 */ |
|
else { |
|
memcpy(itoa_str, itoa_conversion_table[n] + (3 - digits), digits); |
|
} |
|
} |
|
/* For n > 180 need to calculate string content */ |
|
else { |
|
/* Calculate digits from least to most significant number */ |
|
do { |
|
itoa_str[digits - 1] = n % 10 + '0'; |
|
n /= 10; |
|
} |
|
while (--digits > 0); |
|
} |
|
|
|
/* Remove specified number of leading '0', always keep last one */ |
|
uint8_t i = 0; |
|
while ((i < digits1 - 1) && (itoa_str[i] == '0')) { |
|
if (blanks > 0) { |
|
/* Convert only specified number of leading '0' */ |
|
itoa_str[i] = ' '; |
|
blanks--; |
|
} |
|
|
|
i++; |
|
} |
|
|
|
return (itoa_str); |
|
} |
|
|
|
void display_value1(uint8_t segments, uint32_t value, uint8_t digits, uint8_t blanks, uint8_t disp_mode) |
|
{ |
|
char *str; |
|
|
|
str = itoa(value, digits, blanks); |
|
|
|
/* Display string in blink mode */ |
|
display_chars(segments, str, disp_mode); |
|
} |
|
|
|
void display_symbol(uint8_t symbol, uint8_t mode) |
|
{ |
|
if (symbol <= LCD_SEG_L2_DP) { |
|
/* Get LCD memory address for symbol from table */ |
|
uint8_t *lcdmem = (uint8_t *)segments_lcdmem[symbol]; |
|
|
|
/* Get bits for symbol from table */ |
|
uint8_t bits = segments_bitmask[symbol]; |
|
|
|
/* Bitmask for symbols equals bits */ |
|
uint8_t bitmask = bits; |
|
|
|
/* Write LCD memory */ |
|
write_lcd_mem(lcdmem, bits, bitmask, mode); |
|
} |
|
} |
|
|
|
void display_char(uint8_t segment, char chr, uint8_t mode) |
|
{ |
|
/* Write to single 7-segment character */ |
|
if ((segment >= LCD_SEG_L1_3) && (segment <= LCD_SEG_L2_DP)) { |
|
uint8_t bits; /* Bits to write */ |
|
|
|
/* Get LCD memory address for segment from table */ |
|
uint8_t *lcdmem = (uint8_t *)segments_lcdmem[segment]; |
|
|
|
/* Get bitmask for character from table */ |
|
uint8_t bitmask = segments_bitmask[segment]; |
|
|
|
/* Get bits from font set */ |
|
if ((chr >= 0x30) && (chr <= 0x5A)) { |
|
/* Use font set */ |
|
bits = lcd_font[chr - 0x30]; |
|
} |
|
else if (chr == 0x2D) { |
|
/* '-' not in font set */ |
|
bits = BIT1; |
|
} |
|
else { |
|
/* Other characters map to ' ' (blank) */ |
|
bits = 0; |
|
} |
|
|
|
/* When addressing LINE2 7-segment characters need to swap high- and low-nibble, */ |
|
/* because LCD COM/SEG assignment is mirrored against LINE1 */ |
|
if (segment >= LCD_SEG_L2_5) { |
|
uint8_t bits1 = ((bits << 4) & 0xF0) | ((bits >> 4) & 0x0F); |
|
bits = bits1; |
|
|
|
/* When addressing LCD_SEG_L2_5, need to convert ASCII '1' and 'L' to 1 bit, */ |
|
/* because LCD COM/SEG assignment is special for this incomplete character */ |
|
if (segment == LCD_SEG_L2_5) { |
|
if ((chr == '1') || (chr == 'L')) { |
|
bits = BIT7; |
|
} |
|
} |
|
} |
|
|
|
/* Physically write to LCD memory */ |
|
write_lcd_mem(lcdmem, bits, bitmask, mode); |
|
} |
|
} |
|
|
|
void display_chars(uint8_t segments, char *str, uint8_t mode) |
|
{ |
|
uint8_t length = 0; /* Write length */ |
|
uint8_t char_start = 0; /* Starting point for consecutive write */ |
|
|
|
switch (segments) { |
|
/* LINE1 */ |
|
case LCD_SEG_L1_3_0: |
|
length = 4; |
|
char_start = LCD_SEG_L1_3; |
|
break; |
|
|
|
case LCD_SEG_L1_2_0: |
|
length = 3; |
|
char_start = LCD_SEG_L1_2; |
|
break; |
|
|
|
case LCD_SEG_L1_1_0: |
|
length = 2; |
|
char_start = LCD_SEG_L1_1; |
|
break; |
|
|
|
case LCD_SEG_L1_3_1: |
|
length = 3; |
|
char_start = LCD_SEG_L1_3; |
|
break; |
|
|
|
case LCD_SEG_L1_3_2: |
|
length = 2; |
|
char_start = LCD_SEG_L1_3; |
|
break; |
|
|
|
/* LINE2 */ |
|
case LCD_SEG_L2_5_0: |
|
length = 6; |
|
char_start = LCD_SEG_L2_5; |
|
break; |
|
|
|
case LCD_SEG_L2_4_0: |
|
length = 5; |
|
char_start = LCD_SEG_L2_4; |
|
break; |
|
|
|
case LCD_SEG_L2_3_0: |
|
length = 4; |
|
char_start = LCD_SEG_L2_3; |
|
break; |
|
|
|
case LCD_SEG_L2_2_0: |
|
length = 3; |
|
char_start = LCD_SEG_L2_2; |
|
break; |
|
|
|
case LCD_SEG_L2_1_0: |
|
length = 2; |
|
char_start = LCD_SEG_L2_1; |
|
break; |
|
|
|
case LCD_SEG_L2_5_4: |
|
length = 2; |
|
char_start = LCD_SEG_L2_5; |
|
break; |
|
|
|
case LCD_SEG_L2_5_2: |
|
length = 4; |
|
char_start = LCD_SEG_L2_5; |
|
break; |
|
|
|
case LCD_SEG_L2_3_2: |
|
length = 2; |
|
char_start = LCD_SEG_L2_3; |
|
break; |
|
|
|
case LCD_SEG_L2_4_2: |
|
length = 3; |
|
char_start = LCD_SEG_L2_4; |
|
break; |
|
} |
|
|
|
/* Write to consecutive digits */ |
|
for (uint8_t i = 0; i < length; i++) { |
|
/* Use single character routine to write display memory */ |
|
display_char(char_start + i, *(str + i), mode); |
|
} |
|
} |
|
|
|
uint8_t switch_seg(uint8_t line, uint8_t index1, uint8_t index2) |
|
{ |
|
if (line == LINE1) { |
|
return index1; |
|
} |
|
/* line == LINE2 */ |
|
else { |
|
return index2; |
|
} |
|
} |
|
|
|
void start_blink(void) |
|
{ |
|
LCDBBLKCTL |= LCDBLKMOD0; |
|
} |
|
|
|
void stop_blink(void) |
|
{ |
|
LCDBBLKCTL &= ~LCDBLKMOD0; |
|
} |
|
|
|
void clear_blink_mem(void) |
|
{ |
|
LCDBMEMCTL |= LCDCLRBM; |
|
} |
|
|
|
void set_blink_rate(uint8_t bits) |
|
{ |
|
LCDBBLKCTL &= ~(BIT7 | BIT6 | BIT5); |
|
LCDBBLKCTL |= bits; |
|
} |
|
|
|
void display_all_off(void) |
|
{ |
|
uint8_t *lcdptr = (uint8_t *)0x0A20; |
|
for (uint8_t i = 1; i <= 12; i++) { |
|
*lcdptr = 0x00; |
|
lcdptr++; |
|
} |
|
}
|
|
|