Skip to content

TP3465V 16 Bit Mode to the 2.2″ TFT LCD

The Elecfreaks LCD is very nice but each of the 320X240 pixels requires you to send 16 bits over SPI.  Even an arduino takes a noticeable length of time to clear the screen and for the olduino it can be quite long.  I got 16 bit mode working a while ago and finally worked it into a screen clearing routine today.  With an 8 bit transfer routine coded in assembler it took right around .9 seconds to clear the screen.  With a carefully crafted 16 bit clear routine it takes about .6 sec.  The fundamental reason for it is that I have to leave a nop gap between pairs of writes to the SPI chip so I chew up an extra instruction there.  Then, even though I’ve unrolled the loop there’s some overhead, and the timer interrupt steals some cycles each ms.  The result is that the best i can do is a bit over 2 mb/sec rather than the theoretical 4 mb.

The first routine below is an assembly language fill routine that uses 8 bit mode. It gets passed the count as well as the value to send. Knowing it’s always 2 bytes/pixel it does double up the loop payload. The second routine uses 16 bit mode and sends 8 bytes per loop pass.

 

void zfilla(unsigned int n, unsigned char c){ //send n copies of c
	__asm
	;prolog will have prepped ix
	ld	e,(ix+4)
	ld	d,(ix+5)
	srl d			;divide de
	rr	e		;by 2
; here count/2 is in de, value is at (ix+6)
; now we want lsb of count, msb+1(*) in d (* unless already 0)
	ld b,e          ; Number of loops is in DE
	dec de          ; Calculate DB value (destroys B, D and E)
	inc d
	ld a,(ix+6)
l_zfilla_00101:
		out (0x81),a
		nop
		out (0x81),a
	djnz l_zfilla_00101
	dec d
	jp nz,l_zfilla_00101
	;epilog will restore ix and return
	__endasm;
n;c; //refs to keep compiler happy
}
void zclear(char c){ //fill the lcd by sending 153600 c's
	__asm
	ld	de,#19200 ;153600/8

; here count is in de, value is at (ix+4)
; now we want lsb of count, msb+1(*) in d (* unless already 0)
	ld b,e          ; Number of loops is in DE
	dec de          ; Calculate DB value (destroys B, D and E)
	inc d

	ld	a,0xFF	;set channel 0 to 16 bits
	out (0x8c),a ;by writing to the MWM bit
	nop

	ld a,(ix+4)
l_zclear_00101:
		out (0x80),a ;second byte
		out (0x81),a ;first byte
		nop
		out (0x80),a ;second byte
		out (0x81),a ;first byte
		nop
		out (0x80),a ;second byte
		out (0x81),a ;first byte
		nop
		out (0x80),a ;second byte
		out (0x81),a ;first byte
	djnz l_zclear_00101
	dec d
	jp nz,l_zclear_00101

	ld	a,0x00	;set channel 0 to 8 bits
	out (0x8c),a

	;epilog will restore ix and return
	__endasm;
c; //refs to keep compiler happy
}

I always want the last word so that wordpress doesn’t eat my code!

TP3465V 16 Bit Mode Works Just Fine

16-08-26 16 bit working

This has been quietly bugging me for months.  I tried 16 bit mode on the TP3465V spi/microwire chip and just saw munged bits output.  I thought about timing issues but it just seemed unlikely that it wouldn’t work.  I went back to the data sheet and re-wrote simpler code and discovered my error: I was writing the bytes in the wrong sequence! You have to “Write the LOW data byte in the SMB register and then write the HIGH data byte into the FMB byte location. All 16 data bits are shifted out after the trailing edge of the Write strobe for the FMB register”

I’ll have to go back to my lcd screen fill code to see if it makes much difference in application.


void bit16(){
__asm

ld a,0xFF ;set channel 0 to 16 bits
out (0x8c),a ;by writing to the MWM bit

ld a,0x34
out (0x80),a ;second byte

ld a,0x12
out (0x81),a ;first

ld a,0x00 ;set channel 0 to 8 bits
out (0x8c),a
__endasm;
}

I always want the last word so that wordpress doesn’t eat my code!

A bit disappointed in the Z80 SPI speed

