can_tms320f28xx.cpp
来自「美国COPLEY驱动器,程序开发工具之一.」· C++ 代码 · 共 675 行 · 第 1/2 页
CPP
675 行
//-----------------------------------------------------------
// A couple other parameters also effect the bit rate setup.
// SAM - if set, take multiple bus samples. BRP must be > 4.
// SJW - Synch jump width. Max number of TQ to adjust the bit
// timing to align the edges of the bit. Can be 1 to 4
// TQ, but can't be greater then TSEG2
//-----------------------------------------------------------
int sam = (brp>4) ? 1 : 0;
int sjw = (tseg2>4 ) ? 4 : tseg2;
// Build up the actual value to be loaded into the CAN register
btc = 0x00000400;
btc |= (0x07 & (tseg2-1));
btc |= (0x0F & (tseg1-1)) << 3;
btc |= (0x01 & sam) << 7;
btc |= (0x03 & (sjw-1)) << 8;
btc |= (0xFF & (brp-1)) << 16;
baud = b;
return 0;
}
// Utility function used to split a 32-bit value into 4 bytes.
static void Split( uint32 l, byte *bptr )
{
bptr[0] = 0x00FF & (l >> 24);
bptr[1] = 0x00FF & (l >> 16);
bptr[2] = 0x00FF & (l >> 8);
bptr[3] = 0x00FF & (l);
}
// Utility function used to pack 4 bytes into a 32-bit value
static uint32 Pack( byte *bptr )
{
uint32 l;
l = (uint32)(bptr[0]&0x00FF) << 24;
l |= (uint32)(bptr[1]&0x00FF) << 16;
l |= (uint32)(bptr[2]&0x00FF) << 8;
l |= (uint32)(bptr[3]&0x00FF);
return l;
}
/***************************************************************************/
/**
Receive the next CAN frame.
@param frame A reference to the frame object that will be filled by the read.
@param timeout The timeout (ms) to wait for the frame. A timeout of 0 will
return immediately if no data is available. A timeout of < 0 will
wait forever.
@return A pointer to an error object on failure, NULL on success.
*/
/***************************************************************************/
const Error *F28xxCAN::RecvFrame( CanFrame &frame, int32 timeout )
{
// Make sure the port is open
if( !regPtr )
return &CanError::NotOpen;
// Wait for the new message
const Error *err = recvSem.Get(timeout);
if( err ) return err;
mutex.Lock();
// Copy the last message in the queue
HWI_disable();
F28xx_Mailbox *mbPtr = head;
head = head->next;
if( !head )
tail = 0;
else
head->prev = 0;
HWI_enable();
frame.type = (mbPtr->ctrl & 0x10) ? CAN_FRAME_REMOTE : CAN_FRAME_DATA;
if( mbPtr->id & 0x80000000 )
frame.id = 0x20000000 | (mbPtr->id & 0x1FFFFFFF);
else
frame.id = 0x000007FF & (mbPtr->id >> 18);
frame.length = mbPtr->ctrl & 0x0F;
Split( mbPtr->data[0], &(frame.data[0]) );
Split( mbPtr->data[1], &(frame.data[4]) );
// Free the queue location
HWI_disable();
mbPtr->next = free;
free = mbPtr;
HWI_enable();
mutex.Unlock();
return 0;
}
/***************************************************************************/
/**
Write a CAN frame to the CAN network.
@param frame A reference to the frame to write.
@param timeout The time to wait for the frame to be successfully sent.
If the timeout is 0, the frame is written to the output queue and
the function returns without waiting for it to be sent.
If the timeout is <0 then the function will delay forever.
@return A pointer to an error object on failure, NULL on success.
*/
/***************************************************************************/
const Error *F28xxCAN::XmitFrame( CanFrame &frame, int32 timeout )
{
// Make sure the port is open
CAN_REGS *regs = (CAN_REGS *)regPtr;
if( !regs )
return &CanError::NotOpen;
// Wait for a free transmit mailbox
const Error *err = xmitSem.Get(timeout);
if( err )
return err;
mutex.Lock();
// The transmit mailboxes on this chip implement a priority
// mechanism that I don't use. To ensure that I send my
// messages in the correct order I need to send each message
// out at a priority level lower then the last. When I hit
// zero priority, I need to wait for the interrupt handler to
// reset my priority to the max.
while( nextXmitPri < 0 )
{
mutex.Unlock();
if( !timeout )
return &ThreadError::Timeout;
Thread::sleep(1);
if( timeout > 0 ) timeout--;
mutex.Lock();
}
// Find a pointer to a free mailbox
uint32 mask = 0x80000000;
uint32 me = CanRegRead( regs->ME );
int i;
for( i=31; (me & mask) && (i>=RECV_MB_CT); i--, mask>>=1 );
// Make sure we found a free mailbox. This should always be true,
// if it isn't there must be a bug in this driver.
if( i < RECV_MB_CT )
{
mutex.Unlock();
return &CanError::Driver;
}
// Copy the message into the mailbox
CAN_MB *mb = ®s->Mailbox[i];
if( frame.id & 0x20000000 )
CanRegWrite( mb->id, (0x1FFFFFFF & frame.id) | 0x80000000 );
else
CanRegWrite( mb->id, (0x000007FF & frame.id) << 18 );
uint32 ctrl = (frame.length <= 8) ? frame.length : 8;
if( frame.type == CAN_FRAME_REMOTE )
ctrl |= 0x10;
CanRegWrite( mb->data[0], Pack( &frame.data[0] ) );
CanRegWrite( mb->data[1], Pack( &frame.data[4] ) );
HWI_disable();
ctrl |= (nextXmitPri << 8);
nextXmitPri--;
CanRegWrite( mb->ctrl, ctrl );
// Start the transmit
me = CanRegRead( regs->ME ) | mask;
CanRegWrite( regs->ME, me );
CanRegWrite( regs->TRS, mask );
HWI_enable();
mutex.Unlock();
return 0;
}
/***************************************************************************/
/**
CAN Hardware Interrupt handler.
It's assumed that the DSPBIOS configuration has been setup so that this
function's address is listed in the vector table for the correct interrupt.
*/
/***************************************************************************/
void F28xxCAN_IntHandler( void )
{
// Acknowledge this interrupt
PIE_REGS *pie = (PIE_REGS *)PIE_BASE;
pie->ACK = 0x100;
if( openPort ) openPort->HandleInt();
}
void F28xxCAN::HandleInt( void )
{
int i;
CAN_REGS *regs = (CAN_REGS *)regPtr;
uint32 ints;
while( (ints=CanRegRead(regs->GIF0)) != 0 )
{
if( !(ints & 0x8000) )
CanRegWrite( regs->GIF0, ints );
// Check for a new mailbox interrupt
// (transmit or receive)
else
{
i = ints & 0x1F;
uint32 mask = 1;
mask <<= i;
// Handle receive message
if( i < RECV_MB_CT )
{
// If there's space in my receive queue,
// copy the received message there.
// If not, I'm going to loose it.
F28xx_Mailbox *mb = free;
if( !mb )
{
CanRegWrite( regs->RMP, mask );
continue;
}
free = free->next;
mb->time = CanRegRead( regs->MOTS[i] );
mb->id = CanRegRead( regs->Mailbox[i].id );
mb->ctrl = CanRegRead( regs->Mailbox[i].ctrl );
mb->data[0] = CanRegRead( regs->Mailbox[i].data[0] );
mb->data[1] = CanRegRead( regs->Mailbox[i].data[1] );
recvSem.Put();
if( !tail )
{
head = tail = mb;
mb->prev = mb->next = 0;
}
else if( mb->time - tail->time > 0 )
{
mb->next = 0;
mb->prev = tail;
tail->next = mb;
tail = mb;
}
else if( mb->time - head->time < 0 )
{
mb->next = head;
mb->prev = 0;
head->prev = mb;
head = mb;
}
else
{
F28xx_Mailbox *old = tail;
while( mb->time - old->time < 0 )
old = old->prev;
mb->prev = old;
mb->next = old->next;
old->next = mb;
mb->next->prev = mb;
}
// Release the mailbox
CanRegWrite( regs->RMP, mask );
}
// Handle transmit done
else
{
CanRegWrite( regs->TA, mask );
xmitSem.Put();
// Disable any mailboxes which are now finished
uint32 enable = CanRegRead(regs->ME) & ~mask;
CanRegWrite( regs->ME, enable );
// If there are no transmits pending, then reset the next
// transmit priority to the max value.
if( !CanRegRead(regs->TRS) )
nextXmitPri = 31;
}
}
}
return;
}
/***************************************************************************/
/**
* Read from a CAN register. We can't just read from the registers like
* memory because of Errata in the chip.
*/
/***************************************************************************/
static uint32 CanRegRead( LREG &ptr )
{
// Read the register twice with ints disabled
// Return the first read if non-zero. If the
// first read was zero, return the second.
asm( " push st1" );
asm( " setc intm" );
uint32 x = ptr;
if( !x ) x = ptr;
asm( " pop st1" );
return x;
}
/***************************************************************************/
/**
* Write to a CAN register. We can't just write to the registers like
* memory because of Errata in the chip.
*/
/***************************************************************************/
static void CanRegWrite( LREG &ptr, uint32 data )
{
asm( " push st1" );
asm( " setc intm" );
ptr = data;
ptr = data;
asm( " pop st1" );
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?