📄 can_tms320f28xx.cpp
字号:
/************************************************************/
/* */
/* 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 + -