diff lcd.c @ 9:be0a1ac64d97

- Add ellipse drawing. - Factor out stripe drawing to a function. - Rename LCD functions to match other code. - Add filled circles. - Rotate coords for landsacpe.
author Daniel O'Connor <darius@dons.net.au>
date Sun, 05 Feb 2012 16:41:42 +1030
parents 58d76cf522ff
children
line wrap: on
line diff
--- a/lcd.c	Sat Feb 04 13:29:31 2012 +1030
+++ b/lcd.c	Sun Feb 05 16:41:42 2012 +1030
@@ -57,6 +57,8 @@
 
 #include <stdio.h>
 #include <stdint.h>
+#include <stdlib.h>
+#include <ctype.h>
 #include "stm32f10x.h"
 #include "lcd.h"
 #include "delay.h"
@@ -64,20 +66,30 @@
 #define Bank1_LCD_C	((uint32_t)0x60000000)    /* Register Address */
 #define Bank1_LCD_D	((uint32_t)0x60020000)    /* Data Address */
 
+#define COLINCVAL 7968 /* 255.0 / 320.0 * 10000 */
+
+void colinc(uint16_t *mag, uint16_t *err, uint16_t amt, uint16_t max) {
+	*err += amt;
+	if (*err > max) {
+		(*mag) = (*mag) + 1;
+		(*err) = (*err) - max;
+	}
+}
+
 void
