Other Parts Discussed in Thread: C2000WARE
Hi -
I finally got hardware and am trying to get CAN communication up and running. The F28377S can receive CAN packets. I see them come to my application in the CCS debugger. I can't get transmit to work. I get the data loaded into the interface - I see that, but the messages don't go to the RAM. I don't see any activity on the scope.
My problem might be with the arbitration or mask registers. For receive, I set up the arbitration acceptance and mask registers and this seems to work. I've tried doing this on the transmit side as well - no joy. Also, I tried only using the arbitration register for TX - again, no joy.
I would greatly appreciate some insight. My 335 and 377S code is attached.
----------------------------------------------------------------------------- // FILE: CANModule.c // // Description: CAN driver // // Version: 1.0 (Feb 5, 2015) // // Target: TMS320F28335 // // Details: Peripheral Interface to ECAN hardware // The hardware supports extended CAN (ECAN) and standard CAN // (SCC). This drivers uses SCC CAN. // // Reference: sprueu1 - TMS320F2833x, 2823x Enhanced Controller Area // Network (eCAN) Reference Guide // //----------------------------------------------------------------------------- //-------------------------Includes-------------------------------------------- #include "Defs.h" #include "ProcessorModule.h" #include "PeripheralHeaderIncludes.h" #include "GMNIAddressing.h" #include "CANModule.h" #include "Errors.h" #include "ParamDB.h" #include "DebugModule.h" #include "CommandProtocol.h" #include "Instructions.h" #include "InstructionEvents.h" //-------------------------Defines-------------------------------------------- #define LOOP_COUNTS ((Uint32)10000) // Bail out loop counts so we don't get stuck forever #define NUM_MAILBOXES ((int)16) // Number of mailboxes allowed in standard CAN mode #define ACCEPTANCE_MASK 0xFF03FFFF // Bits 18 through 28 are for standard CAN, masking is done with 0s // In this application, the node ID is used as the message ID. It is stored in 6 bits so... // Bits 18 through 23 must match the message ID - (bit 31)xxxx,xxxx,0000,00xx,xxxx,xxxx,xxxx,xxxx(bit0) #define MAX_TX_ATTEMPTS ((Uint32)2) //-------------------------Globals-------------------------------------------- CanQueue canQueue; // Storage for CAN messages coming in from the bus CanQueue localCommQueue; // Storage for CAN messages coming from the same CAN node as the sender. // Every node can see all messages from all other nodes but it can't see its own. // Reference: www.keil.com/.../canprimer_v2.pdf static Uint16 currDestID; // Ecanb interface is used to talk to the main instrument CAN bus on Encore static volatile struct ECAN_REGS *ECanRegs = &ECanbRegs; static volatile struct ECAN_MBOXES *ECanMboxes = &ECanbMboxes; static volatile struct LAM_REGS *ECanLAMRegs = &ECanbLAMRegs; //----------------------------------------------------------------------------- // NOTE: Accessing ECAN control and status registers // // Only 32-bit access is allowed to these registers. 16-bit access // to these registers could potentially corrupt the register contents or return // false data. This is especially true while writing to/reading from a bit // (or group of bits) among bits 16 - 31 // // This applies to the following registers: // CANME CANMD CANTRS CANTRR CANTA CANAA CANRMP CANRML // CANRFP CANGAM CANMC CANBTC CANES CANTEC CANREC CANGIF0 // CANGIM CANGIF1 CANMIM CANMIL CANOPC CANTIOC CANRIOC CANTSC // CANTOC CANTOS // // A shadow register is employed to fascilitate 32 bit reads/writes. //----------------------------------------------------------------------------- static volatile struct ECAN_REGS ECanRegsShadow; //----------------------------------------------------------------------------- // ECan_Init // // Standard CAN initialization. Using CAN-B on the controller board. // Talks to the main controller bus. //----------------------------------------------------------------------------- void ECan_Init(Uint16 bcastAddr) { volatile struct MBOX *Mailbox; int i; canQueue.size = 0; localCommQueue.size = 0; EALLOW; // EALLOW enables access to protected bits // Configure eCAN RX and TX pins for CAN operation using eCAN regs // See Note at top of file ECanRegsShadow.CANTIOC.all = ECanRegs->CANTIOC.all; ECanRegsShadow.CANTIOC.bit.TXFUNC = 1; // Enable transmit ECanRegs->CANTIOC.all = ECanRegsShadow.CANTIOC.all; ECanRegsShadow.CANRIOC.all = ECanRegs->CANRIOC.all; ECanRegsShadow.CANRIOC.bit.RXFUNC = 1; // Enable receive ECanRegs->CANRIOC.all = ECanRegsShadow.CANRIOC.all; // Configure CAN for SCC mode (standard CAN controller mode) - (to access mailboxes 15 thru 0) // We're not using eCAN, we are using SCC (mailboxes 0 to 15) ECanRegsShadow.CANMC.all = ECanRegs->CANMC.all; ECanRegsShadow.CANMC.bit.SCB = 0; // SCC compatibility bit ECanRegsShadow.CANMC.bit.ABO = 1; // enable auto-bus on ECanRegs->CANMC.all = ECanRegsShadow.CANMC.all; // Initialize all bits of 'Message Control Register' to zero // Some bits of MSGCTRL register come up in an unknown state. For proper operation, // all bits (including reserved bits) of MSGCTRL must be initialized to zero Mailbox = &ECanMboxes->MBOX0; for (i = 0; i < NUM_MAILBOXES; ++i) { Mailbox->MSGCTRL.all = 0x00000000; ++Mailbox; } // CANMC CCR bit set to 1: // The CPU requests write access to the configuration register CANBTC and the acceptance mask // registers (CANGAM, LAM[0], and LAM[3]) of the SCC. After setting this bit, the CPU must wait until // the CCE flag of CANES register is at 1 before proceeding to the CANBTC register. ECanRegsShadow.CANMC.all = ECanRegs->CANMC.all; ECanRegsShadow.CANMC.bit.CCR = 1; // Change configuration request bit ECanRegs->CANMC.all = ECanRegsShadow.CANMC.all; // Wait for CCE bit to be set.. // CCE = 1 when the CPU has write access to the configuration registers. // CCE is change configuration enable bit do { ECanRegsShadow.CANES.all = ECanRegs->CANES.all; } while(ECanRegsShadow.CANES.bit.CCE != 1 ); // Clear bit timing config register ECanRegs->CANBTC.all = 0; // Configure bit timing // Bit Rate = (SYSCLKOUT / 2) / ((BRPreg + 1) * BitTime) // where SYSCLKOUT = 150 MHz // BitTime = (TSEG1REG + 1) + (TSEG2REG + 1) + 1 ECanRegsShadow.CANBTC.all = ECanRegs->CANBTC.all; ECanRegsShadow.CANBTC.bit.BRPREG = 4; // 4 for 1 Mbps gives 15 MHz CAN module clock ECanRegsShadow.CANBTC.bit.TSEG2REG = 2; // 15 time quanta per bit - 80% sampling point ECanRegsShadow.CANBTC.bit.TSEG1REG = 10; // 15 time quanta per bit - 80% sampling point ECanRegsShadow.CANBTC.bit.SAM = 1; // 0: 1 sample; 1: Samples 3 times and takes majority reading ECanRegsShadow.CANBTC.bit.SJWREG = 0; // 0: SJW (synch jump width, extends seg1 and shortens seg2); 1: SJW = 2 (1 for 800 Kb) ECanRegs->CANBTC.all = ECanRegsShadow.CANBTC.all; // CANGAM (global acceptance mask) used for mailboxes 6 to 15 ECanRegs->CANGAM.all = ACCEPTANCE_MASK; // Bits 18 through 23 must match the msg ID ECanRegsShadow.CANGAM.all = ECanRegs->CANGAM.all; ECanRegsShadow.CANGAM.bit.AMI = 1; // Acceptance mask identifier - 1: CAN will accept standard and extended frames. // IDE of receive mailbox is a "don't care". Is overwritten by transmitted msg. // Uses bits 18 to 28 of CANGAM for msg filtering in standard CAN mode ECanRegs->CANGAM.all = ECanRegsShadow.CANGAM.all; // LAM0 (local accecptance mask) used for mailboxes 0 to 2 ECanLAMRegs->LAM0.all = ACCEPTANCE_MASK; // Bits 18 through 23 must match the msg ID ECanLAMRegs->LAM0.bit.LAMI = 1; // Acceptance mask identifier - 1: CAN will accept standard and extended frames. // Uses bits 18 to 28 of CANGAM for msg filtering in standard CAN mode // LAM3 (local accecptance mask) used for mailboxes 3 to 5 ECanLAMRegs->LAM3.all = ACCEPTANCE_MASK; // Bits 18 through 23 must match the msg ID ECanLAMRegs->LAM3.bit.LAMI = 1; // Acceptance mask identifier - 1: CAN will accept standard and extended frames. // Uses bits 18 to 28 of CANGAM for msg filtering in standard CAN mode // CANMC CCR bit set to 0: // The CPU requests normal operation after configuration of register CANBTC and the acceptance mask // registers (CANGAM, LAM[0], and LAM[3]) of the SCC is finished. ECanRegsShadow.CANMC.all = ECanRegs->CANMC.all; ECanRegsShadow.CANMC.bit.CCR = 0; // Change configuration request bit ECanRegs->CANMC.all = ECanRegsShadow.CANMC.all; // Wait for CCE bit to be cleared.. // CCE = 0 when the CPU does not have write access to the configuration registers. do { ECanRegsShadow.CANES.all = ECanRegs->CANES.all; } while(ECanRegsShadow.CANES.bit.CCE != 0 ); currDestID = 0x3F; // Initialize for later - dummy value used here ECanRegs->CANME.all = 0; // Disable all mailboxes, required before writing the MSGIDs Mailbox = &ECanMboxes->MBOX0; // Start at first mailbox // setup 1 transfer mailbox Mailbox->MSGID.bit.IDE = 0; // No extended ID, use SCC (statndard CAN) Mailbox->MSGID.bit.STDMSGID = (currDestID & 0x3F); // Destination ID - use dummy value here. Set to destination at time of transmission // STDMSGID is 11 bits (bit10 to bit0) which corresponds to bit28 to bit18 of MSGID ++Mailbox; // setup 5 receive mailboxes for (i = 0; i < 5; ++i) { Mailbox->MSGID.bit.IDE = 0; // IDE is a "don't care" and is overwritten by transmitted msg when AMI = 1 // Set here anyway - no harm in setting it here as well Mailbox->MSGID.bit.AME = 1; // Acceptance mask is enabled Mailbox->MSGID.bit.STDMSGID = cntrlrNodeAddr; // Message ID, cntrlrNodeAddr is the controller node id ++Mailbox; } // setup 10 broadcast receive mailboxes for (i = 0; i < 10; ++i) { Mailbox->MSGID.bit.IDE = 0; // IDE is a "don't care" and is overwritten by transmitted msg when AMI = 1 // Set here anyway - no harm in setting it here as well Mailbox->MSGID.bit.AME = 1; // Acceptance mask is enabled Mailbox->MSGID.bit.STDMSGID = bcastAddr; // Message ID ++Mailbox; } ECanRegs->CANMD.all = 0x0000FFFE; // Sets mailbox for receive ECanRegs->CANOPC.all = 0x0000FFBD; // protect data except for the last receive mailboxes ECanRegs->CANME.all = 0x0000FFFF; // Enable Mailboxes EDIS; } //----------------------------------------------------------------------------- // EcanRX // // Receive message on the CAN interface. //----------------------------------------------------------------------------- void EcanRX(void) { Uint32 rcvMask, mask; volatile struct MBOX *Mailbox; // check for overflow if (ECanRegs->CANRML.all != 0) { DEBUG_LOG(0xFC100000); } do { // check for RMP = receive message pending rcvMask = ECanRegs->CANRMP.all; if (rcvMask) { // read CAN data into canQueue - start with highest mailbox Mailbox = &ECanMboxes->MBOX15; mask = 0x00008000; while (mask != 0) { // If there's a message, put it into the can Q if ((mask & rcvMask) != 0) { if (canQueue.size < CAN_QUEUE_SIZE) { canQueue.data[canQueue.size].len = Mailbox->MSGCTRL.bit.DLC; // Data length code canQueue.data[canQueue.size].low = Mailbox->MDL.all; // Low message data canQueue.data[canQueue.size].high = Mailbox->MDH.all; // High message data ++canQueue.size; } else { // CAN queue overflow DEBUG_LOG(0xFC200000 | rcvMask); } } --Mailbox; mask >>= 1; } // Allow further packet reception ECanRegs->CANRMP.all = rcvMask; // Set all receive bits to 1 to clear CANRMP rcvMask = ~rcvMask; while ((ECanRegs->CANRMP.all & rcvMask) != ECanRegs->CANRMP.all) {} // Waits for bits to clear } } while (ECanRegs->CANRMP.all != 0); } //----------------------------------------------------------------------------- // EcanTX // // Transmits data to the destination on the CAN bus or puts it into // the local communication queue if the node is self-messaging. //----------------------------------------------------------------------------- void EcanTX(Uint16 destID, Uint32 low, Uint32 high, Uint16 len) { Uint32 i, j, k; BOOL tryRecover = TRUE; if (destID == cntrlrNodeAddr || GMNI_ADDR_BCAST == destID) { // Packet for local node unicast or to be broadcast to itself, put it into local message communication queue if (localCommQueue.size < CAN_QUEUE_SIZE) { localCommQueue.data[localCommQueue.size].low = low; localCommQueue.data[localCommQueue.size].high = high; localCommQueue.data[localCommQueue.size].len = len; ++localCommQueue.size; } else { // local mailbox overflow DEBUG_LOG(0xFC300000); } } //else // Send all outgoing messages to the CAN bus - both unicast and broadcast if (destID != cntrlrNodeAddr) { // Reset the destination msg ID if the destination changed from the previous message if (currDestID != destID) { ECanRegsShadow.CANME.all = ECanRegs->CANME.all; ECanRegsShadow.CANME.bit.ME0 = 0; // Disable TX Mailbox ECanRegs->CANME.all = ECanRegsShadow.CANME.all; ECanMboxes->MBOX0.MSGID.bit.STDMSGID = (destID & 0x3F); // Destination ID ECanRegsShadow.CANME.all = ECanRegs->CANME.all; ECanRegsShadow.CANME.bit.ME0 = 1; // Enable TX Mailbox ECanRegs->CANME.all = ECanRegsShadow.CANME.all; currDestID = destID; } ECanMboxes->MBOX0.MSGCTRL.bit.DLC = len; // Data length code ECanMboxes->MBOX0.MDL.all = low; // Writes low byte ECanMboxes->MBOX0.MDH.all = high; // Writes high byte ECanRegs->CANTRS.all = 0x00000001; // Starts transfer for (i = 0; i < MAX_TX_ATTEMPTS; ++i) // Try to transmit and then again on error { // If the transmit ACK isn't set within a reasonable number of times throught this loop, // exit the loop. In the case of a timeout, a controller may not be connected to the system. // We don't want to get stuck in this loop. // Typical times for the CANTA to be set in thecontroller are less than ~130 usec. // Typical loop counts are less than 229. ECanRegsShadow.CANTA.all = ECanRegs->CANTA.all; for (j = 0; j < LOOP_COUNTS && ECanRegsShadow.CANTA.bit.TA0 == 0; ++j) { ECanRegsShadow.CANTA.all = ECanRegs->CANTA.all; } if (j >= LOOP_COUNTS) { // Got some kind of an error if (tryRecover) // Allow 1 recovery attempt { ECanRegsShadow.CANES.all = ECanRegs->CANES.all; if (ECanRegsShadow.CANES.bit.SA1) // Check stuck at dominant error { // Try to clear it dominant bit error ECanRegsShadow.CANMC.all = ECanRegs->CANMC.all; ECanRegsShadow.CANMC.bit.CCR = 1; // Change configuration request - write access ECanRegs->CANMC.all = ECanRegsShadow.CANMC.all; ECanRegsShadow.CANES.all = ECanRegs->CANES.all; for (k = 0; k < LOOP_COUNTS && ECanRegsShadow.CANES.bit.CCE == 0; ++k) { // Wait for CCE to be 1 then the cpu will have write access to the config registers ECanRegsShadow.CANES.all = ECanRegs->CANES.all; } ECanRegsShadow.CANMC.all = ECanRegs->CANMC.all; ECanRegsShadow.CANMC.bit.CCR = 0; // Change configuration request - return to normal operation ECanRegs->CANMC.all = ECanRegsShadow.CANMC.all; } tryRecover = FALSE; } else { // Report error DEBUG_LOG(0xFC400000); DEBUG_LOG(ECanRegsShadow.CANES.all); instrStates[0].errCode = ERRCODE(ERRCODE_HI_CAN, ERRCODE_LOW_NO_MSG_TX); return; } } else { // Got transmit Ack - everything is fine break; } } ECanRegsShadow.CANTA.all = 0; ECanRegsShadow.CANTA.bit.TA0 = 1; // Clear transfer acknowledge for next transmission ECanRegs->CANTA.all = ECanRegsShadow.CANTA.all; ECanRegsShadow.CANTA.all = ECanRegs->CANTA.all; for (i = 0; i < LOOP_COUNTS && ECanRegsShadow.CANTA.bit.TA0 == 1; ++i) { // Wait for transfer acknowledge to clear ECanRegsShadow.CANTA.all = ECanRegs->CANTA.all; } } } //----------------------------------------------------------------------------- // End of file //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // FILE: CANModule.c // // Description: CAN driver // // Version: 1.0 (Feb 5, 2015) // // Target: TMS320F28377S // // Details: Peripheral Interface to DCAN hardware // The hardware supports extended CAN (ECAN) and standard CAN // (SCC). This driver uses SCC CAN. // // Reference: spruhx5d - TMS320x2837x, 2837x Technical // Reference Guide // //----------------------------------------------------------------------------- //-------------------------Includes-------------------------------------------- #include "Defs.h" #include "ProcessorModule.h" #include "F2837xS_device.h" #include "hw_types.h" #include "hw_can.h" #include "GMNIAddressing.h" #include "CANModule.h" #include "Errors.h" #include "ParamDB.h" #include "DebugModule.h" #include "CommandProtocol.h" #include "Instructions.h" #include "InstructionEvents.h" //-------------------------Defines-------------------------------------------- #define LOOP_COUNTS ((Uint32)20000) // Bail out loop counts so we don't get stuck forever #define NUM_MAILBOXES ((int)16) // Number of mailboxes allowed in standard CAN mode #define CAN_BRP_REG (19) #define CAN_BRP_EX_REG (0) #define CAN_TSEG1_REG (6) #define CAN_TSEG2_REG (1) #define CAN_SJW_REG (1) #define MSG_DATA_LENGTH (8) #define ACCEPTANCE_MASK (0x00FC0000) // Bits 18 through 28 are for standard CAN, masking is done with 1s // In this application, the node ID is used as the message ID. It is stored in 6 bits so... // Bits 18 through 23 must match the message ID - (bit 31)xxxx,xxxx,1111,11xx,xxxx,xxxx,xxxx,xxxx(bit0) #define CAN_IF3ARB_STD_ID_M (0x1FFC0000U) #define IF3_MAILBOXES (0x0000FFFE) #define FIRST_UNICAST_MB (2) // First CAN unicast mailbox #define LAST_UNICAST_MB (6) // Last CAN unicast mailbox #define LAST_BCAST_MB (16) // Last CAN broadcast mailbox #define LAST_CAN_MB (32) // Last CAN mailbox #define TX_MAILBOX (1) // Transmit MB //-------------------------Globals-------------------------------------------- CanQueue canQueue; // Storage for CAN messages coming in from the bus CanQueue localCommQueue; // Storage for CAN messages coming from the same CAN node as the sender. // Every node can see all messages from all other nodes but it can't see its own. // Reference: www.keil.com/.../canprimer_v2.pdf static Uint16 currDestID = 0x3F; // Dummy initial value, will be changed on first TX //----------------------------------------------------------------------------- // NOTE: Accessing DCAN control and status registers // // 32-bit DCAN registers must be read/written as 32-bit values. If 16-bit // access is used, the values can be corrupted. The compiler provides // an intrinsic __bit_peripheral_32. A macro is given to provide access // to the intrinsic: HWREG_BP // //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- // DCanInit // // Standard CAN initialization. Using CAN-B on the controller board. // Talks to the main controller bus. //----------------------------------------------------------------------------- void DCanInit(Uint16 bcastAddr, Uint32 base) { Uint16 mailBox; // Message object (mailbox) index Uint32 mailBoxID; Uint16 endOfBlock; // End of receive FIFOs - either unicast block or broadcast block Uint32 bitReg; Uint32 maskReg; canQueue.size = 0; localCommQueue.size = 0; //---------------------Start DCan init---------------------------- // Place CAN controller in init state, regardless of previous state. This // will put controller in idle, and allow the message object RAM to be // programmed. // CAN_CTL register // CAN_O_CTL is offset from register base // Bits: Init (b0) = 1; // ABO Auto-Bus_On (b9): Enabled // PMD Parity checking (b10-b13) = 0101 (default at reset) // DAR Disable automatic retransmission: 0 we want retransmission HWREGH(base + CAN_O_CTL) |= ((Uint16)CAN_CTL_INIT | (Uint16)CAN_CTL_ABO | (Uint16)CAN_INIT_PARITY_DISABLE); // Set bus-off timer value - number of clock cycles after bus-off happens and recovery starts // CAN_ABOTR register // CAN_O_ABOTR is offset from register base // Bits: ABO_Time (b0-b31) HWREG_BP(base + CAN_O_ABOTR) = 2; // Guess TODO try 0, 2, 5, 10?? // Initialize the message RAM before using it // CAN_INIT register // CAN_O_RAM_INIT is offset from base // Bits: CAN_RAM_INIT (b4) = 1; KEYs (b0-b3) = 1010 HWREGH(base + CAN_O_RAM_INIT) = CAN_RAM_INIT_CAN_RAM_INIT | CAN_RAM_INIT_KEY; // Wait until RAM Init is complete while (!((HWREGH(base + CAN_O_RAM_INIT) & CAN_RAM_INIT_MASK) == (CAN_RAM_INIT_RAM_INIT_DONE | CAN_RAM_INIT_KEY2 | CAN_RAM_INIT_KEY0))) { // RAM_INIT_DONE will be 1 // CAN_RAM_INIT will be 0 // KEYs will be 0101 } // Force module to reset state // CAN_CTL register // CAN_O_CTL is offset from register base // Bits: SWR (b15) = 1 This bit is EALLOW protected EALLOW; HWREGH(base + CAN_O_CTL) |= CAN_CTL_SWR; EDIS; // Delay 14 cycles - 1us DELAY_US(1); // Enable write access to the configuration register // CAN_CTL register // CAN_O_CTL is offset from register base // Bits: CCE (b6): 1 HWREGH(base + CAN_O_CTL) |= CAN_CTL_CCE; //--------------------Set up bit timing----------------------------- // Set up the CAN bus bit rate to 1 Mbps // Refer to the Driver Library User Guide for information on how to set // tighter timing control. Additionally, consult the device data sheet // for more information about the CAN module clocking. // To set the bit timing register, the controller must be placed in init // mode (if not already), and also configuration change (CCE) bit enabled // This was done above // Configure bit timing // Bit Rate = (SYSCLKOUT) / ((BRPreg + 1) * BitTime) = 1,000,000 Mb/s // where SYSCLKOUT = 200 MHz; BRPreg = 19; TSEG1reg = 1; TSEG2reg = 1; SJWreg = 1 // BitTime = (TSEG1REG + 1) + (TSEG2REG + 1) + 1 = 10 // By default at reset, the peripheral clock (SYSCLKOUT) is used bitReg = (Uint32)((Uint32)CAN_BRP_REG & CAN_BTR_BRP_M); bitReg |= (Uint32)(((Uint32)CAN_SJW_REG << CAN_BTR_SJW_S) & CAN_BTR_SJW_M); bitReg |= (Uint32)(((Uint32)CAN_TSEG1_REG << CAN_BTR_TSEG1_S) &CAN_BTR_TSEG1_M); bitReg |= (Uint32)(((Uint32)CAN_TSEG2_REG << CAN_BTR_TSEG2_S) & CAN_BTR_TSEG2_M); bitReg |= (Uint32)(((Uint32)CAN_BRP_EX_REG << CAN_BTR_BRPE_S) & CAN_BTR_BRPE_M); HWREG_BP(base + CAN_O_BTR) = bitReg; // Disable write access to the configuration registers; CAN_CTL_INIT still set // CAN_CTL register // CAN_O_CTL is offset from register base // Bits: CCE (b6): 0 HWREGH(base + CAN_O_CTL) &= ~((uint16_t)CAN_CTL_CCE); //----------------------Set up mailboxes-------------------------------- // 1 Transmit mailbox // 5 Unicast receive mailboxes // 10 Broadcast receive mailboxes // Make sure interface 1 isn't busy while ((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) == CAN_IF1CMD_BUSY) { } //-----TX mailbox ----- // CAN_IF1MSK register - interface 1 mask reg // CAN_O_IF1MSK is offset from register base // Bits: Dir (b29): DIR: 1 = TX; // MessageID (b0-b28): 0x00FC0000 Filter on acceptance mask // MDir (b30): 0 - Don't filter on direction // MXtd (b31): 0 - Don't filter on extended id HWREG_BP(base + CAN_O_IF1MSK) = 0; //HWREG_BP(base + CAN_O_IF1MSK) = (ACCEPTANCE_MASK & CAN_IF1ARB_STD_ID_M); // CAN_IF1ARB register - interface 1 arbitration reg // CAN_O_IF1ARB is offset from register base // Bits: Dir (b29): DIR: 1 = TX; // MessageID (b0-b28): destID: dummy (0x3f << 18) place holder destID for tx msg. Will be filled out with destination when sent; // Xtd (b30): 0 - Standard Identier (11 bits) // MsgVal (b31): 1 - Use mailbox HWREG_BP(base + CAN_O_IF1ARB) = CAN_IF1ARB_DIR | (ACCEPTANCE_MASK & CAN_IF1ARB_STD_ID_M) | CAN_IF1ARB_MSGVAL; // CAN_IF1MCTL - interface 1 message control // CAN_O_IF1MCTL is offset from register base // Bits: DLC (b0-b3): 8 - data length; // EoB (b7): 1 - End of Block; // UMask (b12): 0 - Don't use mask for acceptance filtering on transmit //HWREG_BP(base + CAN_O_IF1MCTL) = CAN_IF1MCTL_UMASK | HWREG_BP(base + CAN_O_IF1MCTL) = ((Uint32)MSG_DATA_LENGTH & CAN_IF1MCTL_DLC_M) | CAN_IF1MCTL_EOB; // Transfer data to the message object RAM HWREG_BP(base + CAN_O_IF1CMD) = CAN_IF1CMD_ARB | CAN_IF1CMD_CONTROL | CAN_IF1CMD_MASK | CAN_IF1CMD_DIR | (TX_MAILBOX & CAN_IF1CMD_MSG_NUM_M); //-----5 Unicast RX mailboxes and 10 Broadcast Rx mailboxes----- // Use either IF1 or IF2 to set up message objects (mailboxes) - we'll use IF1 // Once the message objects are set up, we can use IF3 for receives for (mailBox = FIRST_UNICAST_MB; mailBox <= LAST_BCAST_MB; ++mailBox) { // Make sure interface 1 isn't busy while ((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) == CAN_IF1CMD_BUSY) { } // CAN_IF1MSK register - interface 1 mask register // CAN_O_IF1MSK is the offset from register base // Bits: Mask (b0-b28): mask for standard frame bits 18 through 28 // MXtd (b31): 0 - Not using extended IDs for acceptance filtering // MDir (b30): 0 - Not using direction for acceptance filtering HWREG_BP(base + CAN_O_IF1MSK) = (ACCEPTANCE_MASK & CAN_IF1ARB_STD_ID_M); // CAN_IF1ARB register - interface 1 arbitration reg // CAN_O_IF1ARB is offset from register base // Bits: Dir (b29): 0 - RX; // MessageID (b0-b28): msg ID is the controller node addr; // MsgVal (b31): 1 - Use mailbox if (mailBox <= LAST_UNICAST_MB) { // Set up unicast mailboxes mailBoxID = cntrlrNodeAddr; } else { // Set up broadcast mailboxes mailBoxID = bcastAddr; } HWREG_BP(base + CAN_O_IF1ARB) = ((mailBoxID << CAN_IF1ARB_STD_ID_S) & CAN_IF1ARB_STD_ID_M) | CAN_IF1ARB_MSGVAL; // CAN_IF1MCTL - interface 1 message control // CAN_O_IF1MCTL is offset from register base // Bits: DLC (b0-b3): 8 - data length; // EoB (b7): 1 - End of Block; Using FIFO so set EoB for last unicast mailbox and last broadcast mailbox // UMask (b12): 1 - Use mask for acceptance filtering if (LAST_UNICAST_MB == mailBox || LAST_BCAST_MB == mailBox) { endOfBlock = CAN_IF1MCTL_EOB; } else { endOfBlock = 0; } HWREG_BP(base + CAN_O_IF1MCTL) = CAN_IF1MCTL_UMASK | ((Uint32)MSG_DATA_LENGTH & CAN_IF1MCTL_DLC_M) | endOfBlock; // Transfer data to the message object RAM HWREG_BP(base + CAN_O_IF1CMD) = CAN_IF1CMD_ARB | CAN_IF1CMD_CONTROL | CAN_IF1CMD_MASK | CAN_IF1CMD_DIR | (mailBox & CAN_IF1CMD_MSG_NUM_M); } // Enable IF3 to receive all RX message whether unicast or broadcast HWREG_BP(base + CAN_O_IF3UPD) = IF3_MAILBOXES; // Mailboxes 2 through 16 // Setup IF3 so that the next IF3 update can't happen until all data is read from the interface // CAN_IF3OBS register - IF3 Observation register // CAN_O_IF3OBS is the offset from register base // Bits: Data_A (b3): 1 - no new IF3 update until data has been read // Data_B (b4): 1 - no new IF3 update until data has been read HWREGH(base + CAN_O_IF3OBS) = CAN_IF3OBS_DATA_A | CAN_IF3OBS_DATA_B; //CAN_IF3OBS_IF3SM; // Ask the forum TODO // Clear message valid bit for all mailboxes not being used for (mailBox = (LAST_BCAST_MB + 1); mailBox <= LAST_CAN_MB; ++mailBox) { HWREG_BP(base + CAN_O_IF1ARB) = 0; // Set MsgVal to 0 HWREG_BP(base + CAN_O_IF1CMD) = CAN_IF1CMD_ARB | (mailBox & CAN_IF1CMD_MSG_NUM_M); } // Start the CAN module after initialization HWREGH(base + CAN_O_CTL) &= ~(CAN_CTL_INIT | CAN_CTL_CCE); } //----------------------------------------------------------------------------- // DcanRX // // Receive message on the CAN interface. //----------------------------------------------------------------------------- #define RCV_MAILBOXES_MASK (0x0000FFFE) void DcanRX(Uint32 base) { volatile Uint32 msgsPending = 0; volatile Uint16 msgCtrl; volatile Uint16 msgObs; msgObs = HWREGH(base + CAN_O_IF3OBS); // Read all the incoming messages that are in the message RAM through IF3 (CAN interface 3) while ((msgObs & CAN_IF3OBS_IF3UPD) == CAN_IF3OBS_IF3UPD) { ///do ///{ // Check for rx mailboxes with NewData bit set in the message RAM ///msgsPending = (HWREG_BP(base + CAN_O_NDAT_21) & RCV_MAILBOXES_MASK); // Check IF3 Observation register to see if new data has shown up in IF3 - IF3Upd bit ///msgObs = HWREGH(base + CAN_O_IF3OBS); // Check IF3 to see if a message already has been automatically transferred to the interface //msgCtrl = HWREGH(base + CAN_O_IF3MCTL); // If there's a message in IF3, put it into the can Q ///if ((msgCtrl & CAN_IF3MCTL_NEWDAT) == CAN_IF3MCTL_NEWDAT) if ((msgObs & CAN_IF3OBS_IF3UPD) == CAN_IF3OBS_IF3UPD) { if (canQueue.size < CAN_QUEUE_SIZE) { canQueue.data[canQueue.size].len = (Uint16)(msgCtrl & CAN_IF3MCTL_DLC_M); // Data length code canQueue.data[canQueue.size].low = HWREG_BP(base + CAN_O_IF3DATA); // Low message data - bytes 0 through 3 canQueue.data[canQueue.size].high = HWREG_BP(base + CAN_O_IF3DATB); // High message data - bytes 4 through 7 ++canQueue.size; } else { // CAN queue overflow DEBUG_LOG(0xFC200000 | msgsPending); } } msgObs = HWREGH(base + CAN_O_IF3OBS); } } //----------------------------------------------------------------------------- // DcanTX // // Transmits data to the destination on the CAN bus or puts it into // the local communication queue if the node is self-messaging. //----------------------------------------------------------------------------- void DcanTX(Uint32 base, Uint32 destID, Uint32 low, Uint32 high, Uint16 len) { // Toggle between IF1 and IF2 every transmit TODO may do this ///canIF = (canIFToggle) ? 1 : 2; ///canIFToggle = (canIFToggle) ? 0 : 1; volatile Uint32 canStatus; Uint16 loopCounts; // For timeout volatile Uint32 msgArb; // Message for this controller node - don't send it out to the bus, put it in the local CAN queue if (destID == cntrlrNodeAddr || GMNI_ADDR_BCAST == destID) { // Packet for local node unicast or to be broadcast to itself, put it into local message communication queue if (localCommQueue.size < CAN_QUEUE_SIZE) { localCommQueue.data[localCommQueue.size].low = low; localCommQueue.data[localCommQueue.size].high = high; localCommQueue.data[localCommQueue.size].len = len; ++localCommQueue.size; } else { // local mailbox overflow DEBUG_LOG(0xFC300000); } } // Send all outgoing messages to the CAN bus - both unicast and broadcast // Using IF1 (interface 1) for CAN TXs if (destID != cntrlrNodeAddr) { // // Set IF command to read arbitration value // // Set up the request for data from the message object. // Transfer the message object to the IF register. // HWREG_BP(base + CAN_O_IF1CMD) = CAN_IF1CMD_ARB | (TX_MAILBOX & CAN_IF1CMD_MSG_NUM_M); // Make sure IF1 is not busy with a previous transmit between IF1 and CAN RAM while ((HWREGH(base + CAN_O_IF1CMD) & CAN_IF1CMD_BUSY) == CAN_IF1CMD_BUSY) { // Wait } // Read IF arb message msgArb = HWREG_BP(base + CAN_O_IF1ARB); // Write DATA to interface 1 HWREG_BP(base + CAN_O_IF1DATA) = low; HWREG_BP(base + CAN_O_IF1DATB) = high; // Reset the destination msg ID if the destination changed from the previous message if (currDestID != destID) { HWREG_BP(base + CAN_O_IF1ARB) = msgArb | ((destID << CAN_IF1ARB_STD_ID_S) & CAN_IF1ARB_STD_ID_M); } // Transfer the IF message object to the TX mailbox in RAM // Not changing the direction, length or mailBox ID HWREG_BP(base + CAN_O_IF1CMD) = (CAN_IF1CMD_DATA_B | CAN_IF1CMD_DATA_A | /*CAN_IF1CMD_CONTROL |*/ CAN_IF1CMD_DIR | CAN_IF1CMD_ARB | CAN_IF1CMD_TXRQST | (TX_MAILBOX & CAN_IF1CMD_MSG_NUM_M) ); //HWREG_BP(base + CAN_O_IF1CMD) |= CAN_IF1CMD_TXRQST; //HWREG_BP(base + CAN_O_IF1CMD) = 1; //CanbRegs.CANIF1CMD.bit.MSG_NUM = 1; //HWREG_BP(base + CAN_O_IF1CMD) |= (1 & CAN_IF1CMD_MSG_NUM_M); // Check the transfer acknowledge to make sure the msg made it to at least one node on the bus // Don't wait forever or we may get stuck here // Don't try any recovery. Let CAN do recovery and get msg through /* loopCounts = 0; canStatus = HWREG(base + CAN_O_ES); while ( !(canStatus & CAN_ES_TXOK) && loopCounts++ < LOOP_COUNTS) { canStatus = HWREG(base + CAN_O_ES); if (loopCounts + 1 >= LOOP_COUNTS) { // Report error DEBUG_LOG(0xFC400000); DEBUG_LOG(canStatus); instrStates[0].errCode = ERRCODE(ERRCODE_HI_CAN, ERRCODE_LOW_NO_MSG_TX); } } */ } } //----------------------------------------------------------------------------- // End of file //-----------------------------------------------------------------------------
Thanks -
Mary