CANUSB4-ISO/Source/CAN/CAN_USB4.asm

786 Zeilen
16 KiB
NASM

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