Skip to content

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.

Bit Bang Serial 19200 Baud Receive

It works, but ick.  I’m doing this because I started it but I’m doubtful it’s going to work well enough to use.  Adjusting the timing isn’t that hard but it occurs to me that, since this is unbuffered, I would have to deal with each character received within a very  short time or put some pacing on the sender which might obviate the benefit.  Also, I need to add a timeout which complicates things further.  Even testing it seems tricky.

On the left below is the output from a simple test routine, it prints a ! then calls bbrecv and prints what it gets.  The T’s indicate a timeout but you can see me input 1,2,3.  On the right is the trace of my reads of the serial line.  The RX signal has dot’s in it where the logic analyzer is sampling the data bits.  My reads line up almost perfectly with them.  There is an extra read with a short gap that happens pretty well every time that is something to do with the monitor responding to an interrupt.  I tried disabling interrupts altogether and the extra read went away.

 

My code is below for the bbrecv routine and the test program.  Again, thanks and apologies to Jack Ganssle. http://www.ganssle.com/articles/auart.htm
Also thanks to http://wikiti.brandonw.net/index.php?title=Z80_Instruction_Set for the z80 instruction timing tables.

;
;  CIN - input a character to C within 1 second.
;  trying for 19.2 kbps, bit time is 52 uS, 208 cycles
;  character is returned in C with carry set if timeout occurs (also returns 'T')
;
cin:	di			;disable interrupts for timing
	ld	b,8		; bit count
	ld	hl,186*256	; timeout limit
ci1:	in	a,(0x40) 	; 11 read serial line
	and	0x80		; 7  isolate serial bit
	jp	z,gotit		; 10 wait till serial data comes
	in	a,(0x40) 	; 11 read serial line
	and	0x80		; 7  isolate serial bit
	jp	z,gotit		; 10 wait till serial data comes

	dec	l		; 4  check timeout limit
	jp	nz,ci1		; 10 go test again
	dec	h		;  4 check rest of to limit
	jp	nz,ci1		; 10 go test again
	jp	cto		; no character within tolimit*(84)/4 - approx 1s
gotit:	;we are now at the beginning of the start bit plus maybe 28 to 45 cycles

	ld	l,3		;  7 now need to wait 104 cycles - (45+7) already = 52 cycles
ci2:	dec	l		;  4
	jp	nz,ci2		; 10 wait till middle of start bit (3*14 is 42 more)
	jp	cnxt		; waste an extra 10 cycles (+10 makes 45+7+42+10=104)
cnxt:

ci3:	ld	l,14		;  7 next bit in 208-7 cycles, loop is 14, count is 14
ci4:	dec	l		;  4
	jp	nz,ci4		; 10 now wait one entire bit time
	nop			;  4 so total delay 7+14*14+4=207

	in	a,(0x40)	; 11 read serial character
	rla			;  4 shift into carry bit
	ld	a,c		;  4 this is where we assemble char
	rra			;  4 rotate it into the character from carry
	ld	c,a		;  4
	dec	b		;  4 dec bit count
	jp	z,ci5		; 10 j if done all bits (41 cycles to here)
	ld	l,10		;  7 next bit is in 208-68 cycles, loop above is 14, count is 10
	jp	jpci4		; 10 waste 10 cycles to balance out
jpci4:	jp	ci4		; 10 do next bit (68 cycles here!)
ci5:	ld	l,c		; return location per fastcall protocol

	or	a		; clear carry flag for success
	ei			; enable interrupts
	ret

cto:	ld	l,'T'		; failure is timeout
	scf			; set carry flag to show timeout
	ei			; enable interrupts
	ret

/*
   19.2kbps serial sending routine
   Thanks and apologies to Jack Ganssle
*/
#include <olduino.h>
#include <stdio.h>
void  bbsend(char c) __z88dk_fastcall{
	__asm
	;
	; Output the character in L
	;
			di	;disable interrupts for timing
			ld		c,l				; move input to c
			ld		hl,#0x0909		;preload bit time constants
	cout:   ld      b,10            ; # bits to send
	                                ; (start, 8 data, 2 stop)
	        xor     a               ; clear carry for start bit
	co1:    jp      nc,cc1          ; if carry, will set line high
			ld		a,0xFF			;set the line high
			out		(0x40),a
	        jp      cc2
	cc1:	ld		a,0x7F			; set serial line low
			out		(0x40),a		;set the line low
	        jp      cc2             ; idle; balance # cycles with those
	                                ; from setting output high
	cc2:    ld      l,h	     		; times per bit
	co2:    dec     l
	        jp      nz,co2          ; idle for most of one bit time
	        nop
	        nop
	        nop			          	; fill out bit time
	        scf                     ; set carry high for next bit
	        ld      a,c             ; a=character
	        rra                     ; shift it into the carry
	        ld      c,a
	        dec     b               ; --bit count
	        jp      nz,co1          ; send entire character
			ei	;enable interrupts
	        ret
	__endasm;
	c;
}
unsigned char bbrecv() __z88dk_fastcall{
	__asm
#include "bbrecv.inc"
	__endasm;
	return 'K';	//keep compiler happy
}
void main()
{
	unsigned char x;
	unsigned int j;
	while(1){
		delay(1000);
		bbsend('!');
		x=bbrecv();
		bbsend(x);
		bbsend(' ');
	}
}
#include <olduino.c>