⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 can_tms320f28xx.cpp

📁 美国COPLEY驱动器,程序开发工具之一.
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/************************************************************/
/*                                                          */
/*  Copley Motion Libraries                                 */
/*                                                          */
/*  Author: Stephen Glow                                    */
/*                                                          */
/*  Copyright (c) 2002-2005 Copley Controls Corp.           */
/*                          http://www.copleycontrols.com   */
/*                                                          */
/************************************************************/

/*
	CAN object for Texas Instruments TMS320F28xx DSP on board CAN controller.
	This module is expected to run with TI's DSPBIOS operating system.
*/

#include <std.h>
#include <hwi.h>
#include <c28.h>
#include "can/can_tms320f28xx.h"
#include "CML.h"

CML_NAMESPACE_USE();

typedef volatile unsigned long LREG;
typedef volatile unsigned int REG;

/* local defines */
#define CAN_ADDRESS           0x6000
#define RECV_MB_CT            24
#define PCLKCR                (REG*)0x701C
#define GPFMUX                (REG*)0x70D4
#define PIE_BASE              0x0CE0

typedef struct
{
	LREG  id;           // CAN message ID
	LREG  ctrl;         // Mailbox control bits
	LREG  data[2];      // Message data
} CAN_MB;

typedef struct
{
	LREG  ME;           // 0x6000 - Mailbox enable
	LREG  MD;           // 0x6002 - Mailbox direction
	LREG  TRS;          // 0x6004 - Transmit request set
	LREG  TRR;          // 0x6006 - Transmit request reset
	LREG  TA;           // 0x6008 - Transmission acknowledge
	LREG  AA;           // 0x600A - Abort acknowledge
	LREG  RMP;          // 0x600C - Receive message pending
	LREG  RML;          // 0x600E - Receive message lost
	LREG  RFP;          // 0x6010 - Remote frame pending
	LREG  rsvd1;        // 0x6012 - Reserved
	LREG  MC;           // 0x6014 - Master control
	LREG  BTC;          // 0x6016 - Bit-timing configuration
	LREG  ES;           // 0x6018 - Error and status
	LREG  TEC;          // 0x601A - Transmit error counter
	LREG  REC;          // 0x601C - Receive error counter
	LREG  GIF0;         // 0x601E - Global interrupt flag 0
	LREG  GIM;          // 0x6020 - Global interrupt mask
	LREG  GIF1;         // 0x6022 - Global interrupt flag 1
	LREG  MIM;          // 0x6024 - Mailbox interrupt mask
	LREG  MIL;          // 0x6026 - Mailbox interrupt level
	LREG  OPC;          // 0x6028 - Overwrite protection control
	LREG  TIOC;         // 0x602A - TX I/O control
	LREG  RIOC;         // 0x602C - RX I/O control
	LREG  LNT;          // 0x602E - Local network time (Reserved in SCC mode)
	LREG  TOC;          // 0x6030 - Time-out control (Reserved in SCC mode)
	LREG  TOS;          // 0x6032 - Time-out status (Reserved in SCC mode)
	LREG  rsvd2[6];     // 0x6034 - Reserved
	LREG  LAM[32];      // 0x6040 - Local Acceptance Masks
	LREG  MOTS[32];     // 0x6080 - Message Object Time Stamps
	LREG  MOTO[32];     // 0x60C0 - Message Object Time-Outs
	CAN_MB Mailbox[32]; // 0x6100 - CAN Mailboxes
} CAN_REGS;

typedef struct
{
	REG CTRL;
	REG ACK;
	struct
	{
		REG ENA;
		REG FLG;
	} VECT[12];
} PIE_REGS;

// Macros used to enable/disable writing to some registers
#define EnableRegAccess()    asm( " eallow" );
#define DisableRegAccess()   asm( " edis" );

// Local functions 
static uint32 CanRegRead( LREG &addr );
static void CanRegWrite( LREG &ptr, uint32 data );