-lcd_wr_reg(uint16_t index, uint16_t val) {
+lcd_writereg(uint16_t index, uint16_t val) {
     *(__IO uint16_t *)(Bank1_LCD_C) = index;
     *(__IO uint16_t *)(Bank1_LCD_D) = val;
 }
 
 uint16_t
-lcd_rd_reg(uint16_t index) {
+lcd_readreg(uint16_t index) {
     *(__IO uint16_t *)(Bank1_LCD_C) = index;
     return(*(__IO uint16_t *)(Bank1_LCD_D));
 }
 
 uint16_t
-lcd_rd_data(int first) {
+lcd_readdata(int first) {
     uint16_t a = 0;
     if (first)
 	a = *(__IO uint16_t *) (Bank1_LCD_D); 	/* Dummy */
@@ -87,14 +99,14 @@
 }
 
 void
-lcd_wr_startdata(uint16_t x, uint16_t y) {
-    lcd_wr_reg(0x20, x);
-    lcd_wr_reg(0x21, y);
+lcd_startgram(uint16_t x, uint16_t y) {
+    lcd_writereg(0x20, x);
+    lcd_writereg(0x21, y);
     *(__IO uint16_t *)(Bank1_LCD_C) = 0x22;	/* Start GRAM write */
 }
 
 void
-lcd_wr_data(uint16_t val) {
+lcd_writedata(uint16_t val) {
     *(__IO uint16_t *)(Bank1_LCD_D) = val;
 }
 
@@ -114,7 +126,7 @@
 
 void
 lcd_init(void) {
-    uint16_t				id;
+    uint16_t	id, x, y;
 
     /* Initialise LCD panel */
 
@@ -125,124 +137,115 @@
     GPIO_SetBits(GPIOE, GPIO_Pin_1);
     delay(50);
 
-    id = lcd_rd_reg(0x00);
+    id = lcd_readreg(0x00);
     if (id != 0x9325) {
 	printf("LCD ID doesn't match, expected 0x9325 got 0x%x\r\n", id);
 	return;
     }
     printf("LCD ID matches\r\n");
     
-    lcd_wr_reg(0x00e3, 0x3008); /* Set internal timing (not documented) */
-    lcd_wr_reg(0x00e7, 0x0012); /* Set internal timing (not documented) */
-    lcd_wr_reg(0x00ef, 0x1231); /* Set internal timing (not documented) */
-    lcd_wr_reg(0x0000, 0x0001); /* Start Oscillation */
+    lcd_writereg(0x00e3, 0x3008); /* Set internal timing (not documented) */
+    lcd_writereg(0x00e7, 0x0012); /* Set internal timing (not documented) */
+    lcd_writereg(0x00ef, 0x1231); /* Set internal timing (not documented) */
+    lcd_writereg(0x0000, 0x0001); /* Start Oscillation */
     delay(50);
-    lcd_wr_reg(0x0001, 0x0100); /* set SS (S720 -> S1) */
-    lcd_wr_reg(0x0002, 0x0700); /* set line inversion (B/C + EOR) */
-    lcd_wr_reg(0x0004, 0x0000); /* no resizing */
-    lcd_wr_reg(0x0008, 0x0202); /* set the back porch and front porch (2 lines each) */
-    lcd_wr_reg(0x0009, 0x0000); /* set non-display area refresh cycle ISC[3:0] */
-    lcd_wr_reg(0x000a, 0x0000); /* FMARK function */
+    lcd_writereg(0x0001, 0x0100); /* set SS (S720 -> S1) */
+    lcd_writereg(0x0002, 0x0700); /* set line inversion (B/C + EOR) */
+    lcd_writereg(0x0004, 0x0000); /* no resizing */
+    lcd_writereg(0x0008, 0x0202); /* set the back porch and front porch (2 lines each) */
+    lcd_writereg(0x0009, 0x0000); /* set non-display area refresh cycle ISC[3:0] */
+    lcd_writereg(0x000a, 0x0000); /* FMARK function */
 
-    lcd_wr_reg(0x000c, 0x0000); /* RGB ctl - Internal clock, 18bit interface */
-    lcd_wr_reg(0x000d, 0x0000); /* Frame marker Position */
-    lcd_wr_reg(0x000f, 0x0000); /* RGB interface polarity */
+    lcd_writereg(0x000c, 0x0000); /* RGB ctl - Internal clock, 18bit interface */
+    lcd_writereg(0x000d, 0x0000); /* Frame marker Position */
+    lcd_writereg(0x000f, 0x0000); /* RGB interface polarity */
 
     /* Power On sequence  */
-    lcd_wr_reg(0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */
-    lcd_wr_reg(0x0011, 0x0007); /* DC1[2:0], DC0[2:0], VC[2:0] */
-    lcd_wr_reg(0x0012, 0x0000); /* VREG1OUT voltage */
-    lcd_wr_reg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */
+    lcd_writereg(0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */
+    lcd_writereg(0x0011, 0x0007); /* DC1[2:0], DC0[2:0], VC[2:0] */
+    lcd_writereg(0x0012, 0x0000); /* VREG1OUT voltage */
+    lcd_writereg(0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */
     delay(200);                 /* Dis-charge capacitor power voltage */
-    lcd_wr_reg(0x0010, 0x1690); /* SAP, BT[3:0], AP, DSTB, SLP, STB */
-    lcd_wr_reg(0x0011, 0x0227); /* R11h = 0x0221 at VCI = 3.3V, DC1[2:0], DC0[2:0], VC[2:0] */
+    lcd_writereg(0x0010, 0x1690); /* SAP, BT[3:0], AP, DSTB, SLP, STB */
+    lcd_writereg(0x0011, 0x0227); /* R11h = 0x0221 at VCI = 3.3V, DC1[2:0], DC0[2:0], VC[2:0] */
     delay(50);                  /* delay 50ms */
-    lcd_wr_reg(0x0012, 0x001c); /* External reference voltage= Vci; */
+    lcd_writereg(0x0012, 0x001c); /* External reference voltage= Vci; */
     delay(50);                  /* delay 50ms */
-    lcd_wr_reg(0x0013, 0x1800); /* R13 = 1200 when R12 = 009D; VDV[4:0] for VCOM amplitude */
-    lcd_wr_reg(0x0029, 0x001c); /* R29 = 000C when R12 = 009D; VCM[5:0] for VCOMH */
-    lcd_wr_reg(0x002b, 0x000d); /* Frame Rate = 91Hz */
+    lcd_writereg(0x0013, 0x1800); /* R13 = 1200 when R12 = 009D; VDV[4:0] for VCOM amplitude */
+    lcd_writereg(0x0029, 0x001c); /* R29 = 000C when R12 = 009D; VCM[5:0] for VCOMH */
+    lcd_writereg(0x002b, 0x000d); /* Frame Rate = 91Hz */
     delay(50);                  /* delay 50ms */
 
     /* Set GRAM area */
-    lcd_wr_reg(0x0050, 0x0000); /* Horizontal GRAM Start Address */
-    lcd_wr_reg(0x0051, 0x00ef); /* Horizontal GRAM End Address */
-    lcd_wr_reg(0x0052, 0x0000); /* Vertical GRAM Start Address */
-    lcd_wr_reg(0x0053, 0x013f); /* Vertical GRAM Start Address */
+    lcd_writereg(0x0050, 0x0000); /* Horizontal GRAM Start Address */
+    lcd_writereg(0x0051, 0x00ef); /* Horizontal GRAM End Address */
+    lcd_writereg(0x0052, 0x0000); /* Vertical GRAM Start Address */
+    lcd_writereg(0x0053, 0x013f); /* Vertical GRAM Start Address */
 
-    lcd_wr_reg(0x0060, 0xa700); /* Gate Scan Line, drive G320 -> G1 */
-    lcd_wr_reg(0x0061, 0x0003); /* VLE & REV */
-    lcd_wr_reg(0x006a, 0x0000); /* set scrolling line */
+    lcd_writereg(0x0060, 0xa700); /* Gate Scan Line, drive G320 -> G1 */
+    lcd_writereg(0x0061, 0x0003); /* VLE & REV */
+    lcd_writereg(0x006a, 0x0000); /* set scrolling line */
 
     /* Partial Display Control */
-    lcd_wr_reg(0x0080, 0x0000); /* Image 1 */
-    lcd_wr_reg(0x0081, 0x0000);
-    lcd_wr_reg(0x0082, 0x0000);
-    lcd_wr_reg(0x0083, 0x0000); /* Image 2 */
-    lcd_wr_reg(0x0084, 0x0000);
-    lcd_wr_reg(0x0085, 0x0000);
+    lcd_writereg(0x0080, 0x0000); /* Image 1 */
+    lcd_writereg(0x0081, 0x0000);
+    lcd_writereg(0x0082, 0x0000);
+    lcd_writereg(0x0083, 0x0000); /* Image 2 */
+    lcd_writereg(0x0084, 0x0000);
+    lcd_writereg(0x0085, 0x0000);
 
     /* Panel Control */
-    lcd_wr_reg(0x0090, 0x0010);
-    lcd_wr_reg(0x0092, 0x0000);
-    lcd_wr_reg(0x0093, 0x0003);
-    lcd_wr_reg(0x0095, 0x0110);
-    lcd_wr_reg(0x0097, 0x0000); /* Undocumented */
-    lcd_wr_reg(0x0098, 0x0000); /* Undocumented */
+    lcd_writereg(0x0090, 0x0010);
+    lcd_writereg(0x0092, 0x0000);
+    lcd_writereg(0x0093, 0x0003);
+    lcd_writereg(0x0095, 0x0110);
+    lcd_writereg(0x0097, 0x0000); /* Undocumented */
+    lcd_writereg(0x0098, 0x0000); /* Undocumented */
 
-    lcd_wr_reg(0x0007, 0x0133); /* Display on, 262k colour mode (vs 8) */
+    lcd_writereg(0x0007, 0x0133); /* Display on, 262k colour mode (vs 8) */
 
-    lcd_wr_reg(0x0003, 0x1030); /* set GRAM write direction and enable BGR, 64K colours, 1 transfers/pixel. */
+    lcd_writereg(0x0003, 0x1030); /* set GRAM write direction and enable BGR, 64K colours, 1 transfers/pixel. */
 
     /* Adjust the Gamma Curve */
-    lcd_wr_reg(0x0030, 0x0006);
-    lcd_wr_reg(0x0031, 0x0101);
-    lcd_wr_reg(0x0032, 0x0003);
-    lcd_wr_reg(0x0035, 0x0106);
-    lcd_wr_reg(0x0036, 0x0b02);
-    lcd_wr_reg(0x0037, 0x0302);
-    lcd_wr_reg(0x0038, 0x0707);
-    lcd_wr_reg(0x0039, 0x0007);
-    lcd_wr_reg(0x003c, 0x0600);
-    lcd_wr_reg(0x003d, 0x020b);
+    lcd_writereg(0x0030, 0x0006);
+    lcd_writereg(0x0031, 0x0101);
+    lcd_writereg(0x0032, 0x0003);
+    lcd_writereg(0x0035, 0x0106);
+    lcd_writereg(0x0036, 0x0b02);
+    lcd_writereg(0x0037, 0x0302);
+    lcd_writereg(0x0038, 0x0707);
+    lcd_writereg(0x0039, 0x0007);
+    lcd_writereg(0x003c, 0x0600);
+    lcd_writereg(0x003d, 0x020b);
 
     fputs("Testing\r\n", stdout);
-    lcd_wr_startdata(0, 0);
-    lcd_wr_data(0xa5a5);
-    lcd_wr_data(0x5a5a);
-    lcd_wr_startdata(0, 0);
-    if ((id = lcd_rd_data(1)) != 0xa5a5)
+    lcd_startgram(0, 0);
+    lcd_writedata(0xa5a5);
+    lcd_writedata(0x5a5a);
+    lcd_startgram(0, 0);
+    if ((id = lcd_readdata(1)) != 0xa5a5)
 	printf("Expected 0xa5a5 got 0x%04x\r\n", id);
     
-    if ((id = lcd_rd_data(0)) != 0x5a5a)
+    if ((id = lcd_readdata(0)) != 0x5a5a)
 	printf("Expected 0x5a5a got 0x%04x\r\n", id);
 
     fputs("Filling\r\n", stdout);
     /* Fill panel */
-    lcd_wr_startdata(0, 0);
+    lcd_startgram(0, 0);
 
-    for (int x = 0; x < 320; x++) {
-	for (int y = 0; y < 240; y++) {
-	    if (((x / 5) % 3) == 0)
-		lcd_wr_data(LCD_RED);
-	    else if (((x / 5) % 3) == 1)
-		lcd_wr_data(LCD_GREEN);
-	    else
-		lcd_wr_data(LCD_BLUE);
-	}
-    }
-
-    lcd_circle(50, 50, 20, LCD_BLACK);
-
+    for (y = 0; y < 320; y++)
+	for (x = 0; x < 240; x++)
+	    lcd_writedata(LCD_BLACK);
 }
 
 void
 lcd_pixel(uint16_t x, uint16_t y, uint16_t colour) {
-    if (x > LCD_HEIGHT || y > LCD_WIDTH)
+    if (x > LCD_WIDTH || y > LCD_HEIGHT)
 	return;
 
-    lcd_wr_startdata(x, y);
-    lcd_wr_data(colour);
+    /* Rotate for landscape */
+    lcd_startgram(y, x);
+    lcd_writedata(colour);
 }
 
 /* 
@@ -250,7 +253,7 @@
  * From http://en.wikipedia.org/wiki/Midpoint_circle_algorithm 
  */
 void
-lcd_circle(uint16_t x0, uint16_t y0, uint16_t radius, uint16_t colour) {
+lcd_circle(uint16_t x0, uint16_t y0, uint16_t radius, uint8_t fill, uint16_t colour) {
     int16_t	f;
     uint16_t	ddF_x, ddF_y, x, y;
     
@@ -260,15 +263,18 @@
     x = 0;
     y = radius;
  
-    lcd_pixel(x0, y0 + radius, colour);
-    lcd_pixel(x0, y0 - radius, colour);
-    lcd_pixel(x0 + radius, y0, colour);
-    lcd_pixel(x0 - radius, y0, colour);
- 
+
+    if (fill) {
+	lcd_line(x0, y0 + radius, x0, y0 - radius, colour);
+	lcd_line(x0 + radius, y0, x0 - radius, y0, colour);
+    } else {
+	lcd_pixel(x0, y0 + radius, colour);
+	lcd_pixel(x0, y0 - radius, colour);
+	lcd_pixel(x0 + radius, y0, colour);
+	lcd_pixel(x0 - radius, y0, colour);
+    }
+    
     while(x < y) {
-	// ddF_x == 2 * x + 1;
-	// ddF_y == -2 * y;
-	// f == x*x + y*y - radius*radius + 2*x - y + 1;
 	if(f >= 0) {
 	    y--;
 	    ddF_y += 2;
@@ -277,14 +283,21 @@
 	x++;
 	ddF_x += 2;
 	f += ddF_x;    
-	lcd_pixel(x0 + x, y0 + y, colour);
-	lcd_pixel(x0 - x, y0 + y, colour);
-	lcd_pixel(x0 + x, y0 - y, colour);
-	lcd_pixel(x0 - x, y0 - y, colour);
-	lcd_pixel(x0 + y, y0 + x, colour);
-	lcd_pixel(x0 - y, y0 + x, colour);
-	lcd_pixel(x0 + y, y0 - x, colour);
-	lcd_pixel(x0 - y, y0 - x, colour);
+	if (fill) {
+	    lcd_line(x0 + x, y0 + y, x0 - x, y0 + y, colour);
+	    lcd_line(x0 + x, y0 - y, x0 - x, y0 - y, colour);
+	    lcd_line(x0 + y, y0 + x, x0 - y, y0 + x, colour);
+	    lcd_line(x0 + y, y0 - x, x0 - y, y0 - x, colour);
+	} else {
+	    lcd_pixel(x0 + x, y0 + y, colour);
+	    lcd_pixel(x0 - x, y0 + y, colour);
+	    lcd_pixel(x0 + x, y0 - y, colour);
+	    lcd_pixel(x0 - x, y0 - y, colour);
+	    lcd_pixel(x0 + y, y0 + x, colour);
+	    lcd_pixel(x0 - y, y0 + x, colour);
+	    lcd_pixel(x0 + y, y0 - x, colour);
+	    lcd_pixel(x0 - y, y0 - x, colour);
+	}
     }
 }
 
@@ -295,23 +308,132 @@
  */
 void
 lcd_line(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t colour) {
-    uint16_t dx, dy, d, x, y;
-
-    dx = x1 - x0;
-    dy = y1 - y0;
+    uint16_t	dx, dy;
+    int16_t	sx, sy, err, e2;
+    
+    dx = abs(x1 - x0);
+    dy = abs(y1 - y0);
     
-    d = 2 * dy - dx;
-    lcd_pixel(x0, y0, colour);
-    y = y0;
+    if (x0 < x1) 
+	sx = 1;
+    else
+	sx = -1;
+    
+    if (y0 < y1)
+	sy = 1;
+    else
+	sy = -1;
     
-    for (x = x0 + 1; x <= x1; x++) {
-	if (d > 0) {
-	    y++;
-	    lcd_pixel(x, y, colour);
-	    d += 2 * dy - 2 * dx;
-	} else {
-	    lcd_pixel(x, y, colour);
-	    d += 2 * dy;
+    err = dx - dy;
+ 
+    while (1) {
+
+	lcd_pixel(x0, y0, colour);
+
+	if (x0 == x1 && y0 == y1)
+	    break;
+	
+	e2 = 2 * err;
+	
+	if (e2 > -dy) {
+	    err = err - dy;
+	    x0 = x0 + sx;
+	}
+	
+	if (e2 <  dx) {
+	    err = err + dx;
+	    y0 = y0 + sy;
 	}
     }
 }
+
+static void
+_lcd_ellipsedraw(uint16_t xc, uint16_t yc, uint16_t x, uint16_t y, uint8_t fill, uint16_t colour) {
+    if (fill) {
+	lcd_line(xc + x, yc + y, xc - x, yc + y, colour);
+	lcd_line(xc - x, yc - y, xc + x, yc - y, colour);
+    } else {
+	lcd_pixel(xc + x, yc + y, colour);	/* 1st quadrant */
+	lcd_pixel(xc - x, yc + y, colour);	/* 2nd quadrant */
+	lcd_pixel(xc - x, yc - y, colour);	/* 3rd quadrant */
+	lcd_pixel(xc + x, yc - y, colour);	/* 4th quadrant */
+    }
+}
+
+/* Draw an ellipse, from
+ * http://rooparam.blogspot.com.au/2009/09/midpoint-ellipse-algorithm.html
+ */
+void lcd_ellipse(int xc, int yc, int rx, int ry, uint8_t fill, uint16_t colour) {
+    long long int rx_2 = rx * rx, ry_2 = ry * ry;
+    long long int p = ry_2 - rx_2 * ry + (ry_2 >> 2);
+    int x = 0, y = ry;
+    long long int two_ry_2_x = 0, two_rx_2_y = (rx_2 << 1) * y;
+
+    _lcd_ellipsedraw(xc, yc, x, y, fill, colour);
+
+    while (two_rx_2_y >= two_ry_2_x) {
+	x++;
+	two_ry_2_x += ry_2 << 1;
+         
+	p += two_ry_2_x + ry_2;
+            
+	if (p >= 0){
+	    y--;
+	    two_rx_2_y -= rx_2 << 1;
+              
+	    p -= two_rx_2_y;
+	}
+	_lcd_ellipsedraw(xc, yc, x, y, fill, colour);
+    }
+   
+    p = (long long int)(ry_2 * (x + 1 / 2.0) * (x + 1 / 2.0) + rx_2 * (y - 1) * (y - 1) - rx_2 * ry_2);
+    while (y >= 0) {
+	p += rx_2;
+	y--;
+	two_rx_2_y -= rx_2 << 1;
+	p -= two_rx_2_y;
+         
+	if (p <= 0) {
+	    x++;
+	    two_ry_2_x += ry_2 << 1;
+	    p += two_ry_2_x;
+	}
+	_lcd_ellipsedraw(xc, yc, x, y, fill, colour);
+    }
+}
+
+void lcd_stripes(void) {
+    uint16_t	x, y, mag, err;
+
+    lcd_startgram(0, 0);
+
+    mag = err = 0;
+    for (y = 0; y < 320; y++) {
+	for (x = 0; x < 240; x++) {
+	    if (((x / 80) % 3) == 0) {
+		lcd_writedata(RGB24_565(mag, 0, 0));
+	    } else if (((x / 80) % 3) == 1) {
+		lcd_writedata(RGB24_565(0, mag, 0));
+	    } else {
+		lcd_writedata(RGB24_565(0, 0, mag));
+	    }
+	}
+	colinc(&mag, &err, COLINCVAL, 10000);
+    }
+}
+uint16_t
+lcd_parsecol(char c) {
+    c = toupper(c);
+    if (c == 'R')
+	return(LCD_RED);
+    else if (c == 'G')
+	return(LCD_GREEN);
+    else if (c == 'B')
+	return(LCD_BLUE);
+    else if (c == 'L')
+	return(LCD_BLACK);
+    else
+	return(LCD_WHITE);
+
+}
+