Skip to content

Finally! Bidirectional SPI

January 23, 2016

I re-soldered a connection with no change.  I started to think about timing and the SPI protocol and could I be reading the data back before the TP3465V was ready.  Yes I could!  There’s a status register that goes from 00 to 0x80 when the chip is done the transmission.  I changed the receive code to return that instead of the data.  Sure enough, I was getting 0’s back. I put in a no-op to give the chip a microsecond and bingo – 80’s.  I put the code back to the original and i see my ip address come back in nice as pie. I’m a bit surprised i wasn’t overrunning it streaming data out to it but there you go. I’ll have to see if this turns into a speed problem.

16-01-23 puttygo

//hspi2.c - routines for hardware spi on olduino with shield adapter outboard clock
//spixfer sends and receives, spisend output only
//spisendN spireceiveN, multibyte send and receive
//dec 18 cleanup
//Feb 16 fix spelling of spiSend
//15-12-04 begin adapting for zmc
//16-01-23 putting some nop's in spirxvn
#ifdef __CPUTYPE1802
unsigned char spixfer(unsigned char value){
	//this code depends on the argument being in Reg 12 and returned value in reg 15
	asm("	glo 12\n" //get the char to be sent
		"	dec 2\n"  //make a work area
		"	str 2\n"  //save the character
		"	out 6\n"  //this loads the shift register and starts the outboard clock
		"	dec 2\n"
		"	sex 2\n"  //delay to allow outbound shift to complete
		"	inp 6\n"  //read the shift register
		"	plo 15\n" //leave it in 15
		"	inc 2\n"  //restore the stack
		"	cretn\n");
	//The return below is NOT executed. It just prevents a compiler warning
	//the cretn inside the asm block above returns the value from the spi transfer
	//sorry.
	return 0;
}
void spiSend(unsigned char value){ //this is for output only
	//this code depends on the argument being in Reg 12
	asm("	glo 12\n" //get the char to send
		"	dec 2\n"  //make a work area
		"	str 2\n"  //place the outbound char
		"	out 6\n" //this loads the MOSR and starts the outboard clock
		"	cretn\n"
	);
	//there needs to be a 1 instruction gap before the next spi accesee - return is 12 or so
}
void spiNroutines(){//wrapper for assembly routines
	//spiSendN(unsigned char *, unsigned int n){//send n bytes over spi
	//spiReceiveN(unsigned char *, unsigned int n){//Receive n bytes over spi
		//the assembler loops count on having the buffer address in R12 and a non-zero count in R13
		asm("	align 16\n" //make sure jumps stay on page
			"_spiSendN:\n"
			"	sex 12\n" //point X to the buffer
			"$$spiSendLoop:\n" //we will do this N times
			"	out 6\n"  //this sends out a byte
			"	dec 13\n" //decrement the byte count
			"	glo 13\n" //check bottom byte of counter
			"	bnz $$spiSendLoop\n" //back for more if needed - 4 inst. per byte
			"	ghi 13\n" //check high byte of counter if necessary
			"	bnz $$spiSendLoop\n"
			"	sex 2\n"  //reset X register
			"	cretn\n" //return to caller
		);
		asm("	align 16\n" //make sure jumps stay on page
			"_spiReceiveN:\n"
			"	sex 12\n" //point X to the buffer
			"	dec 12\n" //back off so the first OUT will leave us in the 1st position
			"$$spiRxvLoop:\n" //we will do this N times
			"	out 6\n"  //this sends out garbage and clocks in the 1st character
			"	dec 13\n" //decrement the byte count(and allow shift to complete)
			"	inp 6\n"  //this reads the nth byte into the nth buffer location
			"	glo 13\n" //check bottom byte of counter
			"	bnz $$spiRxvLoop\n" //back for more if needed - 6 inst. per byte
			"	ghi 13\n" //check high byte of counter if necessary
			"	bnz $$spiRxvLoop\n"
			"	sex 2\n"  //reset X register
			"	cretn\n"
		);
} //that's it
#endif
#ifdef __CPUTYPEZ80
void spiInit(){//spi hardware init - Z80 only
	out(0x8f,0xfe);	//port direction CS0 is output
	out(0x8A,0xFF);	//cs0 inactive
	out(0x8D,0x00);	//clockrate is 4mhz
}

void spiSend(unsigned char value){ //this is for output only
	out(0x81,value);
}
void spiSendNc(unsigned char* loc, unsigned int N){ //this is for output only
	while(N!=0){
		out(0x81,*loc);
		N--;
		loc++;
	}
}
void spiSendN(unsigned char* loc, unsigned int N){ //this is for output only
//following code pretty much copied from compiler output for above with out(... replaced by inline assembly;C:\Users\Bill\Desktop\olduinoZ\hwspilcd\/hspi2.c:80: while(N!=0){
//i'm quite sure it could be done better
__asm
	ld	hl, #4
	add	hl, sp
	ld	e, (hl)
	inc	hl
	ld	d, (hl)
	ld	hl, #2
	add	hl, sp
	ld	c, (hl)
	inc	hl
	ld	b, (hl)
;here the count is in de and the sending location is in bc
1$:
	ld	a,d
	or	a,e
	ret	Z
;out(0x81,*loc);
	ld	a,(bc)
	out (#0x81),a
;N--;
	dec	de
;loc++;
	inc	bc
	jr	1$
__endasm;
	N;loc;	//these don't do anything but they keep the compiler happy

}
void spiReceiveN(unsigned char* loc, unsigned int N){ //this is for input only
//following code pretty much copied from compiler output for above with out(... replaced by inline assembly;C:\Users\Bill\Desktop\olduinoZ\hwspilcd\/hspi2.c:80: while(N!=0){
//i'm quite sure it could be done better
__asm
	ld	hl, #4
	add	hl, sp
	ld	e, (hl)
	inc	hl
	ld	d, (hl)
	ld	hl, #2
	add	hl, sp
	ld	c, (hl)
	inc	hl
	ld	b, (hl)
;here the count is in de and the receiving location is in bc
1$:
	ld	a,d
	or	a,e
	ret	Z
;*loc=in(0x81);
	out	(#0x81),a	;trigger a transfer
	nop				;added 16-01-23 to allow tp3465 to respond
	in	a,(#0x81)	;retrieve the result
	ld	(bc),a		;store it
;N--;
	dec	de
;loc++;
	inc	bc
	jr	1$
__endasm;
	N;loc;	//these don't do anything but they keep the compiler happy
}
#endif
Advertisements

From → Olduino/Z

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: