; UM245R connected to a PIC18F4420, clocked at 40MHz ; ; /RXF -> RB0 (INT) ; TXE -> RB2 ; /RD -> RE0 ; WR -> RE1 ; ; /RES TL -> RB1 (for external VCC sensing) ; ; /RB3 -> BUSY SIGNAL (yellow led) ; RE2 -> /ENA (enable external bus) ; PC<0:7> -> MA<0:7> RAM address ; RB4 -> ADL clock PD<0:7> to MA<8:15> ; RB5 -> ADH clock PD<0:2> to MA<16:18> ; RA0 -> /POE (ram output enasble) ; RA1 -> /PCE (ram chip enable) ; RA2 -> DIR ; RA3 -> /G2 - MEM to PD (DIR = 1) or (PD to MEM, DIR = 0) ; RA4 -> /G1 - UM to MEM (DIR = 1) or (MEM to UM if DIR = 0) ; RA5 -> /G0 - UM <-> PD (DIR = 1 UM -> PD) ; RA6 -> /PWE (ram write enable) ; ; PC<0:7> - all output ; RA<0:6> all output ; PD<0:7> in/out ; RE<0:2> all output ; RB<0:2> INPUT ; RB<3:5> OUT ; ; RA<0:6> HIGH ; RB<3:5> LOW ; RD LOW ; RE0 HIGH ; RE1 LOW ; RE2 HIGH list p=18f4420 #include p18f4420.inc #include eerom.inc startup code 0x0000 movlb 0x00 ; BSR = 0 rcall init ; init I/O & Timers goto start HighISR code 0x0008 retfie FAST LowISR code 0x0018 retfie start: movlw LOW(T256MS) ; set an initial delay of 256ms movwf mscnt movlw HIGH(T256MS) movwf mscnt+1 rcall mswait ; just to be sure UM245 is on rcall vccsense ; sensing external vcc ; if /RXF is low, read and discard data from UM245 btfsc PORTB, RB0 bra start1 ; /RXF high bcf LATE, RE0 ; dummy read bsf LATE, RE0 ; in this loop we wait a command from host and sense external vcc start1: rcall vccsense ; sensing external vcc movlw 0xFF cpfseq extvcc bra disable ; no external vcc ; external vcc is on movlw 0xFF cpfseq loaded bra disable ; no memory loaded bsf PORTB, RB3 ; /BUSY -> high bcf PORTE, RE2 ; /ENA -> low - enable ext. buffer & access ;setf memext ; set emulation flag bra start10 disable: ; disable external access to memory bcf PORTB, RB3 ; /BUSY -> low bsf PORTE, RE2 ; /ENA -> high - disable ext. buffer & access ;clrf memext ; clear emulation flag start10: btfsc PORTB, RB0 ; wait fifo data available bra start1 rcall getcmd ; get command (2 bytes) movwf umdat1 ; save 2nd byte (if any) btfsc umrx,7 ; 2nd byte received? bra checkcmd ; yes, check command nack: rcall sndnack ; send nack bra start1 ; main loop ; check command checkcmd: movlw HOST_CONNECT1 ; HOST_CONNECT command? subwf umdat0,w bnz chknxt ; check next command movlw HOST_CONNECT2 subwf umdat1,w bnz nack ; send nack to host & main loop rcall sndack ; send positive ack to host ; now wait for complete sequence of connect command rcall getbyte btfss umrx,7 ; 3th byte received bra nack ; abort sequence movwf umdat0 rcall getbyte btfss umrx,7 ; 4th byte received bra nack ; abort sequence movwf umdat1 movlw HOST_CONNECT3 subwf umdat0,w bnz nack ; send nack to host & main loop movlw HOST_CONNECT4 subwf umdat1,w bnz nack ; send nack to host & main loop rcall sndack ; send positive ack to host rcall getbyte btfss umrx,7 ; 5th byte received bra nack ; abort sequence movwf umdat0 rcall getbyte btfss umrx,7 ; 6th byte received bra nack ; abort sequence movwf umdat1 movlw HOST_CONNECT5 subwf umdat0,w bnz nack ; send nack to host & main loop movlw HOST_CONNECT6 subwf umdat1,w bnz nack ; send nack to host & main loop rcall sndack ; send positive ack to host setf conn ; set connected flag bra start1 ; main loop ; upload/download expect 2 more bytes chknxt: rcall getbyte ; expect 3th byte of command btfss umrx,7 ; 3th byte received bra nack ; abort sequence movwf pagecnt ; page count (256 bytes block's) rcall getbyte ; expect 4th byte of command btfss umrx,7 ; 3th byte received bra nack ; abort sequence movwf bankcnt ; bank count (64K block's) btfss conn,7 ; abort if not connected bra nack movlw HOST_UPLOAD1 ; upload from host? subwf umdat0,w bnz chknxt1 ; check next command movlw HOST_UPLOAD2 subwf umdat1,w bnz nack ; send nack to host & main loop rcall sndack ; send positive ack rcall upload ; receive from host bra start1 ; main loop chknxt1: movlw HOST_DOWNLOAD1 ; upload from host? subwf umdat0,w bnz nack ; abort movlw HOST_DOWNLOAD2 subwf umdat1,w bnz nack ; send nack to host & main loop rcall sndack ; send positive ack rcall download ; send to host bra start1 ; main loop ; transfer from host upload: bsf PORTA, RA4 ; /G1 -> high bsf PORTA, RA3 ; /G2 -> high bsf PORTA, RA2 ; DIR -> high (read port) bsf PORTA, RA5 ; /G0 -> high bsf LATA, RA0 ; memory /OE -> high bsf LATA, RA1 ; memory /CE -> high bsf LATA, RA6 ; memory /WE -> high clrf madh ; set high memory address clrf madl ; clear page number ldw pagecnt movwf pagecnt2 ; set page's counter ldw bankcnt movwf bankcnt2 ; set bank's counter ; wait, within 20ms timeout, for /RXF low movlw TMR0P256 ; TMR0 stop, prescaler = 256, 16 bit movwf T0CON bcf INTCON, TMR0IF ; clear timeout flag movlw HIGH(T1670MS) ; set timeout movwf TMR0H ; TMR0H first movlw LOW(T1670MS) movwf TMR0L ; load both TMR0L/H bsf T0CON, TMR0ON ; start Timer 0 upload1: btfss PORTB, RB0 ; wait /RXF -> low bra upload2 ; detected /RXF btfss INTCON, TMR0IF bra upload1 ; no timeout -- wait ; abort because timeout return upload2: bcf PORTB, RB3 ; /BUSY -> low bsf PORTE, RE2 ; /ENA -> high - disable ext. buffer & access bcf LATA, RA4 ; /G1 -> low: enable UM245/RAM buffer clrf LATC ; clear memory address clrf DDRD ; RD<0:7> all outputs bcf LATA, RA1 ; memory /CE -> low setbnk: ldw madh ; set bank movwf LATD nop bsf LATB, RB5 ; clock ADH bcf LATB, RB5 setpage: ldw madl ; set page movwf LATD nop bsf LATB, RB4 ; clock ADL bcf LATB, RB4 ; wait RX fifo data available from UM245 within a little timeout getdata: clrf ndelay clrf ndelay+1 waitrxf: btfss PORTB, RB0 ; wait /RXF -> low bra getdata2 ; detected /RXF low, RX fifo data available incfsz ndelay,f bra waitrxf ; no timeout -- wait incfsz ndelay+1,f bra waitrxf ; no timeout -- wait ; abort transfer clrf loaded ; memory data is invalid abrt: ; abort operation bsf LATA, RA1 ; memory /CE -> high bsf LATA, RA4 ; /G1 -> high: disable UM245/RAM buffer setf DDRD ; RD<0:7> all's input return ; keep memory unaavailable to extern world ; read byte from UM245 port and write to memory getdata2: bcf LATE, RE0 ; /RD -> low ; need a nop here ?? bcf LATA, RA6 ; memory /WE -> low bsf LATA, RA6 ; memory /WE -> high bsf LATE, RE0 ; /RD -> high waitrxfh: btfss PORTB, RB0 ; wait /RXF -> high bra waitrxfh incfsz LATC, f ; update memory address bra getdata ; loop for 256 bytes incf madl, f ; update memory page decfsz pagecnt2,f ; finish? bra setpage ; next page incf madh, f ; update bank decfsz bankcnt2,f ; finish? bra setbnk ; next bank bsf LATA, RA1 ; memory /CE -> high bsf LATA, RA4 ; /G1 -> high: disable UM245/RAM buffer bcf PORTA, RA5 ; /G0 -> low rcall sndack ; send ack to host bsf PORTA, RA5 ; /G0 -> high setf loaded ; memory data is valid bra download1 ; send back to host: verify data ; transfer to host download: bsf PORTA, RA4 ; /G1 -> high bsf PORTA, RA3 ; /G2 -> high bsf PORTA, RA2 ; DIR -> high (read port) bsf PORTA, RA5 ; /G0 -> high bsf LATA, RA0 ; memory /OE -> high bsf LATA, RA1 ; memory /CE -> high bsf LATA, RA6 ; memory /WE -> high bcf PORTB, RB3 ; /BUSY -> low bsf PORTE, RE2 ; /ENA -> high - disable ext. buffer & access download1: clrf madh ; set high memory address clrf madl ; clear page number ldw pagecnt movwf pagecnt2 ; set page's counter ldw bankcnt movwf bankcnt2 ; set bank's counter bcf LATA, RA4 ; /G1 -> low: enable UM245/RAM buffer clrf LATC ; clear memory address clrf DDRD ; RD<0:7> all outputs bcf LATA, RA1 ; memory /CE -> low bcf PORTA, RA2 ; DIR -> low (write UM245 port) bcf LATA, RA1 ; memory /CE -> low setbnk2: ldw madh ; set bank movwf LATD nop bsf LATB, RB5 ; clock ADH bcf LATB, RB5 setpage2: ldw madl ; set page movwf LATD nop bsf LATB, RB4 ; clock ADL bcf LATB, RB4 ; send data to TX fifo within a little timeout putdata: clrf ndelay clrf ndelay+1 waittxe: btfss PORTB, RB2 ; wait /TXE -> low bra putdata2 ; detected /TXE low incfsz ndelay,f bra waittxe ; no timeout -- wait incfsz ndelay+1,f bra waittxe ; no timeout -- wait ; abort transfer bra abrt putdata2: ; read byte from memory and write to UM245 port bcf LATA, RA0 ; memory /RD -> low ; need a nop here ?? bsf LATE, RE1 ; UM245 WE -> high bcf LATE, RE1 ; UM245 WE -> low bsf LATA, RA0 ; memory /RD -> low waittxeh: btfss PORTB, RB2 ; wait /TXE -> high bra waittxeh incfsz LATC, f ; update memory address bra putdata ; loop for 256 bytes incf madl, f ; update memory page decfsz pagecnt2,f ; finish? bra setpage2 ; no, next page incf madh, f ; update bank decfsz bankcnt2,f ; finish? bra setbnk2 ; no, next bank bsf LATA, RA1 ; memory /CE -> high bsf LATA, RA4 ; /G1 -> high: disable UM245/RAM buffer bra abrt ; end of transfer ; get a double byte command from host getcmd: setf LATD bsf PORTA, RA4 ; /G1 -> high bsf PORTA, RA3 ; /G2 -> high bsf PORTA, RA2 ; DIR -> high (read port) bcf PORTA, RA5 ; /G0 -> low - enable data buffer for UM245 bcf PORTE, RE0 ; /RD toggle nop ldw PORTD ; read UM245 data port bsf PORTE, RE0 getcmd1: btfss PORTB, RB0 ; wait /RXF -> high bra getcmd1 movwf umdat0 ; save data 0 ; now wait, within 20ms timeout, for second byte of this command ; get a byte from UM245 port within 20ms timeout getbyte: clrf umrx ; clear received flag bcf PORTA, RA5 ; /G0 -> low - enable data buffer for UM245 movlw TMR0P8 ; TMR0 stop, prescaler = 16, 16 bit mode movwf T0CON bcf INTCON, TMR0IF ; clear timeout flag movlw HIGH(T20MS) ; set timeout 20ms movwf TMR0H movlw LOW(T20MS) movwf TMR0L ; load TMR0L/H bsf T0CON, TMR0ON ; start Timer 0 ; loop byte within 20ms timeout getbyte2: btfsc INTCON, TMR0IF bra getbyte4 ; timeout btfsc PORTB, RB0 ; wait /RXF -> low bra getbyte2 bcf PORTE, RE0 ; /RD toggle nop ldw PORTD ; read UM245 data port bsf PORTE, RE0 getbyte3: btfss PORTB, RB0 ; wait /RXF -> high bra getbyte3 setf umrx ; set flag received byte getbyte4: bcf T0CON, TMR0ON ; stop Timer 0 bcf INTCON, TMR0IF ; clear timeout flag ;bsf PORTA, RA5 ; /G0 -> high - disable data buffer for UM245 return ; no ; send an ACK to host sndack: movlw DEV_ACK bra sndresp ; send a NACK to host sndnack: movlw DEV_NACK ; send response (ack or nack) to host within some timeout sndresp: bcf PORTA, RA2 ; set DIR -> low: write to UM245 port movwf LATD ; save byte to send clrf DDRD ; RD<0:7> all's output bcf PORTA, RA5 ; /G0 -> low - enable data buffer for UM245 movlw TMR0P8 ; TMR0 stop, prescaler = 16, 16 bit mode movwf T0CON bcf INTCON, TMR0IF ; clear timeout flag movlw HIGH(T20MS) ; set timeout 20ms movwf TMR0H movlw LOW(T20MS) movwf TMR0L ; load TMR0L/H bsf T0CON, TMR0ON ; start Timer 0 ; wait /TXE low within 20ms timeout sendresp2: btfsc INTCON, TMR0IF bra sendresp3 ; timeout btfsc PORTB, RB2 ; wait /TXE -> low bra sendresp2 bsf PORTE, RE1 ; WR toggle bcf PORTE, RE1 sendresp3: setf DDRD ; RD<0:7> all's input bsf PORTA, RA5 ; /G0 -> high - disable data buffer for UM245 bsf PORTA, RA2 ; set DIR -> high: read from UM245 port return ; Init micro init: bcf RCON, 6 ; disable SBOREN bit bsf RCON, 1 ; enable POR bit clrf INTCON ; disable interrupt clrf INTCON2 ; RB0, RB1, RB2 negative edge clrf INTCON3 clrf PIR1 clrf PIR2 clrf PIE1 clrf PIE2 clrf ADCON0 ; disable A/D module setf DDRA ; all I/O in input mode setf DDRB setf DDRC setf DDRD movlw B'00000111' ; RE port movwf LATE movlw B'00001111' ; all I/O are digital movwf ADCON1 setf LATA ; all I/O out at high level setf LATB setf LATC setf LATD setf LATE bcf LATE, RE1 ; RE1 = WR -> low bcf LATB, RB3 ; RB3 = /BUSY -> low bcf LATB, RB4 ; RB4 = ADL -> low bcf LATB, RB5 ; RB5 = ADH -> low bcf INTCON2, RBPU ; disable pull-up on PORT B clrf DDRA ; RA<0:6> all's output movlw B'11000111' ; RB<3:5> output, RB<0:2> input movwf DDRB clrf DDRC ; RC<0:7> all's output clrf DDRE ; RE<0:2> all's output movlw TMR0P8 ; TMR0 stop, prescaler = 8, 16 bit movwf T0CON ; at 40MHz, period = 800ns ; instruction cycle time = 100nS clrram: lfsr FSR0, 0x0 ; clear RAM bank 0, 1 & 2 movlw 0x03 clrram1: clrf POSTINC0 cpfseq FSR0H bra clrram1 return ; sense external vcc and set/reset flag extvcc vccsense: clrf extvcc ; clear external vcc flag btfss PORTB, RB1 ; RB1 - sensing external vcc return ; no external vcc setf extvcc ; external vcc is on return ; wait for specified milliseconds (mscnt) mswait: movlw TMR0P256 ; TMR0 stop, prescaler = 256, 16 bit movwf T0CON bcf INTCON, TMR0IF ; clear timeout flag movlw mscnt+1 ; set timeout movwf TMR0H ; TMR0H first movlw mscnt movwf TMR0L ; load both TMR0L/H bsf T0CON, TMR0ON ; start Timer 0 mswait1: btfss INTCON, TMR0IF ; wait counter overflow flag bra mswait1 bcf T0CON, TMR0ON ; stop Timer 0 bcf INTCON, TMR0IF ; clear timeout flag return end