This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F28377S: Porting ECAN from F28335 to DCAN on F28377S - Can't Transmit

Part Number: TMS320F28377S
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

  • Mary,

                The DCAN follows a different programming model than the eCAN. In DCAN, we use the IFx registers as a "window" to access the mailbox (MBX) RAM. i.e. you don’t access the MBX RAM "directly" the way you do with eCAN. Furthermore, there is no "direct visibility" of the MBX RAM area in DCAN (unless RDA=1).

     

    You say you are able to receive data. If this is true, it is reasonable to assume there are no hardware issues in your setup.

     

    Have you tried the example code in c2000ware? Comparing your code to the (proven) example code is the fastest way to figure out what is wrong with your code.

  • Hi -

    I completely realize the DCAN follows a different model than ECAN.  I am using the interfaces (IFx registers) as a window into the mailbox RAM.  This is evidenced by my code.  I posted both the 335 and the 377S code.  And I am using the TI example code to write my code.  I am looking for a specific reason that you may be aware of as to why the transmit data does not go out.

    Thanks-

    Mary