/********************************************************************** | |
* $Id$ lpc18xx_can.c 2011-06-02 | |
*//** | |
* @file lpc18xx_can.c | |
* @brief Contains all functions support for C CAN firmware library | |
* on LPC18xx | |
* @version 1.0 | |
* @date 02. June. 2011 | |
* @author NXP MCU SW Application Team | |
* | |
* Copyright(C) 2011, NXP Semiconductor | |
* All rights reserved. | |
* | |
*********************************************************************** | |
* Software that is described herein is for illustrative purposes only | |
* which provides customers with programming information regarding the | |
* products. This software is supplied "AS IS" without any warranties. | |
* NXP Semiconductors assumes no responsibility or liability for the | |
* use of the software, conveys no license or title under any patent, | |
* copyright, or mask work right to the product. NXP Semiconductors | |
* reserves the right to make changes in the software without | |
* notification. NXP Semiconductors also make no representation or | |
* warranty that such application will be suitable for the specified | |
* use without further testing or modification. | |
**********************************************************************/ | |
/* Peripheral group ----------------------------------------------------------- */ | |
/** @addtogroup C_CAN | |
* @{ | |
*/ | |
/* Includes ------------------------------------------------------------------- */ | |
#include "LPC18xx.h" | |
#include "lpc18xx_can.h" | |
#include "lpc18xx_cgu.h" | |
/* If this source file built with example, the LPC18xx FW library configuration | |
* file in each example directory ("lpc18xx_libcfg.h") must be included, | |
* otherwise the default FW library configuration file must be included instead | |
*/ | |
#ifdef __BUILD_WITH_EXAMPLE__ | |
#include "lpc18xx_libcfg.h" | |
#else | |
#include "lpc18xx_libcfg_default.h" | |
#endif /* __BUILD_WITH_EXAMPLE__ */ | |
#ifdef _C_CAN | |
/* Private Macros ---------------------------------------------------------- */ | |
#ifndef __GNUC__ | |
/* Macro for reading and writing to CCAN IF registers */ | |
#define CAN_IF_Read(reg, IFsel) (LPC_C_CAN0->##IFsel##_##reg) | |
#define CAN_IF_Write(reg, IFsel, val) (LPC_C_CAN0->##IFsel##_##reg=val) | |
/* Macro for writing IF to specific RAM message object */ | |
#define CAN_IF_readBuf(IFsel,msg) \ | |
LPC_C_CAN0->##IFsel##_##CMDMSK_W=RD|MASK|ARB|CTRL|CLRINTPND|DATAA|DATAB; \ | |
LPC_C_CAN0->##IFsel##_##CMDREQ=msg; \ | |
while (LPC_C_CAN0->##IFsel##_##CMDREQ & IFCREQ_BUSY ); | |
/* Macro for reading specific RAM message object to IF */ | |
#define CAN_IF_writeBuf(IFsel,msg) \ | |
LPC_C_CAN0->##IFsel##_##CMDMSK_W=WR|MASK|ARB|CTRL|CLRINTPND|DATAA|DATAB; \ | |
LPC_C_CAN0->##IFsel##_##CMDREQ=msg; \ | |
while (LPC_C_CAN0->##IFsel##_##CMDREQ & IFCREQ_BUSY ); | |
#else | |
#define CAN_IF_Read(reg, IFsel) (LPC_C_CAN0->IFsel##_##reg) | |
#define CAN_IF_Write(reg, IFsel, val) (LPC_C_CAN0->IFsel ## _ ## reg = val) | |
/* Macro for writing IF to specific RAM message object */ | |
#define CAN_IF_readBuf(IFsel,msg) \ | |
LPC_C_CAN0->IFsel##_##CMDMSK_W=RD|MASK|ARB|CTRL|CLRINTPND|DATAA|DATAB; \ | |
LPC_C_CAN0->IFsel##_##CMDREQ=msg; \ | |
while (LPC_C_CAN0->IFsel##_##CMDREQ & IFCREQ_BUSY ); | |
/* Macro for reading specific RAM message object to IF */ | |
#define CAN_IF_writeBuf(IFsel,msg) \ | |
LPC_C_CAN0->IFsel##_##CMDMSK_W=WR|MASK|ARB|CTRL|CLRINTPND|DATAA|DATAB; \ | |
LPC_C_CAN0->IFsel##_##CMDREQ=msg; \ | |
while (LPC_C_CAN0->IFsel##_##CMDREQ & IFCREQ_BUSY ); | |
#endif | |
#define IF1 0 | |
#define IF2 1 | |
#define CAN_STATUS_INTERRUPT 0x8000 /* 0x0001-0x0020 are the # of the message | |
object */ | |
/* 0x8000 is the status interrupt */ | |
/* CAN Message interface register definitions */ | |
/* bit field of IF command request n register */ | |
#define IFCREQ_BUSY 0x8000 /* 1 is writing is progress, cleared when | |
RD/WR done */ | |
/* CAN CTRL register */ | |
#define CTRL_INIT (1 << 0) | |
#define CTRL_IE (1 << 1) | |
#define CTRL_SIE (1 << 2) | |
#define CTRL_EIE (1 << 3) | |
#define CTRL_DAR (1 << 5) | |
#define CTRL_CCE (1 << 6) | |
#define CTRL_TEST (1 << 7) | |
/* CAN Test register */ | |
#define TEST_BASIC (1 << 2) | |
#define TEST_SILENT (1 << 3) | |
#define TEST_LBACK (1 << 4) | |
/* CAN Status register */ | |
#define STAT_LEC (0x7 << 0) | |
#define STAT_TXOK (1 << 3) | |
#define STAT_RXOK (1 << 4) | |
#define STAT_EPASS (1 << 5) | |
#define STAT_EWARN (1 << 6) | |
#define STAT_BOFF (1 << 7) | |
#define NO_ERR 0 // No Error | |
#define STUFF_ERR 1 // Stuff Error : More than 5 equal bits in a sequence have occurred in a part | |
// of a received message where this is not allowed. | |
#define FORM_ERR 2 // Form Error : A fixed format part of a received frame has the wrong format. | |
#define ACK_ERR 3 // AckError : The message this CAN Core transmitted was not acknowledged | |
// by another node. | |
#define BIT1_ERR 4 // Bit1Error : During the transmission of a message (with the exception of | |
// the arbitration field), the device wanted to send a recessive level (bit of | |
// logical value �1�), but the monitored bus value was dominant. | |
#define BIT0_ERR 5 // Bit0Error : During the transmission of a message (or acknowledge bit, | |
// or active error flag, or overload flag), the device wanted to send a | |
// LOW/dominant level (data or identifier bit logical value �0�), but the | |
// monitored Bus value was HIGH/recessive. During busoff recovery this | |
// status is set each time a | |
// sequence of 11 HIGH/recessive bits has been monitored. This enables | |
// the CPU to monitor the proceeding of the busoff recovery sequence | |
// (indicating the bus is not stuck at LOW/dominant or continuously | |
// disturbed). | |
#define CRC_ERR 6 // CRCError: The CRC checksum was incorrect in the message received. | |
/* bit field of IF command mask register */ | |
#define DATAB (1 << 0) /* 1 is transfer data byte 4-7 to message object, 0 is not */ | |
#define DATAA (1 << 1) /* 1 is transfer data byte 0-3 to message object, 0 is not */ | |
#define NEWDAT (1 << 2) /* Clear NEWDAT bit in the message object */ | |
#define CLRINTPND (1 << 3) | |
#define CTRL (1 << 4) /* 1 is transfer the CTRL bit to the message object, 0 is not */ | |
#define ARB (1 << 5) /* 1 is transfer the ARB bits to the message object, 0 is not */ | |
#define MASK (1 << 6) /* 1 is transfer the MASK bit to the message object, 0 is not */ | |
#define WR (1 << 7) /* 0 is READ, 1 is WRITE */ | |
#define RD 0x0000 | |
/* bit field of IF mask 2 register */ | |
#define MASK_MXTD (1 << 15) /* 1 extended identifier bit is used in the RX filter unit, 0 is not */ | |
#define MASK_MDIR (1 << 14) /* 1 direction bit is used in the RX filter unit, 0 is not */ | |
/* bit field of IF identifier 2 register */ | |
#define ID_MVAL (1 << 15) /* Message valid bit, 1 is valid in the MO handler, 0 is ignored */ | |
#define ID_MTD (1 << 14) /* 1 extended identifier bit is used in the RX filter unit, 0 is not */ | |
#define ID_DIR (1 << 13) /* 1 direction bit is used in the RX filter unit, 0 is not */ | |
/* bit field of IF message control register */ | |
#define NEWD (1 << 15) /* 1 indicates new data is in the message buffer. */ | |
#define MLST (1 << 14) /* 1 indicates a message loss. */ | |
#define INTP (1 << 13) /* 1 indicates message object is an interrupt source */ | |
#define UMSK (1 << 12) /* 1 is to use the mask for the receive filter mask. */ | |
#define TXIE (1 << 11) /* 1 is TX interrupt enabled */ | |
#define RXIE (1 << 10) /* 1 is RX interrupt enabled */ | |
#if REMOTE_ENABLE | |
#define RMTEN (1 << 9) /* 1 is remote frame enabled */ | |
#else | |
#define RMTEN 0 | |
#endif | |
#define TXRQ (1 << 8) /* 1 is TxRqst enabled */ | |
#define EOB (1 << 7) /* End of buffer, always write to 1 */ | |
#define DLC 0x000F /* bit mask for DLC */ | |
#define ID_STD_MASK 0x07FF | |
#define ID_EXT_MASK 0x1FFFFFFF | |
#define DLC_MASK 0x0F | |
/* Private Variables ---------------------------------------------------------- */ | |
/* Statistics of all the interrupts */ | |
/* Buss off status counter */ | |
volatile uint32_t BOffCnt = 0; | |
/* Warning status counter. At least one of the error counters | |
in the EML has reached the error warning limit of 96 */ | |
volatile uint32_t EWarnCnt = 0; | |
/* More than 5 equal bits in a sequence in received message */ | |
volatile uint32_t StuffErrCnt = 0; | |
/* Wrong format of fixed format part of a received frame */ | |
volatile uint32_t FormErrCnt = 0; | |
/* Transmitted message not acknowledged. */ | |
volatile uint32_t AckErrCnt = 0; | |
/* Send a HIGH/recessive level, but monitored LOW/dominant */ | |
volatile uint32_t Bit1ErrCnt = 0; | |
/* Send a LOW/dominant level, but monitored HIGH/recessive */ | |
volatile uint32_t Bit0ErrCnt = 0; | |
/* The CRC checksum was incorrect in the message received */ | |
volatile uint32_t CRCErrCnt = 0; | |
/* Message object new data error counter */ | |
volatile uint32_t ND1ErrCnt = 0; | |
MSG_CB TX_cb, RX_cb; | |
message_object can_buff[CAN_MSG_OBJ_MAX]; | |
message_object recv_buff; | |
#if CAN_DEBUG | |
uint32_t CANStatusLog[100]; | |
uint32_t CANStatusLogCount = 0; | |
#endif | |
//#ifdef __GNUC__ | |
//uint32_t CAN_IF_Read(uint32_t reg,uint32_t IFsel){ | |
// if(IFsel == IF1){ | |
// return (LPC_C_CAN0->IF1_reg); | |
// }else{ | |
// return (LPC_C_CAN0->IF2_reg); | |
// } | |
//} | |
//void CAN_IF_Write(uint32_t reg, uint32_t IFsel,uint32_t val){ | |
// if(IFsel == IF1){ | |
// (LPC_C_CAN0->IF1_reg=val); | |
// }else{ | |
// (LPC_C_CAN0->IF2_reg=val); | |
// } | |
//} | |
// | |
///* Macro for writing IF to specific RAM message object */ | |
//void CAN_IF_readBuf(uint32_t IFsel,uint32_t msg){ | |
// if(IFsel == IF1){ | |
// LPC_C_CAN0->IF1_CMDMSK_W=RD|MASK|ARB|CTRL|CLRINTPND|DATAA|DATAB; | |
// LPC_C_CAN0->IF1_CMDREQ=msg; | |
// while (LPC_C_CAN0->IF1_CMDREQ & IFCREQ_BUSY ); | |
// }else{ | |
// LPC_C_CAN0->IF2_CMDMSK_W=RD|MASK|ARB|CTRL|CLRINTPND|DATAA|DATAB; | |
// LPC_C_CAN0->IF2_CMDREQ=msg; | |
// while (LPC_C_CAN0->IF2_CMDREQ & IFCREQ_BUSY ); | |
// } | |
// | |
//} | |
// | |
///* Macro for reading specific RAM message object to IF */ | |
//void CAN_IF_writeBuf(uint32_t IFsel,uint32_t msg){ | |
// if(IFsel == IF1){ | |
// LPC_C_CAN0->IF1_CMDMSK_W=WR|MASK|ARB|CTRL|CLRINTPND|DATAA|DATAB; | |
// LPC_C_CAN0->IF1_CMDREQ=msg; | |
// while (LPC_C_CAN0->IF1_CMDREQ & IFCREQ_BUSY ); | |
// }else{ | |
// LPC_C_CAN0->IF2_CMDMSK_W=WR|MASK|ARB|CTRL|CLRINTPND|DATAA|DATAB; | |
// LPC_C_CAN0->IF2_CMDREQ=msg; | |
// while (LPC_C_CAN0->IF2_CMDREQ & IFCREQ_BUSY ); | |
// } | |
//} | |
//#endif | |
/*********************************************************************//** | |
* @brief Handle valid received message | |
* @param[in] msg_no Message Object number | |
* @return None | |
**********************************************************************/ | |
void CAN_RxInt_MessageProcess( uint8_t msg_no ) | |
{ | |
uint32_t msg_id; | |
uint32_t *p_add; | |
uint32_t reg1, reg2; | |
/* Import message object to IF2 */ | |
CAN_IF_readBuf(IF2, msg_no); /* Read the message into the IF registers */ | |
p_add = (uint32_t *)&recv_buff; | |
if( CAN_IF_Read(ARB2, IF2) & ID_MTD ) /* bit 28-0 is 29 bit extended frame */ | |
{ | |
/* mask off MsgVal and Dir */ | |
reg1 = CAN_IF_Read(ARB1, IF2); | |
reg2 = CAN_IF_Read(ARB2, IF2); | |
msg_id = (reg1|(reg2<<16)); | |
} | |
else | |
{ | |
/* bit 28-18 is 11-bit standard frame */ | |
msg_id = (CAN_IF_Read(ARB2, IF2) &0x1FFF) >> 2; | |
} | |
p_add[0] = msg_id; | |
p_add[1] = CAN_IF_Read(MCTRL, IF2) & 0x000F; /* Get Msg Obj Data length */ | |
p_add[2] = (CAN_IF_Read(DA2, IF2)<<16) | CAN_IF_Read(DA1, IF2); | |
p_add[3] = (CAN_IF_Read(DB2, IF2)<<16) | CAN_IF_Read(DB1, IF2); | |
/* Clear interrupt pending bit */ | |
CAN_IF_Write(MCTRL, IF2, UMSK|RXIE|EOB|CAN_DLC_MAX); | |
/* Save changes to message RAM */ | |
CAN_IF_writeBuf(IF2, msg_no); | |
return; | |
} | |
/*********************************************************************//** | |
* @brief Handle valid transmit message | |
* @param[in] msg_no Message Object number | |
* @return None | |
**********************************************************************/ | |
void CAN_TxInt_MessageProcess( uint8_t msg_no ) | |
{ | |
/* Clear interrupt pending bit */ | |
CAN_IF_Write(MCTRL, IF2, UMSK|RXIE|EOB|CAN_DLC_MAX); | |
/* Save changes to message RAM */ | |
CAN_IF_writeBuf(IF2,msg_no); | |
return; | |
} | |
/*********************************************************************//** | |
* @brief CAN interrupt handler | |
* @param[in] None | |
* @return None | |
**********************************************************************/ | |
volatile uint32_t nd_tmp; | |
void CAN_IRQHandler(void) | |
{ | |
uint32_t canstat = 0; | |
uint32_t can_int, msg_no; | |
while ( (can_int = LPC_C_CAN0->INT) != 0 ) /* While interrupt is pending */ | |
{ | |
canstat = LPC_C_CAN0->STAT; /* Read CAN status register */ | |
if ( can_int & CAN_STATUS_INTERRUPT ) | |
{ | |
/* Passive state monitored frequently in main. */ | |
if ( canstat & STAT_EWARN ) | |
{ | |
EWarnCnt++; | |
return; | |
} | |
if ( canstat & STAT_BOFF ) | |
{ | |
BOffCnt++; | |
return; | |
} | |
switch (canstat&STAT_LEC) /* LEC Last Error Code (Type of the last error to occur on the CAN bus) */ | |
{ | |
case NO_ERR: | |
break; | |
case STUFF_ERR: | |
StuffErrCnt++; | |
break; | |
case FORM_ERR: | |
FormErrCnt++; | |
break; | |
case ACK_ERR: | |
AckErrCnt++; | |
break; | |
case BIT1_ERR: | |
Bit1ErrCnt++; | |
break; | |
case BIT0_ERR: | |
Bit0ErrCnt++; | |
break; | |
case CRC_ERR: | |
CRCErrCnt++; | |
break; | |
default: | |
break; | |
} | |
/* Clear all warning/error states except RXOK/TXOK */ | |
LPC_C_CAN0->STAT &= STAT_RXOK|STAT_TXOK; | |
} | |
else | |
{ | |
if ( (canstat & STAT_LEC) == 0 ) /* NO ERROR */ | |
{ | |
msg_no = can_int & 0x7FFF; | |
if((msg_no >= 1 ) && (msg_no <= 16)) | |
{ | |
LPC_C_CAN0->STAT &= ~STAT_RXOK; | |
/* Check if message number is correct by reading NEWDAT registers. | |
By reading out the NEWDAT bits, the CPU can check for which Message | |
Object the data portion was updated | |
Only first 16 message object used for receive : only use ND1 */ | |
if((1<<(msg_no-1)) != LPC_C_CAN0->ND1) | |
{ | |
/* message object does not contain new data! */ | |
ND1ErrCnt++; | |
break; | |
} | |
CAN_RxInt_MessageProcess(msg_no); | |
RX_cb(msg_no); | |
} | |
else | |
{ | |
LPC_C_CAN0->STAT &= ~STAT_TXOK; | |
CAN_TxInt_MessageProcess(msg_no); | |
TX_cb(msg_no); | |
} | |
} | |
} | |
} | |
return; | |
} | |
/*********************************************************************//** | |
* @brief Initialize CAN peripheral | |
* @param[in] BitClk CAN bit clock setting | |
* @param[in] ClkDiv CAN bit clock setting | |
* @param[in] Tx_cb point to call-back function when transmitted | |
* @param[in] Rx_cb point to call-back function when received | |
* @return None | |
**********************************************************************/ | |
void CAN_Init( uint32_t BitClk, CCAN_CLKDIV_Type ClkDiv , MSG_CB Tx_cb, MSG_CB Rx_cb) | |
{ | |
RX_cb = Rx_cb; | |
TX_cb = Tx_cb; | |
if ( !(LPC_C_CAN0->CNTL & CTRL_INIT) ) | |
{ | |
/* If it's in normal operation already, stop it, reconfigure | |
everything first, then restart. */ | |
LPC_C_CAN0->CNTL |= CTRL_INIT; /* Default state */ | |
} | |
LPC_C_CAN0->CLKDIV = ClkDiv; /* Divider for CAN VPB3 clock */ | |
LPC_C_CAN0->CNTL |= CTRL_CCE; /* Start configuring bit timing */ | |
LPC_C_CAN0->BT = BitClk; | |
LPC_C_CAN0->BRPE = 0x0000; | |
LPC_C_CAN0->CNTL &= ~CTRL_CCE; /* Stop configuring bit timing */ | |
LPC_C_CAN0->CNTL &= ~CTRL_INIT; /* Initialization finished, normal operation now. */ | |
while ( LPC_C_CAN0->CNTL & CTRL_INIT ); | |
/* By default, auto TX is enabled, enable all related interrupts */ | |
LPC_C_CAN0->CNTL |= (CTRL_IE|CTRL_SIE|CTRL_EIE); | |
return; | |
} | |
/*********************************************************************//** | |
* @brief Send a message to the CAN port | |
* @param[in] msg_no message object number | |
* @param[in] msg_ptr msg buffer pointer | |
* @return None | |
**********************************************************************/ | |
void CAN_Send(uint8_t msg_no, uint32_t *msg_ptr ) | |
{ | |
uint32_t tx_id, Length; | |
if(msg_ptr == NULL) return; | |
/* first is the ID, second is length, the next four are data */ | |
tx_id = *msg_ptr++; | |
Length = *msg_ptr++; | |
if(Length>CAN_DLC_MAX)Length = CAN_DLC_MAX; | |
CAN_IF_Write(MCTRL, IF1, UMSK|TXIE|TXRQ|EOB|RMTEN|(Length & DLC_MASK)); | |
CAN_IF_Write(DA1, IF1, *msg_ptr); /* Lower two bytes of message pointer */ | |
CAN_IF_Write(DA2, IF1, (*msg_ptr++)>>16); /* Upper two bytes of message pointer */ | |
CAN_IF_Write(DB1, IF1, *msg_ptr); /* Lower two bytes of message pointer */ | |
CAN_IF_Write(DB2, IF1, (*msg_ptr)>>16); /* Upper two bytes of message pointer */ | |
/* Configure arbitration */ | |
if(!(tx_id & (0x1<<30))) /* bit 30 is 0, standard frame */ | |
{ | |
/* Mxtd: 0, Mdir: 1, Mask is 0x7FF */ | |
CAN_IF_Write(MSK2, IF1, MASK_MDIR | (ID_STD_MASK << 2)); | |
CAN_IF_Write(MSK1, IF1, 0x0000); | |
/* MsgVal: 1, Mtd: 0, Dir: 1, ID = 0x200 */ | |
CAN_IF_Write(ARB1, IF1, 0x0000); | |
CAN_IF_Write(ARB2, IF1, ID_MVAL| ID_DIR | (tx_id << 2)); | |
} | |
else /* Extended frame */ | |
{ | |
/* Mxtd: 1, Mdir: 1, Mask is 0x7FF */ | |
CAN_IF_Write(MSK2, IF1, MASK_MXTD | MASK_MDIR | (ID_EXT_MASK >> 16)); | |
CAN_IF_Write(MSK1, IF1, ID_EXT_MASK & 0x0000FFFF); | |
/* MsgVal: 1, Mtd: 1, Dir: 1, ID = 0x200000 */ | |
CAN_IF_Write(ARB1, IF1, tx_id & 0x0000FFFF); | |
CAN_IF_Write(ARB2, IF1, ID_MVAL|ID_MTD | ID_DIR | (tx_id >> 16)); | |
} | |
/* Write changes to message RAM */ | |
CAN_IF_writeBuf(IF1, msg_no); | |
return; | |
} | |
/*********************************************************************//** | |
* @brief Listen for a message on CAN bus | |
* @param[in] msg_no message object number | |
* @param[in] msg_ptr msg buffer pointer | |
* @param[in] RemoteEnable Enable/disable remote frame support, should be: | |
* - TRUE: enable | |
* - FALSE: disable | |
* @return None | |
**********************************************************************/ | |
void CAN_Recv(uint8_t msg_no, uint32_t *msg_ptr, Bool RemoteEnable) | |
{ | |
uint32_t rx_id = *msg_ptr; | |
uint32_t rmten = 0; | |
if(RemoteEnable){ | |
rmten = 1<<8; | |
} | |
if(!(rx_id & (0x1<<30))){ /* standard frame */ | |
/* Mxtd: 0, Mdir: 0, Mask is 0x7FF */ | |
CAN_IF_Write(MSK1, IF1, 0x0000); | |
CAN_IF_Write(MSK2, IF1, ID_STD_MASK << 2); | |
/* MsgVal: 1, Mtd: 0, Dir: 0 */ | |
CAN_IF_Write(ARB1, IF1, 0x0000); | |
CAN_IF_Write(MCTRL, IF1, rmten|UMSK|RXIE|EOB|CAN_DLC_MAX); | |
CAN_IF_Write(DA1, IF1, 0x0000); | |
CAN_IF_Write(DA2, IF1, 0x0000); | |
CAN_IF_Write(DB1, IF1, 0x0000); | |
CAN_IF_Write(DB2, IF1, 0x0000); | |
CAN_IF_Write(ARB2, IF1, ID_MVAL | ((rx_id) << 2)); | |
/* Transfer data to message RAM */ | |
CAN_IF_writeBuf(IF1, msg_no); | |
} | |
else{ | |
rx_id &= (0x1<<30)-1 ; /* Mask ID bit */ | |
/* Mxtd: 1, Mdir: 0, Mask is 0x1FFFFFFF */ | |
CAN_IF_Write(MSK1, IF1, ID_EXT_MASK & 0xFFFF); | |
CAN_IF_Write(MSK2, IF1, MASK_MXTD | (ID_EXT_MASK >> 16)); | |
/* MsgVal: 1, Mtd: 1, Dir: 0 */ | |
CAN_IF_Write(ARB1, IF1, (rx_id) & 0xFFFF); | |
CAN_IF_Write(MCTRL, IF1, rmten|UMSK|RXIE|EOB|CAN_DLC_MAX); | |
CAN_IF_Write(DA1, IF1, 0x0000); | |
CAN_IF_Write(DA2, IF1, 0x0000); | |
CAN_IF_Write(DB1, IF1, 0x0000); | |
CAN_IF_Write(DB2, IF1, 0x0000); | |
CAN_IF_Write(ARB2, IF1, ID_MVAL | ID_MTD | ((rx_id) >> 16)); | |
/* Transfer data to message RAM */ | |
CAN_IF_writeBuf(IF1, msg_no); | |
} | |
return; | |
} | |
/*********************************************************************//** | |
* @brief Read a message from Message RAM to buffer | |
* @param[in] msg_no message object number | |
* @param[in] buff msg buffer pointer | |
* @return None | |
**********************************************************************/ | |
void CAN_ReadMsg(uint32_t msg_no, message_object* buff){ | |
int i; | |
buff->id = recv_buff.id; | |
buff->dlc = recv_buff.dlc; | |
if(recv_buff.dlc>CAN_DLC_MAX) recv_buff.dlc = CAN_DLC_MAX; | |
for(i=0;i<recv_buff.dlc;i++) | |
buff->data[i] = recv_buff.data[i]; | |
} | |
#endif /* _C_CAN*/ | |
/** | |
* @} | |
*/ | |
/* --------------------------------- End Of File ------------------------------ */ | |