summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJörg Hohensohn <hohensoh@rockbox.org>2003-12-12 22:11:08 +0000
committerJörg Hohensohn <hohensoh@rockbox.org>2003-12-12 22:11:08 +0000
commit56271b571abdff74672d174345ae3197e170953c (patch)
tree1511da159203b4992de0bbec842def93b3a8284d
parente3be10107d74b3124ad4ff365f9894c09a316297 (diff)
downloadrockbox-56271b571abdff74672d174345ae3197e170953c.zip
rockbox-56271b571abdff74672d174345ae3197e170953c.tar.gz
rockbox-56271b571abdff74672d174345ae3197e170953c.tar.bz2
rockbox-56271b571abdff74672d174345ae3197e170953c.tar.xz
LCD flip (upside down) and a high-performance blit function
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@4143 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/drivers/lcd-recorder.c48
-rw-r--r--firmware/drivers/lcd.c113
-rw-r--r--firmware/export/lcd.h4
3 files changed, 158 insertions, 7 deletions
diff --git a/firmware/drivers/lcd-recorder.c b/firmware/drivers/lcd-recorder.c
index a409c9f..0a95e82 100644
--- a/firmware/drivers/lcd-recorder.c
+++ b/firmware/drivers/lcd-recorder.c
@@ -103,10 +103,8 @@ static struct scrollinfo scroll[SCROLLABLE_LINES];
static int xmargin = 0;
static int ymargin = 0;
static int curfont = FONT_SYSFIXED;
+static int xoffset = 0; /* needed for flip */
-#ifndef SIMULATOR
-static
-#endif
unsigned char lcd_framebuffer[LCD_WIDTH][LCD_HEIGHT/8];
/* All zeros and ones bitmaps for area filling */
@@ -163,6 +161,25 @@ void lcd_init (void)
sizeof(scroll_stack), scroll_name);
}
+
+/* Performance function that works with an external buffer
+ note that y and height are in 8-pixel units! */
+void lcd_blit (unsigned char* p_data, int x, int y, int width, int height, int stride) __attribute__ ((section (".icode")));
+void lcd_blit (unsigned char* p_data, int x, int y, int width, int height, int stride)
+{
+ /* Copy display bitmap to hardware */
+ while (height--)
+ {
+ lcd_write (true, LCD_CNTL_PAGE | (y++ & 0xf));
+ lcd_write (true, LCD_CNTL_HIGHCOL | (((x+xoffset)>>4) & 0xf));
+ lcd_write (true, LCD_CNTL_LOWCOL | ((x+xoffset) & 0xf));
+
+ lcd_write_data(p_data, width);
+ p_data += stride;
+ }
+}
+
+
/*
* Update the display.
* This must be called after all other LCD functions that change the display.
@@ -176,8 +193,8 @@ void lcd_update (void)
for (y = 0; y < LCD_HEIGHT/8; y++)
{
lcd_write (true, LCD_CNTL_PAGE | (y & 0xf));
- lcd_write (true, LCD_CNTL_HIGHCOL);
- lcd_write (true, LCD_CNTL_LOWCOL);
+ lcd_write (true, LCD_CNTL_HIGHCOL | ((xoffset>>4) & 0xf));
+ lcd_write (true, LCD_CNTL_LOWCOL | (xoffset & 0xf));
for (x = 0; x < LCD_WIDTH; x++)
lcd_write (false, lcd_framebuffer[x][y]);
@@ -210,8 +227,8 @@ void lcd_update_rect (int x_start, int y,
for (; y <= ymax; y++)
{
lcd_write (true, LCD_CNTL_PAGE | (y & 0xf));
- lcd_write (true, LCD_CNTL_HIGHCOL | ((x_start>>4) & 0xf));
- lcd_write (true, LCD_CNTL_LOWCOL | (x_start & 0xf));
+ lcd_write (true, LCD_CNTL_HIGHCOL | (((x_start+xoffset)>>4) & 0xf));
+ lcd_write (true, LCD_CNTL_LOWCOL | ((x_start+xoffset) & 0xf));
for (x = x_start; x < xmax; x++)
lcd_write (false, lcd_framebuffer[x][y]);
@@ -232,6 +249,23 @@ void lcd_set_invert_display(bool yesno)
lcd_write(true, LCD_SET_NORMAL_DISPLAY);
}
+/* turn the display upside down (call lcd_update() afterwards) */
+void lcd_set_flip(bool yesno)
+{
+ if (yesno)
+ {
+ lcd_write(true, LCD_SET_SEGMENT_REMAP);
+ lcd_write(true, LCD_SET_COM_OUTPUT_SCAN_DIRECTION);
+ xoffset = 132 - LCD_WIDTH; /* 132 colums minus the 112 we have */
+ }
+ else
+ {
+ lcd_write(true, LCD_SET_SEGMENT_REMAP | 0x01);
+ lcd_write(true, LCD_SET_COM_OUTPUT_SCAN_DIRECTION | 0x08);
+ xoffset = 0;
+ }
+}
+
/**
* Rolls up the lcd display by the specified amount of lines.
* Lines that are rolled out over the top of the screen are
diff --git a/firmware/drivers/lcd.c b/firmware/drivers/lcd.c
index 3f6acee..aaa93b3 100644
--- a/firmware/drivers/lcd.c
+++ b/firmware/drivers/lcd.c
@@ -173,3 +173,116 @@ void lcd_write(bool command, int byte)
: /* %0 */ "I"(LCD_CS|LCD_DS|LCD_SD|LCD_SC),
/* %1 */ "z"(LCDR));
}
+
+
+/* A high performance function to write data to the display,
+ one or multiple bytes.
+ Ultimately, all calls to lcd_write(false, xxx) should be substituted by
+ this, it will be most efficient if the LCD buffer is tilted to have the
+ X row as consecutive bytes, so we can write a whole row */
+/* FixMe: somehow the red LED is affected by this, although I don't touch
+ any other bit. Therefore not used yet, except for lcd_blit() */
+void lcd_write_data(unsigned char* p_bytes, int count) __attribute__ ((section (".icode")));
+void lcd_write_data(unsigned char* p_bytes, int count)
+{
+ do
+ {
+ unsigned byte;
+ unsigned sda1; /* precalculated SC=low,SD=1 */
+ unsigned clk0sda0; /* precalculated SC and SD low */
+
+ cli(); /* make port modifications atomic */
+
+ /* precalculate the values for later bit toggling, init data write */
+ asm (
+ "mov.b @%2,%0\n" /* sda1 = PBDRL */
+ "or %4,%0\n" /* sda1 |= LCD_DS | LCD_SD DS and SD high, */
+ "and %3,%0\n" /* sda1 &= ~(LCD_CS | LCD_SC) CS and SC low */
+ "mov %0,%1\n" /* sda1 -> clk0sda0 */
+ "and %5,%1\n" /* clk0sda0 &= ~LCD_SD both low */
+ "mov.b %1,@%2\n" /* PBDRL = clk0sda0 */
+ : // outputs
+ /* %0 */ "=r"(sda1),
+ /* %1 */ "=r"(clk0sda0)
+ : // inputs
+ /* %2 */ "r"(LCDR),
+ /* %3 */ "r"(~(LCD_CS | LCD_SC)),
+ /* %4 */ "r"(LCD_DS | LCD_SD),
+ /* %5 */ "r"(~LCD_SD)
+ );
+
+ byte = *p_bytes++ << 24; /* fetch to MSB position */
+
+ /* unrolled loop to serialize the byte */
+ asm (
+ "mov %4,r0\n" /* we need &PBDRL in r0 for "or.b x,@(r0,gbr)" */
+
+ "shll %0\n" /* shift the MSB into carry */
+ "bf 1f\n"
+ "mov.b %1,@%4\n" /* if it was a "1": set SD high, SC low still */
+ "1: \n"
+ "or.b %2, @(r0,gbr)\n" /* rise SC (independent of SD level) */
+ "shll %0\n" /* shift for next round, now for longer hold time */
+ "mov.b %3,@%4\n" /* SC and SD low again */
+
+ "bf 1f\n"
+ "mov.b %1,@%4\n"
+ "1: \n"
+ "or.b %2, @(r0,gbr)\n"
+ "shll %0\n"
+ "mov.b %3,@%4\n"
+
+ "bf 1f\n"
+ "mov.b %1,@%4\n"
+ "1: \n"
+ "or.b %2, @(r0,gbr)\n"
+ "shll %0\n"
+ "mov.b %3,@%4\n"
+
+ "bf 1f\n"
+ "mov.b %1,@%4\n"
+ "1: \n"
+ "or.b %2, @(r0,gbr)\n"
+ "shll %0\n"
+ "mov.b %3,@%4\n"
+
+ "bf 1f\n"
+ "mov.b %1,@%4\n"
+ "1: \n"
+ "or.b %2, @(r0,gbr)\n"
+ "shll %0\n"
+ "mov.b %3,@%4\n"
+
+ "bf 1f\n"
+ "mov.b %1,@%4\n"
+ "1: \n"
+ "or.b %2, @(r0,gbr)\n"
+ "shll %0\n"
+ "mov.b %3,@%4\n"
+
+ "bf 1f\n"
+ "mov.b %1,@%4\n"
+ "1: \n"
+ "or.b %2, @(r0,gbr)\n"
+ "shll %0\n"
+ "mov.b %3,@%4\n"
+
+ "bf 1f\n"
+ "mov.b %1,@%4\n"
+ "1: \n"
+ "or.b %2, @(r0,gbr)\n"
+
+ "or.b %5, @(r0,gbr)\n" /* restore port */
+ :
+ : /* %0 */ "r"(byte),
+ /* %1 */ "r"(sda1),
+ /* %2 */ "I"(LCD_SC),
+ /* %3 */ "r"(clk0sda0),
+ /* %4 */ "r"(LCDR),
+ /* %5 */ "I"(LCD_CS|LCD_DS|LCD_SD|LCD_SC)
+ );
+
+ sti();
+
+ } while (--count); /* tail loop is faster */
+}
diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h
index c4632a0..c81d2de 100644
--- a/firmware/export/lcd.h
+++ b/firmware/export/lcd.h
@@ -44,10 +44,13 @@ extern void lcd_scroll_speed( int speed );
extern void lcd_scroll_delay( int ms );
extern void lcd_set_contrast(int val);
extern void lcd_write( bool command, int byte );
+extern void lcd_write_data( unsigned char* p_bytes, int count );
extern int lcd_default_contrast(void);
#if defined(SIMULATOR) || defined(HAVE_LCD_BITMAP)
extern void lcd_update(void);
+/* performance function */
+extern void lcd_blit (unsigned char* p_data, int x, int y, int width, int height, int stride);
/* update a fraction of the screen */
extern void lcd_update_rect(int x, int y, int width, int height);
@@ -134,6 +137,7 @@ extern void lcd_clearpixel(int x, int y);
extern void lcd_invertpixel(int x, int y);
extern void lcd_roll(int pixels);
extern void lcd_set_invert_display(bool yesno);
+extern void lcd_set_flip(bool yesno);
extern void lcd_bidir_scroll(int threshold);
extern void lcd_scroll_step(int pixels);
extern void lcd_setfont(int font);