📄 lcd_support.c
字号:
//==========================================================================
//
// Lcd_support.c
//
// Agilent AAED2000 - LCD support routines
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos 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 General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s): gthomas
// Contributors: gthomas
// Date: 2001-11-03
// Description: Simple LCD support
//####DESCRIPTIONEND####
#include <pkgconf/hal.h>
#include <cyg/infra/diag.h>
#include <cyg/hal/hal_io.h> // IO macros
#include <cyg/hal/hal_if.h> // Virtual vector support
#include <cyg/hal/hal_arch.h> // Register state info
#include <cyg/hal/hal_intr.h> // HAL interrupt macros
#include <cyg/hal/aaed2000.h> // Board definitions
#include <cyg/hal/lcd_support.h>
#include <cyg/hal/hal_cache.h>
#include <string.h>
#ifdef CYGPKG_ISOINFRA
# include <pkgconf/isoinfra.h>
# ifdef CYGINT_ISO_STDIO_FORMATTED_IO
# include <stdio.h> // sscanf
# endif
#endif
#include CYGHWR_MEMORY_LAYOUT_H
#define LCD_FRAMEBUFFER CYGMEM_REGION_lcd
static cyg_uint32 lcd_framebuffer;
#ifndef FALSE
#define FALSE 0
#define TRUE 1
#endif
// Physical dimensions of LCD display
#define DISPLAY_WIDTH 640
#define DISPLAY_HEIGHT 480
// Logical layout
#ifdef CYGSEM_AAED2000_LCD_PORTRAIT_MODE
#define LCD_WIDTH DISPLAY_HEIGHT
#define LCD_HEIGHT DISPLAY_WIDTH
#else
#define LCD_WIDTH DISPLAY_WIDTH
#define LCD_HEIGHT DISPLAY_HEIGHT
#endif
#define LCD_DEPTH 16
#define RGB_RED(x) (((x)&0x1F)<<0)
#define RGB_GREEN(x) (((x)&0x1F)<<5)
#define RGB_BLUE(x) (((x)&0x1F)<<10)
// Physical screen info
//static int lcd_depth = LCD_DEPTH; // Should be 1, 2, or 4
static int lcd_bpp;
#ifdef CYGSEM_AAED2000_LCD_PORTRAIT_MODE
static int lcd_width = LCD_WIDTH;
#endif
static int lcd_height = LCD_HEIGHT;
// Black on light blue
static int bg = RGB_RED(0x17) | RGB_GREEN(0x17) | RGB_BLUE(0x1F);
#ifdef CYGSEM_AAED2000_LCD_COMM
static int fg = RGB_RED(0) | RGB_GREEN(0) | RGB_BLUE(0);
#endif
// Compute the location for a pixel within the framebuffer
static cyg_uint32 *
lcd_fb(int row, int col)
{
return (cyg_uint32 *)(lcd_framebuffer+(((row*DISPLAY_WIDTH)+col)*2));
}
void
lcd_on(bool enable)
{
cyg_uint32 ctl;
if (!enable) return; // FIXME - need a way to [safely] blank screen
// Turn on PWM [pulse wave modulated] voltage pump
HAL_WRITE_UINT32(AAEC_PUMP_CONTROL, 0x800); // Magic FIXME
HAL_WRITE_UINT32(AAEC_PUMP_FREQUENCY, 0x3733); // Magic FIXME
// Turn on Power
HAL_READ_UINT32(AAED_EXT_GPIO, ctl);
ctl |= AAED_EXT_GPIO_LCD_PWR_EN;
HAL_WRITE_UINT32(AAED_EXT_GPIO, ctl);
// Power must be on for 0..20ms before enabling signals
CYGACC_CALL_IF_DELAY_US(500); // 500us should be long enough
HAL_READ_UINT32(AAEC_LCD_CONTROL, ctl);
ctl |= AAEC_LCD_CONTROL_ENAB | AAEC_LCD_CONTROL_PWR_ENAB;
HAL_WRITE_UINT32(AAEC_LCD_CONTROL, ctl);
}
// Initialize LCD hardware
void
lcd_init(int depth)
{
cyg_uint32 ctl;
HAL_VIRT_TO_PHYS_ADDRESS(LCD_FRAMEBUFFER, lcd_framebuffer);
lcd_clear();
HAL_READ_UINT32(AAEC_LCD_CONTROL, ctl);
if (ctl & (AAEC_LCD_CONTROL_ENAB | AAEC_LCD_CONTROL_PWR_ENAB)) {
// LCD currently on - turn it off carefully
ctl &= ~(AAEC_LCD_CONTROL_ENAB | AAEC_LCD_CONTROL_PWR_ENAB);
HAL_WRITE_UINT32(AAEC_LCD_CONTROL, ctl);
// Now wait a little
CYGACC_CALL_IF_DELAY_US(500);
// Turn off Power
HAL_READ_UINT32(AAED_EXT_GPIO, ctl);
ctl &= ~AAED_EXT_GPIO_LCD_PWR_EN;
HAL_WRITE_UINT32(AAED_EXT_GPIO, ctl);
// Now wait for 1.0 second
CYGACC_CALL_IF_DELAY_US(1000*1000);
}
HAL_WRITE_UINT32(AAEC_LCD_CONTROL, 0x00010028); // Magic FIXME
HAL_WRITE_UINT32(AAEC_LCD_TIMING0, 0x2B135F9C); // Magic FIXME
HAL_WRITE_UINT32(AAEC_LCD_TIMING1, 0x211401DF); // Magic FIXME
HAL_WRITE_UINT32(AAEC_LCD_TIMING2, 0x067F1820); // Magic FIXME
HAL_WRITE_UINT32(AAEC_LCD_TIMING3, 0x00000000); // Magic FIXME
HAL_WRITE_UINT32(AAEC_LCD_UPBASE, lcd_framebuffer);
HAL_WRITE_UINT32(AAEC_LCD_LPBASE, lcd_framebuffer);
#if 0 // For some reason, this crashes miserably
lcd_framebuffer = LCD_FRAMEBUFFER; // Logical operations use cached space
#endif
lcd_on(true);
lcd_bpp = 16;
}
// Get information about the frame buffer
int
lcd_getinfo(struct lcd_info *info)
{
if (lcd_bpp == 0) {
return 0; // LCD not initialized
}
info->width = DISPLAY_WIDTH;
info->height = DISPLAY_HEIGHT;
info->bpp = lcd_bpp;
info->fb = (void*)LCD_FRAMEBUFFER;
info->rlen = DISPLAY_WIDTH * 2;
info->type = FB_TRUE_RGB555;
return 1; // Information valid
}
// Clear screen
void
lcd_clear(void)
{
#ifndef CYGSEM_AAED2000_LCD_PORTRAIT_MODE
cyg_uint32 *fb_row0, *fb_rown;
cyg_uint32 _bg = (bg<<16)|bg;
fb_row0 = lcd_fb(0, 0);
fb_rown = lcd_fb(lcd_height, 0);
while (fb_row0 != fb_rown) {
*fb_row0++ = _bg;
}
#else
int row, col;
for (row = 0; row < lcd_height; row++) {
for (col = 0; col < lcd_width; col++) {
set_pixel(row, col, bg);
}
}
#endif
}
#ifdef CYGSEM_AAED2000_LCD_COMM
//
// Additional support for LCD/Keyboard as 'console' device
//
#ifdef CYGOPT_AAED2000_LCD_COMM_LOGO
#include "banner.xpm"
#endif
#include "font.h"
// Virtual screen info
static int curX = 0; // Last used position
static int curY = 0;
//static int width = LCD_WIDTH / (FONT_WIDTH*NIBBLES_PER_PIXEL);
//static int height = LCD_HEIGHT / (FONT_HEIGHT*SCREEN_SCALE);
#define SCREEN_PAN 20
#define SCREEN_WIDTH 80
#define SCREEN_HEIGHT (LCD_HEIGHT/FONT_HEIGHT)
#define VISIBLE_SCREEN_WIDTH (LCD_WIDTH/FONT_WIDTH)
#define VISIBLE_SCREEN_HEIGHT (LCD_HEIGHT/FONT_HEIGHT)
static char screen[SCREEN_HEIGHT][SCREEN_WIDTH];
static int screen_height = SCREEN_HEIGHT;
static int screen_width = SCREEN_WIDTH;
static int screen_pan = 0;
// Usable area on screen [logical pixel rows]
static int screen_start = 0;
static int screen_end = LCD_HEIGHT/FONT_HEIGHT;
static bool cursor_enable = true;
// Functions
static void lcd_drawc(cyg_int8 c, int x, int y);
// Note: val is a 16 bit, RGB555 value which must be mapped
// onto a 12 bit value.
#define RED(v) ((v>>12) & 0x0F)
#define GREEN(v) ((v>>7) & 0x0F)
#define BLUE(v) ((v>>1) & 0x0F)
#ifdef CYGSEM_AAED2000_LCD_PORTRAIT_MODE
#error PORTRAIT MODE NOT IMPLEMENTED
// Translate coordinates, rotating clockwise 90 degrees
static void
set_pixel(int row, int col, unsigned short val)
{
// fp->pixels[col][(DISPLAY_WIDTH-1)-row] = val;
int _row = (240-1) - col;
int _col = row;
unsigned char *pxptr = (unsigned char *)(0xC0000000 + (_row * 480) + ((_col * 3) / 2));
diag_printf("%s\n", __FUNCTION__); return;
if ((row >= LCD_HEIGHT) || (col >= LCD_WIDTH)) return;
if (0)
{
int old = start_console();
diag_printf("row=%d/%d, col=%d/%d, pxptr = %p\n", row, _row, col, _col, pxptr);
end_console(old);
}
if ((row % 2) == 0) {
// Even row
*pxptr++ = RED(val) | (GREEN(val) << 4);
*pxptr = (*pxptr & 0xF0) | BLUE(val);
} else {
// Odd row
*pxptr = (*pxptr & 0x0F) | (RED(val) << 4);
*++pxptr = GREEN(val) | (BLUE(val) << 4);
}
}
#else
static void
set_pixel(int row, int col, unsigned short val)
{
unsigned short *pix = (unsigned short *)lcd_fb(row, col);
*pix = val;
}
#endif
static int
_hexdigit(char c)
{
if ((c >= '0') && (c <= '9')) {
return c - '0';
} else
if ((c >= 'A') && (c <= 'F')) {
return (c - 'A') + 0x0A;
} else
if ((c >= 'a') && (c <= 'f')) {
return (c - 'a') + 0x0a;
}
return 0;
}
static int
_hex(char *cp)
{
return (_hexdigit(*cp)<<4) | _hexdigit(*(cp+1));
}
static unsigned short
parse_color(char *cp)
{
int red, green, blue;
while (*cp && (*cp != 'c')) cp++;
if (cp) {
cp += 2;
if (*cp == '#') {
red = _hex(cp+1);
green = _hex(cp+3);
blue = _hex(cp+5);
#ifdef USE_RGB565
return RGB_RED(red>>3) | RGB_GREEN(green>>2) | RGB_BLUE(blue>>3);
#else
return RGB_RED(red>>3) | RGB_GREEN(green>>3) | RGB_BLUE(blue>>3);
#endif
} else {
// Should be "None"
return 0xFFFF;
}
} else {
return 0xFFFF;
}
}
#ifndef CYGINT_ISO_STDIO_FORMATTED_IO
static int
get_int(char **_cp)
{
char *cp = *_cp;
char c;
int val = 0;
while ((c = *cp++) && (c != ' ')) {
if ((c >= '0') && (c <= '9')) {
val = val * 10 + (c - '0');
} else {
return -1;
}
}
*_cp = cp;
return val;
}
#endif
#ifdef CYGOPT_AAED2000_LCD_COMM_LOGO
int
show_xpm(char *xpm[], int screen_pos)
{
int i, row, col, offset;
char *cp;
int nrows, ncols, nclrs;
unsigned short colors[256]; // Mapped by character index
cp = xpm[0];
#ifdef CYGINT_ISO_STDIO_FORMATTED_IO
if (sscanf(cp, "%d %d %d", &ncols, &nrows, &nclrs) != 3) {
#else
if (((ncols = get_int(&cp)) < 0) ||
((nrows = get_int(&cp)) < 0) ||
((nclrs = get_int(&cp)) < 0)) {
#endif
diag_printf("Can't parse XPM data, sorry\n");
return 0;
}
// printf("%d rows, %d cols, %d colors\n", nrows, ncols, nclrs);
for (i = 0; i < 256; i++) {
colors[i] = 0x0000;
}
for (i = 0; i < nclrs; i++) {
cp = xpm[i+1];
colors[(unsigned int)*cp] = parse_color(&cp[1]);
// printf("Color[%c] = %x\n", *cp, colors[(unsigned int)*cp]);
}
#ifdef CYGOPT_AAED2000_LCD_COMM_LOGO_TOP
offset = screen_pos;
#else
offset = screen_pos-nrows;
#endif
for (row = 0; row < nrows; row++) {
cp = xpm[nclrs+1+row];
for (col = 0; col < ncols; col++) {
set_pixel(row+offset, col, colors[(unsigned int)*cp++]);
}
}
#ifdef CYGOPT_AAED2000_LCD_COMM_LOGO_TOP
screen_start = (nrows + (FONT_HEIGHT-1))/FONT_HEIGHT;
screen_end = LCD_HEIGHT/FONT_HEIGHT;
return offset+nrows;
#else
screen_start = 0;
screen_height = offset / FONT_HEIGHT;
screen_end = screen_height;
return offset;
#endif
}
#endif
void
lcd_screen_clear(void)
{
int row, col, pos;
for (row = 0; row < screen_height; row++) {
for (col = 0; col < screen_width; col++) {
screen[row][col] = ' ';
}
}
#ifdef CYGOPT_AAED2000_LCD_COMM_LOGO
// Note: Row 0 seems to wrap incorrectly
#ifdef CYGOPT_AAED2000_LCD_COMM_LOGO_TOP
pos = 0;
#else
pos = (LCD_HEIGHT-1);
#endif
show_xpm(banner_xpm, pos);
#endif // CYGOPT_AAED2000_LCD_COMM_LOGO
curX = 0; curY = screen_start;
if (cursor_enable) {
lcd_drawc(CURSOR_ON, curX-screen_pan, curY);
}
}
// Position cursor
void
lcd_moveto(int X, int Y)
{
if (cursor_enable) {
lcd_drawc(screen[curY][curX], curX-screen_pan, curY);
}
if (X < 0) X = 0;
if (X >= screen_width) X = screen_width-1;
curX = X;
if (Y < screen_start) Y = screen_start;
if (Y >= screen_height) Y = screen_height-1;
curY = Y;
if (cursor_enable) {
lcd_drawc(CURSOR_ON, curX-screen_pan, curY);
}
}
// Render a character at position (X,Y) with current background/foreground
static void
lcd_drawc(cyg_int8 c, int x, int y)
{
cyg_uint8 bits;
int l, p;
int xoff, yoff;
#ifndef CYGSEM_AAED2000_LCD_PORTRAIT_MODE
cyg_uint32 *fb;
#endif
if ((x < 0) || (x >= VISIBLE_SCREEN_WIDTH) ||
(y < 0) || (y >= screen_height)) return;
for (l = 0; l < FONT_HEIGHT; l++) {
bits = font_table[c-FIRST_CHAR][l];
yoff = y*FONT_HEIGHT + l;
xoff = x*FONT_HEIGHT;
#ifndef CYGSEM_AAED2000_LCD_PORTRAIT_MODE
// Caution - only works for little-endian & font sizes multiple of 2
fb = lcd_fb(yoff, xoff);
for (p = 0; p < FONT_WIDTH; p += 2) {
switch (bits & 0x03) {
case 0:
*fb++ = (bg << 16) | bg;
break;
case 1:
*fb++ = (bg << 16) | fg;
break;
case 2:
*fb++ = (fg << 16) | bg;
break;
case 3:
*fb++ = (fg << 16) | fg;
break;
}
bits >>= 2;
}
#else
for (p = 0; p < FONT_WIDTH; p++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -