changeset 4:2c87e30c982d

Add LCD init, touch screen writing etc.. PWM of LCD backlight doesn't work yet though..
author Daniel O'Connor <darius@dons.net.au>
date Tue, 03 Jan 2012 22:37:18 +1030
parents 74e9b3baac1e
children efa2c22266e3
files BSDmakefile docs/SST25VF016B.pdf lcd.c lcd.h main.c
diffstat 5 files changed, 480 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/BSDmakefile	Sun Jan 01 11:01:13 2012 +1030
+++ b/BSDmakefile	Tue Jan 03 22:37:18 2012 +1030
@@ -9,7 +9,7 @@
 		syscalls.c \
 		system_stm32f10x.c \
 
-STM32LIBS=	usart gpio rcc rtc pwr bkp fsmc
+STM32LIBS=	usart gpio rcc rtc pwr bkp fsmc spi tim
 
 .for f in ${STM32LIBS}
 SRCS+=		stm32f10x_${f}.c
Binary file docs/SST25VF016B.pdf has changed
--- a/lcd.c	Sun Jan 01 11:01:13 2012 +1030
+++ b/lcd.c	Tue Jan 03 22:37:18 2012 +1030
@@ -55,14 +55,185 @@
   40	D15		PD10/FSMC_D15
 */
 
+#include <stdio.h>
 #include "stm32f10x.h"
 #include "lcd.h"
 
+#define Bank1_LCD_C	((uint32_t)0x60000000)    /* Register Address */
+#define Bank1_LCD_D	((uint32_t)0x60020000)    /* Data Address */
+
+unsigned long colour1 = 0;
+
+void
+LCD_WR_Reg(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) {
+    *(__IO uint16_t *)(Bank1_LCD_C) = index;
+    return(*(__IO uint16_t *)(Bank1_LCD_D));
+}
+
+uint16_t
+LCD_RD_Data(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_WR_Data(uint16_t val) {
+    *(__IO uint16_t *)(Bank1_LCD_D) = val;
+}
+
+/* Callers imply this is in milliseconds but that seems unlikely */
+void
+Delay(__IO uint32_t nCount) {
+    for(; nCount != 0; nCount--)
+	;
+}
+
+uint8_t
+SPI_WriteByte(uint8_t out) {
+    uint8_t in = 0; 
+
+    /* Wait until the transmit buffer is empty */
+    while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET)
+	;
+    
+    /* Send the byte  */
+    SPI_I2S_SendData(SPI1, out); 
+
+    /* Wait until a data is received */
+    while (SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_RXNE) == RESET)
+	;
+    
+    /* Get the received data */
+    in = SPI_I2S_ReceiveData(SPI1); 
+
+    /* Return the shifted data */
+    return (in);
+}
+
+#define TP_SELECT()	GPIO_ResetBits(GPIOB, GPIO_Pin_7)
+#define TP_DESELECT()	GPIO_SetBits(GPIOB, GPIO_Pin_7)
+uint16_t
+TPRead(uint8_t type) { 
+    uint16_t x = 0;
+
+    /* Select device */
+    TP_SELECT();
+
+    /* Do conversion */
+    Delay(10);
+    SPI_WriteByte(type);
+
+    /* Read result */
+    Delay(10);
+    x = SPI_WriteByte(0x00);
+    x <<= 8;
+    x |= SPI_WriteByte(0x00);
+    Delay(10);
+
+    /* De-select device */
+    TP_DESELECT();
+
+    /* Right justify 12 bit result */
+    x = x >> 3;
+    return (x);
+}
+
+#define FL_SELECT()	GPIO_ResetBits(GPIOA, GPIO_Pin_4)
+#define FL_DESELECT()	GPIO_SetBits(GPIOA, GPIO_Pin_4)
+
+#define FL_READ		0x03
+#define FL_HSREAD	0x0b
+#define FL_32KERASE	0x52
+#define FL_64KERASE	0xd8
+#define FL_CHIPERASE	0x60
+#define FL_BYTEPROG	0x02
+#define FL_AAIWP	0xad
+#define FL_RDSR		0x05
+#define FL_EWSR		0x50
+#define FL_WRSR		0x01
+#define FL_WREN		0x06
+#define FL_WRDI		0x04
+#define FL_RDID		0x90
+#define FL_JEDECID	0x9f
+#define FL_EBSY		0x70
+#define FL_DBSY		0x80
+
+uint16_t
+FlashReadID(void) {
+    uint8_t	fac, dev;
+    
+    FL_SELECT();			/* Select device */
+
+    SPI_WriteByte(FL_RDID);		/* Send command */
+    SPI_WriteByte(0x00);		/* Send address cycles (ID data starts at 0) */
+    SPI_WriteByte(0x00);
+    SPI_WriteByte(0x00);
+    fac = SPI_WriteByte(0x00);		/* Read ID */
+    dev = SPI_WriteByte(0x00);
+  
+    FL_DESELECT();			/* De-select device */
+
+    return fac << 8 | dev;
+}
+
+uint8_t
+FlashReadStatus(void) {
+    uint8_t	status;
+    
+    FL_SELECT();			/* Select device */
+
+    SPI_WriteByte(FL_RDSR);		/* Send command */
+    SPI_WriteByte(0x00);		/* Send dummy byte for address cycle */
+    status = SPI_WriteByte(0x00);	/* Read status */
+  
+    FL_DESELECT();			/* De-select device */
+
+    return status;
+}
+
+void
+FlashWriteStatus(uint8_t status) {
+    /* Enable status write */
+    FL_SELECT();			/* Select device */
+    SPI_WriteByte(FL_EWSR);		/* Send command */
+    SPI_WriteByte(0x00);		/* Send data byte */
+    FL_DESELECT();
+
+    /* Actually write status */
+    FL_SELECT();			/* Re-select device for new command */			
+    SPI_WriteByte(FL_WRSR);		/* Send command */
+    SPI_WriteByte(status);		/* Send data byte */
+    FL_DESELECT();			/* De-select device */
+}
+
 void
 LCD_init(void) {
     GPIO_InitTypeDef			GPIO_InitStructure;
+    SPI_InitTypeDef			SPI_InitStructure;
     FSMC_NORSRAMInitTypeDef		FSMC_NORSRAMInitStructure;
     FSMC_NORSRAMTimingInitTypeDef	p;
+#if 0
+    TIM_TimeBaseInitTypeDef		TIM_TimeBaseStructure;
+    TIM_OCInitTypeDef			TIM_OCInitStructure;
+    TIM_BDTRInitTypeDef			TIM_BDTRInitStructure;  
+#endif
+    uint16_t				id;
+    
+    /* Enable FSMC clock */
+    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);
+
+    /* Enable GPIOD clock */
+    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
 
     /* Configures LCD Control lines (FSMC Pins) in alternate function Push-Pull mode.
      *
@@ -82,6 +253,69 @@
     GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
     GPIO_Init(GPIOE, &GPIO_InitStructure);
 
+    /* Configure backlight control (PD13/FSMC_A18 remapped to TIM4_CH2) */
+#if 0
+    /* Enable TIM4 clock */
+    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
+
+    /* Enable timer function */
+    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
+    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+    GPIO_Init(GPIOD, &GPIO_InitStructure);
+
+    /* Remap TIM4_CH2 to PD13 */
+    GPIO_PinRemapConfig(GPIO_Remap_TIM4, ENABLE);
+    
+    /* Reset TIM4 */
+    TIM_DeInit(TIM4);
+
+    /* Time Base configuration */
+    TIM_TimeBaseStructure.TIM_Prescaler = 0x00;
+    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
+    TIM_TimeBaseStructure.TIM_Period = 0x8000;
+    TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;
+    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0;
+    TIM_TimeBaseInit(TIM4 ,&TIM_TimeBaseStructure);
+
+    /* Channel 1, 2, 3 and 4 Configuration in PWM mode */
+    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; 
+    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 
+    TIM_OCInitStructure.TIM_Pulse = 0; 
+    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; 
+    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;         
+    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
+    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;          
+    TIM_OC2Init(TIM4, &TIM_OCInitStructure); 
+
+    /* Automatic Output enable, Break, dead time and lock configuration*/
+    TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
+    TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
+    TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; 
+    TIM_BDTRInitStructure.TIM_DeadTime = 0x75;
+    TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;
+    TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;
+    TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
+
+    TIM_BDTRConfig(TIM4, &TIM_BDTRInitStructure);
+
+    /* TIM1 counter enable */
+    TIM_Cmd(TIM4,ENABLE);
+#else
+    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
+    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+    GPIO_Init(GPIOD, &GPIO_InitStructure);
+
+    GPIO_SetBits(GPIOD, GPIO_Pin_13);
+#endif
+
+    /* Configure reset pin (PE1) as GPIO out PP */
+    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
+    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+    GPIO_Init(GPIOE, &GPIO_InitStructure);
+
     /* Configures the Parallel interface (FSMC) for LCD (Parallel mode) */
     /* FSMC_Bank1_NORSRAM4 timing configuration */
     p.FSMC_AddressSetupTime = 1;
