TITLE "Source for CAN-USB4 interface for CBUS" ; filename CAN_USB4.asm 15/09/14 ; ; Uses 4 MHz resonator and PLL for 16 MHz clock ; This interface does not have a Node Number ; The setup timer is TMR3. This should not be used for anything else ; CAN bit rate of 125 Kbits/sec ; Standard frame only ; Uses 'Gridconnect' protocol for USB ; Works with FTDI 245AM for now. ; ; added RUN LED switch on. ; no full diagnostics yet. ; Doesn't use interrupts - for speed. ; Working at full speed with minimum CAN frames (no data bytes) ; 390 uSec per frame ; PC gets all frames 08/05/08 ; Mod so it sends response to RTR (FLiM compatibility) ; Fixed CAN_ID at 7E to avoid conflict with CAN_RS ; RTR response removed. Avoids possibility of buffer overflow ; Allows true sniffer capability for checking self enum. of other modules. ; FLiM should never have a CAN_ID of 7E ; This version is based on the CAN_USBm code but changed for the 25K80 and ; for use with the 14K50 as an altenative to Andrew's C code vrsion ; Incorporates ECAN overflow and busy mechanism as in the CAN_CAN ; Working with the 14K50 OK. 17/09/14 ; ; Assembly options LIST P=18F25K80,r=hex,N=75,C=120,T=ON include "p18f25K80.inc" ;definitions Change these to suit hardware. #DEFINE CDAV 5 #DEFINE UREQ 4 #DEFINE CREQ 1 #DEFINE UDAV 0 ;set config registers ;config for 18F25K80 CONFIG FCMEN = OFF, FOSC = HS1, IESO = OFF, PLLCFG = ON CONFIG PWRTEN = ON, BOREN = SBORDIS, BORV=0, SOSCSEL = DIG CONFIG WDTEN = OFF, WDTPS = 128 ;watchdog 512 mSec CONFIG MCLRE = ON, CANMX = PORTB CONFIG BBSIZ = BB1K CONFIG XINST = OFF,STVREN = ON,CP0 = OFF CONFIG CP1 = OFF, CPB = OFF, CPD = OFF,WRT0 = OFF,WRT1 = OFF, WRTB = OFF CONFIG WRTC = OFF,WRTD = OFF, EBTR0 = OFF, EBTR1 = OFF, EBTRB = OFF ; processor uses 4 MHz. Resonator ;**************************************************************** ; define RAM storage CBLOCK 0 ;file registers - access bank ;interrupt stack for low priority ;hpint uses fast stack W_tempL St_tempL Bsr_tempL PCH_tempH ;save PCH in hpint PCH_tempL ;save PCH in lpint (if used) Fsr_temp0L Fsr_temp0H Fsr_temp1L Fsr_temp1H Fsr_temp2L Fsr_hold Fsr_holx TempCANCON TempCANSTAT CanID_tmp ;temp for CAN Node ID IDtemph ;used in ID shuffle IDtempl Datmode ;flag for data waiting Count ;counter for loading Count1 Latcount ;latency counter Temp ;temps Temp1 ;the above variables must be in access space (00 to 5F) Buffer ;temp buffer in access bank for data RXbuf ;:0x1C USB serial receive packet buffer RXbuf1 RXbuf2 RXbuf3 RXbuf4 RXbuf5 RXbuf6 RXbuf7 RXbuf8 RXbuf9 RXbufA RXbufB RXbufC RXbufD RXbufE RxbufF RXbuf10 RXbuf11 RXbuf12 RXbuf13 RXbuf14 RXbuf15 RXbuf16 RXbuf17 RXbuf18 RXbuf19 ENDC ;ends at 5F CBLOCK h'60' ;rest of bank 0 Rx0con ;start of receive packet 0 Rx0sidh Rx0sidl Rx0eidh Rx0eidl Rx0dlc Rx0d0 Rx0d1 Rx0d2 Rx0d3 Rx0d4 Rx0d5 Rx0d6 Rx0d7 Tx0con ;start of transmit frame 0 Tx0sidh Tx0sidl Tx0eidh Tx0eidl Tx0dlc Tx0d0 Tx0d1 Tx0d2 Tx0d3 Tx0d4 Tx0d5 Tx0d6 Tx0d7 ;add variables to suit ;**************************************************************** ; used in ASCII to HEX and HEX to ASCII and decimal conversions Abyte1 ;first ascii char of a hex byte for ascii input Abyte2 ;second ascii char of a hex byte Hbyte1 ;first ascii char of a hex byte for ascii output Hbyte2 Atemp ;temp store Htemp Hexcon ;answer to ascii to hex conversion ;************************************************************* ; used in USB transmit and receive Srbyte_n ;number of serial bytes received in packet Stbyte_n ;number of serial bytes to send TXmode ;state during serial send RXmode ;state during serial receive RXtemp ;temp store for received byte RXnum ;number of chars in receive string Datnum ;no. of data bytes in a received frame ;************************************************************** ENDC CBLOCK 0x100 TXbuf ;USB transmit packet buffer to PC TXbuf1 TXbuf2 TXbuf3 TXbuf4 TXbuf5 TXbuf6 TXbuf7 TXbuf8 TXbuf9 TXbuf10 TXbuf11 TXbuf12 TXbuf13 TXbuf14 TXbuf15 TXbuf16 TXbuf17 Txbuf18 TXbuf19 TXbuf20 TXbuf21 TXbuf22 TXbuf23 TXbuf24 TXbuf25 ENDC ;**************************************************************** ; ; start of program code ORG 0000h nop ;for debug goto setup ORG 0008h goto hpint ;high priority interrupt ORG 0018h goto lpint ;low priority interrupt ;******************************************************************* ORG 0840h ;start of program ; ; ; high priority interrupt. hpint nop btfsc PIR5,IRXIF ;a bus error? bra err btfsc PIR5,ERRIF bra err bra no_err err bsf CANCON,ABAT ;abort transmission bcf PIR5,ERRIF ;clear interrupts bcf PIR5,IRXIF bcf PIE5,ERRIF bcf PIR5,IRXIF retfie 1 no_err movlb .15 btfss PIR5,FIFOWMIF,0 bra no_fifo bcf PIR5,FIFOWMIF,0 ;clear FIFO flag bcf PIR5,4,0 ;clear busy frame flag bsf TXB1CON,TXREQ ;send busy frame bcf PIE5,FIFOWMIE,0 ;disable FIFO interrupt movlb .14 bsf TXBIE,TXB1IE ;enable IRQ for busy frame sent bsf PIE5,4,0 ;enable IRQ for busy frame sent movlb 0 retfie 1 no_fifo bcf PIR5,4,0 ;clear busy frame flag movlb .14 bcf TXBIE,TXB1IE ;no busy frame IRQ movlb 0 bsf PIE5,FIFOWMIE ;wait for next FIFO IRQ retfie 1 ;************************************************************** ; ; ; low priority interrupt. (if used) ; lpint retfie ;********************************************************************* main btfsc COMSTAT,7 ;fast loop for CAN detection bra incan btfsc PORTB,UDAV bra inusb bra main ; move incoming CAN frame to serial output buffer incan movf CANCON,W ;sort out ECAN buffer andlw B'00001111' movwf TempCANCON movf ECANCON,W andlw B'11110000' iorwf TempCANCON,W movwf ECANCON movlw .13 movwf Count lfsr FSR0,RXB0SIDH ; ;start of CAN frame in RB0 lfsr FSR1,Rx0sidh incan1 movff POSTINC0,POSTINC1 ;save ECAN buffer decfsz Count bra incan1 bcf RXB0CON,RXFUL lfsr FSR0,Rx0sidh lfsr FSR1,TXbuf ;start of serial string for PC movlw ":" ;serial start movwf POSTINC1 btfsc Rx0sidl,3 ;is it extended bra exide movlw "S" ;standard frames only movwf POSTINC1 bra serload exide movlw "X" movwf POSTINC1 serload movf POSTINC0,W ;get byte call hexasc ;convert to acsii movff Hbyte1,POSTINC1 movff Hbyte2,POSTINC1 movf POSTINC0,W ;get byte call hexasc ;convert to acsii movff Hbyte1,POSTINC1 movff Hbyte2,POSTINC1 btfsc Rx0sidl,3 ;is it extended bra exload incf FSR0L ;skip the extended ID bytes incf FSR0L bra serlo1 exload movf POSTINC0,W ;get byte call hexasc ;convert to acsii movff Hbyte1,POSTINC1 movff Hbyte2,POSTINC1 movf POSTINC0,W ;get byte call hexasc ;convert to acsii movff Hbyte1,POSTINC1 movff Hbyte2,POSTINC1 serlo1 movff POSTINC0,Datnum ;get dlc byte btfsc Datnum,6 ;is it an RTR bra rtrset movlw "N" movwf POSTINC1 bra datbyte rtrset movlw "R" movwf POSTINC1 bcf Datnum,6 ;Datnum now has just the number datbyte tstfsz Datnum bra datload bra back2 datload movf POSTINC0,W ;get byte call hexasc ;convert to acsii movff Hbyte1,POSTINC1 movff Hbyte2,POSTINC1 decfsz Datnum bra datload back2 movlw ";" movwf POSTINC1 movf FSR1L,W ;get last movwf Count1 ;number of bytes to send lfsr FSR1,TXbuf ;set to output usbwr movlw B'00000000' movwf TRISC notwr1 btfsc PORTB,CREQ ;CREQ must be lo to write to USB initially bra notwr1 notwr bsf PORTB,CDAV btfss PORTB,CREQ ;CREQ must be hi to write to USB bra notwr movff POSTINC1,PORTC ;output byte nop ;settling time nop bcf PORTB,CDAV ;flag to USB nop nop decfsz Count1 bra notwr1 movlw B'11111111' movwf TRISC ;back to inputs endwr bra main inusb clrf RXmode ;clear receive mode flags movlw B'11111111' movwf TRISC ;set to input btfss PORTB,UDAV ;any USB data? bra notin ;loop bsf PORTB,UREQ ;can take inusb1 btfsc PORTB,UDAV ;is data bra inusb1 nop bcf PORTB,UREQ movlw ":" subwf PORTC,W bnz notin ;not start of frame inusb2 btfss PORTB,UDAV ;is data bra inusb2 bsf PORTB,UREQ inusb3 btfsc PORTB,UDAV bra inusb3 nop bcf PORTB,UREQ movlw "S" ;is it S (standard) or X (extended) subwf PORTC,W bz instd movlw "X" subwf PORTC,W bz inext bra notin ;neither so abort instd bcf RXmode,3 ;flag standard bra instart inext bsf RXmode,3 ;flag extended instart clrf RXnum ;byte counter lfsr FSR2,RXbuf ;set to start inloop btfss PORTB,UDAV ;read all USB till end bra inloop bsf PORTB,UREQ ;can take inloop1 btfsc PORTB,UDAV ;data? bra inloop1 nop bcf PORTB,UREQ movlw ";" ;end? subwf PORTC,W bz lastin movff PORTC,POSTINC2 ;bug fix bra inloop lastin movff PORTC,POSTINC2 lfsr FSR2,RXbuf ;point to serial receive buffer lfsr FSR1,Tx0sidh ;point to CAN TX buffer 1 - lowest priority txload movff POSTINC2,Abyte1 movff POSTINC2,Abyte2 call aschex movwf POSTINC1 ;put in CAN TX buffer movlw "N" subwf INDF2,W bz txload1 movlw "R" subwf INDF2,W bz txload5 bra txload txload5 bsf RXmode,2 ;flag R txload1 incf FSR2L ;miss N or R incf FSR1L ;miss dlc btfsc RXmode,3 ;is it ext bra txload2 incf FSR1L ;miss out EIDH and EIDL if not extended incf FSR1L txload2 movlw ";" subwf INDF2,W bz txdone txload4 movff POSTINC2,Abyte1 movff POSTINC2,Abyte2 call aschex movwf POSTINC1 ;put in CAN TX buffer incf RXnum,F bra txload2 txdone movf RXnum,W ;get number of data bytes btfsc RXmode,2 ;is it a RTR iorlw B'01000000' ;set RTR bit movwf Tx0dlc movlw B'00001000' btfsc RXmode,3 ;extended? iorwf Tx0sidl,F ;add extended bit clrf RXmode ;ready for next movlw .10 movwf Latcount ;ten tries at low priority call sendTX0 notin bcf PORTB,UREQ ;clear goto main ;*************************************************************************** ; main setup routine ;************************************************************************* setup bcf WDTCON,SWDTEN ;WDT off during reset movlb 0 clrf INTCON ;no interrupts yet movlb .15 clrf ANCON0 ;disable A/D clrf ANCON1 clrf CM1CON clrf CM2CON setf WPUB ;pullups set movlb 0 ;port settings will be hardware dependent. RB2 and RB3 are for CAN. ;set S_PORT and S_BIT to correspond to port used for setup. ;rest are hardware options movlw B'00100000' ;Port A outputs except reset pin movwf TRISA ; movlw B'00001011' ;RB0 is UDAV, RB1 is CREQ, RB2 = CANTX, RB3 = CANRX, RB4 = UREQ, RB5 = CDAV ;RB6,7 for debug and ICSP and diagnostic LEDs movwf TRISB clrf PORTB bsf PORTB,2 ;CAN recessive bcf PORTB,4 ;USB write strobe bcf PORTB,5 ;USB read strobe movlw B'11111111' ;Port C USB interface movwf TRISC ; next segment is essential. clrf BSR ;set to bank 0 clrf EECON1 ;no accesses to program memory bsf CANCON,7 ;CAN to config mode movlw B'10110000' movwf ECANCON ;CAN mode 2 bsf ECANCON,5 movlb .15 clrf RXB0CON clrf RXB1CON bsf TXB0CON,TXABT ;abort any pending messages bsf TXB1CON,TXABT movlb .14 clrf BSEL0 ;8 frame FIFO clrf B0CON clrf B1CON clrf B2CON clrf B3CON clrf B4CON clrf B5CON bcf TXBIE,TXB1IE ;no interrupt on busy movlw B'00000011' ;set CAN bit rate at 125000 for now. 4 MHz movwf BRGCON1 movlw B'10011110' ;set phase 1 etc movwf BRGCON2 movlw B'00000011' ;set phase 2 etc movwf BRGCON3 movlb 0 movlw B'00100000' movwf CIOCON ;CAN to high when off mskload lfsr FSR0,RXM0SIDH ;Clear masks, point to start mskloop clrf POSTINC0 cpfseq FSR0L bra mskloop bcf COMSTAT,RXB0OVFL ;clear overflow flags if set bcf COMSTAT,RXB1OVFL clrf PIR5 ;clear all flags clrf CANCON ;out of CAN setup mode clrf CCP1CON clrf IPR1 ;all peripheral interrupts are low priority clrf IPR2 clrf PIE2 clrf PIR5 ;can FLAGS clrf EEADRH ;clear EEPROM Hi byte movlw B'10001000' ;Config TX1 buffer for busy frame movwf CANCON movlb .15 ;buffer in bank 15 movlw B'00000011' movwf TXB0CON ;no send yet movwf TXB1CON clrf TXB1SIDH clrf TXB1SIDL clrf TXB1DLC movlb 0 ;back to bank 0 clrf CANCON ;out of CAN setup mode movlw 3 movwf Tx0con ;set transmit priority movlw B'00100011' movwf IPR3 ;high priority CAN RX and Tx error interrupts(for now) clrf IPR1 ;all peripheral interrupts are low priority clrf IPR2 clrf PIE2 clrf INTCON2 ; clrf INTCON3 ; clrf PIR1 clrf PIR2 clrf PIR5 movlw B'10110001' movwf IPR5 ;FIFOHWM and TXB are high priority movlw B'10110001' movwf PIE5 ;FIFOHWM IRQ, error interrupts and TX complete only bcf PORTB,6 bsf PORTB,7 ;put run LED on. goto main ;**************************************************************************** ; start of subroutines ;***************************************************************************** ; send a busy frame - already preloaded in TX0. sendTX1 movlb .15 ;set to bank 1 bsf TXB1CON,TXREQ ;send immediately movlb 0 ;back to bank 0 return ;****************************************************************** ; Send contents of Tx1 buffer via CAN TXB1 sendTX0 movlb .15 ;check for buffer access tx_loop btfsc TXB0CON,TXREQ bra tx_loop movlb 0 lfsr FSR0,Tx0con lfsr FSR1,TXB0CON ldTX0 movf POSTINC0,W movwf POSTINC1 ;load TXB1 movlw Tx0d7+1 cpfseq FSR0L bra ldTX0 movlb .15 ;bank 15 tx0test btfsc TXB0CON,TXREQ ;test if clear to send bra tx0test bsf TXB0CON,TXREQ ;OK so send tx1done movlb 0 ;bank 0 return ;successful send ;************************************************************************ ; converts one hex byte to two ascii bytes hexasc movwf Htemp ;save hex. comes in W swapf Htemp,W andlw B'00001111' ;mask addlw 30h movwf Hbyte1 movlw 39h cpfsgt Hbyte1 bra nxtnib movlw 7 addwf Hbyte1,F nxtnib movlw B'00001111' andwf Htemp,W addlw 30h movwf Hbyte2 movlw 39h cpfsgt Hbyte2 bra ascend movlw 7 addwf Hbyte2,F ascend return ;Hbyte1 has high nibble, Hbyte2 has low nibble ;**************************************************************************** ; converts two ascii bytes to one hex byte. ; for consistency, ascii hi byte in Abyte1, ascii low byte in Abyte2 ; answer in Hexcon aschex movlw 30h subwf Abyte1,F movlw 9 cpfsgt Abyte1 bra hinib movlw 7 subwf Abyte1,F hinib movf Abyte1,W movwf Hexcon swapf Hexcon,F movlw 30h subwf Abyte2,F movlw 9 cpfsgt Abyte2 bra hexend movlw 7 subwf Abyte2,F hexend movf Abyte2,W iorwf Hexcon,W return ; ;************************************************************************ end