;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

                LIST      P=16C84, F=INHX8M
                ;thermal printer controler
innerloop = 0ff
lilloop = 01
bigloop =0ff


strobe          macro   bt
                bsf     0x13,bt         ;bit for strobe
                bcf 0b,7                ;dont want interupts
                call outsr              ;clock it out
                call lildly             ;let it burn in
                bsf 0b,7                ;re-enable interupts
                bcf 0x13,bt             ;so next outsr clears it
                endm


                ORG     0x0000

                GOTO    main

                ORG     0x0004    
                ;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

                
                movwf   0c              ;save 'W' in reg file 0c
                swapf   3,w             ;grab the flags
                movwf   0d              ;in reg 'd'
                                        ;should now be safe to continue!
                bsf     5,0             ;say we are busy


                ;read both ports to get byte of data
                rrf     5,w             ;read port a shifting data down one
                andlw   0f              ;only keep bottom bits
                movwf   0x16            ;keep incomming data here
                rrf     6,w             ;read port b shifting down one
                andlw   0f              ;wipe out extraneous bits
                movwf   0x17            ;waste another register
                swapf   0x17,w          ;get 'b' data lower into upper W
                iorwf   0x16,f          ;or top bits into data
                ;bit pattern from host now in 0x16

                incf    0e,f            ;increment our count of bytes
                
                ;clock data into thermal head
                movlw   08              ;for 8 bits
                movwf   0x17            ;better keep count of it
clkhd:          rlf     0x16,f          ;rotate it thru carry
                bsf     0x12,4          ;set data high
                btfss   3,0             ;check the carry flag
                bcf     0x12,4          ;clear data if required
                call outsr
                bsf     0x12,5          ;clock that bit in
                call outsr
                bcf     0x12,5          ;drop clock again
                call outsr
                decfsz  0x17,f          ;have we finished loop yet ?
                goto 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
                movlw   0xc0 ;try 192           ;216 max bytes per line 1728 bits
                subwf   0e,w            ;check max against our byte count
                btfss   3,2             ;the same? result of zero?
                goto 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.

                bsf 0x12,6              ;latch bit for thermal head
                call outsr              ;send- no one else better be using it
                bcf 0x12,6              ;put back
                call outsr              ;send that to

                goto exint              ;leave int handler

continue:       ;tell host we are no longer busy, get next byte
                bcf     5,0             ;bring BSY low
                ;and fall thru to exit :)
