For more detailed info, see the source or refer to the APPNOTES of NXP which are documented in the test-source.
First module defines the used CAN clockrates.
Code: Select all
MODULE CANBR;
(* BRP+1 = Fpclk/(CANBitRate * QUANTAValue)
QUANTAValue = 1 + (Tseg1+1) + (Tseg2+1)
QUANTA value varies based on the Fpclk and sample point
e.g. (1) sample point is 87.5%, Fpclk is 48Mhz
the QUANTA should be 16
(2) sample point is 90%, Fpclk is 12.5Mhz
the QUANTA should be 10
Fpclk = Fclk /APBDIV
or
BitRate = Fcclk/(APBDIV * (BRP+1) * ((Tseg1+1)+(Tseg2+1)+1))
*)
CONST
(* Here are some popular bit timing settings for LPC23xx, google on "SJA1000"
CAN bit timing, the same IP used insIde LPC2000 CAN controller. There are several
bit timing calculators on the internet.
http://www.port.de/engl/canprod/sv_req_form.html
*)
(**
* Bit Timing Values for 16MHz clk frequency
*)
BITRATE100K16MHZ = 0001C0009H;
BITRATE125K16MHZ = 0001C0007H;
BITRATE250K16MHZ = 0001C0003H;
BITRATE500K16MHZ = 0001C0001H;
BITRATE1000K16MHZ = 0001C0000H;
(*
* Bit Timing Values for 24MHz clk frequency
*)
BITRATE100K24MHZ = 0001C000EH;
BITRATE125K24MHZ = 0001C000BH;
BITRATE250K24MHZ = 0001C0005H;
BITRATE500K24MHZ = 0001C0002H;
BITRATE1000K24MHZ = 000090001H;
(*
* Bit Timing Values for 48MHz clk frequency
*)
BITRATE100K48MHZ = 0001C001DH;
BITRATE125K48MHZ = 0001C0017H;
BITRATE250K48MHZ = 0001C000BH;
BITRATE500K48MHZ = 0001C0005H;
BITRATE1000K48MHZ = 0001C0002H;
(*
* Bit Timing Values for 60MHz clk frequency
*)
BITRATE100K60MHZ = 000090031H;
BITRATE125K60MHZ = 000090027H;
BITRATE250K60MHZ = 000090013H;
BITRATE500K60MHZ = 000090009H;
BITRATE1000K60MHZ = 000090004H;
(*
* Bit Timing Values for 28.8MHz pclk frequency, 1/2 of 576.Mhz CCLK
*)
BITRATE100K28dot8MHZ = 000090017H;
(* When Fcclk is 50Mhz and 60Mhz and APBDIV is 4,
so Fpclk is 12.5Mhz and 15Mhz respectively.
when Fpclk is 12.5Mhz, QUANTA is 10 and sample point is 90%
when Fpclk is 15Mhz, QUANTA is 10 and sample point is 90% *)
(* Common CAN bit rates for 12.5Mhz(50Mhz CCLK) clock frequency *)
BITRATE125K12dot5MHZ = 000070009H;
BITRATE250K12dot5MHZ = 000070004H;
(**
* Bit Timing Values for 15MHz(60Mhz CCLK) clk frequency
*)
BITRATE100K15MHZ = 00007000EH;
BITRATE125K15MHZ = 00007000BH;
BITRATE250K15MHZ = 000070005H;
BITRATE500K15MHZ = 000070002H;
(* Bitrate 100Kbps
PClk=18Mhz (processorclock / 5)
BRP=5 -> 3Mhz Can Clock -> BRPRegvalue=4H
T1=10 -> T1Regvalue=9H, T2=8 -> T2Regvalue=7H
Total Can Bittime = T1Regvalue+T2Regvalue+3 = 19 clocks
*)
BITRATE100K18MHZ* = 00790004H;
BITRATE100K18MHZ2*= 00780009H;
BITRATE50K18MHZ* = 0005002CH;
END CANBR.
Code: Select all
MODULE CAN;
(*****************************************************************************
* can.c: CAN module API file for NXP LPC23xx/24xx Family Microprocessors
*
* Copyright(C) 2006, NXP Semiconductor
* All rights reserved.
*
* History
* 2006.09.13 ver 1.00 Preliminary version, first Release
* Ported to Oberon-07 24 sept 2011 W. Nijland
*****************************************************************************)
IMPORT SYSTEM, VIC, LPC := LPC2378;
CONST
MemBase = 0E0038000H; (* Acceptance Filter RAM *)
MaxPorts = 2; (* Number of CAN port on the chip *)
(* Acceptance filter mode in AFMR register *)
AccfOff* = 01H;
AccfBypass* = 02H;
AccfOn* = 0H;
AccfFullCan* = 04H;
(* This number applies to all FULLCAN Ids, explicit STD Ids, group STD Ids,
explicit EXT Ids, and group EXT Ids. *)
AccfIdENNum = 4;
(* Identifiers for FULLCAN, EXP STD, GRP STD, EXP EXT, GRP EXT *)
FullCanId = 0100H;
ExpStdId* = 0100H;
GrpStdId = 0200H;
ExpExtId = 0100000H;
GrpExtId = 0200000H;
(* Type definition to hold a CAN message *)
TYPE
pMsg = POINTER TO Msg;
Msg* = RECORD
Frame*: INTEGER; (* Bits 16..19: DLC - Data Length Counter *)
(* Bit 30: Set if this is a RTR message *)
(* Bit 31: Set if this is a 29-bit Id message *)
MsgId*: INTEGER; (* CAN Message Id (11-bit or 29-bit) *)
DataA*: INTEGER; (* CAN Message Data Bytes 0-3 *)
DataB*: INTEGER (* CAN Message Data Bytes 4-7 *)
END;
(* Receive Queue: one queue for each CAN port *)
VAR
MsgBufRx1, MsgBufRx2 : Msg;
CAN1RxDone*, CAN2RxDone* : BOOLEAN;
CAN1RxCount*: INTEGER;
CAN2RxCount*: INTEGER;
CAN1ErrCount*: INTEGER;
CAN2ErrCount*: INTEGER;
(* Interface to retrieve the recently received buffer *)
PROCEDURE GetMsg*(CONST CHAN1 : BOOLEAN; VAR buf : Msg);
BEGIN
IF CHAN1 THEN
buf := MsgBufRx1;
CAN1RxDone := FALSE
ELSE
buf := MsgBufRx2;
CAN2RxDone := FALSE
END
END GetMsg;
(******************************************************************************
** Function name: CAN_ISR_Rx1
**
** Descriptions: CAN Rx1 interrupt handler
**
** parameters: None
** Returned value: None
**
******************************************************************************)
PROCEDURE* ISRRx1;
CONST
RRB = 2;
BEGIN
SYSTEM.GET(LPC.CAN1RFS, MsgBufRx1.Frame); (* Frame *)
SYSTEM.GET(LPC.CAN1RID, MsgBufRx1.MsgId); (* Id *)
SYSTEM.GET(LPC.CAN1RDA, MsgBufRx1.DataA); (* Data A *)
SYSTEM.GET(LPC.CAN1RDB, MsgBufRx1.DataB); (* Data B *)
CAN1RxDone := TRUE;
SYSTEM.PUT(LPC.CAN1CMR, {RRB}) (* release receive buffer *)
END ISRRx1;
(******************************************************************************
** Function name: CAN_ISR_Rx2
**
** Descriptions: CAN Rx2 interrupt handler
**
** parameters: None
** Returned value: None
**
******************************************************************************)
PROCEDURE* ISRRx2;
CONST
RRB = 2;
BEGIN
(* initialize destination pointer *)
SYSTEM.GET(LPC.CAN2RFS, MsgBufRx2.Frame); (* Frame *);
SYSTEM.GET(LPC.CAN2RID, MsgBufRx2.MsgId); (* Id *)
SYSTEM.GET(LPC.CAN2RDA, MsgBufRx2.DataA); (* Data A *)
SYSTEM.GET(LPC.CAN2RDB, MsgBufRx2.DataB); (* Data B *)
CAN2RxDone := TRUE;
SYSTEM.PUT(LPC.CAN2CMR, {RRB}) (* release receive buffer *)
END ISRRx2;
(*****************************************************************************
** Function name: CAN_Handler
**
** Descriptions: CAN interrupt handler
**
** parameters: None
** Returned value: None
**
*****************************************************************************)
PROCEDURE IRQHandler [4];
CONST
RB1 = 8; RB2 = 9;
ES = 6; (* Error Status bit *)
VAR
bits, status: SET;
BEGIN
(* WNIWNI __enable_interrupt; (* handles nested interrupt *) *)
SYSTEM.GET(LPC.CANRXSR, status);
IF RB1 IN status THEN
INC(CAN1RxCount);
ISRRx1
END;
IF RB2 IN status THEN
INC(CAN2RxCount);
ISRRx2
END;
SYSTEM.GET(LPC.CAN1GSR, bits);
IF ES IN bits THEN (* ES *)
(* The error count includes both TX and RX *)
CAN1ErrCount := LSR(SYSTEM.VAL(INTEGER, bits), 16)
END;
SYSTEM.GET(LPC.CAN2GSR, bits);
IF ES IN bits THEN
(* The error count includes both TX and RX *)
CAN2ErrCount := LSR(SYSTEM.VAL(INTEGER, bits), 16)
END;
(* WNIWNI disable interrupt *)
SYSTEM.PUT(LPC.VICAddress, 0); (* Acknowledge Interrupt *)
END IRQHandler;
(******************************************************************************
** Function name: CAN_Init
**
** Descriptions: Initialize CAN, install CAN interrupt handler
**
** parameters: bitrate
** Returned value: none
**
******************************************************************************)
PROCEDURE Init*(btr: INTEGER);
CONST
RIE = 0; (* Receiver Interrupt Enable *)
VAR
bits : SET;
BEGIN
CAN1RxDone := FALSE; CAN2RxDone := FALSE;
SYSTEM.GET(LPC.PCONP, bits);
SYSTEM.PUT(LPC.PCONP, bits + {13,14}); (* Enable clock to the peripherals Can1 & Can2 *)
SYSTEM.GET(LPC.PINSEL0, bits); bits := bits - {0..3, 8..11};
SYSTEM.PUT(LPC.PINSEL0, bits + {0, 2, 9, 11}); (* port0.0~1, function 0x01, port0.4~5, function 0x10 *)
SYSTEM.PUT(LPC.CAN1MOD, 1); SYSTEM.PUT(LPC.CAN2MOD, 1); (* Reset CAN *)
SYSTEM.PUT(LPC.CAN1IER, {}); SYSTEM.PUT(LPC.CAN2IER, {}); (* Disable Receive Interrupt *)
SYSTEM.PUT(LPC.CAN1GSR, 0); SYSTEM.PUT(LPC.CAN2GSR, 0); (* Reset error counter when CANxMOD is in reset *)
SYSTEM.PUT(LPC.CAN1BTR, btr); SYSTEM.PUT(LPC.CAN2BTR, btr);
SYSTEM.PUT(LPC.CAN1MOD, 0); SYSTEM.PUT(LPC.CAN2MOD, 0); (* CAN in normal operation mode *)
(* Install CAN interrupt handler *)
VIC.InstallHandler(VIC.CAN, SYSTEM.ADR(IRQHandler), VIC.NormalPriority); (*, FALSE);*)
SYSTEM.PUT(LPC.CAN1IER, {RIE}); SYSTEM.PUT(LPC.CAN2IER, {RIE}); (* Enable receive interrupts *)
END Init;
PROCEDURE* INTOR(a, b : INTEGER) : INTEGER;
BEGIN
RETURN SYSTEM.VAL(INTEGER, SYSTEM.VAL(SET, a) + SYSTEM.VAL(SET, b))
END INTOR;
PROCEDURE* INTAND(a, b : INTEGER) : INTEGER;
BEGIN
RETURN SYSTEM.VAL(INTEGER, SYSTEM.VAL(SET, a) * SYSTEM.VAL(SET, b))
END INTAND;
(******************************************************************************
** Function name: CAN_SetAccf_Lookup
**
** Descriptions: Initialize CAN, install CAN interrupt handler
**
** parameters: bitrate
** Returned value: none
**
******************************************************************************)
PROCEDURE SetAccfLookup;
VAR
address, i, Idhigh, Idlow : INTEGER;
BEGIN
address := 0;
(* Set explicit standard Frame *)
SYSTEM.PUT(LPC.CANSFFSA, address);
i := 0;
WHILE i < AccfIdENNum DO
Idlow := INTOR(LSL(i, 29), LSL(ExpStdId, 16));
Idhigh := INTOR(LSL(i+1, 13), ExpStdId);
SYSTEM.PUT(MemBase + address, INTOR(Idlow, Idhigh));
INC(address, 4);
INC(i, 2)
END;
(* Set group standard Frame *)
SYSTEM.PUT(LPC.CANSFFGRPSA, address);
i := 0;
WHILE i < AccfIdENNum DO
Idlow := INTOR(LSL(i, 29), LSL(GrpStdId, 16));
Idhigh := INTOR(LSL(i+1, 13), GrpStdId);
SYSTEM.PUT(MemBase + address, INTOR(Idlow, Idhigh));
INC(address, 4);
INC(i, 2)
END;
(* Set explicit extended Frame *)
SYSTEM.PUT(LPC.CANEFFSA, address);
i := 0;
WHILE i < AccfIdENNum DO
Idlow := INTOR(LSL(i, 29), ExpExtId);
SYSTEM.PUT(MemBase + address, Idlow);
INC(address, 4);
INC(i)
END;
(* Set group extended Frame *)
SYSTEM.PUT(LPC.CANEFFGRPSA, address);
i := 0;
WHILE i < AccfIdENNum DO
Idlow := INTOR(LSL(i, 29), GrpExtId);
SYSTEM.PUT(MemBase + address, Idlow);
INC(address, 4);
INC(i)
END;
(* Set End of Table *)
SYSTEM.PUT(LPC.CANEOT, address); (* EOT = EndOfTable *)
END SetAccfLookup;
(******************************************************************************
** Function name: CAN_SetAccf
**
** Descriptions: Set acceptance filter and SRAM associated with
**
** parameters: ACMF mode
** Returned value: None
**
**
******************************************************************************)
PROCEDURE SetAccf* (AccfMode: INTEGER);
BEGIN
IF AccfMode = AccfOff THEN
SYSTEM.PUT(LPC.CANAFMR, AccfMode);
SYSTEM.PUT(LPC.CAN1MOD, 1); SYSTEM.PUT(LPC.CAN2MOD, 1); (* Reset CAN *)
SYSTEM.PUT(LPC.CAN1IER, 0); SYSTEM.PUT(LPC.CAN2IER, 0); (* Disable Receive Interrupt *)
SYSTEM.PUT(LPC.CAN1GSR, 0); SYSTEM.PUT(LPC.CAN2GSR, 0); (* Reset error counter when CANxMOD is in reset *)
ELSIF AccfMode = AccfBypass THEN
SYSTEM.PUT(LPC.CANAFMR, AccfMode);
ELSIF (AccfMode = AccfOn) OR (AccfMode = AccfFullCan) THEN
SYSTEM.PUT(LPC.CANAFMR, AccfOff);
SetAccfLookup;
SYSTEM.PUT(LPC.CANAFMR, AccfMode)
END
END SetAccf;
(******************************************************************************
** Function name: CAN_SendMessage
**
** Descriptions: Send message block to CAN1 or CAN2
**
** parameters: pointer to the CAN message
** Returned value: true or false, if message buffer is available,
** message can be sent successfully, return TRUE,
** otherwise, return FALSE.
**
******************************************************************************)
PROCEDURE SendMessage*(CONST chan1 :BOOLEAN; VAR TxBuf: Msg): BOOLEAN;
CONST
mask = 0C00F0000H;
TR = 0;
STB1 = 5; STB2 = 6; STB3 = 7;
TBS1 = 2; TBS2 = 10; TBS3 = 18;
VAR
CANStatus : SET;
retval : BOOLEAN;
BEGIN
retval := TRUE;
IF chan1 THEN
SYSTEM.GET(LPC.CAN1SR, CANStatus);
IF TBS1 IN CANStatus THEN
SYSTEM.PUT(LPC.CAN1TFI1, INTAND(TxBuf.Frame, mask));
SYSTEM.PUT(LPC.CAN1TID1, TxBuf.MsgId);
SYSTEM.PUT(LPC.CAN1TDA1, TxBuf.DataA);
SYSTEM.PUT(LPC.CAN1TDB1, TxBuf.DataB);
SYSTEM.PUT(LPC.CAN1CMR, {TR,STB1})
ELSIF TBS2 IN CANStatus THEN
SYSTEM.PUT(LPC.CAN1TFI2, INTAND(TxBuf.Frame, mask));
SYSTEM.PUT(LPC.CAN1TID2, TxBuf.MsgId);
SYSTEM.PUT(LPC.CAN1TDA2, TxBuf.DataA);
SYSTEM.PUT(LPC.CAN1TDB2, TxBuf.DataB);
SYSTEM.PUT(LPC.CAN1CMR, {TR, STB2})
ELSIF TBS3 IN CANStatus THEN
SYSTEM.PUT(LPC.CAN1TFI3, INTAND(TxBuf.Frame, mask));
SYSTEM.PUT(LPC.CAN1TID3, TxBuf.MsgId);
SYSTEM.PUT(LPC.CAN1TDA3, TxBuf.DataA);
SYSTEM.PUT(LPC.CAN1TDB3, TxBuf.DataB);
SYSTEM.PUT(LPC.CAN1CMR, {TR, STB3})
ELSE
retval := FALSE
END
ELSE
SYSTEM.GET(LPC.CAN2SR, CANStatus);
IF TBS1 IN CANStatus THEN
SYSTEM.PUT(LPC.CAN2TFI1, INTAND(TxBuf.Frame, mask));
SYSTEM.PUT(LPC.CAN2TID1, TxBuf.MsgId);
SYSTEM.PUT(LPC.CAN2TDA1, TxBuf.DataA);
SYSTEM.PUT(LPC.CAN2TDB1, TxBuf.DataB);
SYSTEM.PUT(LPC.CAN2CMR, {TR, STB1})
ELSIF TBS2 IN CANStatus THEN
SYSTEM.PUT(LPC.CAN2TFI2, INTAND(TxBuf.Frame, mask));
SYSTEM.PUT(LPC.CAN2TID2, TxBuf.MsgId);
SYSTEM.PUT(LPC.CAN2TDA2, TxBuf.DataA);
SYSTEM.PUT(LPC.CAN2TDB2, TxBuf.DataB);
SYSTEM.PUT(LPC.CAN2CMR, {TR, STB2})
ELSIF TBS3 IN CANStatus THEN
SYSTEM.PUT(LPC.CAN2TFI3, INTAND(TxBuf.Frame, mask));
SYSTEM.PUT(LPC.CAN2TID3, TxBuf.MsgId);
SYSTEM.PUT(LPC.CAN2TDA3, TxBuf.DataA);
SYSTEM.PUT(LPC.CAN2TDB3, TxBuf.DataB);
SYSTEM.PUT(LPC.CAN2CMR, {TR, STB3})
ELSE
retval := FALSE
END
END;
RETURN retval
END SendMessage;
PROCEDURE VarInit;
BEGIN
CAN1ErrCount := 0;
CAN2ErrCount := 0;
CAN1RxCount := 0;
CAN2RxCount := 0
END VarInit;
BEGIN
VarInit
END CAN.
Code: Select all
MODULE cantest;
IMPORT SYSTEM, Main, CAN, CANBR, LPC := LPC2378, Out, SYSClock, Timer;
(*****************************************************************************
* cantest.c: CAN test module file for NXP LPC23xx Family Microprocessors
*
* Copyright(C) 2006, NXP Semiconductor
* All rights reserved.
*
* History
* 2006.09.13 ver 1.00 Preliminary version, first Release
* Ported to Oberon-07 24 sept 2011 W. Nijland
******************************************************************************)
VAR
MsgBufTX1, MsgBufTX2: CAN.Msg; (* TX Buffers *)
MsgBufRX1, MsgBufRX2: CAN.Msg; (* RX Buffers *)
PROCEDURE WriteHex(a : INTEGER);
VAR
i, v : INTEGER;
xa : ARRAY 20 OF CHAR;
BEGIN
xa := "01234567890ABCDEF";
i := 4;
WHILE i > 0 DO
DEC(i);
v := LSR(a, i * 8) MOD 256;
Out.Char(xa[v DIV 16]);
Out.Char(xa[v MOD 16])
END
END WriteHex;
(* Show relevant info on selected Can-channel *)
PROCEDURE DumpCANBTR(CONST can1 : BOOLEAN);
VAR
f, i, brp, sjw, t1, t2, sam : INTEGER;
BEGIN
IF can1 THEN
SYSTEM.GET(LPC.CAN1BTR, i);
f := SYSClock.GetFpclk(SYSClock.CAN1PCLKOffset);
Out.String("CAN1-Clock = "); Out.Int(f DIV SYSClock.MHZ, 0); Out.String("MHz"); Out.Ln
ELSE
SYSTEM.GET(LPC.CAN2BTR, i);
f := SYSClock.GetFpclk(SYSClock.CAN2PCLKOffset);
Out.String("CAN2-Clock = "); Out.Int(f DIV SYSClock.MHZ, 0); Out.String("MHz"); Out.Ln
END;
brp := i MOD 512;
sjw := LSR(i, 14) MOD 4;
t1 := LSR(i, 16) MOD 16;
t2 := LSR(i, 20) MOD 8;
Out.String("BaudRatePrescaler="); Out.Int(brp+1, 0); Out.Ln;
Out.String("Synchronization Jump Width ="); Out.Int(sjw+1, 0); Out.String(" Clocks"); Out.Ln;
Out.String("TimeSegment1="); Out.Int(t1+1,0); Out.String(" Clocks"); Out.Ln;
Out.String("TimeSegment2="); Out.Int(t2+1,0); Out.String(" Clocks"); Out.Ln;
Out.String("Nominal CAN bittime ="); Out.Int(t1+t2+3,0); Out.String(" Clocks"); Out.Ln;
IF ODD(LSR(i, 23)) THEN
Out.String("Bus is sampled 3 times.")
ELSE
Out.String("Bus is sampled once.")
END;
Out.Ln
END DumpCANBTR;
PROCEDURE BufInfo(CONST can1 : BOOLEAN);
BEGIN
Out.Ln;
Out.String("Received messages on ");
IF can1 THEN
Out.String("Chan1, RxCount="); Out.Int(CAN.CAN1RxCount,0); Out.String(", Errcount="); Out.Int(CAN.CAN1ErrCount,0); Out.Ln;
ELSE
Out.String("Chan2, RxCount="); Out.Int(CAN.CAN2RxCount,0); Out.String(", Errcount="); Out.Int(CAN.CAN2ErrCount,0); Out.Ln
END;
END BufInfo;
(*****************************************************************************
** Function name: main
**
** Descriptions: main routine for CAN module test
**
** parameters: None
** Returned value: int
**
*****************************************************************************)
PROCEDURE run(CONST AcceptanceFilterEnabled : BOOLEAN);
CONST
RBS=0; TBS=2; TCS=3; (*Transmit Complete Status *)
VAR
i, s : INTEGER;
ne : BOOLEAN;
BEGIN
(* Please note, this PCLK is set abitrary. The bit timing is based
on the setting of the PCLK, if different PCLK is used, please study 'can.mod'
& 'canbr.mod' carefully and set your CAN bit timing accordingly. *)
CAN.Init(CANBR.BITRATE50K18MHZ);
(* This program is testing CAN1 and CAN2 on the Olimex LPC-2378-STK boards,
sends one message from CAN1(TX) and verify received message on CAN2(RX)
if it's a match, both CAN TX and RX are working.
For more details on acceptance filter program, see NXP appnote AN10438 and the
zip file associated with that appnote or appnote AN10674 *)
IF AcceptanceFilterEnabled THEN
(* Test Acceptance Filter *)
(* Even though the filter RAM is set for all type of identifiers,
the test module tests explicit standard identifier only *)
MsgBufTX1.Frame := 000080000H; (* 11-bit, no RTR, DLC is 8 bytes *)
MsgBufTX1.MsgId := CAN.ExpStdId; (* Explicit Standard ID *)
MsgBufTX1.DataA := 055AA55AAH;
MsgBufTX1.DataB := 0AA55AA55H;
CAN.SetAccf(CAN.AccfOn);
Out.String("Acceptance Filter is Enabled"); Out.Ln
ELSE
(* Initialize MsgBuf *)
MsgBufTX1.Frame := 080080000H; (* 29-bit, no RTR, DLC is 8 bytes *)
MsgBufTX1.MsgId := 000012345H; (* CAN ID *)
MsgBufTX1.DataA := 03C3C3C3CH;
MsgBufTX1.DataB := 0C3C3C3C3H;
CAN.SetAccf(CAN.AccfBypass);
Out.String("No Acceptance Filter Enabled"); Out.Ln
END;
MsgBufRX2.Frame := 00H;
MsgBufRX2.MsgId := 00H;
MsgBufRX2.DataA := 00H;
MsgBufRX2.DataB := 00H;
DumpCANBTR(TRUE); (* dump of both channels not needed, both use the same clock rates *)
i := 0;
Timer.Start;
REPEAT
Out.String("i=");Out.Int(i,0);
(* Transmit message on CAN 1 *)
REPEAT UNTIL CAN.SendMessage(TRUE, MsgBufTX1);
s := Timer.Elapsed();
(* Cycle here until a complete message is received or 50 ms has lapsed *)
REPEAT UNTIL CAN.CAN2RxDone OR (Timer.Elapsed()-s > 50);
IF CAN.CAN2RxDone THEN
CAN.GetMsg(FALSE, MsgBufRX2); (* this also resets CAN2RxDone *)
IF AcceptanceFilterEnabled THEN
ne := (MsgBufTX1.MsgId # MsgBufRX2.MsgId) OR (MsgBufTX1.DataA # MsgBufRX2.DataA) OR (MsgBufTX1.DataB # MsgBufRX2.DataB)
ELSE
IF 10 IN SYSTEM.VAL(SET, MsgBufRX2.Frame) THEN (* bypass mode *)
MsgBufRX2.Frame := SYSTEM.VAL(INTEGER, SYSTEM.VAL( SET, MsgBufRX2.Frame) - {10})
END;
ne := (MsgBufTX1.Frame # MsgBufRX2.Frame) OR (MsgBufTX1.MsgId # MsgBufRX2.MsgId) OR (MsgBufTX1.DataA # MsgBufRX2.DataA) OR (MsgBufTX1.DataB # MsgBufRX2.DataB)
END;
(* The frame field is not checked, as ID index varies based on the
entries set in the filter RAM. *)
IF ne THEN
WriteHex(MsgBufTX1.Frame); Out.Char('='); WriteHex(MsgBufRX2.Frame); Out.Ln;
WriteHex(MsgBufTX1.MsgId); Out.Char('='); WriteHex(MsgBufRX2.MsgId); Out.Ln;
WriteHex(MsgBufTX1.DataA); Out.Char('='); WriteHex(MsgBufRX2.DataA); Out.Ln;
WriteHex(MsgBufTX1.DataB); Out.Char('='); WriteHex(MsgBufRX2.DataB); Out.Ln;
Out.String("Unexpected: Frames are not equal!"); Out.Ln;
END;
(* Everything is correct, reset buffer *)
MsgBufRX2.Frame := 00H;
MsgBufRX2.MsgId := 00H;
MsgBufRX2.DataA := 00H;
MsgBufRX2.DataB := 00H;
MsgBufTX1.Frame := 000080000H; (* 11-bit, no RTR, DLC is 8 bytes *)
MsgBufTX1.MsgId := CAN.ExpStdId;
MsgBufTX1.DataA := 014231211H;
MsgBufTX1.DataB := 018171615H
ELSE (* no message received *)
Out.Char('-')
END; (* Message on CAN 2 received *)
INC(i)
UNTIL i > 99;
Timer.Stop;
BufInfo(FALSE); (* reception on Can2, not Can1 *)
Out.String("Cantest done."); Out.Ln
END run;
BEGIN
Timer.Init(Timer.MSecs);
run(TRUE); (* AcceptanceFilterEnabled = TRUE *)
run(FALSE) (* AcceptanceFilterEnabled = FALSE *)
END cantest.