dnl (c)INRIA 1999 Christophe.Lavarenne@inria.fr dnl $Id: CAN.m4x,v 1.2 2000/04/17 13:11:52 lavarenn Exp lavarenn $ dnl WARNING: this file must be processed by GNU m4 (REQUIRED!) divert(-1) # SynDEx v5 generic executive kernel, extension for CAN interface between # a host `386' processorType_ and other processorTypes ######################################################################### # # This file is expected to be loaded after either 386.m4x or 555.m4x or 332.m4x # # CL: THE 332 PART MUST BE EITHER REVISITED, OR DELETED!!! ######################################################################### # WARNING: macros names must match the regexp [_A-Za-z][_A-Za-z0-9]* # (They MAY NOT begin with a digit!) define(`_386_endian_',`LittleEndian') define(`_555_endian_',`BigEndian') define(`_332_endian_',`BigEndian') ######################################################################### # Principles of operation # Each communication medium, i.e. here each CAN bus, is a sequential resource # where interprocessor data transfers must be ordered. Rather than a dynamic # ordering, done at run time by the CAN arbitration on transfers contents, # and which requires identification information to be transfered and decoded, # a static ordering is chosen at compile time, where each transfer is uniquely # identified simply by its position in the communication sequence. As the CAN # bus has no centralized communication sequencer, the communication sequence # must be distributed and synchronized on all the processors sharing the bus: # at each communication step, all processors know the transfer type and size, # the transmitting processor knows its source buffer address, each receiving # processor knows its destination buffer address, and each remaining processor # is synchronizing, i.e. waits for data as if it were receiving, but does not # store the data. Moreover, to avoid dynamic buffer allocation and overruns, # the transmitting processor does not start transmitting data before it has # received, from each receiving processor, an empty synchronizing frame meaning # that the destination buffer is available for reception. # ---------------------- # Present implementation # Each communication step (see `CAN_send_', `CAN_recv_' and `CAN_sync_' macros) # takes as arguments the data buffer name, the transmitting processor type and # name, and the receiving processors names. The number of empty synchronizing # frames to be received before transfering data frames, is therefore $#-3 (the # number of arguments of the macro, minus 3). # Each communication step is processed in several stages under the control of # an automaton. Initially, and after each communication step completes, a # synch-frame counter is reset, and then incremented by the interrupt triggered # by each received synch-frame (automaton state: CAN_init_state). # When a communication step is initiated (see CAN_send_shared, CAN_recv_shared, # and CAN_sync_shared), the base address and the byte size of the data buffer # (computed from the data buffer name), as well as the address of the next # instruction in the communication sequence, are stored in a "transfer context" # for later use, and the synch-frame counter is decremented by the number of # synch-frames to be received. Moreover, in the case of a receive step, a # synch-frame is transmitted, regardless of the number of synch-frames already # received, but with a CAN message identifier different for each processor; # as only the number of synch-frames matters, it is easier to let the CAN bus # arbitrate any contention between synch-frames, than to statically order # synch-frames (which would require each receiving processor to transmit its # synch-frame only after it has received the number of synch-frames which were # to be transmitted before it). The automaton then waits for synch-frames # in the CAN_send/recv_waitingSynch_state, counting receive interrupts. # When the synch-frame counter reaches zero, all the receiving processors have # their destination buffer ready for reception, then data transfers may begin # using and updating the "transfer context" which holds the number of data # bytes remaining to transfer and the address of the next byte to transfer. # In the case of the transmitting processor (CAN_sending_state), CAN frame # buffers are loaded with data and submitted for transmission; for a receiving # processor (CAN_recving_state), frame buffers are (stored and re-)submitted # for reception; for a synchronizing processor (CAN_sync_state), frame buffers # are only submitted for reception (their contents is not stored to memory). # After each frame buffer(s) submission (one 8-bytes frame buffer for the 386 # and 332, 16 frame buffers for the 555), the automaton waits for the end-of- # transfer interrupt, letting the processor execute the computation sequence. # When the number of bytes remaining to transfer reaches zero, the # communication sequence is resumed (CAN_resume_state) at the address stored # when the communication step was initiated. # # CL000412: # On the 555, two frames with the same ID will be received in the same buffer; # therefore, to be able to use the 16 frame buffers, a different ID should be # used for each frame buffer. Too complicated for a first version, only two # frame buffers are used, one for emission, the other for recption; as all # frames have the same ID, and as the reception buffers also receives the # frames emitted locally, only the reception buffer triggers an interrupt. ######################################################################### define(`CAN_IDMSB_',0x55)dnl SynDEx-ordered frames identifier ifelse( lang_,`asm555', `# ============== mpc555 ================== # ------------------- # CAN_shared_(mediaName,procrNames) define(`CAN_shared_', ` pushdef(`CPid_', substr($1,eval(len($1)-1)))dnl TouCAN module identifier ifelse(translit(CPid_,01),`',, `error_(`CAN media name "$1" does not end with `0' or `1'.')')dnl CANbase_`'CPid_=ifelse(CPid_,`0',0x307000,0x307400) ifdef(`CAN_shared_once',,`define(`CAN_shared_once')dnl `# TouCAN Register Map (see mpc555 User Manual table 16-10 p16-21)' `# WARNING: in the User Manual, registers names are different in the table' `# and in their bit description; here bit description names are used.' `# The names are offsets relative to TouCAN_[01] registers base address.' CANMCR =0x80 `# 16 bits Module Configuration Register' `# (see table 16-11 p16-23)' CANICR =0x84 `# 16 bits Interrupt Configuration Register' `# 5:7=IRL Interrupt Request Level' `# 8:9=ILBS Interrupt Level Byte Select' CANCTRL0=0x86 `# 8 bits Control Register 0' CANCTRL1=0x87 `# 8 bits Control Register 1' PRESDIV =0x88 `# 8 bits Control and Prescaler Divider Register' `# (see table 16-8 p16-9)' CANCTRL2=0x89 `# 8 bits Control Register 2' TIMER =0x8A `# 16 bits Free-Running Timer Register' RXGMASK =0x90 `# 32 bits Receive Global Mask' `# 0:10=MID28:18, 11=0, 12=1(IDE), 13:30=MID17:0, 31=0' RX14MASK=0x94 `# 32 bits Receive Buffer 14 Mask' RX15MASK=0x98 `# 32 bits Receive Buffer 15 Mask' ESTAT =0xA0 `# 16 bits Error and Status Register' `# (See table 16-21 p16-30)' IMASK =0xA2 `# 16 bits Interrupt Masks' `# 0:15 Message Buffer0:15, 0=disable/1=enable' IFLAG =0xA4 `# 16 bits Interrupt Flags' RXECTR =0xA6 `# 8 bits Receive Error Counter' TXECTR =0xA7 `# 8 bits Transmit Error Counter' CANMSG0=0x100 `# 16 bytes Message Buffer 0' CANMSG1=0x110 `# 16 bytes Message Buffer 1' CANMSG15=0x1f0 `# 16 bytes Message Buffer 15' # Extended ID (CAN2.0B) Message Buffer Structure (see fig 16-3 p16-4) # offset 0: 16 bits Control/Status, 0:7=timeStamp 8:11=code 12:15=length # offset 2: 0:10=ID28:18 11=SRR 12=IDE 13:15=ID17:15 16:30=ID14:0 31=RTR # offset 6: 8 bytes Data, followed by 2 bytes Reserved # Standard ID (CAN2.0A) Message Buffer Structure (see fig 16-4 p16-4) # offset 0: 16 bits Control/Status, 0:7=timeStamp 8:11=code 12:15=length # offset 2: 0:10=ID28:18 11=RTR 12:15=0000 16:31=TimeStamp # offset 6: 8 bytes Data, followed by 2 bytes Reserved # RX Status8:11 code (see table 16-2 p16-5) # 0=INACTIVE 4=EMPTY 2=FULL 6=OVERRUN odd=BUSY(receiving) # Read Status to lock buffer (not locked if BUSY returned). # To unlock, lock another buffer or read Free-Running Timer Register. # p16-14: frame received in lowest numbered matching receive buffer # TX Control8:11 code (see table 16-3 p16-5) # 8=TxFree 0xC=TxRequest (see table for Remote Transmission codes) # set CANCTRL1.LBUF=1 to transmit lowest numbered buffer first CAN_INACTIVE=0x00 `# offset1 byte command for inactive buffers' CAN_EMPTY =0x40 `# offset1 byte command for ready to receive' CAN_TXREQ =0xC0 `# offset1 byte command for transmit request' CAN_bpf_=8 `# number of bytes transferred by frame, 9/10 if CAN2.0A/B' CAN_init_state: # handler for init state: count received synch-frames # ctxt=r26 0:iptr, 4:stat, 8:base=r28, 12:nsyn=r29, 16:size, 20:addr subi r29,r29,1; stw r29,12(r26) # decr nsyn b CAN_it_end # shared part called by every CAN_send_ communication step CAN_send_shared: # r31=returnAddress lr:{CAN_ctxt_X,nsyn,size,addr} # ctxt28 0:iptr27,4:stat,8:base,12:nsyn29,16:size30,20:addr31 mflr r27; mtlr r31 # lr=returnAddress r27:{ctxt,nsyn,size,addr} lmw r28,0(r27); la r27,16(r27); stw r27,0(r28) # save iptr lwz r27,12(r28); add. r29,r29,r27 # add nsyn to synch-frames to be received stmw r29,12(r28) # save nsyn,size,addr beq 0f # if all synch-frames received, otherwise: lis r27,CAN_send_waitingSynch_state@h ori r27,r27,CAN_send_waitingSynch_state@l; stw r27,4(r28) # save stat blr # return to caller 0: mr r26,r28; lwz r28,8(r26) # setup regs as if loaded by CAN_it_X b 0f # ctxt26 8:base28 etc. CAN_send_waitingSynch_state: # handler waiting synch-frames before sending # ctxt26 0:iptr, 4:stat, 8:base28, 12:nsyn29, 16:size30, 20:addr31 subic. r29,r29,1; stw r29,12(r26) # decr and save nsyn bne CAN_it_end # if still waiting, otherwise: 0: lis r27,CAN_sending_state@h; ori r27,r27,CAN_sending_state@l; stw r27,4(r26) CAN_sending_state: # handler for sending data frames # ctxt26 temp27 0:iptr,4:stat,8:base28,12:nsyn,16:size30,20:addr31 # copy 8 bytes in any case, and update addr and size: lwz r27,0(r31); stw r27,CANMSG1+6(r28) lwz r27,4(r31); stw r27,CANMSG1+10(r28) li r29,CAN_TXREQ+8 addi r31,r31,CAN_bpf_; subic. r30,r30,CAN_bpf_; stmw r30,16(r26) bgt 0f; add r29,r29,r30 # adjust TxDL if last frame lis r27,CAN_resume_state@h; ori r27,r27,CAN_resume_state@l; stw r27,4(r26) 0: stb r29,CANMSG1+1(r28) # request Tx b CAN_it_end # shared part called by every CAN_recv_ communication step CAN_recv_shared: # r31=returnAddress lr:{CAN_ctxt_X,nsyn,size,addr} mflr r27; mtlr r31 # lr=returnAddress r27:{ctxt,nsyn,size,addr} # ctxt28 0:iptr27, 4:stat, 8:base, 12:nsyn29, 16:size30, 20:addr31 lmw r28,0(r27); la r27,16(r27); stw r27,0(r28) # save iptr27 # add nsyn to synch-frames to be received, then save nsyn29,size30,addr31 lwz r27,12(r28); add r29,r29,r27; stmw r29,12(r28) # request Tx of synch-frame (length=0): lwz r31,8(r28); li r27,CAN_TXREQ; stb r27,CANMSG1+1(r31) lis r27,CAN_recv_waitingSynch_state@h ori r27,r27,CAN_recv_waitingSynch_state@l; stw r27,4(r28) # save stat blr # return to caller CAN_recv_waitingSynch_state: # handler waiting synch-frames before receiving # ctxt26 temp27 0:iptr, 4:stat, 8:base28, 12:nsyn29, 16:size30, 20:addr31 subic. r29,r29,1; stw r29,12(r26) # decr and save nsyn bne CAN_it_end # if still waiting other synch-frames, otherwise: lis r27,CAN_recving_state@h; ori r27,r27,CAN_recving_state@l; stw r27,4(r26) b CAN_it_end CAN_recving_state: # handler for storing 16 full received frames # ctxt26 temp27 buff29 0:iptr,4:stat,8:base28,12:nsyn,16:size30,20:addr31 # Data buffers are allocated by multiples of 4 bytes, then # 4 bytes may be transfered together before testing size: lwz r27,CANMSG0+ 6(r28); stw r27,0(r31); subic. r30,r30,4; ble 0f lwz r27,CANMSG0+10(r28); stw r27,4(r31); subic. r30,r30,4; addi r31,r31,8 0: stmw r30,16(r26); ble CAN_resume_state b CAN_it_end # byte-reverse 2/4/8-bytes items after reception from LittleEndian processor CAN_recv_brev2: # lr:{size/2,addr-2} mflr r28; lmw r30,0(r28) addi r28,r28,8; mtlr r28 # lr=retAddr r30=size r31=addr 0: lhzu r28,2(r31); sthbrx r28,0,r31; subic. r30,r30,1; bgt 0b blr # return to caller CAN_recv_brev4: # lr:{size/4,addr-4} mflr r28; lmw r30,0(r28) addi r28,r28,8; mtlr r28 # lr=retAddr r30=size r31=addr 0: lwzu r28,4(r31); stwbrx r28,0,r31; subic. r30,r30,1; bgt 0b blr # return to caller CAN_recv_brev8: # lr:{size/8,addr-8} mflr r28; lmw r30,0(r28) addi r28,r28,8; mtlr r28 # lr=retAddr r30=size r31=addr 0: lwzu r28,8(r31); lwz r29,4(r31); stwbrx r29,0,r31 li r29,4; stwbrx r28,r29,r31; subic. r30,r30,1; bgt 0b blr # return to caller # shared part called by every CAN_sync_ communication step CAN_sync_shared: # r31=returnAddress lr:{CAN_ctxt_X,nsyn} # ctxt30 temp27 0:iptr, 4:stat, 8:base, 12:nsyn31, 16:size, 20:addr mflr r27; mtlr r31 # lr=returnAddress r27:{ctxt,nsyn} # save nsyn = number of synch&data frames to receive: lmw r30,0(r27); stw r31,12(r30) # save nsyn la r27,8(r27); stw r27,0(r30) # save iptr lis r27,CAN_sync_state@h; ori r27,r27,CAN_sync_state@l; stw r27,4(r30) blr # return to caller CAN_sync_state: # handler waiting for synch-frames and then data frames # ctxt26 0:iptr,4:stat27,8:base28,12:nsyn29,16:size,20:addr subic. r29,r29,1; stw r29,12(r26) # save updated nsyn bne CAN_it_end # beq CAN_resume_state CAN_resume_state: # restore message buffers initial state # ctxt26 temp27 0:iptr,4:stat,8:base28,12:nsyn,16:size30,20:addr31 lis r27,CAN_init_state@h; ori r27,r27,CAN_init_state@l; stw r27,4(r26) lwz r27,0(r26) # r27=iptr mtlr r27; blrl # resume communication sequence # b CAN_it_end CAN_it_end: # every sub-handler returns here # The processor state will be restored by the IThandlerEnd: # ifdef(`MB',`lwz r13,24(sp); ')lwz r31,28(sp); mtlr r31 # lmw r26,0(sp); addi sp,sp,32 # restore used registers # rfi # return from interrupt b IThandlerEnd `# --------------------------------------------------' ')dnl end of CAN_shared_once `# Transfer context for CAN_'CPid_ Module: .lcomm CAN_ctxt_`'CPid_,24,4 # 0:iptr address of pending instruction in communication `thread_' sequence # 4:stat address of interrupt sub-handler for current state # 8:base TouCAN registers base address # 12:nsyn number of empty synch-frames to wait for before data-frames # 16:size remaining number of bytes to transfer # 20:addr address of next byte to transfer CAN_it_`'CPid_: `# CAN_'CPid_ `interrupt main handler' # The processor context is already saved by .ithandler: # (this handler only uses r26 to r31, LR and CR) # subi sp,sp,32; stmw r26,0(sp) # save used registers on stack # mflr r31; stw r31,28(sp)`'ifdef(`MB',`; stw r13,24(sp)') B(la r26,CAN_ctxt_`'CPid_); lmw r27,4(r26) `# load interrupt handler context' # ctxt=r26 0:iptr,4:stat=r27,8:base=r28,12:nsyn=r29,16:size=r30,20:addr=r31 mtlr r27 # reset IFLAG to allow new interrupts to be generated: lhz r27,IFLAG(r28); li r27,0; sth r27,IFLAG(r28) blr # jump to sub-handler for current state ') # ---------------- # CAN_ini_(mediaName,procrNames) # CANbase_0=0x307000 and CANbase_1=0x307400 are defined by `CAN_shared_' # `CPid_' is defined by `CAN_shared_' to be either `0' or `1'. # CAN (0 or 1) registers offsets are symbolically defined once by `CAN_shared_' # then `CANbase_`'CPid_+CAN_REGISTER_OFFSET' is used to access CAN registers. define(`IRQlevelCAN0',1)define(`IRQlevelCAN1',2)dnl between 0 and 6 define(`CAN_ini_', ``# TouCAN initialization (see Users Manual 16.4.2 p16-11)' `# setup r28=CANbase_'CPid_, the base address of CAN registers lis r28,CANbase_`'CPid_@h; ori r28,r28,CANbase_`'CPid_@l ifelse(CPid_,1,`dnl PP: WARNING!!! This initializations should be done by the bootloader. `# The following initializations are already done for CAN0 by the bootloader:' `# - reset TouCAN with CANMCR.SOFTRST' lhz r27,CANMCR(r28); ori r27,r27,0x200; sth r27,CANMCR(r28) # set SOFTRST # Robosoft also sets the HALT(0x1000) bit to allow write access to all regs 0: lhz r27,CANMCR(r28); andi. r27,r27,0x200; bne 0b `# wait until SOFTRST=0' # - init TX and RX pins in CANCTRL0: # bit0=0: 0:disable 1:enable BusOffInterrupt # bit1=0: 0:disable 1:enable ErrorInterrupt # bit4=0: RX1=0 = dominantBit # bit5=0: RX0=0 = dominantBit # bit6-7=0: TX0=0/TX1=1 = dominantBit li r0,0x00; stb r0,CANCTRL0(r28) # - init bit timing parameters in CANCTRL1: # bit8=0: SAMPle each bit 0:once 1:threeTimes # bit10=0: TSYNC disabled # bit11=1: LBUF buffer transmitted first 0:lowestID 1:lowestAddr # bit13-15=2: PROPSEG li r0,0x12; stb r0,CANCTRL1(r28) # - init bit timing parameters in CANCTRL2: # bit8-9=0: RJW # bit10-12=1: PSEG1 # bit13-15=1: PSEG2 li r0,0x09; stb r0,CANCTRL2(r28) # - select S-clock rate in PRESDIV: # 250K->0x13 500K->0x09 750K->7 1M->0x04 li r0,0x13; stb r0,PRESDIV(r28) # For more detail see CAN Version 2.0, Section B.17, Timing configuration # BitTIME = [ 1 + (PropSeg+1) + (PSeg1+1) + (PSeg2+1) ] x CanFreq # If PropSeg=2, PSeg1=1, PSeg2=1, BitTIME = 8 x CanFreq # - read ESTAT to clear error bits lhz r0,ESTAT(r28) ')dnl end of initializations for CAN0 already done by the CAN-bootloader # The bootloader does the following: # - freeze the TouCAN with CANMCR.HALT to allow reconfiguration lhz r27,CANMCR(r28); ori r27,r27,0x1000; sth r27,CANMCR(r28) # - select internal arbitration mode in CANCTRL1.LBUF: # LBUF=1 lowest numbered buffer is transmitted first lbz r27,CANCTRL1(r28); ori r27,r27,0x10; stb r27,CANCTRL1(r28) # - init CANMSG0=EMPTY(ready to receive), others INACTIVE la r29,CANMSG0+1(r28); la r30,CANMSG15+1(r28) li r27,CAN_EMPTY; stb r27,0(r29); li r27,CAN_INACTIVE 0: stbu r27,16(r29); cmplw r29,r30; blt 0b # setup SynDEx frames identifier, CANMSG0=recv, CANMSG1=send li r27,0x`'eval(CAN_IDMSB_<<8|lindex(processorName_,shift($@))<<5,16,4) sth r27,CANMSG0+2(r28); sth r27,CANMSG1+2(r28) # - init acceptance mask register: consider only the 8 MSBits of IDs lis r27,0xFF00; stw r27,RXGMASK(r28) # - init interrupt request level in CANICR: LEVEL 0/1 for TouCAN 0/1 li r27,0x0`'indir(IRQlevelCAN`'CPid_)00; sth r27,CANICR(r28) # - install the interrupt handler vector lis r27,CAN_it_`'CPid_@h; ori r27,r27,CAN_it_`'CPid_@l # handler entry point lis r29,SIVECtableLEVEL`'indir(IRQlevelCAN`'CPid_)@ha;dnl stw r27,SIVECtableLEVEL`'indir(IRQlevelCAN`'CPid_)@l(r29) # - enable the corresponding internal interrupt setting SIMASK lis r31,SIMASK@ha; lwz r0,SIMASK@l(r31) oris r0,r0,0x`'eval(0x4000>>(2*indir(IRQlevelCAN`'CPid_)),16,4);dnl stw r0,SIMASK@l(r31); # enable level IRQlevelCAN0/1 for CAN0/1 # - init interrupt masks in IMASK (see also CANCTRL0 and CANMCR.WAKE) # (only the CANMSG0 buffer will generate interrupts) # WARNING: 555UM maps MSB=bit0-LSB=bit15 and says: "setting a bit in # IMASK enables interrupt requests for the corresponding message buffer" # but Robosoft working code shows that CANMSG0 corresponds to LSB=bit15 li r0,0x0001; sth r0,IMASK(r28) # read IFLAG and clear it to avoid any side effect from the bootloader lhz r0,IFLAG(r28); li r0,0; sth r0,IFLAG(r28) # - initialize the interrupt handler context: # ctxt26 0:iptr, 4:stat=r29, 8:base=r30, 12:nsyn=r31, 16:size, 20:addr B(la r26,CAN_ctxt_`'CPid_) # interrupt handler context li r31,0; mr r30,r28 # init nsyn=0 last=base lis r29,CAN_init_state@h; ori r29,r29,CAN_init_state@l stmw r29,4(r26) # init stat,last,nsyn # - release CANMCR.HALT to let TouCAN synchronize with the CAN bus lhz r27,CANMCR(r28); andi. r27,r27,~0x1000&0xFFFF; sth r27,CANMCR(r28) # - read ESTAT to clear error bits lhz r0,ESTAT(r28) # ------------- END OF CAN INITIALIZATIONS ---------------- ') # ---------------- # CAN_end_(mediaName,procrNames) define(`CAN_end_', ``# TouCAN finalization' `# freeze CAN with CANMCR.HALT' lis r28,CANbase_`'CPid_@h; ori r28,r28,CANbase_`'CPid_@l lhz r27,CANMCR(r28); ori r27,r27,0x1000; sth r27,CANMCR(r28) popdef(`CPid_')dnl ') # ----------------- # CAN_send_(bufferName, senderType,senderName {,receiverNames}) # calls _CAN_send_($*) if defined define(`CAN_send_', `_(mflr r31; bl CAN_send_shared)dnl _(.int CAN_ctxt_`'CPid_, eval($#-3), eval($1_size_*type_($1)_size_), $1)') # ----------------- # CAN_recv_(bufferName, senderType,senderName {,receiverNames}) # calls _CAN_recv_($*) if defined # CAN_recv_shared: `# r31=returnAddress lr:{CAN_ctxt_X,nsyn,size,addr}' define(`CAN_recv_', `_(mflr r31; bl CAN_recv_shared)dnl _(.int CAN_ctxt_`'CPid_, eval($#-3), eval($1_size_*type_($1)_size_), $1)dnl ifelse(_$2_endian_,`LittleEndian',`dnl if different endianness: ifelse(type($1)_size_,1,, `dnl if byte order has to be reversed: _(mflr r27; bl CAN_recv_brev`'type_($1)_size_)dnl _(.int $1_size_, $1-type_($1)_size_)dnl _(mtlr r27 `# restore saved Link Register')')')') # ----------------- # CAN_sync_(dataType,dataSize, senderType,senderName {,receiverNames}) define(`CAN_sync_', `_(mflr r31; bl CAN_sync_shared)dnl _(.int CAN_ctxt_`'CPid_, eval($#-4)+(eval($2*$1_size_)+CAN_bpf_-1)/CAN_bpf_)') ############ # DOWNLOADER # For now, only the end of download is supported, # the forward-loading of other processors is not supported. # ------------- # CAN_loadFrom_(procrName {,destMedia}) define(`CAN_loadFrom_',` ifelse($2,,,`error_(`no more than one argument expected for now')')dnl # -------------------------------- see also 555boot.s # CL: the FLASHed bootloader should only accept SynDEx frames, otherwise # the download will be perturbated by dumb CAN stations. # save LR, IMASK, RXGMASK, CANMSG0.ID: mflr r9; lhz r10,IMASK(r28); lwz r11,RXGMASK(r28); lhz r12,CANMSG0+2(r28) # disable all CAN interrupts and accept all frames: li r27,0; sth r27,IMASK(r28); stw r27,RXGMASK(r28) # send controlFlowFrame with dataByte0=0 to request no more executive: # li r27,0; stb r27,CANMSG1+6(r28) # dataByte0=0 # li r27,CAN_TXREQ_+1; stb r27,CANMSG1+1(r28) # request Tx # CL: not implemented in FLASHed bootloader! b 3f 0:# subroutine to wait until a frame is received: lhz r29,IFLAG(r28); andi. r29,r29,0x0001; beq 0b li r29,0; sth r29,IFLAG(r28) # acknowledge IFLAG blr # return to caller 1:# wait flow control frame: dataByte0=nbDataFrames bl 0b; lbz r30,CANMSG0+6(r28) # r30=nbDataFrames 2:# wait full dataFrame with 8 data bytes: bl 0b; subi r31,r31,8 # executiveLength-=8; subic. r30,r30,1; bgt 2b # until --nbDataFrames == 0; cmpwi r31,0; bgt 1b # until executiveLength == 0; 3:# wait controlFlowFrame with request for (no) more executive # bl 0b # CL: not implemented in FLASHed bootloader! # wait prefix frame: 0-3=ProcID, 4-7=executiveLength bl 0b; lwz r31,CANMSG0+10(r28) # r31=executiveLength cmpwi r31,0; bne 1b # null executiveLength marks download end. # restore LR, IMASK, RXGMASK, CANMSG0.ID: mtlr r9; sth r10,IMASK(r28); stw r11,RXGMASK(r28); sth r12,CANMSG0+2(r28) # ----------------------------------- ') # ------------- # CAN_loadDnto_(srceMedia {,procrName}) # UNSUPPORTED FOR NOW unsupported(`CAN_loadDnto_') ', lang_,`asm386', `# ============== i80386 ================== # ------------------- # CAN_shared_(mediaName,procrNames) define(`CAN_shared_', ` pushdef(`CPid_', substr($1,eval(len($1)-1)))dnl CAN module identifier ifelse(translit(CPid_,01),`',, `error_(`CAN media name "$1" does not end with `0' or `1'.')')dnl ifdef(`CAN_shared_once',,`define(`CAN_shared_once') # The Philips 82C200 is a CANv2.0A compatible interface chip. # The Philips SJA1000 is a CANv2.0B compatible interface chip, # upward compatible with the 82C200. # They both have: # - an 8 bits bidirectional bus, multiplexing chip registers address and data # (there are 32 8-bits wide registers) # - an ALE (Address Latch Enable) input to select either address or data # - an INT output collecting all the interrupt sources # The ADLINK7841 revA PCI board includes two 82C200; # the PCI interface automatically selects at boot time: # - the board I/O base address; # . the 1st 82C200 registers are mapped at base+0x00 to base+0x1F # . the 2nd 82C200 registers are mapped at base+0x40 to base+0x5F # the PCI interface handles the multiplexing of registers address and values # - the board IRQ number, shared between the two 82C200. # The ADLINK7841 revB PCI board includes two SJA1000; # the PCI interface automatically selects at boot time: # - the board I/O base address; # . the 1st SJA1000 registers are mapped at base+0x00 to base+0x7F # . the 2nd SJA1000 registers are mapped at base+0x80 to base+0xFF # the PCI interface handles the multiplexing of registers address and values # - the board IRQ number, shared between the two SJA1000. # 82C200 constants # ---------------- CAN_CR_ = 0x0000 # CAN Control register CAN_CMR_ = 0x0001 # CAN Command register CAN_SR_ = 0x0002 # CAN Status register CAN_IR_ = 0x0003 # CAN Interrupt register CAN_ACR_ = 0x0004 # CAN Acceptance Code register CAN_AMR_ = 0x0005 # CAN Acceptance Mask register CAN_BTR0_ = 0x0006 # CAN Bus Timing 0 register CAN_BTR1_ = 0x0007 # CAN Bus Timing 1 register CAN_OCR_ = 0x0008 # CAN Output Control register CAN_TSTR_ = 0x0009 # CAN Test register (unused) CAN_TXID_ = 0x000A # CAN TX IDentifier register (8MS bits) CAN_TXDL_ = 0x000B # CAN TX ID. (3LS bits) and Data Length CAN_TXBUF_ = 0x000C # CAN TX Buffer (Size=8 bytes) CAN_RXID_ = 0x0014 # CAN RX IDentifier register (8MS bits) CAN_RXDL_ = 0x0015 # CAN RX ID. (3LS bits) and Data Length CAN_RXBUF_ = 0x0016 # CAN RX Buffer (Size=8 bytes) CAN_CDR_ = 0x001F # CAN Clock Divider register # TXID and RXID: bits7-0=ID10-3 # TXDL and RXDL: bits7-5=ID2-0, bit4=RTR, bits3-0=DataLength(<=8) # AMR and ACR only work on the 8 MSBits of the frame identifier (RXID) # BTR0 and BTR1 are related to set the CAN speed: # supported values for `CAN_speed_' are: # `125Kbps' `250Kbps' `500Kbps' `750Kbps' `1000Kbps' define(`CAN_speed_',`250Kbps') # WARNING!!! THE FOLLOWING VALUES SHOULD NOT BE CONSTANTS # THEY SHOULD BE OBTAINED THROUGH BIOS CALLS (TO BE CORRECTED) CL000104 # ADLINK7841 constants # --------------------- define(`CAN_IRQ_',0x0C) # CAN IRQ Number CAN_IOB_0=0xE400 # CAN I/O Base Address CAN_IOB_1=CAN_IOB_0+0x80 # CL: TO BE CHECKED!!! # The interrupt vector is saved on initialization and restored on finalization. .lcomm CAN_intVectorOff_,4 # saved interrupt vector offset (32bits) .lcomm CAN_intVectorSel_,2 # saved interrupt vector selector (16bits) # Transfer context for CAN_A and CAN_B Modules: .lcomm CAN_ctxt_0,32 .lcomm CAN_ctxt_1,32 # 0:iptr address of pending instruction in communication `thread_' sequence # 4:stat address of interrupt sub-handler for current state # 8:base I/O base address of CAN interface # 12:nsyn number of empty synch-frames to wait for before data-frames # 16:size remaining number of bytes to transfer # 20:addr address of next byte to transfer # 24:CAN_overrun_ receive overrun errors counter # 28:CAN_busError_ busError errors counter CAN_it_shared: # CAN 0 or 1 interrupt routine pushal # save registers pushw %ds # save data selector of interrupted task movw %cs:___djgpp_ds_alias,%ax # .data selector saved by djgpp bootstrap movw %ax,%ds # setup interrupt context data selector # Determine which of CAN_0_ or CAN_1_ interface triggered the interrupt: movl `$'CAN_ctxt_0,%ebx; movl `$'CAN_IOB_0+CAN_IR_,%edx; inb %dx,%al # CAN_IR_ &1=Rx &2=Tx, reading CAN_IR_ clears it and releases the /INT output testb `$'3,%al; jnz 0f # if CAN_A_ Rx1/Tx2 interrupt, otherwise CAN_B_: movl `$'CAN_ctxt_1,%ebx; movl `$'CAN_IOB_1+CAN_IR_,%edx; inb %dx,%al 0: movl 8(%ebx),%edi # BX=ctxt DI=base # movb %al,%cl # save CAN_IR_ into CL # CL: what should we do for Overrun and Error interrupts processing? # CL: should we do anything else than counting errors? Suggestion: # leal CAN_SR_(%edi),%edx; inb %dx,%al # AL=Status Register # testb `$'0x02,%al; jz 0f; incl CAN_overrun_(%ebx); 0: # testb `$'0x40,%al; jz 0f; incl CAN_busError_(%ebx); 0: # Acknowledge CAN interrupt on 8259 interrupt controller(s): movb `$'0x20,%al `# 8259 interrupt controller EOI code = 0x20'dnl ifelse(eval(CAN_IRQ_<8),1,,` outb %al,`$'0xA0 `# acknowledge interrupt on secondary 8259'') outb %al,`$'0x20 `# acknowledge interrupt on primary 8259' # Execute interrupt handler saved in context stat, with DI=base # CL: should we check that Rx/Tx interrupt is consistent with state? # State should be CAN_sending_state for Tx, and CAN_*_state for Rx, # with * = init, send_waitingSynch, recv_waitingSynch, recving, or synch. # ctxt=BX 0:iptr, 4:stat, 8:baseDI, 12:nsyn, 16:size, 20:addr call 4(%ebx) popw %ds; popal # restore saved data selector and registers iret # return from interrupt # ------------------ # Interrupt handlers CAN_init_state: `# handler for init state: count received synch-frames' `# ctxt=BX 0:iptr, 4:stat, 8:baseDI, 12:nsyn, 16:size, 20:addr' leal CAN_CMR_(%edi),%edx; movb `$'4,%al; outb %al,%dx `# release RxBuf' decl 12(%ebx) `# decr nsyn, i.e. count one synch-frame' ret `# return to caller, waiting for next synch-frame receive interrupt' `# shared part called by every CAN_send_ communication step' CAN_send_shared: `# returnAddress:{CAN_ctxt_X,nsyn,size,addr}' `# ctxtBX 0:iptr, 4:stat, 8:baseDI, 12:nsyn, 16:size, 20:addr' popl %eax; movl 0(%eax),%ebx `# BX=ctxt' leal 16(%eax),%ecx; movl %ecx,0(%ebx) `# save iptr' movl 12(%eax),%ecx; movl %ecx,20(%ebx) `# save addr' movl 8(%eax),%ecx; movl %ecx,16(%ebx) `# save size' movl 4(%eax),%ecx; addl %ecx,12(%ebx) `# add nsyn to synch-frames to receive' jz CAN_send_allSynchReceived `# if all synch-frames received, otherwise:' movl `$'CAN_send_waitingSynch_state,4(%ebx) `# setup stat' ret `# return to caller, waiting for next synch-frame receive interrupt' CAN_send_waitingSynch_state: `# handler waiting synch-frames before sending' `# ctxtBX 0:iptr, 4:stat, 8:baseDI, 12:nsyn, 16:size, 20:addr' leal CAN_CMR_(%edi),%edx; movb `$'4,%al; outb %al,%dx `# release RxBuf' decl 12(%ebx); cmpl `$'0,12(%ebx) `# decr nsyn, test if nsyn==0' jnz 1f `# if still waiting other synch-frames, otherwise:' CAN_send_allSynchReceived: movl 8(%ebx),%edi # DI=base, if jumping from CAN_send_shared movl `$'CAN_sending_state,4(%ebx) CAN_sending_state: `# handler for sending data frames' `# ctxtBX 0:iptr, 4:stat, 8:baseDI, 12:nsyn, 16:size, 20:addrSI' movl 20(%ebx),%esi `# SI=addr, copy 8 bytes in any case:' # The following 32bits I/O accesses do not work, they crash the processor! # movl 0(%esi),%eax; leal CAN_TXBUF_+0(%edi),%edx; outl %eax,%dx # movl 4(%esi),%eax; leal CAN_TXBUF_+4(%edi),%edx; outl %eax,%dx # CL: TO BE OPTIMIZED! leal CAN_TXBUF_(%edi),%edx; movb 0(%esi),%al; outb %al,%dx incl %edx; movb 1(%esi),%al; outb %al,%dx incl %edx; movb 2(%esi),%al; outb %al,%dx incl %edx; movb 3(%esi),%al; outb %al,%dx incl %edx; movb 4(%esi),%al; outb %al,%dx incl %edx; movb 5(%esi),%al; outb %al,%dx incl %edx; movb 6(%esi),%al; outb %al,%dx incl %edx; movb 7(%esi),%al; outb %al,%dx leal 8(%esi),%eax; movl %eax,20(%ebx) `# incr and save addr' movl `$'8,%ecx; subl %ecx,16(%ebx) `# CL=8, decr size' jg 0f `# if remaining bytes to send, otherwise:' movl `$'CAN_resume_state,4(%ebx) `# setup stat for end-of-transmit' addl 16(%ebx),%ecx `# CL=remaining bytes' 0: leal CAN_TXDL_(%edi),%edx; inb %dx,%al; andb `$'0xE0,%al `# get TxID2-0' orb %cl,%al; outb %al,%dx `# setup Tx Data Length' `#leal CAN_TXID_(%edi),%edx; movb `$'CAN_IDMSB_,%al, outb %al,%dx' leal CAN_CMR_(%edi),%edx; movb `$'1,%al; outb %al,%dx `# request Tx' 1: ret `# return to caller, waiting for data-frame end-of-transmit interrupt' `# shared part called by every CAN_recv_ communication step' CAN_recv_shared: `# returnAddress:{CAN_ctxt_X,nsyn,size,addr}' `# ctxtBX 0:iptr, 4:stat, 8:base, 12:nsyn, 16:size, 20:addr' popl %eax; movl 0(%eax),%ebx `# BX=ctxt' leal 16(%eax),%ecx; movl %ecx,0(%ebx) `# save iptr' movl 12(%eax),%ecx; movl %ecx,20(%ebx) `# save addr' movl 8(%eax),%ecx; movl %ecx,16(%ebx) `# save size' movl 4(%eax),%ecx; addl %ecx,12(%ebx) `# add nsyn to synch-frames to receive' movl `$'CAN_recv_waitingSynch_state,4(%ebx) `# setup stat' `# send synch-frame with my sender ID to differentiate each synch-frame:' movl 8(%ebx),%edi `# DI=base, setup CAN_TXDL_ with DataLength=0:' leal CAN_TXDL_(%edi),%edx; inb %dx,%al; andb `$'0xE0,%al; outb %al,%dx leal CAN_CMR_(%edi),%edx; movb `$'1,%al; outb %al,%dx `# request Tx' ret `# return to caller, waiting for next synch-frame receive interrupt' # Note that a transmitted frame is not receive, even with a matching ID; # this synch-frame will generate an end-of-transmit interrupt. CAN_recv_waitingSynch_state: `# handler waiting synch-frames before receiving' `# ctxtBX 0:iptr, 4:stat, 8:baseDI, 12:nsyn, 16:size, 20:addr' leal CAN_CMR_(%edi),%edx; movb `$'4,%al; outb %al,%dx `# release RxBuf' decl 12(%ebx); cmpl `$'0,12(%ebx) `# decr nsyn, and test if nsyn==0' jnz 0f `# if still waiting other synch-frames, otherwise:' movl `$'CAN_recving_state,4(%ebx) `# change stat' 0: ret `# return to caller, waiting for next receive interrupt' CAN_recving_state: `# handler for storing received frames' `# ctxtBX 0:iptr, 4:stat, 8:baseDI, 12:nsyn, 16:size, 20:addrSI' # testb `$'1,%cl; jnz 0f; incl CAN_errorNotRx_(%ebx); ret; 0f movl 20(%ebx),%esi `# SI=addr' `# Data buffers are allocated by multiples of 4 bytes, then' `# moving 1 to 4 bytes may be done in one long move only.' # But the following 32bits I/O access crashes the processor! # leal CAN_RXBUF_+0(%edi),%edx; inl %dx,%eax; movl %eax,0(%esi) leal CAN_RXBUF_(%edi),%edx; inb %dx,%al; movb %al,0(%esi) incl %edx; inb %dx,%al; movb %al,1(%esi) incl %edx; inb %dx,%al; movb %al,2(%esi) incl %edx; inb %dx,%al; movb %al,3(%esi) subl `$'4,16(%ebx) `# decr size' jle 0f `# if no byte remaining to receive, skip second long move' # But the following 32bits I/O access crashes the processor! # leal CAN_RXBUF_+4(%edi),%edx; inl %dx,%eax; movl %eax,4(%esi) incl %edx; inb %dx,%al; movb %al,4(%esi) incl %edx; inb %dx,%al; movb %al,5(%esi) incl %edx; inb %dx,%al; movb %al,6(%esi) incl %edx; inb %dx,%al; movb %al,7(%esi) subl `$'4,16(%ebx) `# decr size' leal 8(%esi),%eax; movl %eax,20(%ebx) `# incr and save addr' 0: leal CAN_CMR_(%edi),%edx; movb `$'4,%al; outb %al,%dx `# release RxBuf' jle CAN_resume_state `# if no byte remaining to receive, otherwise:' ret `# return to caller, waiting for next data-frame receive interrupt' `# byte-reverse 2/4/8-bytes items after reception from BigEndian processor' CAN_recv_brev2: `# returnAddress:{byteSize/2,addr}' popl %ebx; movl 0(%ebx),%ecx; movl 4(%ebx),%esi `# CX=byteSize/2 SI=addr' 0: movw 0(%esi),%ax; xchgb %al,%ah; movw %ax,0(%esi); addl `$'2,%esi; loop 0b leal 8(%ebx),%ebx; jmp %ebx `# return to caller' CAN_recv_brev4: `# returnAddress:{byteSize/4,addr}' popl %ebx; movl 0(%ebx),%ecx; movl 4(%ebx),%esi `# CX=byteSize/4 SI=addr' 0: movl 0(%esi),%eax; bswap %eax; movl %eax,0(%esi); addl `$'4,%esi; loop 0b leal 8(%ebx),%ebx; jmp %ebx `# return to caller' CAN_recv_brev8: `# returnAddress:{byteSize/8,addr}' popl %ebx; movl 0(%ebx),%ecx; movl 4(%ebx),%esi `# CX=byteSize/8 SI=addr' 0: movl 0(%esi),%eax; bswap %eax xchgl %eax,4(%esi); bswap %eax; movl %eax,0(%esi); addl `$'8,%esi; loop 0b leal 8(%ebx),%ebx; jmp %ebx `# return to caller' `# shared part called by every CAN_sync_ communication step' CAN_sync_shared: `# returnAddress:{CAN_ctxt_X,nsyn}' `# ctxtBX 0:iptr, 4:stat, 8:base, 12:nsyn, 16:size, 20:addr' popl %eax; movl 0(%eax),%ebx `# BX=ctxt' leal 8(%eax),%ecx; movl %ecx,0(%ebx) `# save iptr' movl 4(%eax),%ecx; addl %ecx,12(%ebx) `# add nsyn to synch-frames to receive' jz CAN_resume_state `# if all synch/data-frames received, otherwise:' movl `$'CAN_sync_state,4(%ebx) `# save stat' ret `# return to caller, waiting for next receive interrupt' CAN_sync_state: `# handler waiting for synch-frames and then data frames' `# ctxtBX 0:iptr, 4:stat, 8:baseDI, 12:nsyn, 16:size, 20:addr' leal CAN_CMR_(%edi),%edx; movb `$'4,%al; outb %al,%dx `# release RxBuf' decl 12(%ebx); cmpl `$'0,12(%ebx) `# decr nsyn, and test if nsyn==0' jz CAN_resume_state `# if all synch/data-frames received, otherwise:' ret `# return to caller, waiting for next receive interrupt' CAN_resume_state: `# send/recv/sync transfer terminated' `# ctxtBX 0:iptr, 4:stat, 8:baseDI, 12:nsyn, 16:size, 20:addr' movl `$'CAN_init_state,4(%ebx) `# reset initial state' jmp 0(%ebx) `# resume communication sequence at iptr' `# return to caller will be done from within communication sequence' `# --------------------------------------------------' ')dnl End of `CAN_shared_once' ')dnl End of `CAN_shared_' dnl IRQ2INT converts an IRQ number into an INT vector number: define(`IRQ2INT',`0x`'eval($1+ifelse(eval($1<8),1,8,0x70-8),16,2)')dnl dnl IRQ2INTMaskAddr converts an IRQ number to the I/O address dnl of the mask-register of the primary or secondary 8259 interrupt controller: define(`IRQ2INTMaskAddr',`ifelse(eval($1<8),1,0x21,0xA1)')dnl dnl IRQ2INTMask converts an IRQ number to the activation bit-mask dnl of the mask-register of the primary or secondary 8259 interrupt controller: define(`IRQ2INTMask',`0x`'eval(1<<($1&7),16,2)') dnl CANGET($1) returns in %al the contents of CAN register $1: define(`CANGET',`movw `$'CAN_IOB_`'CPid_+$1,%dx; inb %dx,%al') dnl CANSET($1,$2) sets the CAN register $2 to the immediate value $1: define(`CANSET',`movb `$'$1,%al; movw `$'CAN_IOB_`'CPid_+$2,%dx; outb %al,%dx') # ---------------- # CAN_ini_(mediaName,procrNames) define(`CAN_ini_', `ifdef(`CAN_ini_once',,`define(`CAN_ini_once')dnl # Save system CAN interrupt vector: dnl # int 0x21, AH=0x35, AL=intVector => ES:EBX=intAddress dnl pushw %es dnl movw `$'0x3500+IRQ2INT(CAN_IRQ_),%ax; int `$'0x21 dnl movl %ebx,CAN_intVectorOff_; movw %es,CAN_intVectorSel_ dnl popw %es # BL=intNumber AX=0x204(GetPMVector) int0x31(DPMI) --> CX=selector EDX=offset movb `$'IRQ2INT(CAN_IRQ_),%bl; movw `$'0x0204,%ax int `$'0x31 movw %cx,CAN_intVectorSel_; movl %edx,CAN_intVectorOff_ # Setup my own CAN interrupt vector: # CX=selector EDX=offset BL=intNumber AX=0x205(SetPMVector) int0x31(DPMI) movw %cs,%cx; movl `$'CAN_it_shared,%edx movb `$'IRQ2INT(CAN_IRQ_),%bl; movw `$'0x0205,%ax int `$'0x31 dnl # int 0x21, AH=0x25, AL=intVector, DS:EDX=intAddress dnl pushw %ds dnl movw %cs,%ax; movw %ax,%ds; movl `$'CAN_it_shared,%edx dnl movw `$'0x2500+IRQ2INT(CAN_IRQ_),%ax; int `$'0x21 dnl popw %ds # Enable 8259 interrupt-controller mask register inb `$'IRQ2INTMaskAddr(CAN_IRQ_),%al andb `$'0xFF-IRQ2INTMask(CAN_IRQ_),%al outb %al,`$'IRQ2INTMaskAddr(CAN_IRQ_) ')dnl end of `CAN_ini_once' `# ctxtBX 0:iptr, 4:stat, 8:baseDI, 12:nsyn, 16:size, 20:addr' movl `$'CAN_ctxt_`'CPid_,%ebx # BX=ctxt movl `$'CAN_IOB_`'CPid_,%edi; movl %edi,8(%ebx) # DI=base movl `$'CAN_init_state,4(%ebx); movl `$'0,12(%ebx) # init stat, nsyn=0 # init SJA1000 (compatible 82C200) registers: CANSET(0x01,CAN_CR_) # Request CAN reset # Force SJA1000 CAN mode bit (CDR.7) to 0 to enter BasicCan mode. # Note: Ref. Man. of SJA1000 p55 Jan. 2000 by PHILIPS Semiconductors CANGET(CAN_CDR_); andb `$'0x7F,%al; outb %al,%dx # 82C200 Acceptance filter setting. # Note: When a message is received, it is sequentially stored in the empty # RX buffer only if it passes the acceptance test. The acceptance test # verify the following equation: # [(ID.10 .. ID.3) EQUAL (AC.7 .. AC.0)] OR (AM.7 .. AM.0) = 1111 1111 b # where ID is the message identifier, AC.[7-0] the 8 Acceptance Code # Register (ACR) and AM.[7-0] the 8 Acceptance Mask Register (AMR) bits. CANSET(CAN_IDMSB_,CAN_ACR_) # Acceptance Code for SynDEx-ordered frames CANSET(0x00,CAN_AMR_) # Acceptance Mask = 0: accept only SynDEx frames # WARNING: the setting of Byte Timing Registers (BTR0 and BTR1) has been # obtained by hacking the initialization performed by the ADLINK software # (7841UTIL.EXE) available with our PCI CAN interface card. More precise # information has to be found! ! ! CANSET(ifelse( CAN_speed_,`125Kbps',0x03, CAN_speed_,`250Kbps',0x01, CAN_speed_,`500Kbps',0x00, CAN_speed_,`750Kbps',0x00, CAN_speed_,`1000Kbps',0x00, `error_(`CAN_speed_=$1 is not supported (BTR0)')'),CAN_BTR0_) CANSET(ifelse( CAN_speed_,`125Kbps',0x1C, CAN_speed_,`250Kbps',0x1C, CAN_speed_,`500Kbps',0x1C, CAN_speed_,`750Kbps',0x18, CAN_speed_,`1000Kbps',0x14, `error_(`CAN_speed_=$1 is not supported (BTR1)')'),CAN_BTR1_) # Output Control Register: 0xFA = push/pull normal mode CANSET(0xFA,CAN_OCR_) # CR.0 = 0: end reset # CR.1 = 1 Receive Interrupt 1/0:Enable/Disable # CR.2 = 1 Transmit Interrupt Enable # CR.3 = 0 Error Interrupt Enable # CR.4 = 0 Overrun Interrupt Enable # CR.5-7 reserved on SJA1000 # (CR.6 = 1: synchronisation (1 edge) on 82C200) CANSET(0x06,CAN_CR_) CANSET(CAN_IDMSB_,CAN_TXID_) # TxID 8 MSBits of 11 bits identifier CANSET(0x`'eval(lindex(processorName_,shift($@))<<5,16,2),CAN_TXDL_)`'dnl # TxID 3 LSBits of 11 bits identifier CANGET(CAN_IR_) # Read Interrupt reg to clear all pending ITs # CMR.1 = 1: abort TX # CMR.2 = 1: release RX buffer # CMR.3 = 1: reset OVR CANSET(0x0E,CAN_CMR_) # CL: is it really necessary after a CAN reset? ') # ---------------- # CAN_end_(mediaName,procrNames) define(`CAN_end_', `popdef(`CAN_IDLSB_') CANSET(0x00,CAN_CR_) # Disable all CAN ITs # Other finalizations must be done only once, # by the CAN module CAN_0_ or CAN_1_ which terminates last: movl `$'0,CAN_ctxt_`'CPid_+8 # clear base to signal finalization cmpl `$'0,CAN_ctxt_`'ifelse(CPid_,0,1,0)+8; jnz 0f # Disable 8259 interrupt-controller mask register inb `$'IRQ2INTMaskAddr(CAN_IRQ_),%al orb `$'IRQ2INTMask(CAN_IRQ_),%al outb %al,`$'IRQ2INTMaskAddr(CAN_IRQ_) # Restore saved CAN interrupt vector: # CX=selector EDX=offset BL=intNumber AX=0x205(SetPMVector) int0x31(DPMI) movw CAN_intVectorSel_,%cx; movl `$'CAN_intVectorOff_,%edx movb `$'IRQ2INT(CAN_IRQ_),%bl; movw `$'0x0205,%ax int `$'0x31 dnl # int 0x21, AH=0x25, AL=intVector, DS:EDX=intAddress dnl pushw %ds dnl movl CAN_intVectorOff_,%edx; movw CAN_intVectorSel_,%ax; movw %ax,%ds dnl movw `$'0x2500+IRQ2INT(CAN_IRQ_),%ax; int `$'0x21 dnl popw %ds 0: `# see jnz 0f above' ') # ----------------- # CAN_send_(bufferName, senderType,senderName {,receiverNames}) # calls _CAN_send_($*) if defined define(`CAN_send_', `ifdef($1_type_`_CAN_send_',`$1_type_()_CAN_send_($*)', `_(call CAN_send_shared)dnl ctxt,nsyn,size,addr: _(.int CAN_ctxt_`'CPid_, eval($#-3), eval($1_size_*type_($1)_size_), $1)')') # ----------------- # CAN_recv_(bufferName, senderType,senderName {,receiverNames}) # calls _CAN_recv_($*) if defined define(`CAN_recv_', `ifdef($1_type_`_CAN_recv_',`$1_type_()_CAN_recv_($*)', ` _(call CAN_recv_shared)dnl _(.int CAN_ctxt_`'CPid_, eval($#-3), eval($1_size_*type_($1)_size_), $1)dnl ifelse(_$2_endian_,`BigEndian',`dnl if different endianness: ifelse(type($1)_size_,1,, `dnl if byte order has to be reversed: _(call CAN_recv_brev`'type_($1)_size_)dnl _(.int $1_size_, $1)')')')') # ----------------- # CAN_sync_(dataType,dataSize, senderType,senderName {,receiverNames}) # calls _CAN_sync_($*) if defined define(`CAN_sync_', `ifdef($1_type_`_CAN_sync_',`$1_type_()_CAN_sync_($*)', ` _(call CAN_sync_shared)dnl _(.int CAN_ctxt_`'CPid_, eval($#-4 + ($1_size_*$2+7)/8))')') ################ # FORWARD LOADER # For now, only the download of the neighbour processors is supported, # the forward-download of other processors through neighbour processors # is not supported because a controlFlowFrame has been forgotten in the # FLASHed bootloader (which should only accept SynDEx frames, otherwise # the download process will be perturbated by yelling dumb CAN stations). # ------------- # CAN_loadFrom_(procrName {,destMedia}) # UNSUPPORTED FOR NOW unsupported(`CAN_loadFrom_') # ------------- # CAN_loadDnto_(srceMedia {,procrName}) # The macro substituting procrName_CANID_ into an integer is expected # to be defined, in appli.m4x for example: define(`CAN_loadIDs',`ifelse($1,,,` .int $1_CANID_ `# $1'CAN_loadIDs(shift($@))')') define(`CAN_loadDnto_',` ifelse($1,,,`error_(`$1 unexpected: should be empty string')')dnl # -------------------------------- see also 555boot.s .data; CAN_bootloaderIDs:CAN_loadIDs(shift($@)) .int 0 # table end marker .text # DisableCanInterrupts, AcceptAllFrameIDs # init SJA1000 (compatible 82C200) registers: CANSET(0x01,CAN_CR_) # Request CAN reset # Force SJA1000 CAN mode bit (CDR.7) to 0 to enter BasicCan mode. # Note: Ref. Man. of SJA1000 p55 Jan. 2000 by PHILIPS Semiconductors CANGET(CAN_CDR_); andb `$'0x7F,%al; outb %al,%dx # 82C200 Acceptance filter setting. # Note: When a message is received, it is sequentially stored in the empty # RX buffer only if it passes the acceptance test. The acceptance test # verify the following equation: # [(ID.10 .. ID.3) EQUAL (AC.7 .. AC.0)] OR (AM.7 .. AM.0) = 1111 1111 b # where ID is the message identifier, AC.[7-0] the 8 Acceptance Code # Register (ACR) and AM.[7-0] the 8 Acceptance Mask Register (AMR) bits. CANSET(0x00,CAN_ACR_) # Acceptance Code for SynDEx-ordered frames CANSET(0xFF,CAN_AMR_) # Acceptance Mask = 0xFF: accept all frames # WARNING: the setting of Byte Timing Registers (BTR0 and BTR1) has been # obtained by hacking the initialization performed by the ADLINK software # (7841UTIL.EXE) available with our PCI CAN interface card. More precise # information has to be found! ! ! CANSET(ifelse( CAN_speed_,`125Kbps',0x03, CAN_speed_,`250Kbps',0x01, CAN_speed_,`500Kbps',0x00, CAN_speed_,`750Kbps',0x00, CAN_speed_,`1000Kbps',0x00, `error_(`CAN_speed_=$1 is not supported (BTR0)')'),CAN_BTR0_) CANSET(ifelse( CAN_speed_,`125Kbps',0x1C, CAN_speed_,`250Kbps',0x1C, CAN_speed_,`500Kbps',0x1C, CAN_speed_,`750Kbps',0x18, CAN_speed_,`1000Kbps',0x14, `error_(`CAN_speed_=$1 is not supported (BTR1)')'),CAN_BTR1_) # Output Control Register: 0xFA = push/pull normal mode CANSET(0xFA,CAN_OCR_) # CR.0 = 0: end reset # CR.1 = 1 Receive Interrupt 1/0:Enable/Disable # CR.2 = 1 Transmit Interrupt Enable # CR.3 = 0 Error Interrupt Enable # CR.4 = 0 Overrun Interrupt Enable # CR.5-7 reserved on SJA1000 # (CR.6 = 1: synchronisation (1 edge) on 82C200) CANSET(0x00,CAN_CR_) CANSET(0x00,CAN_TXID_) # TxID 8 MSBits of 11 bits identifier CANSET(0x00,CAN_TXDL_)`'dnl # TxID 3 LSBits of 11 bits identifier CANGET(CAN_IR_) # Read Interrupt reg to clear all pending ITs # CMR.1 = 1: abort TX # CMR.2 = 1: release RX buffer # CMR.3 = 1: reset OVR CANSET(0x0E,CAN_CMR_) # CL: is it really necessary after a CAN reset? # CL: the FLASHed bootloader should only accept SynDEx frames, otherwise # the download will be perturbated by dumb CAN stations. # int *bootloaderIDs, file, executiveLength, nbFrames, CanBuf[2]; subl `$'24,%esp # // allocate local variable; EBP: 8:argc 12:argv `# // EBP: -4: return address after "call thread_'mediaName_`_"' # // EBP: -28:bootloaderIDs -24:file -20:execLength -16:nbFrames -12:CanBuf # for(bootloaderIDs=CAN_bootloaderIDs; *bootloaderIDs!=0; ++bootloaderIDs) { movl `$'CAN_bootloaderIDs,-28(%ebp) jmp 4f CanSendFrame: # subroutine to send full frame with 8 data bytes: # .data; printfDot: .asciz "."; # .text; pushl `$'printfDot; call _printf; addl `$'4,%esp movl `$'CAN_IOB_`'CPid_,%edi leal CAN_SR_(%edi),%edx; 0: inb %dx,%al; andb `$'4,%al; jz 0b # wait TxFree leal CAN_TXID_(%edi),%edx; movb `$'0, %al; outb %al,%dx # CL: ID=0 ?? leal CAN_TXDL_(%edi),%edx; movb `$'8, %al; outb %al,%dx leal CAN_TXBUF_(%edi),%edx; movb -12(%ebp),%al; outb %al,%dx incl %edx; movb -11(%ebp),%al; outb %al,%dx incl %edx; movb -10(%ebp),%al; outb %al,%dx incl %edx; movb -9(%ebp),%al; outb %al,%dx incl %edx; movb -8(%ebp),%al; outb %al,%dx incl %edx; movb -7(%ebp),%al; outb %al,%dx incl %edx; movb -6(%ebp),%al; outb %al,%dx incl %edx; movb -5(%ebp),%al; outb %al,%dx leal CAN_CMR_(%edi),%edx; movb `$'1, %al; outb %al,%dx # Request Tx ret CanRecvFrame: # subroutine to receive flowControlFrame: dataByte0=nbFrames movl `$'CAN_IOB_`'CPid_,%edi leal CAN_SR_(%edi),%edx; 0: inb %dx,%al; andl `$'1,%eax; jz 0b # wait RxFull leal CAN_RXBUF_(%edi),%edx; inb %dx,%al; movl %eax,-16(%ebp) # -> nbFrames leal CAN_CMR_(%edi),%edx; movb `$'4,%al; outb %al,%dx # release RxBuf ret .data; printfOK: .asciz "ok\n"; .text OK: pushl `$'printfOK; call _printf; addl `$'4,%esp; ret .data; printfSP: .asciz "sp=%8xh "; .text SP_: pushl %esp; pushl `$'printfSP; call _printf; addl `$'8,%esp; ret # // EBP: -28:bootloaderIDs -24:file -20:execLength -16:nbFrames -12:CanBuf 0:# do { CanBuf[0] = htonl(*bootloaderIDs); bswap %eax; movl %eax,-12(%ebp) # %eax = *bootloaderIDs, see label 4f # if(--argc == 0) { // EBP: 8:argc 12:argv subl `$'1,8(%ebp); jnz 1f # printf("Not enough sdxbin files on command line\n"); .global _printf .data; printfErrMissing: .asciz "Not enough sdxbin files on command line\n" .text; pushl `$'printfErrMissing; call _printf; addl `$'4,%esp # exit(1); // never returns .global _exit; pushl `$'1; call _exit 1:# } printf("Loading %s for procrID %xh\n", *++argv, *bootloaderIDs); movl -28(%ebp),%eax; pushl 0(%eax) # // EBP: 8:argc 12:argv addl `$'4,12(%ebp); movl 12(%ebp),%eax; pushl 0(%eax) # // *++argv .data; printfLoadingSdxfile: .asciz "Loading %s for procrID %xh\n" .text; pushl `$'printfLoadingSdxfile; call _printf; addl `$'12,%esp # // EBP: -28:bootloaderIDs -24:file -20:execLength -16:nbFrames -12:CanBuf # file = open(*argv, O_RDONLY|O_BINARY); // O_BINARY=4 O_RDONLY=0 pushl `$'4; movl 12(%ebp),%eax; pushl 0(%eax) # // *argv .global _open; call _open; addl `$'8,%esp; movl %eax,-24(%ebp) # if (file == -1) { printf("Cannot open it!\n", *argv); exit(2); cmpl `$'-1,%eax; jnz 1f .data; printfErrOpeningSdxfile: .asciz "Cannot open it!\n" .text; pushl `$'printfErrOpeningSdxfile; call _printf; addl `$'4,%esp pushl `$'2; call _exit # // never returns 1:# } read(file, &CanBuf[1], 4); // get executiveLength in bigEndian pushl `$'4; leal -8(%ebp),%eax; pushl %eax; pushl -24(%ebp) .global _read; call _read; addl `$'12,%esp # executiveLength = ntohl(CanBuf[1]); CanSendFrame(CanBuf); movl -8(%ebp),%eax; bswap %eax; movl %eax,-20(%ebp); call CanSendFrame # // EBP: -28:bootloaderIDs -24:file -20:execLength -16:nbFrames -12:CanBuf 2:# do { CanRecvFrame(nbFrames); // wait flowControlFrame call CanRecvFrame 3:# do { executiveLength -= read(file, Canbuf, 8); CanSendFrame(CanBuf); pushl `$'8; leal -12(%ebp),%eax; pushl %eax; pushl -24(%ebp) call _read; addl `$'12,%esp; subl %eax,-20(%ebp); call CanSendFrame # } while (--nbFrames != 0); subl `$'1,-16(%ebp); jnz 3b # } while (executiveLength > 0); close(file); cmpl `$'0,-20(%ebp); jg 2b .global _close; pushl -24(%ebp); call _close; addl `$'4,%esp .data; printfLoaded: .asciz "loaded.\n" .text; pushl `$'printfLoaded; call _printf; addl `$'4,%esp # CanRecvFrame(nbFrames); # } while (nbFrames != 0); # call CanRecvFrame; cmpl `$'0,-16(%ebp); jnz 0b # CL: not implemented in FLASHed bootloader! # } // endfor(bootloaderIDs=...; *bootloaderIDs!=0; ++bootloaderIDs) # // EBP: -28:bootloaderIDs -24:file -20:execLength -16:nbFrames -12:CanBuf addl `$'4,-28(%ebp) 4: movl -28(%ebp),%eax; movl 0(%eax),%eax; orl %eax,%eax; jnz 0b # // prefix with executiveLength=0 marks download end # CanBuf[0]=CanBuf[1]=0; CanSendFrame(CanBuf); movl `$'0,-12(%ebp); movl `$'0,-8(%ebp); call CanSendFrame leal CAN_SR_(%edi),%edx; 0: inb %dx,%al; andb `$'4,%al; jz 0b # wait TxFree addl `$'24,%esp # free allocated local variables # EnableCanInterrupts, AcceptOnlySynDExFrameIDs # CL: the FLASHed bootloader should only accept SynDEx frames, otherwise # the download will be perturbated by dumb CAN stations. # CANSET(0x01,CAN_CR_) # Request CAN reset # CANSET(0x00,CAN_AMR_) # Acceptance Mask = 0: accept only SynDEx frames # CANSET(0x06,CAN_CR_) # Enable Recv and Transmit ITs, end CAN reset # init SJA1000 (compatible 82C200) registers: CANSET(0x01,CAN_CR_) # Request CAN reset # Force SJA1000 CAN mode bit (CDR.7) to 0 to enter BasicCan mode. # Note: Ref. Man. of SJA1000 p55 Jan. 2000 by PHILIPS Semiconductors CANGET(CAN_CDR_); andb `$'0x7F,%al; outb %al,%dx # 82C200 Acceptance filter setting. # Note: When a message is received, it is sequentially stored in the empty # RX buffer only if it passes the acceptance test. The acceptance test # verify the following equation: # [(ID.10 .. ID.3) EQUAL (AC.7 .. AC.0)] OR (AM.7 .. AM.0) = 1111 1111 b # where ID is the message identifier, AC.[7-0] the 8 Acceptance Code # Register (ACR) and AM.[7-0] the 8 Acceptance Mask Register (AMR) bits. CANSET(CAN_IDMSB_,CAN_ACR_) # Acceptance Code for SynDEx-ordered frames CANSET(0x00,CAN_AMR_) # Acceptance Mask = 0: accept only SynDEx frames # WARNING: the setting of Byte Timing Registers (BTR0 and BTR1) has been # obtained by hacking the initialization performed by the ADLINK software # (7841UTIL.EXE) available with our PCI CAN interface card. More precise # information has to be found! ! ! CANSET(ifelse( CAN_speed_,`125Kbps',0x03, CAN_speed_,`250Kbps',0x01, CAN_speed_,`500Kbps',0x00, CAN_speed_,`750Kbps',0x00, CAN_speed_,`1000Kbps',0x00, `error_(`CAN_speed_=$1 is not supported (BTR0)')'),CAN_BTR0_) CANSET(ifelse( CAN_speed_,`125Kbps',0x1C, CAN_speed_,`250Kbps',0x1C, CAN_speed_,`500Kbps',0x1C, CAN_speed_,`750Kbps',0x18, CAN_speed_,`1000Kbps',0x14, `error_(`CAN_speed_=$1 is not supported (BTR1)')'),CAN_BTR1_) # Output Control Register: 0xFA = push/pull normal mode CANSET(0xFA,CAN_OCR_) # CR.0 = 0: end reset # CR.1 = 1 Receive Interrupt 1/0:Enable/Disable # CR.2 = 1 Transmit Interrupt Enable # CR.3 = 0 Error Interrupt Enable # CR.4 = 0 Overrun Interrupt Enable # CR.5-7 reserved on SJA1000 # (CR.6 = 1: synchronisation (1 edge) on 82C200) CANSET(0x06,CAN_CR_) CANSET(CAN_IDMSB_,CAN_TXID_) # TxID 8 MSBits of 11 bits identifier CANSET(0x`'eval(lindex(processorName_,shift(shift(threadArgs_)))<<5,16,2),CAN_TXDL_)`'dnl # TxID 3 LSBits of 11 bits identifier CANGET(CAN_IR_) # Read Interrupt reg to clear all pending ITs # CMR.1 = 1: abort TX # CMR.2 = 1: release RX buffer # CMR.3 = 1: reset OVR CANSET(0x0E,CAN_CMR_) # CL: is it really necessary after a CAN reset? # ------------------------------------------------- ') # reitem nos tiaf noissap as ed iuq emmoh l xuerueh <-- CL ', lang_,`asm68k', `# ============== mc68332 ================== ####################### # CL: MUST BE REVISITED # CL: TO BE CORRECTED: # CAN_send_ should not byteswap its input buffer before sending # because `send_' is not allowed to modify its input buffer which may be shared # instead CAN_recv_ should byteswap its output buffer after receiving ####################### # ------------------- # CAN_shared_(mediaName,procrNames) define(`CAN_shared_', ` ||========================= CAN ==================================== .set _CANA_, 0x20001 | A1-A0=01 select Address .set _CAND_, _CANA_+2 | A1-A0=11 select Data |----------------- CAN 80C200 registers numbers -------------------- .set _CR_, 0x00 | control .set _CMR_, 0x01 | command .set _SR_, 0x02 | status .set _IR_, 0x03 | interrupt .set _ACR_, 0x04 | acceptance code .set _AMR_, 0x05 | acceptance mask .set _BTR0_, 0x06 | bus timing 0 .set _BTR1_, 0x07 | bus timing 1 .set _OCR_, 0x08 | output control .set _TSTR_, 0x09 | test, inutilise ici ! .set _TXID_, 0x0A | TX identifier (8 MSBits) .set _TXDL_, 0x0B | TX id(3 LSBits)+RTR+dataLength(0-8) .set _TXBUF_, 0x0C | first byte of TX buffer (max 8) .set _RXID_, 0x14 | RX identifier (8 MSBits) .set _RXDL_, 0x15 | RX id(3 LSBits)+RTR+dataLength(0-8) .set _RXBUF_, 0x16 | first byte of RX buffer (max 8) .set _CDR_, 0x1F | clock divide alloc_(int,_DMA_SIZE)dnl remaining count of bytes to transfer alloc_(int,_DMA_ADDR)dnl address of next byte to transfer alloc_(int,_DMA_IPTR)dnl address of pending instruction in comm. sequence | ----------------------------------------------------------------------- | -------------- Sous-programmes d appel des CAN RECV, SEND & SYNC ------ | ----------------------------------------------------------------------- | La doc Philips dit que la sortie /INT du 80C200 est active tant que le | registre d interruption IR est non nul (il est annule des qu il est lu). | La doc dit que chaque source d interruption ne peut activer son bit de IR | que si son bit de masquage dans le registre de controle CR est a 1. | L occurence d une source d interruption, masquee ou non, est memorisee par | un bit dans le registre de status SR. | La doc laisse penser que le demasquage d une interruption dont une occurence | a ete memorisee dans SR ne provoque pas l activation du bit correspondant de | IR et donc n active pas la sortie /INT. | Cette implantation des routines d interruption a ete faite selon cette | interpretation de la documentation. | Dans le cas contraire, l implantation serait plus simple : | - CAN_send_shared serait identique a CAN_sync_shared | - le demasquage de l interruption de reception, si le message de synchro | est deja recu, provoquerait l interruption menant au cas can_int_sync. | WARNING: dans tous les cas de figure, il faut verifier qu un emetteur qui | envoie un message avec un identifiant qu il reconnait en reception, ne | declanche pas une interruption de reception (pas clair dans la doc). CAN_recv_shared: move.b `#'_TXDL_,_CANA_ | Tx Data Length register: move.b `#'16,_CAND_ | Request To Receive = sync message move.b `#'_CMR_,_CANA_ | Command register: move.b `#'1,_CAND_ | Request_TX, move.l (%sp)+,_DMA_IPTR | save address of pending instruction move.l %d0,_DMA_SIZE | save data buffer length move.l %a0,_DMA_ADDR | save data buffer address move.b `#'_CR_,_CANA_ | Control register: move.b `#'0x1a,_CAND_ | enable Rx Err Ovr interrupt rts CAN_sync_shared: | then fall into CAN_sync_shared move.l (%sp)+,_DMA_IPTR | save address of pending instruction move.l %d0,_DMA_SIZE | save data buffer length move.l %a0,_DMA_ADDR | save data buffer address move.b `#'_CR_,_CANA_ | Control register: move.b `#'0x1a,_CAND_ | enable Rx Err Ovr interrupt move.w `#'0x2600,%sr | zone critique ???? move.b `#'_SR_,_CANA_ | Status register: btst.b `#'0,_CAND_ | synchro frame already received? jeq CAN_sync_shared_end | if not, wait for synchro frame. move.b `#'_CMR_,_CANA_ | Command register: move.b `#'4,_CAND_ | release Rx buffer move.b `#'_IR_,_CANA_ | Interrupt register: move.b _CAND_,%d5 | read into %d0 (and reset when read) CAN_sync_shared_end: move.w `#'0x2400,%sr | fin zone critique ???? rts CAN_send_shared: | %d0=dataLength %a0=dataAddress move.l (%sp)+,_DMA_IPTR | save address of pending instruction move.l %d0,_DMA_SIZE | save data buffer length move.l %a0,_DMA_ADDR | save data buffer address move.b `#'_CR_,_CANA_ | Control register: move.b `#'0x1a,_CAND_ | enable Rx it BEFORE get status: move.w `#'0x2600,%sr | zone critique ???? move.b `#'_SR_,_CANA_ | Status register: btst.b `#'0,_CAND_ | synchro frame already received? jeq CAN_send_shared_end | if not, wait for synchro frame. move.b `#'_CMR_,_CANA_ | Command register: move.b `#'4,_CAND_ | release Rx buffer move.b `#'_IR_,_CANA_ | Interrupt register: move.b _CAND_,%d5 | read into %d0 (and reset when read) move.w `#'0x2400,%sr | fin zone critique ???? | The first frame sent must have a length between 1 and 8 bytes such that | all remaining frames will be full 8 bytes frames. CAN_send_first_frame: | %d0=dataLength %a0=dataAddress subq.b `#'1,%d0 | send minimum 1, maximum 8 bytes: andi.l `#'7,%d0 | (d0-1)%8+1 bytes addq.b `#'1,%d0 sub.l %d0,_DMA_SIZE | _DMA_SIZE -= number of bytes to send add.l %d0,_DMA_ADDR | _DMA_ADDR += number of bytes sent move.b `#'_TXDL_,_CANA_ | Tx Data Length register move.b %d0,_CAND_ | setup to number of bytes to send move.b `#'_TXBUF_,%d1 | first Tx Buffer register number subq.b `#'1,%d0 | -1 for DBRA 0: move.b %d1,_CANA_ | setup register number move.b (%a0)+,_CAND_ | read and set register value addq.b `#'1,%d1 | next register number dbra %d0,0b move.b `#'_CR_,_CANA_ | Control register: move.b `#'0x1c,_CAND_ | enable Tx Err Ovr interrupt move.b `#'_CMR_,_CANA_ | Command register: move.b `#'1,_CAND_ | Request_TX rts CAN_send_shared_end: move.w `#'0x2400,%sr | fin zone critique ???? rts | ----------------------------------------------------------------------- | -------------- Sous-programme d interruption CAN ---------------------- | ----------------------------------------------------------------------- int_can: movem.l %d0-%d1/%a0,-(%sp) | save registers used during interrupt move.b `#'_IR_,_CANA_ | Interrupt register: move.b _CAND_,%d0 | read into %d0 (and reset when read) btst.b `#'0,%d0 | bit0 = frame just received jne int_can_Rx btst.b `#'1,%d0 | bit1 = frame just sent jne int_can_Tx btst.b `#'2,%d0 | bit2 = too many errors jne int_can_Err btst.b `#'3,%d0 | bit3 = reception overrun error jne int_can_Ovr btst.b `#'4,%d0 | bit4 = wakeup jne int_can_Wake int_can_Wake: jra int_can_end int_can_Err: jra int_can_end int_can_Ovr: jra int_can_end int_can_Rx: clr.l %d0 | clear high bytes of %d0 move.b `#'_RXDL_,_CANA_ | Rx Data Length register: move.b _CAND_,%d0 | get number of received bytes into %d0 btst.b `#'4,%d0 | test RTR (bit4) jne int_can_sync | RTR = synchro (receiver ready) | andi.b `#'15,%d0 | reset high bits of %d0 sub.l %d0,_DMA_SIZE | _DMA_SIZE -= number of received bytes movea.l _DMA_ADDR,%a0 | destination address of received bytes tst.l %a0 jeq int_can_Rx_free | if null, can_nop ignores received bytes move.b `#'_RXBUF_,%d1 | first Rx Buffer register number subi.b `#'1,%d0 | -1 for DBRA 0: move.b %d1,_CANA_ | setup register number move.b _CAND_,(%a0)+ | get and store register value addi.b `#'1,%d1 | next register number dbra %d0,0b move.l %a0,_DMA_ADDR | _DMA_ADDR += number of received bytes int_can_Rx_free: move.b `#'_CMR_,_CANA_ | Command register: move.b `#'4,_CAND_ | Free_RX tst.l _DMA_SIZE | still frames to receive? jne int_can_end int_can_resume: | no more frame to transfer: move.b `#'_CR_,_CANA_ | Control register: move.b `#'0,_CAND_ | disable all CAN interrupts movea.l (_DMA_IPTR),%a0 jbsr (%a0) | resume pending instruction int_can_end: movem.l (%sp)+,%d0-%d1/%a0 | restore saved registers rte int_can_sync: move.b `#'_CMR_,_CANA_ | Command register: move.b `#'4,_CAND_ | release Rx buffer movea.l _DMA_ADDR,%a0 | source address of bytes to send tst.l %a0 jeq int_can_end | if null: CAN_sync, otherwise CAN_send move.l _DMA_SIZE,%d0 | number of bytes to send jbsr CAN_send_first_frame movem.l (%sp)+,%d0-%d1/%a0 | restore saved registers rte int_can_Tx: subi.l `#'8,_DMA_SIZE | remaining number of bytes to send blt int_can_resume | finished when null move.b `#'_TXDL_,_CANA_ | Tx Data Length register move.b `#'8,_CAND_ | setup to number of bytes to send movea.l _DMA_ADDR,%a0 | source address of bytes to send move.b `#'_TXBUF_,%d1 | first Tx Buffer register number move.l `#'7,%d0 | -1 for DBRA 0: move.b %d1,_CANA_ | setup register number move.b (%a0)+,_CAND_ | read and set register value addi.b `#'1,%d1 | next register number dbra %d0,0b move.l %a0,_DMA_ADDR | _DMA_ADDR += number of bytes sent move.b `#'_CMR_,_CANA_ | Command register: move.b `#'1,_CAND_ | Request_TX movem.l (%sp)+,%d0-%d1/%a0 | restore saved registers rte ') # ---------------- # CAN_ini_(mediaName,procrNames) define(`CAN_ini_', ` | 82C200 CS pin (chip select) is connected to the 68332 CS9 pin | CS9 is selected for the address range _CANA_,_CANA_+2K | 82C200 address and data are multiplexed on the same 8 bits bus | 80C200 address/data is selected (ALE pin) by the 68332 A0 address pin 0/1 .set _CSBAR9, 0xFFFA70 | cs9 base address register .set _CSOR9, 0xFFFA72 | cs9 option register move.w `#'0x0200,_CSBAR9 | 0x0200 => CAN address= 0x20000 | => size =2K (x 8 bits) move.w `#'0x79F0,_CSOR9 | asyn. mode, 16 bits R/W acces, | interne DSACK 7 wait, S/U space, | IPL=000, AVEC=0 move.l `#'int_can,0x78 | Initialisation du V.I CAN It_auto6 |------------------- init 82C200 --------------------------------- | move.w `#'0x0034,0xfffc08 | init rs 232 clock | move.w `#'0x7c08,0xfffa04 move.b `#'_CR_,_CANA_ | Request CAN reset move.b `#'0x01,_CAND_ move.b `#'_ACR_,_CANA_ | Set code name: 0x11 move.b `#'0x11,_CAND_ move.b `#'_AMR_,_CANA_ | Set Mask : 0xff (all messages) move.b `#'0xff,_CAND_ move.b `#'_BTR0_,_CANA_ | Set Rate: 500 kbauds move.b `#'0x0,_CAND_ | 0 for 500, 1M 1.6M | move.b `#'0x67,_CAND_ | 67 for 10 move.b `#'_BTR1_,_CANA_ | move.b `#'0x1c,_CAND_ | for 500K | move.b `#'0x14,_CAND_ | for 1M move.b `#'0x18,_CAND_ | for 750k | move.b `#'0x2f,_CAND_ | for 10K move.b `#'_OCR_,_CANA_ move.b `#'0xfa,_CAND_ move.b `#'_CR_,_CANA_ | 1 front de synchro et autorisation it move.b `#'0x20,_CAND_ move.b `#'_TXID_,_CANA_ |TxID 8 MSBits of 11 bits identifier | move.b `#'0x11,_CAND_ move.b `#'1<