@@ -119,4 +353,148 @@
 
     /* Enable FSMC_Bank1_NORSRAM4 */
     FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE);
+
+    /* Initialise LCD panel */
+
+    /* Pull reset pin low */
+    GPIO_ResetBits(GPIOE, GPIO_Pin_1);
+    Delay(0xafff);					   
+    GPIO_SetBits(GPIOE, GPIO_Pin_1);
+    Delay(0xafff);	
+
+    id = LCD_RD_Reg(0x00);
+    if (id != 0x9325) {
+	printf("LCD ID doesn't match, expected 0x9325 got 0x%x\r\n", id);
+	return;
+    }
+    
+    LCD_WR_Reg(0x00e3, 0x3008); /* Set internal timing */
+    LCD_WR_Reg(0x00e7, 0x0012); /* Set internal timing */
+    LCD_WR_Reg(0x00ef, 0x1231); /* Set internal timing */
+    LCD_WR_Reg(0x0000, 0x0001); /* Start Oscillation */
+    LCD_WR_Reg(0x0001, 0x0100); /* set SS and SM bit */
+    LCD_WR_Reg(0x0002, 0x0700); /* set 1 line inversion */
+
+    LCD_WR_Reg(0x0003, 0x1030); /* set GRAM write direction and BGR = 0, 262K colours, 1 transfers/pixel. */
+    LCD_WR_Reg(0x0004, 0x0000); /* Resize register */
+    LCD_WR_Reg(0x0008, 0x0202); /* set the back porch and front porch */
+    LCD_WR_Reg(0x0009, 0x0000); /* set non-display area refresh cycle ISC[3:0] */
+    LCD_WR_Reg(0x000a, 0x0000); /* FMARK function */
+    LCD_WR_Reg(0x000c, 0x0000); /* RGB interface setting */
+    LCD_WR_Reg(0x000d, 0x0000); /* Frame marker Position */
+    LCD_WR_Reg(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 */
+    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] */
+    Delay(50); 			/* Delay 50ms */
+    LCD_WR_Reg(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 */
+    Delay(50); 			/* Delay 50ms */
+    LCD_WR_Reg(0x0020, 0x0000); /* GRAM horizontal Address */
+    LCD_WR_Reg(0x0021, 0x0000); /* GRAM Vertical Address */
+
+    /* Adjust the Gamma Curve */
+    LCD_WR_Reg(0x0030, 0x0007);
+    LCD_WR_Reg(0x0031, 0x0302);
+    LCD_WR_Reg(0x0032, 0x0105);
+    LCD_WR_Reg(0x0035, 0x0206);
+    LCD_WR_Reg(0x0036, 0x0808);
+    LCD_WR_Reg(0x0037, 0x0206);
+    LCD_WR_Reg(0x0038, 0x0504);
+    LCD_WR_Reg(0x0039, 0x0007);
+    LCD_WR_Reg(0x003c, 0x0105);
+    LCD_WR_Reg(0x003d, 0x0808);
+
+    /* 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_WR_Reg(0x0060, 0xa700); /* Gate Scan Line */
+    LCD_WR_Reg(0x0061, 0x0001); /* NDL,VLE, REV */
+    LCD_WR_Reg(0x006a, 0x0000); /* set scrolling line */
+
+    /* Partial Display Control */
+    LCD_WR_Reg(0x0080, 0x0000);
+    LCD_WR_Reg(0x0081, 0x0000);
+    LCD_WR_Reg(0x0082, 0x0000);
+    LCD_WR_Reg(0x0083, 0x0000);
+    LCD_WR_Reg(0x0084, 0x0000);
+    LCD_WR_Reg(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);
+    LCD_WR_Reg(0x0098, 0x0000);
+    LCD_WR_Reg(0x0007, 0x0133); /* 262K colour and display ON */
+  	
+    /* Fill panel with white */
+    LCD_WR_Reg(0x20, 0);
+    LCD_WR_Reg(0x21, 0x013f);
+    *(__IO uint16_t *)(Bank1_LCD_C) = 34;
+    for (colour1 = 0; colour1 < 76800; colour1++) {
+	LCD_WR_Data(0xffff);
+    }
+    colour1 = 0;
+
+    /* Configure touch screen controller
+     *
+     * Connected to SPI1 which is shared with the AT45DB161D.
+     *
+     * The touch screen is selected with PB7.
+     * The flash chip is selected with PA4.
+     */
+
+    /* Enable SPI1 clock */
+    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);
+
+    /* Configure MOSI, MISO and SCLK as alternate function PP */
+    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
+    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
+    GPIO_Init(GPIOA, &GPIO_InitStructure);
+
+    /* Configure flash chip select pin (PA4) as GPIO out PP */
+    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
+    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+    GPIO_Init(GPIOA, &GPIO_InitStructure);
+
+    /* Configure touch chip select pin (PB7) as GPIO out PP */
+    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
+    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
+    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
+    GPIO_Init(GPIOB, &GPIO_InitStructure);
+
+    /* De-select touch & flash */
+    GPIO_SetBits(GPIOA, GPIO_Pin_4);
+    GPIO_SetBits(GPIOB, GPIO_Pin_7);
+    
+    /* SPI1 Config */
+    SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
+    SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
+    SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
+    SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
+    SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
+    SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
+    SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
+    SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
+    SPI_InitStructure.SPI_CRCPolynomial = 7;
+    SPI_Init(SPI1, &SPI_InitStructure);
+
+    /* SPI1 enable */
+    SPI_Cmd(SPI1, ENABLE);  
+
 }