/* local data */
static F28xxCAN *openPort = 0;

/***************************************************************************/
/**
Construct a default CAN object.
The CAN interface is closed initially, and no port address is specified.
*/
/***************************************************************************/
F28xxCAN::F28xxCAN( void ) : CanInterface()
{
	// Default baud to 1,000,000 bps
	SetBaud( 1000000 );

	// Default to not open
	regPtr = 0;
}

/***************************************************************************/
/**
Construct a CAN object with a specified port name.
Note that the port name is currently not used by this CAN 
interface class.
@param port Name of the CAN port to access.
*/
/***************************************************************************/
F28xxCAN::F28xxCAN( const char *port ) : CanInterface(port)
{
	// Default baud to 1,000,000 bps
	SetBaud( 1000000 );

	// Default to not open
	regPtr = 0;
}

/***************************************************************************/
/**
Destructor.  This closes the CAN port.
*/
/***************************************************************************/
F28xxCAN::~F28xxCAN( void ) 
{
	Close();
}

/***************************************************************************/
/**
Open the CAN port.  Before Open is called, the desired baud rate and
port address should be set.

If the baud rate is not explicitly set, the 1,000,000 bits/set will be
used.  If the port address isn't set, then the default address will be
used.

@return A pointer to an error object on failure, NULL on success.
*/
/***************************************************************************/
const Error *F28xxCAN::Open( void )
{
	int i;
	mutex.Lock();

Thread::sleep(1);
	// See if this port has already been open
	if( regPtr || openPort )
	{
		mutex.Unlock();
		return &CanError::AlreadyOpen;
	}

	// Initialize semaphores and receive queue
	free = head = tail = 0;
	for( i=0; i<F28xxCAN_RQLEN; i++ )
	{
		recvQ[i].next = free;
		free = &recvQ[i];
	}
	
	while( !recvSem.Get(0) );

	// Initialize the transmit semaphore to the number
	// of free transmit mailboxes
	while( !xmitSem.Get(0) );
	for( i=0; i<32-RECV_MB_CT; i++ )
		xmitSem.Put();
	nextXmitPri = 31;

	/**************************************************
	* Enable the peripheral clock used by the CAN module
	**************************************************/
	EnableRegAccess();
	*PCLKCR |= 0x4000;

	/**************************************************
	* Assign the CAN pins to the CAN port.  These are
	* GPIO by default on reset.
	**************************************************/
	*GPFMUX |= 0x00C0;

	/**************************************************
	* Find the address of the CAN port registers
	**************************************************/
	CAN_REGS *regs = (CAN_REGS *)CAN_ADDRESS;

	// Reset the CAN hardware and enter configuration mode
	CanRegWrite( regs->MC, 0x00001020 );
	for( i=0; !(CanRegRead(regs->ES) & 0x10) && (i<1000); i++ )
		Thread::sleep(1);

	if( !(CanRegRead(regs->ES) & 0x10) )
	{
		DisableRegAccess();
		mutex.Unlock();
		return &CanError::Unknown;
	}

	// Select HECC mode
	CanRegWrite( regs->MC, 0x00003000 );

	uint32 allRecv = (1L<<RECV_MB_CT) - 1;

	CanRegWrite( regs->MD,   allRecv );      // Use the top 12 for transmit
	CanRegWrite( regs->BTC,  btc );          // Set the bit timing config 
	CanRegWrite( regs->MIM,  0xFFFFFFFF );   // Enable all mailbox interrupts
	CanRegWrite( regs->GIM,  0x00003F01 );   // Use interrupt line 0 for all ints
	CanRegWrite( regs->OPC,  allRecv );      // Don't overwrite messages
	CanRegWrite( regs->TIOC, 8 );            // Configure transmit pin
	CanRegWrite( regs->RIOC, 8 );            // Configure receive pin

	// Setup the acceptance masks to allow all messages
	for( i=0; i<32; i++ )
		CanRegWrite( regs->LAM[i], 0x9FFFFFFF );

	// Clear the control field of each mailbox
	// and set the AME bit (Acceptance mask enable)
	for( i=0; i<32; i++ )
	{
		CanRegWrite( regs->Mailbox[i].ctrl, 0 );
		CanRegWrite( regs->Mailbox[i].id, 0x40000000 );
	}
	
	// Enable all receive mailboxes
	CanRegWrite( regs->ME, allRecv );

	// Exit configuration mode
	CanRegWrite( regs->MC, 0x00002080 );

	// Enable peripherial interrupt vector 9.5 which
	// is the vector used by the CAN controller.
	PIE_REGS *pie = (PIE_REGS *)PIE_BASE;
	pie->VECT[8].ENA |= 0x10;

	// Enable the processor interrupt 
	C28_enableIER( 0x0100 );
	DisableRegAccess();

	for( i=0; (CanRegRead(regs->ES) & 0x10) && (i<1000); i++ )
		Thread::sleep(1);

	if( CanRegRead(regs->ES) & 0x10 )
	{
		mutex.Unlock();
		return &CanError::Unknown;
	}

	regPtr = regs;
	openPort = this;
	mutex.Unlock();

	return 0;
}

/***************************************************************************/
/**
Close the CAN interface.
@return A pointer to an error object on failure, NULL on success.
*/
/***************************************************************************/
const Error *F28xxCAN::Close( void )
{
	mutex.Lock();
	CAN_REGS *regs = (CAN_REGS *)regPtr;
	regPtr = 0;
	mutex.Unlock();

	if( !regs )
		return 0;

	openPort = 0;

	// Enter configuration mode which disables the port
	EnableRegAccess();
	CanRegWrite( regs->MC, 0x00001000 );
	DisableRegAccess();

	return 0;
}


/***************************************************************************/
/**
Set the CAN interface baud rate.
@param b The baud rate to set.
@return A pointer to an error object on failure, NULL on success.
*/
/***************************************************************************/
const Error *F28xxCAN::SetBaud( int32 b )
{
	//-----------------------------------------------------------------------------------
	// Configure the bit timing register based on the desired baud rate.
	//
	// The CAN bit timing is made up of a number of different fields:
	//
	//   BRP   - Baud Rate Prescaler.  This is a divider used to reduce the
	//           input clock (150 MHz) down to a more reasonable rate.
	//           The period of the divided down clock is known as a Time Quanta (TQ)
	//   TSEG1 - Length of the first programmable portion of the CAN bit time in TQ
	//   TSEG2 - Length of the second programmable portion of the bit time in TQ
	//
	//  The actual bit time will be an integer number of time quanta long.
	//  The actual length of a bit is TSEG1 + TSEG2 + 1.  The extra 1 is not 
	//  programmable and is called the synch segment.
	//
	//  I'll be using bit times based on 15 TQ / bit.  TSEG1 will be 11 TQ long and
	//  TSEG2 will be 3 TQ long.  This puts the sample point (which is between TSEG1
	//  and TSEG2) at 80% of the bit time, which is generally considered a good location.
	//-----------------------------------------------------------------------------------
	long brp;
	int tseg1, tseg2;

	switch( b )
	{
		case 1000000: brp =  10; tseg1 = 11; tseg2 = 3; break;
		case  800000: brp =  12; tseg1 = 11; tseg2 = 4; break;
		case  500000: brp =  20; tseg1 = 11; tseg2 = 3; break;
		case  250000: brp =  40; tseg1 = 11; tseg2 = 3; break;
		case  125000: brp =  80; tseg1 = 11; tseg2 = 3; break;
		case   50000: brp = 200; tseg1 = 11; tseg2 = 3; break;
		case   20000: brp = 500; tseg1 = 11; tseg2 = 3; break;
		default: 
			return &CanError::BadParam;
	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -