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 = &regs->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 + -
显示快捷键?