Clearing the TFT LCD just takes a lot of data transfer.  For each of the 240*320 pixels you have to send TWO 8 bit bytes. so that’s 1.2MB.  At 4mhz then, the best you could hope for is 1/3 second or so.  I can’t get anywhere near that though.  The naive fill routine written in Z80 assembler looks like uses a two instruction inner loop(OUT (0x81),a; djnz…).  This adds about 4us between each 2us burst of clock so it takes almost a second to clear the whole screen.  You can improve that a bit by doubling up the OUT’s and halving the count.

I remembered something Matt Millman had said about running the TP3465V in 16 bit mode but I still seem to need a nop between writes or it mungs the bits somehow and, in the end, it’s not much faster.

//16 bit fill routine
void zfillb(unsigned int n, unsigned char c){ //send n copies of c
	__asm
	;prolog will have prepped ix=sp
	ld	e,(ix+4)
	ld	d,(ix+5)
; here length is in de, value is at (ix+6)
	srl d
	rr	e
	ld	a,0xFF	;set channel 0 to 16 bits
	out (0x8c),a ;by writing to the MWM bit

	ld b,e          ; Number of loops is in DE
	dec de          ; Calculate DB value (destroys B, D and E)
	inc d
	ld a,(ix+6)
l_zfillb_00101:
		out (0x81),a	;first byte
		nop
		out (0x80),a	;second the same
	djnz l_zfillb_00101
	dec d
	jp nz,l_zfillb_00101
	;epilog will restore ix and return
	ld	a,0x00	;set channel 0 to 8 bits
	out (0x8c),a
	__endasm;
}
//8 bit follows
void zfilla(unsigned int n, unsigned char c){ //send n copies of c
	__asm
	;prolog will have prepped ix
	ld	e,(ix+4)
	ld	d,(ix+5)
	srl d
; here length is in de, value is at (ix+6)
; now we want lsb of count, msb+1(*) in d (* unless already 0)
	ld b,e          ; Number of loops is in DE
	dec de          ; Calculate DB value (destroys B, D and E)
	inc d
	ld a,(ix+6)
l_zfilla_00101:
		out (0x81),a
		nop
		out (0x81),a
	djnz l_zfilla_00101
	dec d
	jp nz,l_zfilla_00101
	;epilog will restore ix and return
	__endasm;
}

I always want the last word so that wordpress doesn’t eat my code!

Close But No Cigar

Something a bit wonky about the z80 version of the character rendering routine!

Olduino/Z with the Colour LCD

 

This is just the same code I ran on the 1802 for this LCD but I think it’s noteworthy that it IS the same code.  Not exactly, of course, there are some assembly language helpers in each case but that’s almost all in the hspi3 library and controlled by the __CPUTYPE defs.  The other (I think) neat thing is how compatible the hardware is.  In the two left pictures below I’ve just moved the signal and power leads from the 1802 Olduino to exactly the same spots on the Olduino/Z.  I may not be brilliant but I am doggedly persistent.

I’m going to work at getting a web client and text output working bilingually on the two processors and use it for the hack-a-day retro edition.

/*==========================================================================
The LCD connection is the same as Nokia LCD5110 and  is a“8 Bit Pant Demo“

Just for ElecFreaks TFT01-2.2SP, which use SPI serial port and 240x320 pixel.
The driver is ILI9341.

by Elecfreaks

16-04-12 adapting for olduino/Z
==========================================================================*/
#include <cpuz80spd4port40.h>
#include <olduino.h>
#include <stdio.h>
#include <hspi3.h> //Z
#define LCD_WR    4-3   //clock
#define LCD_RS    3-3   //data/mosi
#define LCD_DC    6-3   //data/command
#define LCD_REST  5-3   //RESET
#define LCD_CS    7-3   //slave select
void lcdfiller(unsigned int, unsigned char);
void LCD_Writ_Bus(unsigned char value){
  digitalWrite(LCD_CS,LOW);
  spiSend(value);
  digitalWrite(LCD_CS,HIGH);
}

void LCD_Write_COM(unsigned char VL)
{
  digitalWrite(LCD_DC,LOW);
  LCD_Writ_Bus(VL);
}

void LCD_Write_DATA(unsigned char VL)
{
  digitalWrite(LCD_DC,HIGH);
  LCD_Writ_Bus(VL);
}

