Here is a complete example that can receive 11-bit ID 0x003 or 29-bit ID 0x12345678. I've tested this with Keil Realview and a Keil MCB1000 board with an LPC11C24.
#include "lpc11xx.h"
#include "system_lpc11xx.h"
// CAN message objects 0 to CANOBJ_RXTX-1 are used for receive
#define CANOBJ_RXTX 24
// CAN message objects CANOBJ_RXTX to 31 are used for transmit
// various CAN registers
#define CMDREQ_BSY (1UL << 15)
// CAN CTRL register
#define CTRL_INI (1UL << 0)
#define CTRL_IEN (1UL << 1)
#define CTRL_SIE (1UL << 2)
#define CTRL_EIE (1UL << 3)
#define CTRL_DAR (1UL << 5)
#define CTRL_CCE (1UL << 6)
#define CTRL_TST (1UL << 7)
// CAN CMDMASK register
#define CMDMSK_DATB (1UL << 0)
#define CMDMSK_DATA (1UL << 1)
#define CMDMSK_TREQ (1UL << 2)
#define CMDMSK_IPND (1UL << 3)
#define CMDMSK_CTRL (1UL << 4)
#define CMDMSK_ARB (1UL << 5)
#define CMDMSK_MSK (1UL << 6)
#define CMDMSK_WR (1UL << 7)
#define CMDMSK_RD (0UL << 7)
// CAN MCTRL register
#define MCTRL_DLC (0x0F)
#define MCTRL_EOB (1UL << 7)
#define MCTRL_TXRQT (1UL << 8)
#define MCTRL_RMTEN (1UL << 9)
#define MCTRL_RXIE (1UL << 10)
#define MCTRL_TXIE (1UL << 11)
#define MCTRL_UMASK (1UL << 12)
#define MCTRL_IPND (1UL << 13)
#define MCTRL_MSGLT (1UL << 14)
#define MCTRL_NWDAT (1UL << 15)
// CAN ARB2 register
#define ARB_ID (0x1FFF)
#define ARB_DIR (1UL << 13)
#define ARB_XTD (1UL << 14)
#define ARB_MSGVL (1UL << 15)
// CAN MSK2 register
#define MSK2_MXTD (1UL << 15)
// uses 125kbps on CAN bus with a 48MHz peripheral clock
#define CANBitrate125k_48MHz 0x00001C57UL
// transmit a CAN message
static void Transmit
(
uint8_t msgObjNum, // object number to use for transmission
uint32_t Id, // message identifier (11-bit)
uint8_t Len, // length of message in bytes
uint8_t *pData // message data
)
{
if (msgObjNum < CANOBJ_RXTX) return;
while (LPC_CAN->IF1_CMDREQ & CMDREQ_BSY); // wait until previous copy complete
// prepare registers with message
LPC_CAN->IF1_CMDMSK = CMDMSK_WR|CMDMSK_ARB|CMDMSK_CTRL|CMDMSK_TREQ|CMDMSK_DATA|CMDMSK_DATB;
LPC_CAN->IF1_MCTRL = MCTRL_TXRQT|MCTRL_TXIE|MCTRL_EOB|(Len & MCTRL_DLC);
LPC_CAN->IF1_ARB1 = 0;
LPC_CAN->IF1_ARB2 = ((Id & 0x7FF) << 2)|ARB_DIR|ARB_MSGVL;
// copy data
LPC_CAN->IF1_DA1 = *(uint16_t *)&pData[0];
LPC_CAN->IF1_DA2 = *(uint16_t *)&pData[2];
LPC_CAN->IF1_DB1 = *(uint16_t *)&pData[4];
LPC_CAN->IF1_DB2 = *(uint16_t *)&pData[6];
LPC_CAN->IF1_CMDREQ = msgObjNum + 1; // copy registers to this message object
}
// configures a receive filter
static void SetCANFilter
(
uint32_t Id, // message identifier to receive
uint8_t Ext // set to one for 29-bit identifier, 0 for 11-bit identifier
)
{
uint8_t lp;
uint32_t cMsgObj;
uint32_t msgV;
msgV = (LPC_CAN->MSGV2 << 16) | LPC_CAN->MSGV1;
for (lp = 0; lp < CANOBJ_RXTX; lp++)
{
if ((msgV & (1 << lp)) == 0)
break;
}
if (lp < CANOBJ_RXTX)
{
cMsgObj = lp + 1; // valid message object number found
}
else
{
return;
}
LPC_CAN->IF1_CMDMSK = CMDMSK_WR|CMDMSK_MSK|CMDMSK_ARB|CMDMSK_CTRL;
LPC_CAN->IF1_MCTRL = MCTRL_UMASK|MCTRL_RXIE|MCTRL_EOB|MCTRL_DLC;
if (Ext)
{
LPC_CAN->IF1_MSK1 = Id & 0xFFFF;
LPC_CAN->IF1_MSK2 = ((Id & 0x1FFFFFFF) >> 16) | MSK2_MXTD;
LPC_CAN->IF1_ARB1 = Id & 0xFFFF;
LPC_CAN->IF1_ARB2 = ((Id & 0x1FFFFFFF) >> 16) | ARB_MSGVL | ARB_XTD;
}
else
{
LPC_CAN->IF1_MSK1 = 0;
LPC_CAN->IF1_MSK2 = ((Id & 0x7FF) << 2);
LPC_CAN->IF1_ARB1 = 0;
LPC_CAN->IF1_ARB2 = ((Id & 0x7FF) << 2) | ARB_MSGVL;
}
LPC_CAN->IF1_CMDREQ = cMsgObj; // copy registers to message object
while (LPC_CAN->IF1_CMDREQ & CMDREQ_BSY);
}
// check for a received message
// returns 1 if message received, 0 if no message received
uint8_t PullMessage
(
uint32_t *pId, // filled with identifier of received message
uint8_t *pExt, // set to 1 on return if identifier is 29-bit
uint8_t *pLen, // filled with length in bytes of received message
uint8_t *pData // pass an eight-byte array, filled with received data
)
{
uint32_t cInt;
uint8_t cMsgObj;
cInt = LPC_CAN->INT; // read current interrupt status
switch (cInt)
{
case 0x0000: // no interrupt
return 0;
case 0x8000: // status interrupt, status register was updated
return 0;
default: // message object interrupt
cMsgObj = cInt & 0xFF;
// valid rx object, retrieve data
if ((cMsgObj >= 1) && (cMsgObj <= CANOBJ_RXTX))
{
while (LPC_CAN->IF2_CMDREQ & CMDREQ_BSY); // wait for object availability
LPC_CAN->IF2_CMDMSK = CMDMSK_RD|CMDMSK_MSK|CMDMSK_ARB|CMDMSK_CTRL|CMDMSK_IPND|CMDMSK_TREQ|CMDMSK_DATA|CMDMSK_DATB;
LPC_CAN->IF2_CMDREQ = cMsgObj; // copy this object to registers
while (LPC_CAN->IF2_CMDREQ & CMDREQ_BSY);
// receive overrun occured
if (LPC_CAN->IF2_MCTRL & MCTRL_MSGLT)
{
}
// XTD bit (extended format), copy message to destination
if (LPC_CAN->IF2_ARB2 & (1UL << 14))
{
*pId = ((LPC_CAN->IF2_ARB2 & 0x1FFF) << 16) | (LPC_CAN->IF2_ARB1 & 0xFFFF);
*pExt = 1;
}
// regular message (11bit ID), copy message to destination
else
{
*pId = (LPC_CAN->IF2_ARB2 >> 2) & 0x7FF;
*pExt = 0;
}
*pLen = LPC_CAN->IF2_MCTRL & MCTRL_DLC;
*(uint16_t *)&pData[0] = LPC_CAN->IF2_DA1;
*(uint16_t *)&pData[2] = LPC_CAN->IF2_DA2;
*(uint16_t *)&pData[4] = LPC_CAN->IF2_DB1;
*(uint16_t *)&pData[6] = LPC_CAN->IF2_DB2;
return 1;
}
// tx object
else
{
while (LPC_CAN->IF1_CMDREQ & CMDREQ_BSY); // wait for object availability
LPC_CAN->IF1_CMDMSK = CMDMSK_IPND;
LPC_CAN->IF1_CMDREQ = cMsgObj; // copy this object to registers
while (LPC_CAN->IF1_CMDREQ & CMDREQ_BSY);
}
break;
}
return 0;
}
// interrupt handler
void CAN_IRQHandler(void)
{
uint32_t Id;
uint8_t Ext;
uint8_t Len;
uint8_t Data[8];
// check if a message was received
if (PullMessage(&Id, &Ext, &Len, Data))
{
// message received
Id = Id;
}
}
// main function
int main(void)
{
uint32_t btr = CANBitrate125k_48MHz;
uint16_t lp;
uint8_t TxData[8];
uint8_t RxData[8];
uint32_t RxId;
uint8_t RxLen;
uint8_t RxExt;
SystemInit();
LPC_SYSCON->PRESETCTRL |= (1UL << 3); // clear the reset signal
LPC_SYSCON->SYSAHBCLKCTRL |= (1UL << 17); // enable CAN power
LPC_CAN->CLKDIV = 0; // set CAN clk to match systemclock, here 48MHz
LPC_CAN->CNTL = CTRL_INI; // set CAN to init mode
LPC_CAN->CNTL |= CTRL_CCE; // start config bit timing
LPC_CAN->BT = (uint16_t) btr;
LPC_CAN->BRPE = (uint16_t) (btr >> 16);
LPC_CAN->CNTL &= ~CTRL_CCE; // end config bit timing
// initialize CAN message objects
for (lp = 0; lp < 32; lp++)
{
LPC_CAN->IF1_CMDMSK = CMDMSK_WR|CMDMSK_MSK|CMDMSK_ARB|CMDMSK_CTRL|CMDMSK_DATA|CMDMSK_DATB;
LPC_CAN->IF1_MCTRL = 0;
LPC_CAN->IF1_MSK1 = 0;
LPC_CAN->IF1_MSK2 = 0;
LPC_CAN->IF1_ARB1 = 0;
LPC_CAN->IF1_ARB2 = 0;
LPC_CAN->IF1_DA1 = 0;
LPC_CAN->IF1_DA2 = 0;
LPC_CAN->IF1_DB1 = 0;
LPC_CAN->IF1_DB2 = 0;
LPC_CAN->IF1_CMDREQ = lp+1; // copy from registers to message object
while (LPC_CAN->IF1_CMDREQ & CMDREQ_BSY);
}
LPC_CAN->STAT = 0; // reset CAN status register
LPC_CAN->CNTL |= CTRL_IEN; // enable interrupts
LPC_CAN->CNTL &= ~CTRL_INI; // normal operating mode
// want to receive message 0x003 (11-bit ID)
SetCANFilter(0x003, 0);
// want to receive message 0x00000004 (29-bit ID)
SetCANFilter(0x12345678, 1);
NVIC_EnableIRQ(CAN_IRQn);
// send a message
for (lp = 0; lp < 8; lp++) TxData[lp] = lp;
Transmit(CANOBJ_RXTX, 0x001, 8, TxData);
Transmit(CANOBJ_RXTX + 1, 0x002, 8, TxData);
while(1);
}