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