void Address_set(unsigned int x1,unsigned int y1,unsigned int x2,unsigned int y2)
{//hah - this is already set up properly for endian-independance!
   printf("aset...");
   LCD_Write_COM(0x2a);
   LCD_Write_DATA(x1>>8);
   LCD_Write_DATA(x1);
   LCD_Write_DATA(x2>>8);
   LCD_Write_DATA(x2);

   LCD_Write_COM(0x2b);
   LCD_Write_DATA(y1>>8);
   LCD_Write_DATA(y1);
   LCD_Write_DATA(y2>>8);
   LCD_Write_DATA(y2);

   LCD_Write_COM(0x2C);
   printf("done\n");
}

void LCD_Init(void)
{
    digitalWrite(LCD_REST,LOW);
	delay(10);
    digitalWrite(LCD_REST,HIGH);
        LCD_Write_COM(0xCB);
        LCD_Write_DATA(0x39);
        LCD_Write_DATA(0x2C);
        LCD_Write_DATA(0x00);
        LCD_Write_DATA(0x34);
        LCD_Write_DATA(0x02);

        LCD_Write_COM(0xCF);
        LCD_Write_DATA(0x00);
        LCD_Write_DATA(0XC1);
        LCD_Write_DATA(0X30);

        LCD_Write_COM(0xE8);
        LCD_Write_DATA(0x85);
        LCD_Write_DATA(0x00);
        LCD_Write_DATA(0x78);

        LCD_Write_COM(0xEA);
        LCD_Write_DATA(0x00);
        LCD_Write_DATA(0x00);

        LCD_Write_COM(0xED);
        LCD_Write_DATA(0x64);
        LCD_Write_DATA(0x03);
        LCD_Write_DATA(0X12);
        LCD_Write_DATA(0X81);

        LCD_Write_COM(0xF7);
        LCD_Write_DATA(0x20);

        LCD_Write_COM(0xC0);    //Power control
        LCD_Write_DATA(0x23);   //VRH[5:0]

        LCD_Write_COM(0xC1);    //Power control
        LCD_Write_DATA(0x10);   //SAP[2:0];BT[3:0]

        LCD_Write_COM(0xC5);    //VCM control
        LCD_Write_DATA(0x3e);   //Contrast
        LCD_Write_DATA(0x28);

        LCD_Write_COM(0xC7);    //VCM control2
        LCD_Write_DATA(0x86);   //--

        LCD_Write_COM(0x36);    // Memory Access Control
        LCD_Write_DATA(0x48);   //was 48 C8	   //48 68??//28 E8 ??

        LCD_Write_COM(0x3A);
        LCD_Write_DATA(0x55);

        LCD_Write_COM(0xB1);
        LCD_Write_DATA(0x00);
        LCD_Write_DATA(0x18);

        LCD_Write_COM(0xB6);    // Display Function Control
        LCD_Write_DATA(0x08);
        LCD_Write_DATA(0x82);
        LCD_Write_DATA(0x27);
        LCD_Write_COM(0x11);    //Exit Sleep
        delay(120);

        LCD_Write_COM(0x29);    //Display on
        LCD_Write_COM(0x2c);
printf("init done\n");
}

void hwspilcdasm(){ //asm routines for hardware spi lcd
/*
	asm("	align 16\n"		//make sure lcdclearer jumps will fit on page
		"_lcdfiller:\n" 	//fills R12 bytes of lcd with R13.0
		"$$clrloop:\n"		//come back here for more
			"	dec 2\n	glo 13\n	str 2\n	out 6\n"	//send a fill byte
			"	dec R12\n"	//decrease counter
			"	glo R12\n	bnz $$clrloop\n" //back for more
			"	ghi R12\n	bnz $$clrloop\n" //til done
		"	cretn\n");	//and we're done
*/
}
void zfill(unsigned int n, unsigned char c){ //send n copies of c
	while (n-->0){
		spiSend(c);
	}
}

void Pant(unsigned char VL)
{
  int i;
  Address_set(0,0,240,320);
  digitalWrite(LCD_DC,HIGH);
  digitalWrite(LCD_CS,LOW);
  for(i=0;i<160;i++)
  {
  	zfill(480,VL);
  }
  digitalWrite(LCD_CS,HIGH);
}