--- a/lcd.h	Sun Jan 01 11:01:13 2012 +1030
+++ b/lcd.h	Tue Jan 03 22:37:18 2012 +1030
@@ -1,7 +1,52 @@
 #ifndef LCD_H_
 #define LCD_H_
 
-void	LCD_init(void);
+void		LCD_init(void);
+void		LCD_WR_Reg(uint16_t index, uint16_t val);
+uint16_t	LCD_RD_Reg(uint16_t index);
+uint16_t	LCD_RD_Data(int first);
+void		LCD_WR_Data(uint16_t val);
+
+/* Mode/channel select defines */
+#define TP_READ_SEL(chan, mode, ref, pd) (0x80 | (((chan) & 0x07) << 4) | (((mode) & 0x01) << 3) | (((ref) & 0x01) << 2) | ((pd) & 0x03))
+
+/* Channel select */
+#define TP_CHAN_TEMP0	0
+#define TP_CHAN_Y	1	
+#define TP_CHAN_VBAT	2
+#define TP_CHAN_Z1	3
+#define TP_CHAN_Z2	4
+#define TP_CHAN_X	5
+#define TP_CHAN_AUX	6
+#define TP_CHAN_TEMP1	7
+
+/* Mode select */
+#define TP_MODE_12	0
+#define TP_MODE_8	1
+
+/* Reference type */
+#define TP_REF_DIFF	0
+#define TP_REF_SER	1
+
+/* Power down mode */
+#define TP_PD_AUTO	0
+#define TP_PD_REF_OFF	1
+#define TP_PD_REF_ON	2
+#define TP_PD_ON	3
+
+uint16_t	TPRead(uint8_t type);
+
+uint16_t	FlashReadID(void);
+uint8_t		FlashReadStatus(void);
+
+#define FL_BP0	(1<<2)
+#define FL_BP1	(1<<3)
+#define FL_BP2	(1<<4)
+#define FL_BP3	(1<<5)
+#define FL_BPL	(1<<7)
+void		FlashWriteStatus(uint8_t status);
+
+void		FlashWriteCtl(int enable);
 
 #endif
 
--- a/main.c	Sun Jan 01 11:01:13 2012 +1030
+++ b/main.c	Tue Jan 03 22:37:18 2012 +1030
@@ -128,9 +128,6 @@
     /* Say hello */
     fputs("\r\nHello world\r\n", stdout);
     
-#define Bank1_LCD_D    ((uint32_t)0x60020000)    //disp Data ADDR
-#define Bank1_LCD_C    ((uint32_t)0x60000000)    //disp Reg ADDR
-    
     while (1) {
 	fputs("> ", stdout);
 	
@@ -149,10 +146,57 @@
 		tv.tv_usec = 0;
 		settimeofday(&tv, NULL);
 	    } else if (!strncmp("lcd", cmd.buf, 3)) {
-		*(__IO uint16_t *) (Bank1_LCD_C) = 0x00;
-		printf("LCD ID = %hx\r\n", *(__IO uint16_t *) (Bank1_LCD_D));
+		printf("LCD ID = %hx\r\n", LCD_RD_Reg(0x00));
 	    } else if (!strncmp("read", cmd.buf, 4)) {
 		printf("PB5 = %d\r\n", GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_15));
+	    } else if (!strncmp("touch", cmd.buf, 5)) {
+		for (int i = 0; i < 10; i++) {
+		    uint16_t	x, y, z1, z2;
+		    float	t, t2;
+		    
+		    x = TPRead(TP_READ_SEL(TP_CHAN_X, TP_MODE_12, TP_REF_DIFF, TP_PD_ON));
+		    y = TPRead(TP_READ_SEL(TP_CHAN_Y, TP_MODE_12, TP_REF_DIFF, TP_PD_ON));
+		    z1 = TPRead(TP_READ_SEL(TP_CHAN_Z1, TP_MODE_12, TP_REF_DIFF, TP_PD_ON));
+		    z2 = TPRead(TP_READ_SEL(TP_CHAN_Z2, TP_MODE_12, TP_REF_DIFF, TP_PD_ON));
+		    t = ((float)x / 4096.0) * (((float)z2 / (float)z1) - 1);
+		    t2 = (((float)x / 4096) * ((4096.0 / (float)z1) - 1)) - (1 - ((float)y / (float)4096.0));
+		    printf("X = %5d Y = %5d Z1 = %5d Z2 = %5d T = %7.2f T2 = %7.2f\r\n", x, y, z1, z2, t, t2);
+		}
+	    } else if (!strncmp("fl", cmd.buf, 2)) {
+		uint8_t status;
+		char *flstattbl[] = {
+		    "BUSY",
+		    "WEL",
+		    "BP0",
+		    "BP1",
+		    "BP2",
+		    "BP3",
+		    "AAI",
+		    "BPL"
+		};
+		
+		printf("Flash ID = 0x%04hx (expect 0xbf41)\r\n", FlashReadID());
+		status = FlashReadStatus();
+
+		fputs("Status = ", stdout);
+		for (unsigned int i = 0; i < sizeof(flstattbl) / sizeof(flstattbl[0]); i++)
+		    if (status & 1 << i) {
+			fputs(flstattbl[i], stdout);
+			fputs(" ", stdout);
+		    }
+		printf("(0x%02x)\r\n", status);
+
+		FlashWriteStatus(0x00);
+		
+		status = FlashReadStatus();
+
+		fputs("Status = ", stdout);
+		for (unsigned int i = 0; i < sizeof(flstattbl) / sizeof(flstattbl[0]); i++)
+		    if (status & 1 << i) {
+			fputs(flstattbl[i], stdout);
+			fputs(" ", stdout);
+		    }
+		printf("(0x%02x)\r\n", status);
 	    } else if (!strncmp("zz", cmd.buf, 2)) {
 		NVIC_SystemReset();
 	    } else {
@@ -211,10 +255,7 @@
     RTC_WaitForLastTask();
 
     /* Clock setup */
-    /* Enable clocks we need */
-    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);
-    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |
-			   RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE);
+    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
 
     /* Port configuration */
     /* Configure USART1 TX (PA.09) as alternate function push-pull */
@@ -228,13 +269,16 @@
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
     GPIO_Init(GPIOA, &GPIO_InitStructure);
 
-    /* Configure PB5 as output push-pull */
+    /* Enable GPIOB clock */
+    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
+
+    /* Configure PB5 as output push-pull for LED */
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
     GPIO_Init(GPIOB, &GPIO_InitStructure);
 
-    /* Configure PB15 as input pull-up push-pull */
+    /* Configure PB15 as input pull-up push-pull for push button */
     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;