SX Thermal Printer Controller

;From: andrew.mcmeikan at mitswa.com.au

                ;be carefull when assembling
                ;there is a lookup table that MUST NOT cross a
                ;256 byte boundry ---- CHECK IT


                ;thermal printer controler
innerloop = 0ff
lilloop = 01
bigloop =0ff


strobe          macro   bt
	SETB	$13.bt	;bit for strobe
	CLRB	0b.7	;dont want interupts
	CALL	outsr	;clock it out
	CALL	lildly	;let it burn in
	SETB	0b.7	;re-enable interupts
	CLRB	$13.bt	;so next outsr clears it
                endm


	ORG	$0000

	JMP	main

	ORG	$0004
                ;entry occurs in here when host pulls strobe signal low
                ;to indicate data that requires printing
                ;useing this int routine occupies two levels of stack
                ;one for the return address and one for outsr's return
                ;centronics pinouts
                ; pin 1 strobe is connected to  RB0
                ; pin 2 data1   "       "       RA1
                ; pin 3 data2   "       "       RA2
                ; pin 4 data3   "       "       RA3
                ; pin 5 data4   "       "       RA4
                ; pin 6 data5   "       "       RB1
                ; pin 7 data6   "       "       RB2
                ; pin 8 data7   "       "       RB3
                ; pin 9 data8   "       "       RB4
                ; pin10 ack     "       "       Cap from BSY this dips low
                ;                                       when want next byte
                ; pin11 busy   is connected to  RA0  High= offline
                ; pin12 Paper out is connected to photocell High=no paper
                ;pins 19 to 30 are signal grounds GND
                ; pin31 INT    is connected to RESET (via diode)
                ;                       and is used to initialize printer


	SETB	RA.0	;say we are busy


                ;read both ports to get byte of data
	MOV	W, >>RA	;read port a shifting data down one
	AND	W, #0f	;only keep bottom bits
	MOV	$16, W	;keep incomming data here
	MOV	W, >>RB	;read port b shifting down one
	AND	W, #0f	;wipe out extraneous bits
	MOV	$17, W	;waste another register
	MOV	W, <>$17	;get 'b' data lower into upper W
	OR	$16, W	;or top bits into data
                ;bit pattern from host now in 0x16

	INC	0e	;increment our count of bytes

                ;clock data into thermal head
	MOV	W, #08	;for 8 bits
	MOV	$17, W	;better keep count of it
clkhd:	RL	$16	;rotate it thru carry
	SETB	$12.4	;set data high
	SC		;check the carry flag
	CLRB	$12.4	;clear data if required
	CALL	outsr
	SETB	$12.5	;clock that bit in
	CALL	outsr
	CLRB	$12.5	;drop clock again
	CALL	outsr
	DECSZ	$17	;have we finished loop yet ?
	JMP	clkhd	;guess not
                ;no point doing the extra shift as we are just
                ;throwing the data away once it is in the head


                ;if byte count=max then lets latch and let the main routine
                ;                                         print it
	MOV	W, #$c0	;try 192           ;216 max bytes per line 1728 bits
	MOV	W, 0e-w	;check max against our byte count
	SZ		;the same? result of zero?
	JMP	continue	;no its ok, head not full yet

                ;need to latch thermal head
                ; We do not not lower busy here
                ;as main routine will do so once it has reset
                ;the counter.

	SETB	$12.6	;latch bit for thermal head
	CALL	outsr	;send- no one else better be using it
	CLRB	$12.6	;put back
	CALL	outsr	;send that to

	JMP	exint	;leave int handler

continue:       ;tell host we are no longer busy, get next byte
	CLRB	RA.0	;bring BSY low
                ;and fall thru to exit :)
exint:                                  ;now restore to before interupt
	RETI



main            ;thermal printer control program 192 dpi 9 inch 1728 pixels
                ;need to set up direction bits for ports
                ;and set initial pin levels

	MOV	W, #$C0	
	MOV	!OPTION, W	;set options RTW and RTI on so OptionX can be used

		;pullups
	mov	M, #$0E
	mov	!RA,#$FF
	mov	!RB,#$FF

		;porta as input except RA.0
	MOV	RA, #$ff 	;set all pins high on port a
	mov	M, #$0F
	MOV	W, #$FE		;RA0 as output

		;portb interrupt on neg edge is the default
	MOV	RB, #01f	;make bits 6,7 &5 low
	mov	M, #$0F
	MOV	!RB, #01f	;port b 5,6,7 as output

	MOV	W, #$08	;specify which phase to start on
	MOV	$15, W	;store it somewhere safe
	CLR	$0E	;zero byte count for head
	MOV	W, #$00	;phases off clk,lat,data, strb off
	MOV	$12, W	;data for shift reg 1
	MOV	W, #00	;all strobes off (low)
	MOV	$13, W	;data for shift reg 2
	CALL	outsr	;set all pins high except for stepper
	MOV	W, #$90	;enable RB0 and GIE interupt bits
	MOV	$0B, W	;interupts now turned on!
	CLRB	RA.0	;say we are not busy


p1=8;9 ;1
p2=4;8 ;3         ;ok here are definitions of how the shift registers are wired
p3=2;0c;2         ; ok on 0x12    bit0    stepper phase A
p4=1;4 ;6         ;               bit1    "       "     B
p5=8;6 ;4         ;               bit2    "       "     C
p6=4;2 ;0c        ;               bit3    "       "     D
p7=2;3 ;8         ;               bit4    Data for thermal head
p8=1;1 ;9         ;               bit5    Clock for thermal Head
                  ;               bit6    Latch for thermal head
                  ;               bit7    strobe 1 for thermal head;

                  ;       0x13    bit0 to bit7 rest of strobes for head

mloop:          ;this is the loopy bit of main
                ;we sit in here till we get a full head
                ;then we reset the counter, send an ack to the host
                ;print the line out and advance the paper, then we sit until
                ;the head is full again :)

		;first check if the head is full
	MOV	W, #$C0	;try 192            ;216 max bytes per line 1728 bits
	MOV	W, $0E-w	;check max against our byte count
	SZ		;the same? result of zero?
	JMP	mloop	;no not yet keep waiting
	CLR	$0E	;Ok we've spotted the head full


                ;need to strobe head drivers
	SETB	$12.7	;strb1
	CLRB	$0B.7	;turn off interupts
	CALL	outsr	;Fire!
	CALL	lildly	;let it burn!
	SETB	$0B.7	;re-enable interupts
	CLRB	$12.7	;ok thats done

                strobe 0
                strobe 1
                strobe 2
                strobe 3
                strobe 4
                strobe 5
                strobe 6
                strobe 7

	CLRB	$0B.7	;turn off interupts
	CALL	outsr	;yay! all strobes Fired!
	CLRB	RA.0	;ok we aren't busy any more
	SETB	$0B.7	;re-enable interupts

	CALL	papadv	;move paper on to next line
	JMP	mloop	;lets go back and see if another
                                        ;line is ready yet

phlook:         ;this routine looks up the value for a particular phase
                ;important that this lookup resides within a 256 byte block
                ;as PCL is directly modified.  if called with value grater
                ;than 8 ,will cause who knows what kind of crash!
	ADD	02, W	;ok now its going to jump :)
	NOP	;err dont expect zero ?!?!
	RETW	#p8	;return with phase 8
	RETW	#p7	;coz we are counting down
	RETW	#p6	;remember... see next routine!
	RETW	#p5
	RETW	#p4
	RETW	#p3
	RETW	#p2
	RETW	#p1
	SLEEP	;coz its all gone wrong if it
                                        ;gets here or past!
                                        ;check the listing to be sure
                                        ;it fits between page boundries!

papadv:         ;this routine is to activate a paper advance one step
                ;it will use register #15 to keep track of which
                ;point in the phase cycle it is
	MOV	W, #0f0	;prep mask
	CLRB	$0b.7	;diable interupts
	AND	$12, W	;nock off bottom bits
	MOV	W, $15	;grab our phase number into W
	CALL	phlook
	OR	$12, W	;new pattern now set
	SETB	$0b.7	;ints re-enabled
	DEC	$15	;get next phase number
	SNZ		;did we hit zero?
	JMP	recount	;yep need to reload the counter
	CLRB	$0b.7	;turn off interupts coz of (outsr)
	CALL	outsr	;jump to out put new phase
	SETB	$0b.7	;turn on interupts again
	RET	;and go back
recount:	
	MOV	W, #08	;we hit zero reset it back to 8
	MOV	$15, W	;use it next time round
	CLRB	$0b.7	;clear interupt enable
	CALL	outsr	;I know its just below us
	SETB	$0b.7	;but tis only way to keep
	RET	;the interupts rightly enabled

outsr:          ;this routine takes bytes at 0x12 and 0x13
                ;and clocks them out onto the shift registers
                ;shift registers accessed on port b bits 5,6 & 7
                ;bit 6 as clock - clocks data on POSITIVE edge
                ;bit 7 as data  - non inverted
                ;bit 5 as strobe - latches data on NEGATIVE edge
                ; we are sending lsb first ie bit# 1 on shift register
                ; output pin #8
                ; sending byte at address 0x12 first then 0x13
                ; this puts 0x12 on the last shift register in line
                ;uses reg # 14 to keep count of bits

                ;since this code is NON-RE-ENTERENT, do NOT call it
                ;while interupts are enabled, coz the int handler
                ;calls this routine to access the thermal head.

	MOV	W, #08	;for 8 bits
	MOV	$14, W	;better keep count of it
shiftbits:	
	RR	$12	;rotate it thru carry
	SETB	6.7	;set data high
	SC		;check the carry flag
	CLRB	6.7	;clear data if required
	SETB	6.6	;clock that bit in
	CLRB	6.6	;drop clock again
	DECSZ	$14	;have we finished loop yet ?
	JMP	shiftbits	;guess not
	RR	$12	;preserve the data, shift the carry
                        ;now we have finished one byte lets do the other
	MOV	W, #08	;for 8 bits
	MOV	$14, W	;better keep count of it
shiftbitsagain:	
	RR	$13	;rotate it thru carry
	SETB	6.7	;set data high
	SC		;check the carry flag
	CLRB	6.7	;clear data if required
	SETB	6.6	;clock that bit in
	CLRB	6.6	;drop clock again
	DECSZ	$14	;have we finished loop yet ?
	JMP	shiftbitsagain	;guess not
	RR	$13	;preserve the data, shift the carry
                        ;now we have really finished clocking bits
	SETB	6.5	;bring up the strobe line
	CLRB	6.5	;and LATCH it
	RET	;back to where ever.


lildly	MOV	W, #lilloop
	MOV	$11, W
	JMP	reload
bigdly	MOV	W, #bigloop
	MOV	$11, W
reload	MOV	W, #innerloop
	MOV	$10, W
inloop	NOP
	DECSZ	$10
	JMP	inloop
	DECSZ	$11
	JMP	reload
	RET



	ORG	$2000
                DATA    00
                DATA    00
                DATA    00
                DATA    00


	ORG	$2007
                DATA    0x19            ;fuse settings

	ORG	$2100
                ;data    00
                ;data    00
                ;data    00

                END