void main(){
	//PIN4=0;
	LCD_Init();
	while(1){
		Pant(0xFF); //white
	  	Pant(0xE0);	//red
		Pant(0x18);	//blue
		Pant(0x07);	//green
		Pant(0xE7);	//yellow
		Pant(0x00);	//black
	}
}

#include <olduino.c>
#include <hspi3.c>

I always get the last word.

Olduino/Z Arduino Compatability

ooh, pretty! I wanted to document the connections to the arduino headers and I had seen these ascii pinouts so i tried adapting one from busyducks. I’m quite pleased with the result -it may even be useful!
On the extreme left and right are the labels for the arduino header positions, on the inside are labels for the two 30 pin connectors that go down to the Z80 CPU board.

The Arduino header positions are chosen to fit most shields that will work with an Arduino Uno including Ethernet, SD card, and prototype shields.

  • At the top left is parallel input pin 7 and output 7 which are used for serial I/O
  • below that is a spare chip select which can be used as a bidirectional I/O pin
  • next are output bits 0 to 6 – beside O6 there’s a wired in LED attached to that pin
  • next is the dedicated chip select 0 from the TP3465V SPI chip followed by MOSI, MISO, and SCK from the same chip
  • next is a ground
  • on the top right are five parallel input bits I5 down to I0 where the arduino would have its analog inputs
  • below that is a block of power connections.
		               /RST
           GND CTS VCC TXD RXD RTS
         +-------------------------+
         | [ ] [ ] [ ] [ ] [ ] [ ] |
        +                          +_____________________+
        |                          [RST]                 |
        |     [ ] A11              [BTN]      O0 [ ]     |
     I7 | [ ] [ ] A12                         O1 [ ] [ ] | I5
     O7 | [ ] [ ] A13                         O2 [ ] [ ] | I4
    CS1 | [ ] [ ] A14                         O3 [ ] [ ] | I3
     O0 | [ ] [+] A15                         O4 [+] [ ] | I2
     O1 | [ ] [ ] D4                          O5 [ ] [ ] | I1
     O2 | [ ] [ ] D3    +---------+ [ ]CS2    O6 [ ] [ ] | I0
     O3 | [ ] [ ] D5    |         | [ ]CS3    O7 [ ]     |
     O4 | [ ] [ ] D6    | TP3465V |          OUT [ ] [ ] | N/C
        |     [1] VCC   |         |          GND [1] [ ] | GND
     O5 | [ ] [ ] D2    |         |           I0 [ ] [ ] | GND5
 (*) O6 | [ ] [ ] D7    +---------+           I1 [ ] [ ] | VCC
    CS0 | [ ] [ ] D0                          I2 [ ] [ ] | N/C
   MOSI | [ ] [ ] D1                          I3 [ ]     |
   MISO | [ ] [+] /MREQ                       I4 [+]     |
    SCK | [ ] [ ] /IO                         I5 [ ]     |
    GND | [ ] [ ] /WE                         I6 [ ]     |
     NC | [ ] [ ] /OE                         I7 [ ]     |
        |     [ ] A10                        VCC [ ]     |
        |     [2] A9                         VIN [2]     |
        |     [ ] A8                      /RESET [ ]     |
        |     [ ] A7                         /IN [ ]     |
        |     [ ] A6                        /INT [ ]     |
        |     [ ] A5                       CLOCK [ ]     |
        |     [+] A4                       /WAIT [+]     |
        |     [ ] A3                        /RAM [ ]     |
        |     [ ] A2                        /ROM [ ]     |
        |     [ ] A1                        HALT [ ]     |
        |     [ ] A0                        /NMI [ ]     |
        |     [3] GND                        /M1 [3]     |
        |                                                |
        +------------------------------------------------+  

Thanks to	http://busyducks.com/ascii-art-arduinos

The actual schematic for the Olduino/Z is here, the Z80 CPU board schematic is in this manual.

Olduino/Z Hardware Walkthrough

I spent a little while doing cleanup today.   Besides this video I replaced the code-and-go programming demo video and fixed an error in a graphic on the about Olduino/Z page.