LPC2378 Testing CAN controllers

Download pre-release library modules and new examples to use with Astrobe for LPC2000. Forum members can also upload their own source code examples.
Post Reply
4GlCoder
Posts: 27
Joined: Fri Jul 22, 2011 2:47 pm

LPC2378 Testing CAN controllers

Post by 4GlCoder » Sun Oct 30, 2011 4:00 pm

As the LPC2378-STK has 2 CAN controllers It is easy to check whether that works or not...

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.
The core module handles the Receive-Interrupts and Buffers the received CAN message

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.
And Finally the source to test the CAN handler. I have used the Standard Timer module to avoid too complicated sources.

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.

Post Reply