Skip to content

Bit Bang Serial 19200 Baud Send

March 19, 2016

The other day I finally found some bit bang serial routines.  There are already nice serial routines in Josh’s monitor but they’re 9600 baud and tough to understand.  I wanted my own to try to get faster speed and code I could understand.

With apologies to Jack Ganssle I’ve adapted his sending code to the ZMC hardware and my limited Z80 coding skills.  I’ve removed the automatic baud rate detection and i’m only planning on speeds of 19.2 and above which simplifies my task a bit.

This is a first pass and I’m sure I’ll revise it once I move to the receive side.
The routine gets its input in L and immediately moves it to C which is where the Ganssle code kept it.  It preloads H with a loop constant.  After a start bit, it sends out the serial data LSB first (colour me surprised, I had never noticed that! I guess I’m just used to SPI). The start bit is stuffed into C to begin with then the data bits are RRA’d in one at a time and the stop bits are allowed for by forcing ones into C before each RRA.

The bit timing is done with a two instruction, 14 cycle loop run 9 times plus the baseline 74 cycles plus 3 noops to add up to a bit over 52 uS.

None of this is optimal but I’ve stuck close to the original code where I could.  When I get a receive routine working I’ll review it.  For sending only it might be possible to get to 38400 bps or a 26 uS bit time.  The problem is not the raw speed it’s the granularity of the timing.  At a 26 uS bit time I don’t think you could tolerate as much as a 1 uS error and the shortest Z80 instruction is 2 uS so it would be a matter of luck.  If there was no other complication, the baseline time is 18.5 uS, so just 3 noops would get you to 26.5 which might be close enough.  Anyway, I’ll wait til I’ve done a receive before I worry about it.

/*
   19.2kbps serial sending routine
*/
#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;
}
void main()
{
	//printf("Hello From BBSEND\n");
	while(1){
		delay(500);
		//printf("U");
		bbsend('U');
	}
}
#include <olduino.c>
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: