📄 can_hw.c
字号:
/*----------------------------------------------------------------------------
* A R T X - C A N D r i v e r - H a r d w a r e L a y e r
*----------------------------------------------------------------------------
* Name: CAN_Hw.c
* Purpose: CAN Driver, Hardware specific module for LPC2xxx
* Rev.: V0.20 / october-14-2005
*----------------------------------------------------------------------------
* This code is part of the ARTX-ARM kernel package of Keil Software.
* Copyright (c) 2004-2005 Keil Software. All rights reserved.
*---------------------------------------------------------------------------*/
#include <ARTX.h> /* ARTX kernel functions & defines */
#include <LPC21xx.h> /* LPC21xx definitions */
#include "ARTX_CAN.h" /* CAN Generic functions & defines */
#include "CAN_hw.h" /* CAN hw specific functions & defines */
#include "CAN_reg.h" /* LPC2xxx CAN registers */
/* Values of bit time register for different baudrates
NT = Nominal bit time = TSEG1 + TSEG2 + 3
SP = Sample point = ((TSEG2 +1) / (TSEG1 + TSEG2 + 3)) * 100%
SAM, SJW, TSEG1, TSEG2, NT, SP */
const U32 CAN_BIT_TIME[] = { 0, /* not used */
0, /* not used */
0, /* not used */
0, /* not used */
0x0001C000, /* 0+1, 3+1, 1+1, 0+1, 4, 75% */
0, /* not used */
0x0012C000, /* 0+1, 3+1, 2+1, 1+1, 6, 67% */
0, /* not used */
0x0023C000, /* 0+1, 3+1, 3+1, 2+1, 8, 63% */
0, /* not used */
0x0025C000, /* 0+1, 3+1, 5+1, 2+1, 10, 70% */
0, /* not used */
0x0036C000, /* 0+1, 3+1, 6+1, 3+1, 12, 67% */
0, /* not used */
0, /* not used */
0x0048C000, /* 0+1, 3+1, 8+1, 4+1, 15, 67% */
0x0049C000, /* 0+1, 3+1, 9+1, 4+1, 16, 69% */
};
unsigned char PutString(unsigned char *p);
//#define AFMR (*((volatile unsigned long *) 0xE003C000))
extern unsigned short Can2RxOK;
/*----------------------------------------------------------------------------
* CAN ARTX Hardware Specific Driver Functions for LPC2xxx
*----------------------------------------------------------------------------
* Functions implemented in this module:
* CAN_ERROR CAN_hw_setup (void)
* static U32 CAN_calc_baudrate (U32 baudrate)
* CAN_ERROR CAN_hw_init (U32 ctrl, U32 baudrate)
* CAN_ERROR CAN_hw_start (U32 ctrl)
* CAN_ERROR CAN_hw_tx_empty (U32 ctrl)
* CAN_ERROR CAN_hw_wr (U32 ctrl, CAN_msg *msg)
* static void CAN_hw_rd (U32 ctrl, CAN_msg *msg)
* CAN_ERROR CAN_hw_set (U32 ctrl, CAN_msg *msg)
* CAN_ERROR CAN_hw_rx_object (U32 ctrl, U32 ch, U32 id, CAN_FORMAT format)
* CAN_ERROR CAN_hw_tx_object (U32 ctrl, U32 ch, CAN_FORMAT format)
* Interrupt fuctions
*---------------------------------------------------------------------------*/
/* Static functions used only in this module */
static U32 CAN_calc_baudrate (U32 baudrate);
static void CAN_hw_rd (U32 ctrl, CAN_msg *msg);
static void CAN_TX1_ISR (void) __irq;
static void CAN_RX1_ISR (void) __irq;
static void CAN_TX2_ISR (void) __irq;
static void CAN_RX2_ISR (void) __irq;
static void CAN_TX3_ISR (void) __irq;
static void CAN_RX3_ISR (void) __irq;
static void CAN_TX4_ISR (void) __irq;
static void CAN_RX4_ISR (void) __irq;
/*--------------------------- CAN_hw_setup ----------------------------------
*
* Setup CAN transmit and receive PINs and interrupt vectors
*
* Parameter: none
*
* Return: CAN_ERROR: Error code
*---------------------------------------------------------------------------*/
CAN_ERROR CAN_hw_setup (void) {
#if USE_CAN_CTRL1 == 1
PINSEL1 &= 0xFFEBFFFF; /* Reset CAN1 bits */
PINSEL1 |= 0x00040000; /* Set CAN1 bits to 01 */
/* Set interrupt vector for Tx1 */
*(&VICVectAddr0 + VIC_NUM_CTRL1_TX) = (unsigned long) CAN_TX1_ISR;
*(&VICVectCntl0 + VIC_NUM_CTRL1_TX) = 0x20 | 20;
/* Set interrupt vector for Rx1 */
*(&VICVectAddr0 + VIC_NUM_CTRL1_RX) = (unsigned long) CAN_RX1_ISR;
*(&VICVectCntl0 + VIC_NUM_CTRL1_RX) = 0x20 | 26;
VICIntEnable |= 0x04100000; /* Enable CAN Tx1 and Rx1 Interrupt */
#endif
#if USE_CAN_CTRL2 == 1
PINSEL1 &= 0xFFFC3FFF; /* Reset CAN2 bits */
PINSEL1 |= 0x00014000; /* Set CAN2 bits to 11 */
/* Set interrupt vector for Tx2 */
*(&VICVectAddr0 + VIC_NUM_CTRL2_TX) = (unsigned long) CAN_TX2_ISR;
*(&VICVectCntl0 + VIC_NUM_CTRL2_TX) = 0x20 | 21;
/* Set interrupt vector for Rx2 */
*(&VICVectAddr0 + VIC_NUM_CTRL2_RX) = (unsigned long) CAN_RX2_ISR;
*(&VICVectCntl0 + VIC_NUM_CTRL2_RX) = 0x20 | 27;
VICIntEnable |= 0x08200000; /* Enable CAN Tx2 and Rx2 Interrupt */
#endif
#if USE_CAN_CTRL3 == 1
PINSEL1 &= 0xFFFFC3FF; /* Reset CAN3 bits */
PINSEL1 |= 0x00001800; /* Set CAN3 bits to 11 */
/* Set interrupt vector for Tx3 */
*(&VICVectAddr0 + VIC_NUM_CTRL3_TX) = (unsigned long) CAN_TX3_ISR;
*(&VICVectCntl0 + VIC_NUM_CTRL3_TX) = 0x20 | 22;
/* Set interrupt vector for Rx3 */
*(&VICVectAddr0 + VIC_NUM_CTRL3_RX) = (unsigned long) CAN_RX3_ISR;
*(&VICVectCntl0 + VIC_NUM_CTRL3_RX) = 0x20 | 28;
VICIntEnable = 0x10400000; /* Enable CAN Tx3 and Rx3 Interrupt */
#endif
#if USE_CAN_CTRL4 == 1
PINSEL0 &= 0xF0FFFFFF; /* Reset CAN4 bits */
PINSEL0 |= 0x0F000000; /* Set CAN4 bits to 1111 */
/* Set interrupt vector for Tx4 */
*(&VICVectAddr0 + VIC_NUM_CTRL4_TX) = (unsigned long) CAN_TX4_ISR;
*(&VICVectCntl0 + VIC_NUM_CTRL4_TX) = 0x20 | 23;
/* Set interrupt vector for Rx4 */
*(&VICVectAddr0 + VIC_NUM_CTRL4_RX) = (unsigned long) CAN_RX4_ISR;
*(&VICVectCntl0 + VIC_NUM_CTRL4_RX) = 0x20 | 29;
VICIntEnable = 0x20800000; /* Enable CAN Tx4 and Rx4 Interrupt */
#endif
return CAN_OK;
}
/*--------------------------- CAN_calc_baudrate -----------------------------
*
* Calculate baudrate register value for requested baudrate
*
* Parameter: baudrate: Baudrate
*
* Return: U32: Bitrate register value
*---------------------------------------------------------------------------*/
static U32 CAN_calc_baudrate (U32 baudrate) {
U32 result = 0;
U32 nominal_time;
/* Determine which nominal time to use for PCLK and baudrate */
if (baudrate <= 500000) {
nominal_time = 12;
} else if (((PCLK / 1000000) % 15) == 0) {
nominal_time = 15;
} else if (((PCLK / 1000000) % 16) == 0) {
nominal_time = 16;
} else {
nominal_time = 10;
}
/* Prepare value appropriate for bit time register */
result = (PCLK / nominal_time) / baudrate - 1;
result &= 0x000003FF;
result |= CAN_BIT_TIME[nominal_time];
return result;
}
/*--------------------------- CAN_hw_init -----------------------------------
*
* Initialize the CAN hardware
*
* Parameter: ctrl: Index of the hardware CAN controller (1 .. x)
* baudrate: Baudrate
*
* Return: CAN_ERROR: Error code
*---------------------------------------------------------------------------*/
#define AFMReg (*((volatile unsigned long *) 0xE003C000))
CAN_ERROR CAN_hw_init (U32 ctrl, U32 baudrate)
{
#if(CAN_REG_USE_POINT)
U32 ctrl0 = ctrl-1; /* Controller index 0 .. x-1 */
regCAN_AF *ptrcan_af = CAN_AF_BASE;
regCAN *ptrcan = (regCAN *) CAN_BASE[ctrl0];
ptrcan_af->AFMR = 1; /* Disable acceptance filter */
ptrcan->CANMOD = 1; /* Enter reset mode */
ptrcan->CANMOD = 1;
ptrcan->CANMOD = 1;
os_dly_wait(1);
ptrcan->CANIER = 0; /* Disable all interrupts */
ptrcan->CANGSR = 0; /* Clear status register */
ptrcan->CANBTR = CAN_calc_baudrate(baudrate); /* Set bit timing */
ptrcan->CANIER = 0xffffff;//0x0603; /* Enable Tx and Rx interrupt */
#else
if(ctrl == 1)
{
C1MOD = 1;
C1EWL = 0x60;
C2IER = 0;
C1GSR = 0;
C1BTR = CAN_calc_baudrate(baudrate);
AFMReg = 0x00000002L;
C1IER = 0x0603;
}
else if(ctrl ==2)
{
C2MOD = 1;
C2EWL = 0x60;
C2IER = 0;
C2GSR = 0;
C2BTR = CAN_calc_baudrate(baudrate);
C2IER = 0x0603;
}
#endif
return CAN_OK;
}
/*--------------------------- CAN_hw_start ----------------------------------
*
* Enable the CAN interrupts (recive or/and transmit)
*
* Parameter: ctrl: Index of the hardware CAN controller (1 .. x)
*
* Return: CAN_ERROR: Error code
*---------------------------------------------------------------------------*/
CAN_ERROR CAN_hw_start (U32 ctrl)
{
#if(CAN_REG_USE_POINT)
U32 ctrl0 = ctrl-1; s /* Controller index 0 .. x-1 */
regCAN *ptrcan = (regCAN *) CAN_BASE[ctrl0];
ptrcan->CANMOD = 0x06; /* Enter normal operating mode */
#else
#if(CAN_TEST_STATUS_TO_UART0)
GetCanRegValue();
#endif
if(ctrl == 1)
C1MOD = 0x86;
else if(ctrl == 2)
C2MOD = 0x86;
#endif
return CAN_OK;
}
/*--------------------------- CAN_hw_tx_empty -------------------------------
*
* Check if controller is available for transmission
*
* Parameter: ctrl: Index of the hardware CAN controller (1 .. x)
*
* Return: CAN_ERROR: Error code
*---------------------------------------------------------------------------*/
CAN_ERROR CAN_hw_tx_empty (U32 ctrl) {
U32 ctrl0 = ctrl-1; /* Controller index 0 .. x-1 */
regCAN *ptrcan = (regCAN *) CAN_BASE[ctrl0];
if (!(ptrcan->CANSR & 0x00000004)) /* Transmitter 1 busy */
return CAN_TX_BUSY_ERROR;
return CAN_OK;
}
/*--------------------------- CAN_hw_wr -------------------------------------
*
* Write CAN_msg to the hardware registers of the requested controller
*
* Parameter: ctrl: Index of the hardware CAN controller (1 .. x)
* msg: Pointer to CAN message to be written to hardware
*
* Return: CAN_ERROR: Error code
*---------------------------------------------------------------------------*/
CAN_ERROR CAN_hw_wr (U32 ctrl, CAN_msg *msg) {
U32 ctrl0 = ctrl-1; /* Controller index 0 .. x-1 */
U32 CANData;
regCAN *ptrcan = (regCAN *) CAN_BASE[ctrl0];
CANData = (((U32) msg->len) << 16) & 0x000F0000 |
(msg->format == EXTENDED_FORMAT ) * 0x80000000 |
(msg->type == REMOTE_FRAME) * 0x40000000;
if (ptrcan->CANSR & 0x00000004) /* Transmit buffer 1 free */
{
#if(CAN_TEST_STATUS_TO_UART0)
PutString("Can Transmit buffer 1 free!\r\n\0");
#endif
ptrcan->CANTF1 = CANData; /* Write frame informations */
ptrcan->CANTID1 = msg->id; /* Write CAN message identifier */
ptrcan->CANTDA1 = *(U32 *) &msg->data[0]; /* Write first 4 data bytes */
ptrcan->CANTDB1 = *(U32 *) &msg->data[4]; /* Write second 4 data bytes */
ptrcan->CANCMR = 0x30; /* Start self-transmission */
}
else
return CAN_TX_BUSY_ERROR;
return CAN_OK;
}
/*--------------------------- CAN_hw_rd -------------------------------------
*
* Read CAN_msg from the hardware registers of the requested controller
*
* Parameter: ctrl: Index of the hardware CAN controller (1 .. x)
* msg: Pointer where CAN message will be read
*
* Return: CAN_ERROR: Error code
*---------------------------------------------------------------------------*/
static void CAN_hw_rd (U32 ctrl, CAN_msg *msg) {
U32 ctrl0 = ctrl-1; /* Controller index 0 .. x-1 */
U32 CANData;
U32 *CANAddr;
regCAN *ptrcan = (regCAN *) CAN_BASE[ctrl0];
/* Read frame informations */
CANData = ptrcan->CANRFS;
msg->format = (CANData & 0x80000000) == 0x80000000;
msg->type = (CANData & 0x40000000) == 0x40000000;
msg->len = ((U8)(CANData >> 16)) & 0x0F;
/* Read CAN message identifier */
msg->id = ptrcan->CANRID;
/* Read the data if received message was DATA FRAME */
if (msg->type == DATA_FRAME) {
/* Read first 4 data bytes */
CANAddr = (U32 *) &msg->data[0];
*CANAddr++ = ptrcan->CANRDA;
/* Read second 4 data bytes */
*CANAddr = ptrcan->CANRDB;
}
}
/*--------------------------- CAN_hw_set ------------------------------------
* Set a message that will automatically be sent as an answer to the REMOTE
* FRAME message, as this functionality is not enabled by hardware this
* function is not implemented
*
* Parameter: ctrl: Ignorred
* msg: Pointer to CAN message to be set
*
* Return: CAN_ERROR: Error code
*---------------------------------------------------------------------------*/
CAN_ERROR CAN_hw_set (U32 ctrl, CAN_msg *msg) {
ctrl = ctrl; /* To avoid compiler warning */
msg = msg; /* "unreferenced parameter" */
return CAN_NOT_IMPLEMENTED_ERROR;
}
/*--------------------------- CAN_hw_rx_object ------------------------------
*
* Enable reception of messages, on specified controller with specified
* identifier, by setting acceptance filter
*
* Parameter: ctrl: Index of the hardware CAN controller (1 .. x)
* ch: Ignorred for LPC2xxx
* id: CAN message identifier
* CAN_FORMAT: Format of CAN identifier (standard or extended)
*
* Return: CAN_ERROR: Error code
*---------------------------------------------------------------------------*/
CAN_ERROR CAN_hw_rx_object (U32 ctrl, U32 ch, U32 id, CAN_FORMAT format) {
static S16 CAN_std_cnt = 0;
static S16 CAN_ext_cnt = 0;
regCAN_AF *ptrcan_af = CAN_AF_BASE;
regCAN_AFRAM *ptrcan_afram = CAN_AFRAM_BASE;
U32 buf0, buf1;
S16 cnt1, cnt2, bound1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -