/****************************************Copyright (c)****************************************************
** Guangzhou ZHIYUAN electronics Co.,LTD.
**
** http://www.embedtools.com
**
**--------------File Info---------------------------------------------------------------------------------
** File Name: can.c
** Last modified Date: 2010.02.25
** Last Version: 1.0
** Description: CAN 寄存器级驱动程序
**--------------------------------------------------------------------------------------------------------
** Created By: 张展威
** Created date: 2010.02.25
** Version: 1.0
** Descriptions: The original version 初始版本
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
#include "LPC11xx.h" /* LPC11xx Peripheral Registers */
#include "type.h"
#include "dataType.h"
#include "can_reg_cfg.h"
#include "can.h"
//*****************************************************************************
//
// This is the maximum number that can be stored as an 11bit Message
// identifier.
//
//*****************************************************************************
#define CAN_MAX_11BIT_MSG_ID (0x7ff)
//*****************************************************************************
//
// This is used as the loop delay for accessing the CAN controller registers.
//
//*****************************************************************************
#define CAN_RW_DELAY (5)
//*****************************************************************************
//
//! \internal
//! Checks a CAN base address.
//!
//! \param ptBase is the base address of the CAN controller.
//!
//! This function determines if a CAN controller base address is valid.
//!
//! \return Returns \b true if the base address is valid and \b false
//! otherwise.
//
//*****************************************************************************
#ifdef DEBUG
tBoolean CANBaseValid(unsigned long ulBaseAddr)
{
return(ptBase == LPC_CAN_BASE);
}
#endif
void ASSERT (long ulData)
{
;
}
int CANBaseValid(unsigned long ulBaseAddr)
{
if (ulBaseAddr == LPC_CAN_BASE) {
return 1;
}
return -1;
}
/*********************************************************************************************************
** Function name: __ENTER_CIRTICAL, __EXIT_CIRTICAL
** Descriptions: 临界区代码保护宏
** input parameters: 返回总中断标志 , 原总中断标志
** Descriptions: 必须成对调用,这对宏之间的操作将关闭总中断,退出临界区后恢复原总中断设置
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
#if defined(__arm__) && defined(__ARMCC_VERSION) /* 对应KEIL/RVMDK */
__asm unsigned char __enterCirtical(void) {
MRS R0,PRIMASK /* 返回原总中断的状态 */
CPSID I /* 关闭总中断 */
BX LR
}
__asm void __intEnable() {
CPSIE I /* 打开总中断 */
BX LR
}
#define __ENTER_CIRTICAL() __enterCirtical() /* 进入临界区关闭总中断 */
#define __EXIT_CIRTICAL(isEnable) if(isEnable == 0) {__intEnable();} /* 根据isEnable检查是否开中断 */
#elif defined (__IAR_SYSTEMS_ICC__) /* 对应IAR集成开发工具 */
__enterCirtical(void)
{
asm("MRS R0,PRIMASK"); /* 返回总中断状态 */
asm("CPSID I"); /* 关闭总中断 */
}
#define __ENTER_CIRTICAL() __enterCirtical() /* 进入临界区关闭总中断 */
#define __EXIT_CIRTICAL(isEnable) if(isEnable == 0) {asm("CPSIE I");} /* 根据isEnable检查是否开中断 */
#else /* 对应GCC开发工具 */
__enterCirtical(void)
{
asm("MRS R0,PRIMASK"); /* 返回总中断状态 */
asm("CPSID I"); /* 关闭总中断 */
}
#define __ENTER_CIRTICAL() __enterCirtical() /* 进入临界区关闭总中断 */
#define __EXIT_CIRTICAL(isEnable) if(isEnable == 0) {asm("CPSIE I");} /* 根据isEnable检查是否开中断 */
#endif
/*********************************************************************************************************
** Function name: __canIntNumberGet
** Descriptions: 获取CAN中断号
** input parameters: ulRegAddress:CAN寄存器地址
** output parameters: 无
** Returned value: >0:CAN中断号 -1:无效的CAN寄存器地址
** Created By: 张展威
** Created date: 2009.10.23
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
** Descriptions:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
IRQn_Type __canIntNumberGet(unsigned long ulBase)
{
IRQn_Type lIntNumber;
switch(ulBase) {
case LPC_CAN_BASE:{
lIntNumber = CAN_IRQn;
break;
}
default:{
lIntNumber = (IRQn_Type)-1; /* 基址错误 */
}
}
return(lIntNumber);
}
/*********************************************************************************************************
** Function name: __canRegWrite
** Descriptions: CAN寄存器读操作
** input parameters: ulRegAddress:CAN寄存器地址
** output parameters: 无
** Returned value: unsigned long:寄存器值
** Created By: 张展威
** Created date: 2009.10.23
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
** Descriptions:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
unsigned long __canRegRead(unsigned long ulRegAddress)
{
volatile int iDelay;
unsigned long ulRetVal;
//unsigned long ulReenableInts;
unsigned char ucEnable;
//unsigned long ulIntNumber;
//ulIntNumber = ____canIntNumberGet(ulRegAddress & 0xfffff000);
//ulReenableInts = HWREG(NVIC_EN1) & (1 << (ulIntNumber - 48));
ucEnable = __ENTER_CIRTICAL(); /* 进入临界区 */
HWREG(ulRegAddress);
for(iDelay = 0; iDelay < 5; iDelay++)
{
}
ulRetVal = HWREG(ulRegAddress);
__EXIT_CIRTICAL(ucEnable); /* 退出临界区 */
return(ulRetVal);
}
/*********************************************************************************************************
** Function name: __canRegWrite
** Descriptions: CAN寄存器写操作
** input parameters: ulRegAddress:CAN寄存器地址
** ulRegValue:需要写的数据
** output parameters: 无
** Returned value: 无
** Created By: 张展威
** Created date: 2009.10.23
**--------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
** Descriptions:
**--------------------------------------------------------------------------------------------------------
*********************************************************************************************************/
void __canRegWrite(unsigned long ulRegAddress, unsigned long ulRegValue)
{
volatile int iDelay;
HWREG(ulRegAddress) = ulRegValue;
for(iDelay = 0; iDelay < 5; iDelay++)
{
}
}
//*****************************************************************************
//
//! \internal
//!
//! Copies data from a buffer to the CAN Data registers.
//!
//! \param pucData is a pointer to the data to be written out to the CAN
//! controller's data registers.
//! \param pulRegister is an unsigned long pointer to the first register of the
//! CAN controller's data registers. For example, in order to use the IF1
//! register set on CAN controller 0, the value would be: \b CAN0_BASE \b +
//! \b CAN_O_IF1DA1.
//! \param iSize is the number of bytes to copy into the CAN controller.
//!
//! This function takes the steps necessary to copy data from a contiguous
//! buffer in memory into the non-contiguous data registers used by the CAN
//! controller. This function is rarely used outside of the CANMessageSet()
//! function.
//!
//! This function replaces the original CANWriteDataReg() API and performs the
//! same actions. A macro is provided in can.h to map the original
//! API to this API.
//!
//! \return None.
//
//*****************************************************************************
void CANDataRegWrite(unsigned char *pucData, unsigned long *pulRegister, int iSize)
{
int iIdx;
unsigned long ulValue;
//
// Loop always copies 1 or 2 bytes per iteration.
//
for(iIdx = 0; iIdx < iSize; )
{
//
// Write out the data 16 bits at a time since this is how the registers
// are aligned in memory.
//
ulValue = pucData[iIdx++];
//
// Only write the second byte if needed otherwise it will be zero.
//
if(iIdx < iSize)
{
ulValue |= (pucData[iIdx++] << 8);
}
canRegWrite((unsigned long)(pulRegister++), ulValue);
}
}
//*****************************************************************************
//
//! \internal
//!
//! Copies data from a buffer to the CAN Data registers.
//!
//! \param pucData is a pointer to the location to store the data read from the
//! CAN controller's data registers.
//! \param pulRegister is an unsigned long pointer to the first register of the
//! CAN controller's data registers. For example, in order to use the IF1
//! register set on CAN controller 1, the value would be: \b CAN0_BASE \b +
//! \b CAN_O_IF1DA1.
//! \param iSize is the number of bytes to copy from the CAN controller.
//!
//! This function takes the steps necessary to copy data to a contiguous buffer
//! in memory from the non-contiguous data registers used by the CAN
//! controller. This function is rarely used outside of the CANMessageGet()
//! function.
//!
//! This function replaces the original CANReadDataReg() API and performs the
//! same actions. A macro is provided in can.h to map the original
//! API to this API.
//!
//! \return None.
//
//*****************************************************************************
void CANDataRegRead(unsigned char *pucData, unsigned long *pulRegister, int iSize)
{
int iIdx;
unsigned long ulValue;
//
// Loop always copies 1 or 2 bytes per iteration.
//
for(iIdx = 0; iIdx < iSize; )
{
//
// Read out the data 16 bits at a time since this is how the registers
// are aligned in memory.
//
ulValue = canRegRead((unsigned long)(pulRegister++));
//
// Store the first byte.
//
pucData[iIdx++] = (unsigned char)ulValue;
//
// Only read the second byte if needed.
//
if(iIdx < iSize)
{
pucData[iIdx++] = (unsigned char)(ulValue >> 8);
}
}
}
//*****************************************************************************
//
//! Initializes the CAN controller after reset.
//!
//! \param ptBase is the base address of the CAN controller.
//!
//! After reset, the CAN controller is left in the disabled state. However,
//! the memory used for message objects contains undefined values and must be
//! cleared prior to enabling the CAN controller the first time. This prevents
//! unwanted transmission or reception of data before the message objects are
//! configured. This function must be called before enabling the controller
//! the first time.
//!
//! \return None.
//
//*****************************************************************************
void CANInit(unsigned long ulBaseAddr)
{
int iMsg;
LPC_CAN_TypeDef *ptBase = (LPC_CAN_TypeDef *)ulBaseAddr;
//
// Check the arguments.
//
ASSERT(CANBaseValid((unsigned long)ptBase));
//
// 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.
//
canRegWrite((unsigned long)&ptBase->CNTL, CAN_CTL_INIT);
//
// Wait for busy bit to clear
//
while(canRegRead((unsigned long)&ptBase->IF1_CMDREQ) & CAN_IF1CRQ_BUSY)
{
}
//
// Clear the message value bit in the arbitration register. This indicates
// the message is not valid and is a "safe" condition to leave the message
// object. The same arb reg is used to program all the message objects.
//
canRegWrite((unsigned long)&ptBase->IF1_CMDMSK, CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_ARB |
CAN_IF1CMSK_CONTROL);
canRegWrite((unsigned long)&ptBase->IF1_ARB2, 0);
canRegWrite((unsigned long)&ptBase->IF1_MCTRL, 0);
//
// Loop through to program all 32 message objects
//
for(iMsg = 1; iMsg <= 32; iMsg++)
{
//
// Wait for busy bit to clear
//
while(canRegRead((unsigned long)&ptBase->IF1_CMDREQ) & CAN_IF1CRQ_BUSY)
{
}
//
// Initiate programming the message object
//
canRegWrite((unsigned long)&ptBase->IF1_CMDREQ, iMsg);
}
//
// Make sure that the interrupt and new data flags are updated for the
// message objects.
//
canRegWrite((unsigned long)&ptBase->IF1_CMDMSK, CAN_IF1CMSK_NEWDAT |
CAN_IF1CMSK_CLRINTPND);
//
// Loop through to program all 32 message objects
//
for(iMsg = 1; iMsg <= 32; iMsg++)
{
//
// Wait for busy bit to clear.
//
while(canRegRead((unsigned long)&ptBase->IF1_CMDREQ) & CAN_IF1CRQ_BUSY)
{
}
//
// Initiate programming the message object
//
canRegWrite((unsigned long)&ptBase->IF1_CMDREQ, iMsg);
}
//
// Acknowledge any pending status interrupts.
//
canRegRead((unsigned long)&ptBase->STAT);
}
//*****************************************************************************
//
//! Enables the CAN controller.
//!
//! \param ptBase is the base address of the CAN controller to enable.
//!
//! Enables the CAN controller for message processing. Once enabled, the
//! controller will automatically transmit any pending frames, and process any
//! received frames. The controller can be stopped by calling CANDisable().
//! Prior to calling CANEnable(), CANInit() should have been called to
//! initialize the controller and the CAN bus clock should be configured by
//! calling CANBitTimingSet().
//!
//! \return None.
//
//*****************************************************************************
void
CANEnable(unsigned long ulBaseAddr)
{
LPC_CAN_TypeDef *ptBase = (LPC_CAN_TypeDef *)ulBaseAddr;
//
// Check the arguments.
//
ASSERT(CANBaseValid((unsigned long)ptBase));
//
// Clear the init bit in the control register.
//
canRegWrite((unsigned long)&ptBase->CNTL,
canRegRead((unsigned long)&ptBase->CNTL) & ~CAN_CTL_INIT);
}
//*****************************************************************************
//
//! Disables the CAN controller.
//!
//! \param ptBase is the base address of the CAN controller to disable.
//!
//! Disables the CAN controller for message processing. When disabled, the
//! controller will no longer automatically process data on the CAN bus. The
//! controller can be restarted by calling CANEnable(). The state of the CAN
//! controller and the message objects in the controller are left as they were
//! before this call was made.
//!
//! \return None.
//
//*****************************************************************************
void
CANDisable(unsigned long ulBaseAddr)
{
LPC_CAN_TypeDef *ptBase = (LPC_CAN_TypeDef *)ulBaseAddr;
//
// Check the arguments.
//
ASSERT(CANBaseValid((unsigned long)ptBase));
//
// Set the init bit in the control register.
//
canRegWrite((unsigned long)&ptBase->CNTL,
canRegRead((unsigned long)&ptBase->CNTL) | CAN_CTL_INIT);
}
//*****************************************************************************
//
//! Reads the current settings for the CAN controller bit timing.
//!
//! \param ptBase is the base address of the CAN controller.
//! \param pClkParms is a pointer to a structure to hold the timing parameters.
//!
//! This function reads the current configuration of the CAN controller bit
//! clock timing, and stores the resulting information in the structure
//! supplied by the caller. Refer to CANBitTimingSet() for the meaning of the
//! values that are returned in the structure pointed to by \e pClkParms.
//!
//! This function replaces the original CANGetBitTiming() API and performs the
//! same actions. A macro is provided in can.h to map the original
//! API to this API.
//!
//! \return None.
//
//*****************************************************************************
void
CANBitTimingGet(unsigned long ulBaseAddr, CAN_BIT_CLK_PARM *pClkParms)
{
unsigned int uBitReg;
LPC_CAN_TypeDef *ptBase = (LPC_CAN_TypeDef *)ulBaseAddr;
//
// Check the arguments.
//
ASSERT(CANBaseValid((unsigned long)ptBase));
ASSERT(pClkParms != 0);
//
// Read out all the bit timing values from the CAN controller registers.
//
uBitReg = canRegRead((unsigned long)&ptBase->BT);
//
// Set the phase 2 segment.
//
pClkParms->uPhase2Seg = ((uBitReg & CAN_BIT_TSEG2_M) >> 12) + 1;
//
// Set the phase 1 segment.
//
pClkParms->uSyncPropPhase1Seg = ((uBitReg & CAN_BIT_TSEG1_M) >> 8) + 1;
//
// Set the sychronous jump width.
//
pClkParms->uSJW = ((uBitReg & CAN_BIT_SJW_M) >> 6) + 1;
//
// Set the pre-divider for the CAN bus bit clock.
//
pClkParms->uQuantumPrescaler =
((uBitReg & CAN_BIT_BRP_M) |
((canRegRead((unsigned long)&ptBase->BRPE) & CAN_BRPE_BRPE_M) << 6)) + 1;
}
//*****************************************************************************
//
//! Configures the CAN controller bit timing.
//!
//! \param ptBase is the base address of the CAN controller.
//! \param pClkParms points to the structure with the clock parameters.
//!
//! Configures the various timing parameters for the CAN bus bit timing:
//! Propagation segment, Phase Buffer 1 segment, Phase Buffer 2 segment, and
//! the Synchronization Jump Width. The values for Propagation and Phase
//! Buffer 1 segments are derived from the combination
//! \e pClkParms->uSyncPropPhase1Seg parameter. Phase Buffer 2 is determined
//! from the \e pClkParms->uPhase2Seg parameter. These two parameters, along
//! with \e pClkParms->uSJW are based in units of bit time quanta. The actual
//! quantum time is determined by the \e pClkParms->uQuantumPrescaler value,
//! which specifies the divisor for the CAN module clock.
//!
//! The total bit time, in quanta, will be the sum of the two Seg parameters,
//! as follows:
//!
//! bit_time_q = uSyncPropPhase1Seg + uPhase2Seg + 1
//!
//! Note that the Sync_Seg is always one quantum in duration, and will be added
//! to derive the correct duration of Prop_Seg and Phase1_Seg.
//!
//! The equation to determine the actual bit rate is as follows:
//!
//! CAN Clock /
//! ((\e uSyncPropPhase1Seg + \e uPhase2Seg + 1) * (\e uQuantumPrescaler))
//!
//! This means that with \e uSyncPropPhase1Seg = 4, \e uPhase2Seg = 1,
//! \e uQuantumPrescaler = 2 and an 8 MHz CAN clock, that the bit rate will be
//! (8 MHz) / ((5 + 2 + 1) * 2) or 500 Kbit/sec.
//!
//! This function replaces the original CANSetBitTiming() API and performs the
//! same actions. A macro is provided in can.h to map the original
//! API to this API.
//!
//! \return None.
//
//*****************************************************************************
void
CANBitTimingSet(unsigned long ulBaseAddr, CAN_BIT_CLK_PARM *pClkParms)
{
unsigned int uBitReg;
unsigned int uSavedInit;
LPC_CAN_TypeDef *ptBase = (LPC_CAN_TypeDef *)ulBaseAddr;
//
// Check the arguments.
//
ASSERT(CANBaseValid((unsigned long)ptBase));
ASSERT(pClkParms != 0);
//
// The phase 1 segment must be in the range from 2 to 16.
//
ASSERT((pClkParms->uSyncPropPhase1Seg >= 2) &&
(pClkParms->uSyncPropPhase1Seg <= 16));
//
// The phase 2 segment must be in the range from 1 to 8.
//
ASSERT((pClkParms->uPhase2Seg >= 1) && (pClkParms->uPhase2Seg <= 8));
//
// The synchronous jump windows must be in the range from 1 to 4.
//
ASSERT((pClkParms->uSJW >= 1) && (pClkParms->uSJW <= 4));
//
// The CAN clock pre-divider must be in the range from 1 to 1024.
//
ASSERT((pClkParms->uQuantumPrescaler <= 1024) &&
(pClkParms->uQuantumPrescaler >= 1));
//
// To set the bit timing register, the controller must be placed in init
// mode (if not already), and also configuration change bit enabled. State
// of the init bit should be saved so it can be restored at the end.
//
uSavedInit = canRegRead((unsigned long)&ptBase->CNTL);
canRegWrite((unsigned long)&ptBase->CNTL, uSavedInit | CAN_CTL_INIT | CAN_CTL_CCE);
//
// Set the bit fields of the bit timing register according to the parms.
//
uBitReg = ((pClkParms->uPhase2Seg - 1) << 12) & CAN_BIT_TSEG2_M;
uBitReg |= ((pClkParms->uSyncPropPhase1Seg - 1) << 8) & CAN_BIT_TSEG1_M;
uBitReg |= ((pClkParms->uSJW - 1) << 6) & CAN_BIT_SJW_M;
uBitReg |= (pClkParms->uQuantumPrescaler - 1) & CAN_BIT_BRP_M;
canRegWrite((unsigned long)&ptBase->BT, uBitReg);
//
// Set the divider upper bits in the extension register.
//
canRegWrite((unsigned long)&ptBase->BRPE,
((pClkParms->uQuantumPrescaler - 1) >> 6) & CAN_BRPE_BRPE_M);
//
// Clear the config change bit, and restore the init bit.
//
uSavedInit &= ~CAN_CTL_CCE;
//
// If Init was not set before, then clear it.
//
if(uSavedInit & CAN_CTL_INIT)
{
uSavedInit &= ~CAN_CTL_INIT;
}
canRegWrite((unsigned long)&ptBase->CNTL, uSavedInit);
}
//*****************************************************************************
//
//! Registers an interrupt handler for the CAN controller.
//!
//! \param ptBase is the base address of the CAN controller.
//! \param pfnHandler is a pointer to the function to be called when the
//! enabled CAN interrupts occur.
//!
//! This function registers the interrupt handler in the interrupt vector
//! table, and enables CAN interrupts on the interrupt controller; specific CAN
//! interrupt sources must be enabled using CANIntEnable(). The interrupt
//! handler being registered must clear the source of the interrupt using
//! CANIntClear().
//!
//! If the application is using a static interrupt vector table stored in
//! flash, then it is not necessary to register the interrupt handler this way.
//! Instead, IntEnable() should be used to enable CAN interrupts on the
//! interrupt controller.
//!
//! \sa IntRegister() for important information about registering interrupt
//! handlers.
//!
//! \return None.
//
//*****************************************************************************
//中断注册函数
void IntRegister(unsigned long ulSn, void (*pfnHandler)(void))
{
;
}
void CANIntRegister(unsigned long ulBaseAddr, void (*pfnHandler)(void))
{
unsigned long ulIntNumber;
//
// Check the arguments.
//
ASSERT(CANBaseValid(ulBaseAddr));
//
// Get the actual interrupt number for this CAN controller.
//
ulIntNumber = __canIntNumberGet(ulBaseAddr);
//
// Register the interrupt handler.
//
IntRegister(ulIntNumber, pfnHandler);
//
// Enable the Ethernet interrupt.
//
IntEnable(ulIntNumber);
}
//*****************************************************************************
//
//! Enables individual CAN controller interrupt sources.
//!
//! \param ptBase is the base address of the CAN controller.
//! \param ulIntFlags is the bit mask of the interrupt sources to be enabled.
//!
//! Enables specific interrupt sources of the CAN controller. Only enabled
//! sources will cause a processor interrupt.
//!
//! The \e ulIntFlags parameter is the logical OR of any of the following:
//!
//! - \b CAN_INT_ERROR - a controller error condition has occurred
//! - \b CAN_INT_STATUS - a message transfer has completed, or a bus error has
//! been detected
//! - \b CAN_INT_MASTER - allow CAN controller to generate interrupts
//!
//! In order to generate any interrupts, \b CAN_INT_MASTER must be enabled.
//! Further, for any particular transaction from a message object to generate
//! an interrupt, that message object must have interrupts enabled (see
//! CANMessageSet()). \b CAN_INT_ERROR will generate an interrupt if the
//! controller enters the ``bus off'' condition, or if the error counters reach
//! a limit. \b CAN_INT_STATUS will generate an interrupt under quite a few
//! status conditions and may provide more interrupts than the application
//! needs to handle. When an interrupt occurs, use CANIntStatus() to determine
//! the cause.
//!
//! \return None.
//
//*****************************************************************************
void CANIntEnable(unsigned long ulBaseAddr, unsigned long ulIntFlags)
{
LPC_CAN_TypeDef *ptBase = (LPC_CAN_TypeDef *)ulBaseAddr;
//
// Check the arguments.
//
ASSERT(CANBaseValid((unsigned long)ptBase));
ASSERT((ulIntFlags & ~(CAN_CTL_EIE | CAN_CTL_SIE | CAN_CTL_IE)) == 0);
//
// Enable the specified interrupts.
//
canRegWrite((unsigned long)&ptBase->CNTL,
canRegRead((unsigned long)&ptBase->CNTL) | ulIntFlags);
}
//*****************************************************************************
//
//! Disables individual CAN controller interrupt sources.
//!
//! \param ptBase is the base address of the CAN controller.
//! \param ulIntFlags is the bit mask of the interrupt sources to be disabled.
//!
//! Disables the specified CAN controller interrupt sources. Only enabled
//! interrupt sources can cause a processor interrupt.
//!
//! The \e ulIntFlags parameter has the same definition as in the
//! CANIntEnable() function.
//!
//! \return None.
//
//*****************************************************************************
void CANIntDisable(unsigned long ulBaseAddr, unsigned long ulIntFlags)
{
LPC_CAN_TypeDef *ptBase = (LPC_CAN_TypeDef *)ulBaseAddr;
//
// Check the arguments.
//
ASSERT(CANBaseValid((unsigned long)ptBase));
ASSERT((ulIntFlags & ~(CAN_CTL_EIE | CAN_CTL_SIE | CAN_CTL_IE)) == 0);
//
// Disable the specified interrupts.
//
canRegWrite((unsigned long)&ptBase->CNTL,
canRegRead((unsigned long)&ptBase->CNTL) & ~(ulIntFlags));
}
//*****************************************************************************
//
//! Returns the current CAN controller interrupt status.
//!
//! \param ptBase is the base address of the CAN controller.
//! \param eIntStsReg indicates which interrupt status register to read
//!
//! Returns the value of one of two interrupt status registers. The interrupt
//! status register read is determined by the \e eIntStsReg parameter, which
//! can have one of the following values:
//!
//! - \b CAN_INT_STS_CAUSE - indicates the cause of the interrupt
//! - \b CAN_INT_STS_OBJECT - indicates pending interrupts of all message
//! objects
//!
//! \b CAN_INT_STS_CAUSE returns the value of the controller interrupt register
//! and indicates the cause of the interrupt. It will be a value of
//! \b CAN_INT_INTID_STATUS if the cause is a status interrupt. In this case,
//! the status register should be read with the CANStatusGet() function.
//! Calling this function to read the status will also clear the status
//! interrupt. If the value of the interrupt register is in the range 1-32,
//! then this indicates the number of the highest priority message object that
//! has an interrupt pending. The message object interrupt can be cleared by
//! using the CANIntClear() function, or by reading the message using
//! CANMessageGet() in the case of a received message. The interrupt handler
//! can read the interrupt status again to make sure all pending interrupts are
//! cleared before returning from the interrupt.
//!
//! \b CAN_INT_STS_OBJECT returns a bit mask indicating which message objects
//! have pending interrupts. This can be used to discover all of the pending
//! interrupts at once, as opposed to repeatedly reading the interrupt register
//! by using \b CAN_INT_STS_CAUSE.
//!
//! \return Returns the value of one of the interrupt status registers.
//
//*****************************************************************************
unsigned long CANIntStatus(unsigned long ulBaseAddr, CAN_INT_STS_REG eIntStsReg)
{
unsigned long ulStatus;
LPC_CAN_TypeDef *ptBase = (LPC_CAN_TypeDef *)ulBaseAddr;
//
// Check the arguments.
//
ASSERT(CANBaseValid((unsigned long)ptBase));
//
// See which status the caller is looking for.
//
switch(eIntStsReg)
{
//
// The caller wants the global interrupt status for the CAN controller
// specified by ptBase.
//
case CAN_INT_STS_CAUSE:
{
ulStatus = canRegRead((unsigned long)&ptBase->INT);
break;
}
//
// The caller wants the current message status interrupt for all
// messages.
//
case CAN_INT_STS_OBJECT:
{
//
// Read and combine both 16 bit values into one 32bit status.
//
ulStatus = (canRegRead((unsigned long)&ptBase->IR1) &
CAN_MSG1INT_INTPND_M);
ulStatus |= (canRegRead((unsigned long)&ptBase->IR2) << 16);
break;
}
//
// Request was for unknown status so just return 0.
//
default:
{
ulStatus = 0;
break;
}
}
//
// Return the interrupt status value
//
return(ulStatus);
}
//*****************************************************************************
//
//! Clears a CAN interrupt source.
//!
//! \param ptBase is the base address of the CAN controller.
//! \param ulIntClr is a value indicating which interrupt source to clear.
//!
//! This function can be used to clear a specific interrupt source. The
//! \e ulIntClr parameter should be one of the following values:
//!
//! - \b CAN_INT_INTID_STATUS - Clears a status interrupt.
//! - 1-32 - Clears the specified message object interrupt
//!
//! It is not necessary to use this function to clear an interrupt. This
//! should only be used if the application wants to clear an interrupt source
//! without taking the normal interrupt action.
//!
//! Normally, the status interrupt is cleared by reading the controller status
//! using CANStatusGet(). A specific message object interrupt is normally
//! cleared by reading the message object using CANMessageGet().
//!
//! \note Since there is a write buffer in the Cortex-M3 processor, it may take
//! several clock cycles before the interrupt source is actually cleared.
//! Therefore, it is recommended that the interrupt source be cleared early in
//! the interrupt handler (as opposed to the very last action) to avoid
//! returning from the interrupt handler before the interrupt source is
//! actually cleared. Failure to do so may result in the interrupt handler
//! being immediately reentered (since NVIC still sees the interrupt source
//! asserted).
//!
//! \return None.
//
//*****************************************************************************
void CANIntClear(unsigned long ulBaseAddr, unsigned long ulIntClr)
{
LPC_CAN_TypeDef *ptBase = (LPC_CAN_TypeDef *)ulBaseAddr;
//
// Check the arguments.
//
ASSERT(CANBaseValid((unsigned long)ptBase));
ASSERT((ulIntClr == CAN_INT_INTID_STATUS) ||
((ulIntClr>=1) && (ulIntClr <=32)));
if(ulIntClr == CAN_INT_INTID_STATUS)
{
//
// Simply read and discard the status to clear the interrupt.
//
canRegRead((unsigned long)&ptBase->STAT);
}
else
{
//
// Wait to be sure that this interface is not busy.
//
while(canRegRead((unsigned long)&ptBase->IF1_CMDREQ) & CAN_IF1CRQ_BUSY)
{
}
//
// Only change the interrupt pending state by setting only the
// CAN_IF1CMSK_CLRINTPND bit.
//
canRegWrite((unsigned long)&ptBase->IF1_CMDMSK, CAN_IF1CMSK_CLRINTPND);
//
// Send the clear pending interrupt command to the CAN controller.
//
canRegWrite((unsigned long)&ptBase->IF1_CMDREQ, ulIntClr & CAN_IF1CRQ_MNUM_M);
//
// Wait to be sure that this interface is not busy.
//
while(canRegRead((unsigned long)&ptBase->IF1_CMDREQ) & CAN_IF1CRQ_BUSY)
{
}
}
}
//*****************************************************************************
//
//! Sets the CAN controller automatic retransmission behavior.
//!
//! \param ptBase is the base address of the CAN controller.
//! \param bAutoRetry enables automatic retransmission.
//!
//! Enables or disables automatic retransmission of messages with detected
//! errors. If \e bAutoRetry is \b true, then automatic retransmission is
//! enabled, otherwise it is disabled.
//!
//! \return None.
//
//*****************************************************************************
void CANRetrySet(unsigned long ulBaseAddr, tBoolean bAutoRetry)
{
unsigned long ulCtlReg;
LPC_CAN_TypeDef *ptBase = (LPC_CAN_TypeDef *)ulBaseAddr;
//
// Check the arguments.
//
ASSERT(CANBaseValid((unsigned long)ptBase));
ulCtlReg = canRegRead((unsigned long)&ptBase->CNTL);
//
// Conditionally set the DAR bit to enable/disable auto-retry.
//
if(bAutoRetry)
{
//
// Clearing the DAR bit tells the controller to not disable the
// auto-retry of messages which were not transmited or received
// correctly.
//
ulCtlReg &= ~CAN_CTL_DAR;
}
else
{
//
// Setting the DAR bit tells the controller to disable the auto-retry
// of messages which were not transmited or received correctly.
//
ulCtlReg |= CAN_CTL_DAR;
}
canRegWrite((unsigned long)&ptBase->CNTL, ulCtlReg);
}
//*****************************************************************************
//
//! Returns the current setting for automatic retransmission.
//!
//! \param ptBase is the base address of the CAN controller.
//!
//! Reads the current setting for the automatic retransmission in the CAN
//! controller and returns it to the caller.
//!
//! \return Returns \b true if automatic retransmission is enabled, \b false
//! otherwise.
//
//*****************************************************************************
tBoolean CANRetryGet(unsigned long ulBaseAddr)
{
LPC_CAN_TypeDef *ptBase = (LPC_CAN_TypeDef *)ulBaseAddr;
//
// Check the arguments.
//
ASSERT(CANBaseValid((unsigned long)ptBase));
//
// Read the disable automatic retry setting from the CAN controller.
//
if(canRegRead((unsigned long)&ptBase->CNTL) & CAN_CTL_DAR)
{
//
// Automatic data retransmission is not enabled.
//
return(false);
}
//
// Automatic data retransmission is enabled.
//
return(true);
}
//*****************************************************************************
//
//! Reads one of the controller status registers.
//!
//! \param ptBase is the base address of the CAN controller.
//! \param eStatusReg is the status register to read.
//!
//! Reads a status register of the CAN controller and returns it to the caller.
//! The different status registers are:
//!
//! - \b CAN_STS_CONTROL - the main controller status
//! - \b CAN_STS_TXREQUEST - bit mask of objects pending transmission
//! - \b CAN_STS_NEWDAT - bit mask of objects with new data
//! - \b CAN_STS_MSGVAL - bit mask of objects with valid configuration
//!
//! When reading the main controller status register, a pending status
//! interrupt will be cleared. This should be used in the interrupt handler
//! for the CAN controller if the cause is a status interrupt. The controller
//! status register fields are as follows:
//!
//! - \b CAN_STATUS_BUS_OFF - controller is in bus-off condition
//! - \b CAN_STATUS_EWARN - an error counter has reached a limit of at least 96
//! - \b CAN_STATUS_EPASS - CAN controller is in the error passive state
//! - \b CAN_STATUS_RXOK - a message was received successfully (independent of
//! any message filtering).
//! - \b CAN_STATUS_TXOK - a message was successfully transmitted
//! - \b CAN_STATUS_LEC_MSK - mask of last error code bits (3 bits)
//! - \b CAN_STATUS_LEC_NONE - no error
//! - \b CAN_STATUS_LEC_STUFF - stuffing error detected
//! - \b CAN_STATUS_LEC_FORM - a format error occurred in the fixed format part
//! of a message
//! - \b CAN_STATUS_LEC_ACK - a transmitted message was not acknowledged
//! - \b CAN_STATUS_LEC_BIT1 - dominant level detected when trying to send in
//! recessive mode
//! - \b CAN_STATUS_LEC_BIT0 - recessive level detected when trying to send in
//! dominant mode
//! - \b CAN_STATUS_LEC_CRC - CRC error in received message
//!
//! The remaining status registers are 32-bit bit maps to the message objects.
//! They can be used to quickly obtain information about the status of all the
//! message objects without needing to query each one. They contain the
//! following information:
//!
//! - \b CAN_STS_TXREQUEST - if a message object's TxRequest bit is set, that
//! means that a transmission is pending on that object. The application can
//! use this to determine which objects are still waiting to send a message.
//! - \b CAN_STS_NEWDAT - if a message object's NewDat bit is set, that means
//! that a new message has been received in that object, and has not yet been
//! picked up by the host application
//! - \b CAN_STS_MSGVAL - if a message object's MsgVal bit is set, that means
//! it has a valid configuration programmed. The host application can use this
//! to determine which message objects are empty/unused.
//!
//! \return Returns the value of the status register.
//
//*****************************************************************************
unsigned long CANStatusGet(unsigned long ulBaseAddr, CAN_STS_REG eStatusReg)
{
unsigned long ulStatus;
LPC_CAN_TypeDef *ptBase = (LPC_CAN_TypeDef *)ulBaseAddr;
//
// Check the arguments.
//
ASSERT(CANBaseValid((unsigned long)ptBase));
switch(eStatusReg)
{
//
// Just return the global CAN status register since that is what was
// requested.
//
case CAN_STS_CONTROL:
{
ulStatus = canRegRead((unsigned long)&ptBase->STAT);
canRegWrite((unsigned long)&ptBase->STAT,
~(CAN_STS_RXOK | CAN_STS_TXOK | CAN_STS_LEC_M));
break;
}
//
// Combine the Transmit status bits into one 32bit value.
//
case CAN_STS_TXREQUEST:
{
ulStatus = canRegRead((unsigned long)&ptBase->TXREQ1);
ulStatus |= canRegRead((unsigned long)&ptBase->TXREQ2) << 16;
break;
}
//
// Combine the New Data status bits into one 32bit value.
//
case CAN_STS_NEWDAT:
{
ulStatus = canRegRead((unsigned long)&ptBase->ND1);
ulStatus |= canRegRead((unsigned long)&ptBase->ND2) << 16;
break;
}
//
// Combine the Message valid status bits into one 32bit value.
//
case CAN_STS_MSGVAL:
{
ulStatus = canRegRead((unsigned long)&ptBase->MSGV1);
ulStatus |= canRegRead((unsigned long)&ptBase->MSGV2) << 16;
break;
}
//
// Unknown CAN status requested so return 0.
//
default:
{
ulStatus = 0;
break;
}
}
return(ulStatus);
}
//*****************************************************************************
//
//! Reads the CAN controller error counter register.
//!
//! \param ptBase is the base address of the CAN controller.
//! \param pulRxCount is a pointer to storage for the receive error counter.
//! \param pulTxCount is a pointer to storage for the transmit error counter.
//!
//! Reads the error counter register and returns the transmit and receive error
//! counts to the caller along with a flag indicating if the controller receive
//! counter has reached the error passive limit. The values of the receive and
//! transmit error counters are returned through the pointers provided as
//! parameters.
//!
//! After this call, \e *pulRxCount will hold the current receive error count
//! and \e *pulTxCount will hold the current transmit error count.
//!
//! \return Returns \b true if the receive error count has reached the error
//! passive limit, and \b false if the error count is below the error passive
//! limit.
//
//*****************************************************************************
tBoolean CANErrCntrGet(unsigned long ulBaseAddr, unsigned long *pulRxCount,
unsigned long *pulTxCount)
{
unsigned long ulCANError;
LPC_CAN_TypeDef *ptBase = (LPC_CAN_TypeDef *)ulBaseAddr;
//
// Check the arguments.
//
ASSERT(CANBaseValid((unsigned long)ptBase));
//
// Read the current count of transmit/receive errors.
//
ulCANError = canRegRead((unsigned long)&ptBase->EC);
//
// Extract the error numbers from the register value.
//
*pulRxCount = (ulCANError & CAN_ERR_REC_M) >> CAN_ERR_REC_S;
*pulTxCount = (ulCANError & CAN_ERR_TEC_M) >> CAN_ERR_TEC_S;
if(ulCANError & CAN_ERR_RP)
{
return(true);
}
return(false);
}
//*****************************************************************************
//
//! Configures a message object in the CAN controller.
//!
//! \param ptBase is the base address of the CAN controller.
//! \param ulObjID is the object number to configure (1-32).
//! \param ptMsgObj is a pointer to a structure containing message object
//! settings.
//! \param eMsgType indicates the type of message for this object.
//!
//! This function is used to configure any one of the 32 message objects in the
//! CAN controller. A message object can be configured as any type of CAN
//! message object as well as several options for automatic transmission and
//! reception. This call also allows the message object to be configured to
//! generate interrupts on completion of message receipt or transmission. The
//! message object can also be configured with a filter/mask so that actions
//! are only taken when a message that meets certain parameters is seen on the
//! CAN bus.
//!
//! The \e eMsgType parameter must be one of the following values:
//!
//! - \b MSG_OBJ_TYPE_TX - CAN transmit message object.
//! - \b MSG_OBJ_TYPE_TX_REMOTE - CAN transmit remote request message object.
//! - \b MSG_OBJ_TYPE_RX - CAN receive message object.
//! - \b MSG_OBJ_TYPE_RX_REMOTE - CAN receive remote request message object.
//! - \b MSG_OBJ_TYPE_RXTX_REMOTE - CAN remote frame receive remote, then
//! transmit message object.
//!
//! The message object pointed to by \e ptMsgObj must be populated by the
//! caller, as follows:
//!
//! - \e ulMsgID - contains the message ID, either 11 or 29 bits.
//! - \e ulMsgIDMask - mask of bits from \e ulMsgID that must match if
//! identifier filtering is enabled.
//! - \e ulFlags
//! - Set \b MSG_OBJ_TX_INT_ENABLE flag to enable interrupt on transmission.
//! - Set \b MSG_OBJ_RX_INT_ENABLE flag to enable interrupt on receipt.
//! - Set \b MSG_OBJ_USE_ID_FILTER flag to enable filtering based on the
//! identifier mask specified by \e ulMsgIDMask.
//! - \e ulMsgLen - the number of bytes in the message data. This should be
//! non-zero even for a remote frame; it should match the expected bytes of the
//! data responding data frame.
//! - \e pucMsgData - points to a buffer containing up to 8 bytes of data for a
//! data frame.
//!
//! \b Example: To send a data frame or remote frame(in response to a remote
//! request), take the following steps:
//!
//! -# Set \e eMsgType to \b MSG_OBJ_TYPE_TX.
//! -# Set \e ptMsgObj->ulMsgID to the message ID.
//! -# Set \e ptMsgObj->ulFlags. Make sure to set \b MSG_OBJ_TX_INT_ENABLE to
//! allow an interrupt to be generated when the message is sent.
//! -# Set \e ptMsgObj->ulMsgLen to the number of bytes in the data frame.
//! -# Set \e ptMsgObj->pucMsgData to point to an array containing the bytes
//! to send in the message.
//! -# Call this function with \e ulObjID set to one of the 32 object buffers.
//!
//! \b Example: To receive a specific data frame, take the following steps:
//!
//! -# Set \e eMsgObjType to \b MSG_OBJ_TYPE_RX.
//! -# Set \e ptMsgObj->ulMsgID to the full message ID, or a partial mask to
//! use partial ID matching.
//! -# Set \e ptMsgObj->ulMsgIDMask bits that should be used for masking
//! during comparison.
//! -# Set \e ptMsgObj->ulFlags as follows:
//! - Set \b MSG_OBJ_TX_INT_ENABLE flag to be interrupted when the data frame
//! is received.
//! - Set \b MSG_OBJ_USE_ID_FILTER flag to enable identifier based filtering.
//! -# Set \e ptMsgObj->ulMsgLen to the number of bytes in the expected data
//! frame.
//! -# The buffer pointed to by \e ptMsgObj->pucMsgData and
//! \e ptMsgObj->ulMsgLen are not used by this call as no data is present at
//! the time of the call.
//! -# Call this function with \e ulObjID set to one of the 32 object buffers.
//!
//! If you specify a message object buffer that already contains a message
//! definition, it will be overwritten.
//!
//! \return None.
//
//*****************************************************************************
void CANMessageSet(unsigned long ulBaseAddr, unsigned long ulObjID,
CAN_MSG_OBJ *ptMsgObj, MSG_OBJ_TYPE eMsgType)
{
unsigned short usCmdMaskReg;
unsigned short usMaskReg[2];
unsigned short usArbReg[2];
unsigned short usMsgCtrl;
tBoolean bTransferData;
tBoolean bUseExtendedID;
LPC_CAN_TypeDef *ptBase = (LPC_CAN_TypeDef *)ulBaseAddr;
bTransferData = 0;
//
// Check the arguments.
//
ASSERT(CANBaseValid((unsigned long)ptBase));
ASSERT((ulObjID <= 32) && (ulObjID != 0));
ASSERT((eMsgType == MSG_OBJ_TYPE_TX) ||
(eMsgType == MSG_OBJ_TYPE_TX_REMOTE) ||
(eMsgType == MSG_OBJ_TYPE_RX) ||
(eMsgType == MSG_OBJ_TYPE_RX_REMOTE) ||
(eMsgType == MSG_OBJ_TYPE_TX_REMOTE) ||
(eMsgType == MSG_OBJ_TYPE_RXTX_REMOTE));
//
// Wait for busy bit to clear
//
while(canRegRead((unsigned long)&ptBase->IF1_CMDREQ) & CAN_IF1CRQ_BUSY)
{
}
//
// See if we need to use an extended identifier or not.
//
if((ptMsgObj->ulMsgID > CAN_MAX_11BIT_MSG_ID) ||
(ptMsgObj->ulFlags & MSG_OBJ_EXTENDED_ID))
{
bUseExtendedID = 1;
}
else
{
bUseExtendedID = 0;
}
//
// This is always a write to the Message object as this call is setting a
// message object. This call will also always set all size bits so it sets
// both data bits. The call will use the CONTROL register to set control
// bits so this bit needs to be set as well.
//
usCmdMaskReg = (CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_DATAA | CAN_IF1CMSK_DATAB |
CAN_IF1CMSK_CONTROL);
//
// Initialize the values to a known state before filling them in based on
// the type of message object that is being configured.
//
usArbReg[0] = 0;
usMsgCtrl = 0;
usMaskReg[0] = 0;
usMaskReg[1] = 0;
switch(eMsgType)
{
//
// Transmit message object.
//
case MSG_OBJ_TYPE_TX:
{
//
// Set the TXRQST bit and the reset the rest of the register.
//
usMsgCtrl |= CAN_IF1MCTL_TXRQST;
usArbReg[1] = CAN_IF1ARB2_DIR;
bTransferData = 1;
break;
}
//
// Transmit remote request message object
//
case MSG_OBJ_TYPE_TX_REMOTE:
{
//
// Set the TXRQST bit and the reset the rest of the register.
//
usMsgCtrl |= CAN_IF1MCTL_TXRQST;
usArbReg[1] = 0;
break;
}
//
// Receive message object.
//
case MSG_OBJ_TYPE_RX:
{
//
// This clears the DIR bit along with everthing else. The TXRQST
// bit was cleard by defaulting usMsgCtrl to 0.
//
usArbReg[1] = 0;
break;
}
//
// Receive remote request message object.
//
case MSG_OBJ_TYPE_RX_REMOTE:
{
//
// The DIR bit is set to one for remote receivers. The TXRQST bit
// was cleard by defaulting usMsgCtrl to 0.
//
usArbReg[1] = CAN_IF1ARB2_DIR;
//
// Set this object so that it only indicates that a remote frame
// was received and allow for software to handle it by sending back
// a data frame.
//
usMsgCtrl = CAN_IF1MCTL_UMASK;
//
// Use the full Identifier by default.
//
usMaskReg[0] = 0xffff;
usMaskReg[1] = 0x1fff;
//
// Make sure to send the mask to the message object.
//
usCmdMaskReg |= CAN_IF1CMSK_MASK;
break;
}
//
// Remote frame receive remote, with auto-transmit message object.
//
case MSG_OBJ_TYPE_RXTX_REMOTE:
{
//
// Oddly the DIR bit is set to one for remote receivers.
//
usArbReg[1] = CAN_IF1ARB2_DIR;
//
// Set this object to auto answer if a matching identifier is seen.
//
usMsgCtrl = CAN_IF1MCTL_RMTEN | CAN_IF1MCTL_UMASK;
//
// The data to be returned needs to be filled in.
//
bTransferData = 1;
break;
}
//
// This case should never happen due to the ASSERT statement at the
// beginning of this function.
//
default:
{
return;
}
}
//
// Configure the Mask Registers.
//
if(ptMsgObj->ulFlags & MSG_OBJ_USE_ID_FILTER)
{
if(bUseExtendedID)
{
//
// Set the 29 bits of Identifier mask that were requested.
//
usMaskReg[0] = ptMsgObj->ulMsgIDMask & CAN_IF1MSK1_IDMSK_M;
usMaskReg[1] = ((ptMsgObj->ulMsgIDMask >> 16) &
CAN_IF1MSK2_IDMSK_M);
}
else
{
//
// Lower 16 bit are unused so set them to zero.
//
usMaskReg[0] = 0;
//
// Put the 11 bit Mask Identifier into the upper bits of the field
// in the register.
//
usMaskReg[1] = ((ptMsgObj->ulMsgIDMask << 2) &
CAN_IF1MSK2_IDMSK_M);
}
}
//
// If the caller wants to filter on the extended ID bit then set it.
//
if((ptMsgObj->ulFlags & MSG_OBJ_USE_EXT_FILTER) ==
MSG_OBJ_USE_EXT_FILTER)
{
usMaskReg[1] |= CAN_IF1MSK2_MXTD;
}
//
// The caller wants to filter on the message direction field.
//
if((ptMsgObj->ulFlags & MSG_OBJ_USE_DIR_FILTER) ==
MSG_OBJ_USE_DIR_FILTER)
{
usMaskReg[1] |= CAN_IF1MSK2_MDIR;
}
if(ptMsgObj->ulFlags & (MSG_OBJ_USE_ID_FILTER | MSG_OBJ_USE_DIR_FILTER |
MSG_OBJ_USE_EXT_FILTER))
{
//
// Set the UMASK bit to enable using the mask register.
//
usMsgCtrl |= CAN_IF1MCTL_UMASK;
//
// Set the MASK bit so that this gets trasferred to the Message Object.
//
usCmdMaskReg |= CAN_IF1CMSK_MASK;
}
//
// Set the Arb bit so that this gets transferred to the Message object.
//
usCmdMaskReg |= CAN_IF1CMSK_ARB;
//
// Configure the Arbitration registers.
//
if(bUseExtendedID)
{
//
// Set the 29 bit version of the Identifier for this message object.
//
usArbReg[0] |= ptMsgObj->ulMsgID & CAN_IF1ARB1_ID_M;
usArbReg[1] |= (ptMsgObj->ulMsgID >> 16) & CAN_IF1ARB2_ID_M;
//
// Mark the message as valid and set the extended ID bit.
//
usArbReg[1] |= CAN_IF1ARB2_MSGVAL | CAN_IF1ARB2_XTD;
}
else
{
//
// Set the 11 bit version of the Identifier for this message object.
// The lower 18 bits are set to zero.
//
usArbReg[1] |= (ptMsgObj->ulMsgID << 2) & CAN_IF1ARB2_ID_M;
//
// Mark the message as valid.
//
usArbReg[1] |= CAN_IF1ARB2_MSGVAL;
}
//
// Set the data length since this is set for all transfers. This is also a
// single transfer and not a FIFO transfer so set EOB bit.
//
usMsgCtrl |= (ptMsgObj->ulMsgLen & CAN_IF1MCTL_DLC_M) | CAN_IF1MCTL_EOB;
//
// Enable transmit interrupts if they should be enabled.
//
if(ptMsgObj->ulFlags & MSG_OBJ_TX_INT_ENABLE)
{
usMsgCtrl |= CAN_IF1MCTL_TXIE;
}
//
// Enable receive interrupts if they should be enabled.
//
if(ptMsgObj->ulFlags & MSG_OBJ_RX_INT_ENABLE)
{
usMsgCtrl |= CAN_IF1MCTL_RXIE;
}
//
// Write the data out to the CAN Data registers if needed.
//
if(bTransferData)
{
CANDataRegWrite(ptMsgObj->pucMsgData,
(unsigned long *)(&ptBase->IF1_DA1),
ptMsgObj->ulMsgLen);
}
//
// Write out the registers to program the message object.
//
canRegWrite((unsigned long)&ptBase->IF1_CMDMSK, usCmdMaskReg);
canRegWrite((unsigned long)&ptBase->IF1_MSK1, usMaskReg[0]);
canRegWrite((unsigned long)&ptBase->IF1_MSK2, usMaskReg[1]);
canRegWrite((unsigned long)&ptBase->IF1_ARB1, usArbReg[0]);
canRegWrite((unsigned long)&ptBase->IF1_ARB2, usArbReg[1]);
canRegWrite((unsigned long)&ptBase->IF1_MCTRL, usMsgCtrl);
//
// Transfer the message object to the message object specifiec by ulObjID.
//
canRegWrite((unsigned long)&ptBase->IF1_CMDREQ, ulObjID & CAN_IF1CRQ_MNUM_M);
return;
}
//*****************************************************************************
//
//! Reads a CAN message from one of the message object buffers.
//!
//! \param ptBase is the base address of the CAN controller.
//! \param ulObjID is the object number to read (1-32).
//! \param ptMsgObj points to a structure containing message object fields.
//! \param bClrPendingInt indicates whether an associated interrupt should be
//! cleared.
//!
//! This function is used to read the contents of one of the 32 message objects
//! in the CAN controller, and return it to the caller. The data returned is
//! stored in the fields of the caller-supplied structure pointed to by
//! \e ptMsgObj. The data consists of all of the parts of a CAN message,
//! plus some control and status information.
//!
//! Normally this is used to read a message object that has received and stored
//! a CAN message with a certain identifier. However, this could also be used
//! to read the contents of a message object in order to load the fields of the
//! structure in case only part of the structure needs to be changed from a
//! previous setting.
//!
//! When using CANMessageGet, all of the same fields of the structure are
//! populated in the same way as when the CANMessageSet() function is used,
//! with the following exceptions:
//!
//! \e ptMsgObj->ulFlags:
//!
//! - \b MSG_OBJ_NEW_DATA indicates if this is new data since the last time it
//! was read
//! - \b MSG_OBJ_DATA_LOST indicates that at least one message was received on
//! this message object, and not read by the host before being overwritten.
//!
//! \return None.
//
//*****************************************************************************
void CANMessageGet(unsigned long ulBaseAddr, unsigned long ulObjID,
CAN_MSG_OBJ *ptMsgObj, tBoolean bClrPendingInt)
{
unsigned short usCmdMaskReg;
unsigned short usMaskReg[2];
unsigned short usArbReg[2];
unsigned short usMsgCtrl;
LPC_CAN_TypeDef *ptBase = (LPC_CAN_TypeDef *)ulBaseAddr;
//
// Check the arguments.
//
ASSERT(CANBaseValid((unsigned long)ptBase));
ASSERT((ulObjID <= 32) && (ulObjID != 0));
//
// This is always a read to the Message object as this call is setting a
// message object.
//
usCmdMaskReg = (CAN_IF1CMSK_DATAA | CAN_IF1CMSK_DATAB |
CAN_IF1CMSK_CONTROL | CAN_IF1CMSK_MASK | CAN_IF1CMSK_ARB);
//
// Clear a pending interrupt and new data in a message object.
//
if(bClrPendingInt)
{
usCmdMaskReg |= CAN_IF1CMSK_CLRINTPND;
}
//
// Set up the request for data from the message object.
//
canRegWrite((unsigned long)&ptBase->IF2_CMDMSK, usCmdMaskReg);
//
// Transfer the message object to the message object specifiec by ulObjID.
//
canRegWrite((unsigned long)&ptBase->IF2_CMDREQ, ulObjID & CAN_IF1CRQ_MNUM_M);
//
// Wait for busy bit to clear
//
while(canRegRead((unsigned long)&ptBase->IF2_CMDREQ) & CAN_IF1CRQ_BUSY)
{
}
//
// Read out the IF Registers.
//
usMaskReg[0] = canRegRead((unsigned long)&ptBase->IF2_MSK1);
usMaskReg[1] = canRegRead((unsigned long)&ptBase->IF2_MSK2);
usArbReg[0] = canRegRead((unsigned long)&ptBase->IF2_ARB1);
usArbReg[1] = canRegRead((unsigned long)&ptBase->IF2_ARB2);
usMsgCtrl = canRegRead((unsigned long)&ptBase->IF2_MCTRL);
ptMsgObj->ulFlags = MSG_OBJ_NO_FLAGS;
//
// Determine if this is a remote frame by checking the TXRQST and DIR bits.
//
if((!(usMsgCtrl & CAN_IF1MCTL_TXRQST) &&
(usArbReg[1] & CAN_IF1ARB2_DIR)) ||
((usMsgCtrl & CAN_IF1MCTL_TXRQST) &&
(!(usArbReg[1] & CAN_IF1ARB2_DIR))))
{
ptMsgObj->ulFlags |= MSG_OBJ_REMOTE_FRAME;
}
//
// Get the identifier out of the register, the format depends on size of
// the mask.
//
if(usArbReg[1] & CAN_IF1ARB2_XTD)
{
//
// Set the 29 bit version of the Identifier for this message object.
//
ptMsgObj->ulMsgID = ((usArbReg[1] & CAN_IF1ARB2_ID_M) << 16) |
usArbReg[0];
ptMsgObj->ulFlags |= MSG_OBJ_EXTENDED_ID;
}
else
{
//
// The Identifier is an 11 bit value.
//
ptMsgObj->ulMsgID = (usArbReg[1] & CAN_IF1ARB2_ID_M) >> 2;
}
//
// Indicate that we lost some data.
//
if(usMsgCtrl & CAN_IF1MCTL_MSGLST)
{
ptMsgObj->ulFlags |= MSG_OBJ_DATA_LOST;
}
//
// Set the flag to indicate if ID masking was used.
//
if(usMsgCtrl & CAN_IF1MCTL_UMASK)
{
if(usArbReg[1] & CAN_IF1ARB2_XTD)
{
//
// The Identifier Mask is assumed to also be a 29 bit value.
//
ptMsgObj->ulMsgIDMask =
((usMaskReg[1] & CAN_IF1MSK2_IDMSK_M) << 16) | usMaskReg[0];
//
// If this is a fully specified Mask and a remote frame then don't
// set the MSG_OBJ_USE_ID_FILTER because the ID was not really
// filtered.
//
if((ptMsgObj->ulMsgIDMask != 0x1fffffff) ||
((ptMsgObj->ulFlags & MSG_OBJ_REMOTE_FRAME) == 0))
{
ptMsgObj->ulFlags |= MSG_OBJ_USE_ID_FILTER;
}
}
else
{
//
// The Identifier Mask is assumed to also be an 11 bit value.
//
ptMsgObj->ulMsgIDMask = ((usMaskReg[1] & CAN_IF1MSK2_IDMSK_M) >>
2);
//
// If this is a fully specified Mask and a remote frame then don't
// set the MSG_OBJ_USE_ID_FILTER because the ID was not really
// filtered.
//
if((ptMsgObj->ulMsgIDMask != 0x7ff) ||
((ptMsgObj->ulFlags & MSG_OBJ_REMOTE_FRAME) == 0))
{
ptMsgObj->ulFlags |= MSG_OBJ_USE_ID_FILTER;
}
}
//
// Indicate if the extended bit was used in filtering.
//
if(usMaskReg[1] & CAN_IF1MSK2_MXTD)
{
ptMsgObj->ulFlags |= MSG_OBJ_USE_EXT_FILTER;
}
//
// Indicate if direction filtering was enabled.
//
if(usMaskReg[1] & CAN_IF1MSK2_MDIR)
{
ptMsgObj->ulFlags |= MSG_OBJ_USE_DIR_FILTER;
}
}
//
// Set the interupt flags.
//
if(usMsgCtrl & CAN_IF1MCTL_TXIE)
{
ptMsgObj->ulFlags |= MSG_OBJ_TX_INT_ENABLE;
}
if(usMsgCtrl & CAN_IF1MCTL_RXIE)
{
ptMsgObj->ulFlags |= MSG_OBJ_RX_INT_ENABLE;
}
//
// See if there is new data available.
//
if(usMsgCtrl & CAN_IF1MCTL_NEWDAT)
{
//
// Get the amount of data needed to be read.
//
ptMsgObj->ulMsgLen = (usMsgCtrl & CAN_IF1MCTL_DLC_M);
//
// Don't read any data for a remote frame, there is nothing valid in
// that buffer anyway.
//
if((ptMsgObj->ulFlags & MSG_OBJ_REMOTE_FRAME) == 0)
{
//
// Read out the data from the CAN registers.
//
CANDataRegRead(ptMsgObj->pucMsgData,
(unsigned long *)(&(ptBase->IF2_DA1)),
ptMsgObj->ulMsgLen);
}
//
// Now clear out the new data flag.
//
canRegWrite((unsigned long)&ptBase->IF2_CMDMSK, CAN_IF1CMSK_NEWDAT);
//
// Transfer the message object to the message object specifiec by
// ulObjID.
//
canRegWrite((unsigned long)&ptBase->IF2_CMDREQ, ulObjID & CAN_IF1CRQ_MNUM_M);
//
// Wait for busy bit to clear
//
while(canRegRead((unsigned long)&ptBase->IF2_CMDREQ) & CAN_IF1CRQ_BUSY)
{
}
//
// Indicate that there is new data in this message.
//
ptMsgObj->ulFlags |= MSG_OBJ_NEW_DATA;
}
else
{
//
// Along with the MSG_OBJ_NEW_DATA not being set the amount of data
// needs to be set to zero if none was available.
//
ptMsgObj->ulMsgLen = 0;
}
}
//*****************************************************************************
//
//! Clears a message object so that it is no longer used.
//!
//! \param ptBase is the base address of the CAN controller.
//! \param ulObjID is the message object number to disable (1-32).
//!
//! This function frees the specified message object from use. Once a message
//! object has been ``cleared,'' it will no longer automatically send or
//! receive messages, or generate interrupts.
//!
//! \return None.
//
//*****************************************************************************
void CANMessageClear(unsigned long ulBaseAddr, unsigned long ulObjID)
{
LPC_CAN_TypeDef *ptBase = (LPC_CAN_TypeDef *)ulBaseAddr;
//
// Check the arguments.
//
ASSERT(CANBaseValid((unsigned long)ptBase));
ASSERT((ulObjID >= 1) && (ulObjID <= 32));
//
// Wait for busy bit to clear
//
while(canRegRead((unsigned long)&ptBase->IF1_CMDREQ) & CAN_IF1CRQ_BUSY)
{
}
//
// Clear the message value bit in the arbitration register. This indicates
// the message is not valid.
//
canRegWrite((unsigned long)&ptBase->IF1_CMDMSK, CAN_IF1CMSK_WRNRD | CAN_IF1CMSK_ARB);
canRegWrite((unsigned long)&ptBase->IF1_ARB1, 0);
canRegWrite((unsigned long)&ptBase->IF1_ARB2, 0);
//
// Initiate programming the message object
//
canRegWrite((unsigned long)&ptBase->IF1_CMDREQ, ulObjID & CAN_IF1CRQ_MNUM_M);
}
//*****************************************************************************
//
// Close the Doxygen group.
//! @}
//
//*****************************************************************************