exint:                                  ;now restore to before interupt
                swapf   0d,w            ;put flags back in order in W
                movwf   3               ;stickem bick in flags
                swapf   0c,f            ;flip saved W
                swapf   0c,w            ;flip it back into W
                bcf     0b,1            ;clear INTF flag so we can get more
                RETFIE            



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

                movlw   0               ;pullups and interrupt on neg edge
                option                  ;set options
                movlw 0ff
                movf    5,f             ;set all pins high on port a
                movlw 0fe               ;RA0 as output
                tris    5               ;porta as input except RA0
                movlw   01f             ;make bits 6,7 &5 low
                movf    6,f
                movlw   01f             ;port b 5,6,7 as output
                tris    6               ;make it so !
                movlw   08              ;specify which phase to start on
                movwf   0x15            ;store it somewhere safe
                clrf    0e              ;zero byte count for head
                 movlw  00              ;phases off clk,lat,data, strb off
                 movwf   0x12            ;data for shift reg 1
                 movlw  00              ;all strobes off (low)
                 movwf   0x13            ;data for shift reg 2
                 call outsr             ;set all pins high except for stepper
                movlw   0x90            ;enable RB0 and GIE interupt bits
                movwf    0b             ;interupts now turned on!
                bcf 5,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
                movlw   0xc0 ;try 192            ;216 max bytes per line 1728 bits
                subwf   0e,w            ;check max against our byte count
                btfss   3,2             ;the same? result of zero?
                goto mloop              ;no not yet keep waiting
                clrf    0e              ;Ok we've spotted the head full

                
                ;need to strobe head drivers          
                bsf     0x12,7          ;strb1
                bcf     0xb,7           ;turn off interupts
                call outsr              ;Fire!
                call lildly             ;let it burn!
                bsf 0b,7                ;re-enable interupts
                bcf     0x12,7          ;ok thats done
                
                strobe 0
                strobe 1
                strobe 2
                strobe 3
                strobe 4
                strobe 5
                strobe 6
                strobe 7
                
                bcf     0b,7            ;turn off interupts
                call outsr              ;yay! all strobes Fired!
                bcf 5,0                 ;ok we aren't busy any more
                bsf 0b,7                ;re-enable interupts

                call papadv             ;move paper on to next line
                goto 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!
                addwf   02,f            ;ok now its going to jump :)
                nop                     ;err dont expect zero ?!?!
                retlw   p8              ;return with phase 8
                retlw   p7              ;coz we are counting down
                retlw   p6              ;remember... see next routine!
                retlw   p5
                retlw   p4
                retlw   p3
                retlw   p2
                retlw   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
                movlw   0f0             ;prep mask
                bcf     0b,7            ;diable interupts
                andwf   0x12,f          ;nock off bottom bits
                movf    0x15,w          ;grab our phase number into W
                call phlook
                iorwf   0x12,f          ;new pattern now set
                bsf     0b,7            ;ints re-enabled
                decf    0x15,f          ;get next phase number
                btfsc   3,2             ;did we hit zero?
                goto recount            ;yep need to reload the counter
                bcf     0b,7            ;turn off interupts coz of (outsr)
                call outsr              ;jump to out put new phase
                bsf     0b,7            ;turn on interupts again
                return                  ;and go back
recount:        movlw   08              ;we hit zero reset it back to 8
                movwf   0x15            ;use it next time round
                bcf     0b,7            ;clear interupt enable
                call    outsr           ;I know its just below us 
                bsf     0b,7            ;but tis only way to keep
                return                  ;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.

                movlw   08              ;for 8 bits
                movwf   0x14            ;better keep count of it
shiftbits:      rrf     0x12,f          ;rotate it thru carry
                bsf     6,7             ;set data high
                btfss   3,0             ;check the carry flag
                bcf     6,7             ;clear data if required
                bsf     6,6             ;clock that bit in
                bcf     6,6             ;drop clock again
                decfsz  0x14,f          ;have we finished loop yet ?
                goto shiftbits          ;guess not
                rrf     0x12,f          ;preserve the data, shift the carry
                        ;now we have finished one byte lets do the other
                movlw   08              ;for 8 bits
                movwf   0x14            ;better keep count of it
shiftbitsagain: rrf     0x13,f          ;rotate it thru carry
                bsf     6,7             ;set data high
                btfss   3,0             ;check the carry flag
                bcf     6,7             ;clear data if required
                bsf     6,6             ;clock that bit in
                bcf     6,6             ;drop clock again
                decfsz  0x14,f          ;have we finished loop yet ?
                goto shiftbitsagain     ;guess not
                rrf     0x13,f          ;preserve the data, shift the carry
                        ;now we have really finished clocking bits
                bsf     6,5             ;bring up the strobe line
                bcf     6,5             ;and LATCH it
                return                  ;back to where ever.


lildly          movlw lilloop
                movwf 0x11
                goto reload
bigdly          MOVLW   bigloop
                MOVWF   0x11      
reload          MOVLW   innerloop   
                MOVWF   0x10      
inloop          NOP               
                DECFSZ  0x10      , f       
                GOTO    inloop
                DECFSZ  0x11      , f       
                GOTO    reload
                RETURN            


                                  
                ORG     0X2000
                DATA    00
                DATA    00
                DATA    00
                DATA    00


                ORG     0x2007    
                DATA    0x19            ;fuse settings
                                  
                org     0x2100
                ;data    00
                ;data    00
                ;data    00

                END

Interested: