Mercurial > ~darius > hgwebdir.cgi > stm32test
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); + +} +