Aquí está el resto del archivo que no se ajustó a la respuesta anterior. Esta parte realiza el envío y la recepción reales en tiempo de ejecución.
;*******************************************************************************
;
; CAN receiving task.
;
can_task unbank ;task start address
;
; Wait for the software receive buffer to be empty. Another task may be
; reading the last received frame from the buffer. When done with the data
; in the receive buffer, FLAG_CANIN will be cleared.
;
wait_swbuf unbank ;back here until software buffer ready for next frame
gcall task_yield ;give other tasks a chance to run
dbankif gbankadr
btfsc flag_canin ;software CAN frame receive buffer is empty ?
jump wait_swbuf ;no, back and check again
;
; Clear the software receive buffer to all zeros. This makes it easier later
; to assemble the fields in the buffer from the hardware registers.
;
dbankif gbankadr
bcf flag_canin_ext ;init to not extended frame
bcf flag_canin_rtr ;init to not remote request frame
loadk32 canin_id, 0 ;set ID to 0
clrf canin_ndat ;init number of data bytes
clrf canin_dat+0 ;init the data bytes
clrf canin_dat+1
clrf canin_dat+2
clrf canin_dat+3
clrf canin_dat+4
clrf canin_dat+5
clrf canin_dat+6
clrf canin_dat+7
wait_recv unbank ;back here until a new CAN frame is received
gcall task_yield ;give other tasks a chance to run
dbankif comstat
btfss comstat, 7 ;at least one message in receive FIFO ?
jump wait_recv ;no, go back and check again
;
; Map the current receive buffer to the access bank region F60-F6Dh. This is
; where the fixed receive buffer 0 is located in legacy mode. The symbols
; RXB0xxx will therefore be used to access the buffer, even though it could
; be any of the 8 receive buffers.
;
dbankif cancon
movf cancon, w
andlw b'00001111' ;mask in only ID of the current receive buffer
addlw ecanconr0 ;merge with other control bits
dbankif ecancon
movwf ecancon ;map the current receiver buffer to access window
;
; A new CAN frame has been received and hardware receive buffer containing it
; has been mapped into the access bank where the fixed receive buffer 0
; normally is.
;
dbankif gbankadr
btfsc rxb0con, rtrro ;this is data frame, not remote request ?
bsf flag_canin_rtr ;is remote request frame
btfsc rxb0sidl, exid ;standard frame, not extended ?
jump recv_ext ;extended frame
;
; Standard frame. Get the 11 bit frame ID.
;
swapf rxb0sidl, w
rrncf wreg
andlw b'00000111'
iorwf canin_id+0 ;set ID bits
rlncf rxb0sidh, w
rlncf wreg
rlncf wreg
andlw b'11111000'
iorwf canin_id+0 ;set ID bits
swapf rxb0sidh, w
rrncf wreg
andlw b'00000111'
iorwf canin_id+1 ;set ID bits
jump done_id ;done assembling ID
;
; Extended frame. Get the 29 bit frame ID. In this case, the
; extended ID bits form the low 18 bits of the ID and the standard
; ID bits the high 11.
;
recv_ext dbankis gbankadr
bsf flag_canin_ext ;indicate extended frame
movf rxb0eidl, w
iorwf canin_id+0 ;set ID bits
movf rxb0eidh, w
iorwf canin_id+1 ;set ID bits
movf rxb0sidl, w
andlw b'00000011'
iorwf canin_id+2 ;set ID bits
swapf rxb0sidl, w
rlncf wreg
andlw b'00011100'
iorwf canin_id+2 ;set ID bits
swapf rxb0sidh, w
rlncf wreg
andlw b'11100000'
iorwf canin_id+2 ;set ID bits
rrncf rxb0sidh, w
rrncf wreg
rrncf wreg
andlw b'00011111'
iorwf canin_id+3 ;set ID bits
done_id dbankis gbankadr ;done assembling ID bits into CANIN_ID
;
; Get the data bytes.
;
movf rxb0dlc, w
andlw b'00001111' ;mask in only the number of data bytes
bz done_dat ;no data bytes ?
movwf reg2 ;save number data bytes in REG2
sublw 8 ;compare to max valid number
skip_wle ;number of data bytes is within range ?
jump done_dat ;skip the data bytes, something is wrong
movf reg2, w
movwf canin_ndat ;set 1-8 number of data bytes in frame
;
; Copy the data bytes in a unrolled loop. It would be faster for
; large frames to just copy all 8 bytes all the time. Only the
; actual data bytes are copied mostly to aid in debugging. The
; unused data bytes in the software buffer will therefore be zero.
;
movff rxb0d0, canin_dat+0
dcfsnz reg2
jump done_dat
movff rxb0d1, canin_dat+1
dcfsnz reg2
jump done_dat
movff rxb0d2, canin_dat+2
dcfsnz reg2
jump done_dat
movff rxb0d3, canin_dat+3
dcfsnz reg2
jump done_dat
movff rxb0d4, canin_dat+4
dcfsnz reg2
jump done_dat
movff rxb0d5, canin_dat+5
dcfsnz reg2
jump done_dat
movff rxb0d6, canin_dat+6
dcfsnz reg2
jump done_dat
movff rxb0d7, canin_dat+7
done_dat dbankis gbankadr ;done copying all data bytes into the software buffer
bcf rxb0con, rxful ;mark HW buffer as empty, allow it to be re-used
;
; Tell the rest of the system that a new CAN frame has been received.
; FLAG_CANIN is always set. This can be used by other parts of the system as
; a event flag to read the CAN frame in the CANIN buffer. This other code
; must clear FLAG_CANIN when done so that this task can read the next received
; CAN frame into the buffer.
;
; For some systems, waiting for FLAG_CANIN to be noticed may be too slow. For
; such cases there is a callback mechnism. When the preprocessor string
; constant CANIN_CALLBACK is not the empty string, it is taken as the name of
; a subroutine to call. This routine can perform immediate action from this
; task. In any case, whatever code in the rest of the system handles the
; received CAN frame must also clear FLAG_CANIN when it is done reading the
; CANIN buffer.
;
dbankif gbankadr
bsf flag_canin ;indicate a new received frame is in the CANIN buffer
/if [> [slen canin_callback] 0] then ;callback routine defined ?
/if callback_extern then
extern [chars canin_callback]
/endif
call [chars canin_callback]
/endif
jump wait_swbuf ;back to wait for done with this frame
;*******************************************************************************
;
; Subroutine CAN_SEND_INIT
;
; Init the transmit frame state. REG0 contains flag bits indicating the type
; of frame:
;
; Bit 0 - 0 = standard frame, 11 bit ID
; 1 = extended frame, 29 bit ID
;
; Bit 1 - 0 = data frame
; 1 = remote request frame
;
; The transmit state frame has a interlock so that only one task at a time can
; attempt to send a frame. This routine waits for the transmit frame state to
; be available, then locks it. Since this routine must always be called each
; new CAN frame transmitted, the caller has exclusive access to the transmit
; state until it is released by CAN_SEND.
;
glbsub can_send_init, noregs
;
; Wait for the transmit frame state to not be in use, then lock it for our
; use.
;
sendi_wait unbank
dbankif gbankadr
btfss flag_cansend ;transmit frame still in use ?
jump sendi_avail ;no, it is available
gcall task_yield_save ;give other tasks a chance to run
jump sendi_wait ;back to check again
sendi_avail dbankis gbankadr ;transmit frame state is not in use
bsf flag_cansend ;indicate it is now in use
movff currtask, canwtask ;save ID of task that has transmit state locked
;
; Initialize the transmit frame state.
;
dbankif lbankadr
movf reg0, w ;get the flags byte
andlw b'00000011' ;mask in only the valid flags
movwf wr_flags ;init transmit frame flags byte
loadk32 wr_id, 0 ;init all the ID bits to 0
loadk8 wr_ndat, 0 ;init number of data bytes to 0
leaverest
;*******************************************************************************
;
; Subroutine CAN_SEND_ID
;
; Set the ID of the transmit frame state. If this is a standard frame, then
; the ID is in the low 11 bits of REG1:REG0. If this is a extended frame,
; then the ID is in the low 29 bits of REG3:REG2:REG1:REG0.
;
glbsub can_send_id, noregs
dbankif lbankadr
movff reg0, wr_id+0 ;set low 8 bits of ID
btfsc wr_flags, 0 ;this is a standard frame ?
jump sid_ext ;extended frame
;
; Standard frame. ID is 11 bits.
;
movf reg1, w
andlw b'00000111' ;mask in valid ID bits only
movwf wr_id+1 ;save ID high byte
clrf wr_id+2 ;clear unused ID bytes
clrf wr_id+3
jump sid_leave
;
; Extended frame. ID is 29 bits.
;
sid_ext dbankif lbankadr
movff reg1, wr_id+1
movff reg2, wr_id+2
movf reg3, w
andlw b'00011111' ;mask in valid ID bits of high byte only
movwf wr_id+3
sid_leave unbank ;common exit point
leaverest
;*******************************************************************************
;
; Subroutine CAN_SEND_DAT
;
; Add the byte in REG0 as the next data byte in the transmit frame state.
; Data bytes beyond what the CAN frame can contain are ignored.
;
glbsub can_send_dat, noregs
dbankif lbankadr
btfsc wr_flags, 1 ;normal, not remote request frame
jump sdat_leave ;remote request frames don't have data bytes
movf wr_ndat, w ;get number of data bytes already stored
sublw 7 ;compare to max with any room left
skip_wle ;still room for another data byte ?
jump sdat_leave ;no
lfsr 0, wr_dat ;init pointer to first data byte
movf wr_ndat, w
addwf fsr0l ;add offset to new data byte to write
movff reg0, indf0 ;stuff the data byte into the transmit frame buffer
incf wr_ndat ;update number of data bytes stored
sdat_leave unbank ;common exit point
leaverest
;*******************************************************************************
;
; Subroutine CAN_SEND
;
; Send the frame stored in the current transmit frame state. This routine
; returns when the transmission has been initiated. The actual transmission
; may not occur until later, and may fail. However, after this call the
; information about the frame will have been transferred into the hardware and
; the lock on the software transmit frame state released.
;
glbsub can_send, noregs
;
; Wait for any previous frame to finish transmission.
;
snd_wait unbank
dbankif txb0con
btfss txb0con, txreq ;previous transmission still in progress ?
jump snd_ready ;no
gcall task_yield_save ;give other tasks a chance to run
jump snd_wait
snd_ready unbank ;HW is ready for next transmission
;
; Load the transmit buffer control registers sequentially starting with
; TXB0SIDH. The registers that will be loaded, in order, are:
;
; SIDH
; SIDL
; EIDH
; EIDL
; DLC
;
dbankif lbankadr
lfsr 0, txb0sidh ;init pointer to first sequential register
btfsc wr_flags, 0
jump snd_ext
;
; This is a standard frame, 11 bit ID.
;
rrncf wr_id+0, w
rrncf wreg
rrncf wreg
andlw b'00011111'
movwf indf0 ;set standard address bits
swapf wr_id+1, w
rlncf wreg
andlw b'11100000'
iorwf postinc0 ;set standard address bits
swapf wr_id+0, w
rlncf wreg
andlw b'11100000'
movwf postinc0 ;set standard address bits
clrf postinc0 ;EIDH not used in standard address mode
clrf postinc0 ;EIDL not used in standard address mode
jump snd_doneadr ;done setting address bits
;
; This is a extended frame, 29 bit ID.
;
snd_ext dbankis lbankadr
rlncf wr_id+3, w
rlncf wreg
rlncf wreg
andlw b'11111000'
movwf indf0 ;set ID bits
swapf wr_id+2, w
rrncf wreg
andlw b'00000111'
iorwf postinc0 ;set ID bits
rlncf wr_id+2, w
rlncf wreg
rlncf wreg
andlw b'11100000'
movwf indf0 ;set ID bits
bsf indf0, exide ;indicate this is a extended frame
movf wr_id+2, w
andlw b'00000011'
iorwf postinc0 ;set ID bits
movff wr_id+1, postinc0 ;set ID bits
movff wr_id+0, postinc0 ;set ID bits
snd_doneadr dbankis lbankadr ;done setting address bits
movf wr_ndat, w ;get number of data bytes
btfsc wr_flags, 1 ;data frame ?
iorlw b'01000000' ;no, remote request frame
movwf postinc0
;
; Load the data bytes.
;
movff wr_dat+0, postinc0
movff wr_dat+1, postinc0
movff wr_dat+2, postinc0
movff wr_dat+3, postinc0
movff wr_dat+4, postinc0
movff wr_dat+5, postinc0
movff wr_dat+6, postinc0
movff wr_dat+7, postinc0
;
; Write the transmit buffer control byte. The TXREQ bit will be set to one,
; which starts the transmission.
;
setreg b'00001000', txb0con
; 0------- clear transmit completed flag
; -XXX---- read-only status bits
; ----1--- request transmission
; -----X-- unused
; ------00 priority level
dbankif gbankadr
bcf flag_cansend ;release lock on transmit frame state
leaverest