view lcd.c @ 80:1a4573062b37

Reshuffle in preparation for being able to have a common API for SPI flash and (emulated) EEPROM.
author Daniel O'Connor <darius@dons.net.au>
date Sun, 07 Jul 2013 22:49:02 +0930
parents 662e7f01c991
children
line wrap: on
line source

/*
 * Example code (I think)
 * ~/projects/STM32Strive/奋斗STM32开发板例程/奋斗STM32开发板例程/奋斗STM32开发板MINI/STM32奋斗版ucOS II V2.86 uCGUI 3.9 DEMO-V2/STM32奋斗版ucOS II V2.86 uCGUI 3.9 DEMO
 *
 * Schematics
 * Main board docs/Strive\ Mini\ STM32\ Schematic.pdf 
 * LCD board docs/Strive Mini LCD STM32 Schematic.pdf
 * MCU reference manual docs/CD00171190.pdf
 * MCU Data sheet (pinout) docs/CD00191185.pdf
 * LCD controller data sheet docs/ili9325-v0.35.pdf
 * LCD controller app notes docs/ILI9325AN_V0.22.pdf
 * XXX: not sure what panel is connected
 * 
 */
/*	LCD board	MCU
  1	VCC		
  2	TC_SCK		PA5/SPI1_SCK
  3	GND		
  4	TC_CS		PB7/SPI1_CS3
  5	RST		PE1 FSMC_NBL1? (unlikely)
  6	TC_DIN		PA7/SPI1_MOSI
  7	nOE		PD4/FSMC_nOE
  8    	TC_DOUT		PA6/SPI1_MISO
  9	nWR		PD5/FSMC_nWE
  10	TC_INT		PB6
  11	CS		PD7/FSMC_NE1/FSMC_NCE2
  12	NC		
  13	RS		PD11/FSMC_A16
  14	NC		
  15	D7		PE10/FSMC_D7
  16	NC		
  17	D6		PE9/FSMC_D6
  18	NC		
  19	D3		PD1/FSMC_D3
  20	D13		PD8/FSMC_D13
  21	D5		PE8/FSMC_D5
  22	D12		PE15/FSMC_D12
  23	D4		PE7/FSMC_D4
  24	GND		
  25	NC		
  26	D11		PE14/FSMC_D11
  27	D2		PD0/FSMC_D2
  28	D10		PE13/FSMC_D10
  29	D1		PD15/FSMC_D1
  30	D9		PE12/FSMC_D9
  31	D0		PD14/FSMC_D0
  32	D14		PD9/FSMC_D14
  33	NC		
  34	D8		PE11/FSMC_D8
  35	NC		
  36	NC		
  37	NC		
  38	LCD_PWM		PD13/TIM4_CH2
  39	NC		
  40	D15		PD10/FSMC_D15
*/

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <ctype.h>
#include "stm32f10x.h"
#include "lcd.h"
#include "delay.h"

#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_writereg(uint16_t index, uint16_t val) {
    *(__IO uint16_t *)(Bank1_LCD_C) = index;
    *(__IO uint16_t *)(Bank1_LCD_D) = val;
}

uint16_t
lcd_readreg(uint16_t index) {
    *(__IO uint16_t *)(Bank1_LCD_C) = index;
    return(*(__IO uint16_t *)(Bank1_LCD_D));
}

uint16_t
lcd_readdata(int first) {
    uint16_t a = 0;
    if (first)
	a = *(__IO uint16_t *) (Bank1_LCD_D); 	/* Dummy */
    a = *(__IO uint16_t *) (Bank1_LCD_D); 	/* Read */

    return (a);
}

void
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_writedata(uint16_t val) {
    *(__IO uint16_t *)(Bank1_LCD_D) = val;
}

void
lcd_setpwm(uint16_t val) {
    TIM_OCInitTypeDef			TIM_OCInitStructure;

    /* Channel 2 configuration in PWM mode */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = val;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

    TIM_OC2Init(TIM4, &TIM_OCInitStructure);

}

void
lcd_init(void) {
    uint16_t	id, x, y;

    /* Initialise LCD panel */

    /* Pull reset pin low */
    GPIO_SetBits(GPIOE, GPIO_Pin_1);
    delay(10);
    GPIO_ResetBits(GPIOE, GPIO_Pin_1);
    delay(2000);
    GPIO_SetBits(GPIOE, GPIO_Pin_1);
    delay(500);

    id = lcd_readreg(0x00);
    if (id != 0x9325) {
	printf("LCD ID doesn't match, expected 0x9325 got 0x%x\n", id);
	return;
    }
    printf("LCD ID matches\n");
    
    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(50000);
    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_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_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(200000);  		  /* Dis-charge capacitor power voltage */
    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(50000);                 /* delay 50ms */
    lcd_writereg(0x0012, 0x001c); /* External reference voltage= Vci; */
    delay(50000);                 /* delay 50ms */
    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(50000);                 /* delay 50ms */

    /* Set GRAM area */
    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_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_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_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_writereg(0x0007, 0x0133); /* Display on, 262k colour mode (vs 8) */

    lcd_writereg(0x0003, 0x1030); /* set GRAM write direction and enable BGR, 64K colours, 1 transfers/pixel. */

    /* Adjust the Gamma Curve */
    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("Filling\n", stdout);
    /* Fill panel */
    lcd_startgram(0, 0);

    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_WIDTH || y > LCD_HEIGHT)
	return;

    /* Rotate for landscape */
    lcd_startgram(y, x);
    lcd_writedata(colour);
}

/* 
 * Draw a circle
 * From http://en.wikipedia.org/wiki/Midpoint_circle_algorithm 
 */
void
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;
    
    f = 1 - radius;
    ddF_x = 1;
    ddF_y = -2 * radius;
    x = 0;
    y = radius;
 

    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) {
	if(f >= 0) {
	    y--;
	    ddF_y += 2;
	    f += ddF_y;
	}
	x++;
	ddF_x += 2;
	f += ddF_x;    
	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);
	}
    }
}


/*
 * Draw a line
 * From http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
 */
void
lcd_line(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t colour) {
    uint16_t	dx, dy;
    int16_t	sx, sy, err, e2;
    
    dx = abs(x1 - x0);
    dy = abs(y1 - y0);
    
    if (x0 < x1) 
	sx = 1;
    else
	sx = -1;
    
    if (y0 < y1)
	sy = 1;
    else
	sy = -1;
    
    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);

}