/************************************************************************** MODULE: LPC_CANAll CONTAINS: Philips LPC2000 CAN interface driver. This driver shows how the CAN interface of the Philips LPC2000 can be used to receive ALL messages on the CANbus. All incoming messages are copied into a receive queue. NOTE: COPYRIGHT: LICENSE: VERSION: 1.10, Pf 05-JAN-05, Updates in accordance with errata sheets --------------------------------------------------------------------------- HISTORY: 1.00, Pf 14-JUL-04, First published release 14. May. 2005: - replaced integer types unsigned int with unsigned long where appropriate to avoid "target dependent sizeof(int)" - added volatiles to avoid compiler warnings --------------------------------------------------------------------------- modify by yuanguiyou for tkstudio ide . date:2008/04/08 ***************************************************************************/ #include "types.h" #include "LPC21XX.H" // LPC21XX Peripheral Registers #include "LPC_CANAll.h" #include "config.h" /************************************************************************** GLOBAL VARIABLES ***************************************************************************/ // Receive Queue: one queue for each CAN port CANALL_MSG mRxCAN[MAX_CANPORTS][MAX_QUEUE]; // Receive Queue IN pointer int16_t mRxIN[MAX_CANPORTS]; // Receive Queue OUT pointer int16_t mRxOUT[MAX_CANPORTS]; /************************************************************************** PUBLIC FUNCTIONS ***************************************************************************/ /************************************************************************** Initialization of a CAN interface as described in LPC_CANAll.h ***************************************************************************/ int16_t CANAll_Init ( uint16_t can_port, // CAN interface to use uint16_t can_isrvect, // interrupt vector number to use for Rx ISR (0-15) uint32_t can_btr // CAN BTR value used to set CAN baud rate ) { volatile uint32_t *pSFR; // pointer into SFR space volatile uint32_t *pSFR2; // pointer into SFR space uint32_t offset; // offset added to pSFR // Double check can_isrvect value if (can_isrvect > 15) { // Illegal value for can_isrvect return 0; } // Double check can_port value if ((can_port < 1) || (can_port > MAX_CANPORTS)) { // Illegal value for can_port return 0; } // Reset IN and OUT pointer mRxIN[can_port-1] = 0; mRxOUT[can_port-1] = 0; // Enable pins for selected CAN interface switch (can_port) { case 1: PINSEL1 |= 0x00040000L; // Set bit 18 offset = 0x00000000L; // Use 1st set of CAN registers break; #if (MAX_CANPORTS > 1) case 2: PINSEL1 |= 0x00014000L; // Set bits 14 and 16 offset = 0x00001000L; // Use 2nd set of CAN registers break; #endif #if (MAX_CANPORTS > 2) case 3: PINSEL1 |= 0x00001800L; // Set bits 11 and 12 offset = 0x00002000L; // Use 3rd set of CAN registers break; #endif #if (MAX_CANPORTS > 3) case 4: PINSEL0 |= 0x0F000000L; // Set bits 24 to 27 offset = 0x00003000L; // Use 4th set of CAN registers break; #endif default: return 0; // illegal value used } // Acceptance Filter Mode Register = filter off, receive all AFMR = 0x00000002L; pSFR = (volatile unsigned long *) &C1MOD + offset; // Select Mode register *pSFR = 1; // Go into Reset mode pSFR = (volatile unsigned long *) &C1IER + offset; // Select Interrupt Enable Register *pSFR = 0; // Disable All Interrupts pSFR = (volatile unsigned long *) &C1GSR + offset; // Select Status Register *pSFR = 0; // Clear Status register pSFR = (volatile unsigned long *) &C1BTR + offset; // Select BTR Register *pSFR = can_btr; // Set bit timing // Set and enable receive interrupt pSFR = (volatile uint32_t *) &VICVectAddr0; pSFR += can_isrvect; // Set to desired interrupt vector pSFR2 = (volatile uint32_t *) &VICVectCntl0; pSFR2 += can_isrvect; // Set to desired interrupt control switch (can_port) { case 1: // Set interrupt vector *pSFR = (uint32_t) CANAll_CANISR_Rx1; // Use this Interrupt for CAN Rx1 Interrupt *pSFR2 = 0x20 | 26; // Enable CAN Rx1 Interrupt VICIntEnable = 0x04000000L; break; #if (MAX_CANPORTS > 1) case 2: // Set interrupt vector *pSFR = (uint32_t) CANAll_CANISR_Rx2; // Use this Interrupt for CAN Rx2 Interrupt *pSFR2 = 0x20 | 27; // Enable CAN Rx2 Interrupt VICIntEnable = 0x08000000L; break; #endif #if (MAX_CANPORTS > 2) case 3: // Set interrupt vector *pSFR = (uint32_t) CANAll_CANISR_Rx3; // Use this Interrupt for CAN Rx3 Interrupt *pSFR2 = 0x20 | 28; // Enable CAN Rx3 Interrupt VICIntEnable = 0x10000000L; break; #endif #if (MAX_CANPORTS > 3) case 4: // Set interrupt vector *pSFR = (uint32_t) CANAll_CANISR_Rx4; // Use this Interrupt for CAN Rx4 Interrupt *pSFR2 = 0x20 | 29; // Enable CAN Rx4 Interrupt VICIntEnable = 0x20000000L; break; #endif default: return 0; // illegal value used } pSFR = (volatile uint32_t *) &C1IER + offset; // Select Interrupt register *pSFR = 1; // Enable Receive Interrupt // Enter Normal Operating Mode pSFR = (volatile uint32_t *) &C1MOD + offset; // Select Mode register *pSFR = 0; // Operating Mode return 1; } /************************************************************************** Installing the CAN Err ISR as described in LPC_CANAll.h ***************************************************************************/ int16_t CANAll_SetErrIRQ ( uint16_t can_isrvect // interrupt vector number to use for Err ISR (0-15) ) { volatile uint32_t *pSFR; // pointer into SFR space // Double check can_isrvect value if (can_isrvect > 15) { // Illegal value for can_isrvect return 0; } // Set and enable err interrupt pSFR = (volatile unsigned long *) &VICVectAddr0; pSFR += can_isrvect; // Set to desired interrupt vector // Set interrupt vector *pSFR = (unsigned long) CANAll_CANISR_Err; pSFR = (volatile unsigned long *) &VICVectCntl0; pSFR += can_isrvect; // Set to desired interrupt control *pSFR = 0x20 | 19; // Enable Interrupt source VICIntEnable = 0x00080000L; return 1; } /************************************************************************** Transmitting a CAN message on a selected CAN interface as described in LPC_CANAll.h ***************************************************************************/ int16_t CANAll_PushMessage ( uint16_t can_port, CANALL_MSG *pTransmitBuf ) { volatile unsigned long *pAddr; unsigned long *pCandata; unsigned long offset; // Double check can_port value if ((can_port < 1) || (can_port > MAX_CANPORTS)) { // Illegal value for can_port return 0; } switch (can_port) { case 1: offset = 0x00000000L; // Use 1st set of CAN registers break; #if (MAX_CANPORTS > 1) case 2: offset = 0x00001000L; // Use 2nd set of CAN registers break; #endif #if (MAX_CANPORTS > 2) case 3: offset = 0x00002000L; // Use 3rd set of CAN registers break; #endif #if (MAX_CANPORTS > 3) case 4: offset = 0x00003000L; // Use 4th set of CAN registers break; #endif default: return 0; // illegal value used } pAddr = (volatile unsigned long *) &C1SR + offset; // CANSR if (!(*pAddr & 0x00000004L)) { // Transmit Channel is not available return 0; // No channel available } // Write DLC, RTR and FF pAddr = (volatile unsigned long *) &C1TFI1 + offset; *pAddr = pTransmitBuf->Frame & 0xC00F0000L; // Write CAN ID pAddr++; *pAddr = pTransmitBuf->MsgID; // Write first 4 data bytes pCandata = (unsigned long *) &(pTransmitBuf->DatA); pAddr++; *pAddr = *pCandata; // Write second 4 data bytes pCandata++; pAddr++; *pAddr = *pCandata; // Write self transmission request pAddr = (volatile unsigned long *) &C1CMR + offset; *pAddr = 0x30; // Self Transmission Request Buf 1 return 1; } /************************************************************************** Receiving a CAN message as described in LPC_CANAll.h ***************************************************************************/ int16_t CANAll_PullMessage ( uint16_t can_port, CANALL_MSG *pReceiveBuf ) { unsigned long *pSrc; // Source pointer unsigned long *pDst; // Destination pointer // Double check can_port value if ((can_port < 1) || (can_port > MAX_CANPORTS)) { // Illegal value for can_port return 0; } can_port--; // Adjust to 0 - MAX_CANPORTS-1 // Check if something is in RxQueue if ((mRxIN[can_port]) == (mRxOUT[can_port])) { // Queue is empty return 0; } // Pointers are different, so something is in queue // Initialize pointers pSrc = (unsigned long *) &(mRxCAN[can_port][mRxOUT[can_port]]); pDst = (unsigned long *) &(pReceiveBuf->Frame); *pDst = *pSrc; // Copy Frame pSrc++; pDst++; *pDst = *pSrc; // Copy MsgID pSrc++; pDst++; *pDst = *pSrc; // Copy DatA pSrc++; pDst++; *pDst = *pSrc; // Copy DatB // Adjust OUT pointer mRxOUT[can_port]++; if (mRxOUT[can_port] >= MAX_QUEUE) { mRxOUT[can_port] = 0; } return 1; } /************************************************************************** PRIVATE FUNCTIONS ***************************************************************************/ /************************************************************************** DOES: Interrupt Service Routine for CAN Errors GLOBALS: none RETURNS: nothing ***************************************************************************/ void CANAll_CANISR_Err ( void ) { // DEBUG VERSION: do not return from Errors // Replace this with application specific error handling while (1) { } VICVectAddr = 0xFFFFFFFFL; // acknowledge Interrupt } /************************************************************************** DOES: Interrupt Service Routine for CAN receive on CAN interface 1 GLOBALS: Copies the received message into the gRxCAN[0][] array RETURNS: nothing ***************************************************************************/ void CANAll_CANISR_Rx1 ( void ) { unsigned long *pDest; // initialize destination pointer pDest = (unsigned long *) &(mRxCAN[0][mRxIN[0]]); *pDest = C1RFS; // Frame pDest++; *pDest = C1RID; // ID pDest++; *pDest = C1RDA; // Data A pDest++; *pDest = C1RDB; // Data B // Adjust IN pointer mRxIN[0]++; if (mRxIN[0] >= MAX_QUEUE) { mRxIN[0] = 0; } C1CMR = 0x04; // release receive buffer VICVectAddr = 0xFFFFFFFFL; // acknowledge Interrupt } #if (MAX_CANPORTS > 1) /************************************************************************** DOES: Interrupt Service Routine for CAN receive on CAN interface 2 GLOBALS: Copies the received message into the gRxCAN[1][] array RETURNS: nothing ***************************************************************************/ void CANAll_CANISR_Rx2 ( void ) { unsigned long *pDest; // initialize destination pointer pDest = (unsigned long *) &(mRxCAN[1][mRxIN[1]]); *pDest = C2RFS; // Frame pDest++; *pDest = C2RID; // ID pDest++; *pDest = C2RDA; // Data A pDest++; *pDest = C2RDB; // Data B // Adjust IN pointer mRxIN[1]++; if (mRxIN[1] >= MAX_QUEUE) { mRxIN[1] = 0; } C2CMR = 0x04; // release receive buffer VICVectAddr = 0xFFFFFFFFL; // acknowledge Interrupt } #endif // MAX_CANPORTS > 1 #if (MAX_CANPORTS > 2) /************************************************************************** DOES: Interrupt Service Routine for CAN receive on CAN interface 3 GLOBALS: Copies the received message into the gRxCAN[2][] array RETURNS: nothing ***************************************************************************/ void CANAll_CANISR_Rx3 ( void ) { unsigned long *pDest; // initialize destination pointer pDest = (unsigned long *) &(mRxCAN[2][mRxIN[2]]); *pDest = C3RFS; // Frame pDest++; *pDest = C3RID; // ID pDest++; *pDest = C3RDA; // Data A pDest++; *pDest = C3RDB; // Data B // Adjust IN pointer mRxIN[2]++; if (mRxIN[2] >= MAX_QUEUE) { mRxIN[2] = 0; } C3CMR = 0x04; // release receive buffer VICVectAddr = 0xFFFFFFFFL; // acknowledge Interrupt } #endif // MAX_CANPORTS > 2 #if (MAX_CANPORTS > 3) /************************************************************************** DOES: Interrupt Service Routine for CAN receive on CAN interface 4 GLOBALS: Copies the received message into the gRxCAN[3][] array RETURNS: nothing ***************************************************************************/ void CANAll_CANISR_Rx4 ( void ) { unsigned long *pDest; // initialize destination pointer pDest = (unsigned long *) &(mRxCAN[3][mRxIN[3]]); *pDest = C4RFS; // Frame pDest++; *pDest = C4RID; // ID pDest++; *pDest = C4RDA; // Data A pDest++; *pDest = C4RDB; // Data B // Adjust IN pointer mRxIN[3]++; if (mRxIN[3] >= MAX_QUEUE) { mRxIN[3] = 0; } C4CMR = 0x04; // release receive buffer VICVectAddr = 0xFFFFFFFFL; // acknowledge Interrupt } #endif // MAX_CANPORTS > 4 /*----------------------- END OF FILE ----------------------------------*/