SJA1000 是一种独立控制器,用于移动目标和一般工业环境中的区域网络控制(CAN),它是PHILIPS半导体PCA82C200 CAN 控制器BasicCAN 的替代产品而且它增加了一种新的工作模式PeliCAN, 这种模式支持具有很多新特性的CAN 2.0B 协议.
系统采用两路SJA1000。分别对应at91rm9200的IRQ0和IRQ1脚中断。中断时采用回调的方式调用上层的处理程序,同时缓冲区也在上层应用程序中。
上层应用程序的使用例子
/*******************************************************************************************/
#include "vxWorks.h"
#include "errnoLib.h"
#include "taskLib.h"
#include "intLib.h"
#include "netLib.h"
#include "iv.h"
#include "sysLib.h"
#include "logLib.h"
#include "CAN_Drv.h"
uchar chRecvData[11]={'0','1','2','3','4','5','6','7','8'};
uchar chSendData[8];
STATUS hook_Display(uchar* pDataBuf){
uchar DLC = 0,i;
DLC = (uchar)*pDataBuf&0xf;
for(i=0;i<DLC;i++)
logMsg("Hook: %d - %3d/n",i+1,*((pDataBuf++)+3),0,0,0,0);
}
void main(){
InstallHook(hook_Display,chRecvData);
Open_Can(1);
Open_Can(2);
}
void Send(){
uchar i = 0;
for(i=0;i<8;i++)
chSendData[i] = 4*i+1;
Send_Can(1,0,0,i,0,5,0,0,0,chSendData);
}
SJA1000底层驱动部分
/*******************************************************************************************/
#include "vxWorks.h"
#include "errnoLib.h"
#include "taskLib.h"
#include "intLib.h"
#include "netLib.h"
#include "iv.h"
#include "sysLib.h"
#include "logLib.h"
#include "CAN_Drv.h"
#ifdef _DEBUG
#define DebugPrint(x) logMsg(x,0,0,0,0,0,0)
char chTestData[8] = {'1','2','3','4','5','6','7','8'};
#else
#define DebugPrint(x) ;
#endif
STATUS ClearPIOOutput(AT91S_PIO* PIO,uint bitFlag);
STATUS SetPIOOutput(AT91S_PIO* PIO,uint bitFlag);
STATUS SetCanParam(uchar channel);
STATUS SetCanISR(uchar channel);
STATUS Reset_Can(uchar channel);
STATUS Open_Can(uchar channel);
STATUS Close_Can(uchar channel);
STATUS Send_Can(uchar channel,
uchar FF,uchar RTR,uchar DLC,
uchar DIR,uchar SA,uchar BBC,
uchar MA, uchar RW,
uchar* pCanSendData);
STATUS Recv_Can(uchar channel, char* pCanRecvBuf );
STATUS RecvInt_Can(uchar channel);
STATUS (*RecvHook)(uchar* pDataBuf);
uchar* pchFrameData;
/******************************************************
* 在上层调用的时候处理CAN的接收数据
******************************************************/
void InstallHook(STATUS (*Hookfunc)(uchar*), uchar* pDataBuf){
RecvHook = Hookfunc;
pchFrameData = pDataBuf;
}
/******************************************************
* 写SJA1000的寄存器
******************************************************/
void CAN_ByteWrite(uchar channel, uchar Reg, uchar Val){
if(channel == 1){
*(unsigned char*)CAN1_Port = Reg;
*(unsigned char*)CAN1_Data = Val;
}
else if(channel == 2){
*(unsigned char*)CAN2_Port = Reg;
*(unsigned char*)CAN2_Data = Val;
}
else
DebugPrint("Err in func CAN_ByteWrite() - channel is not correct!/n");
}
/******************************************************
* 读SJA1000的寄存器
******************************************************/
uchar CAN_ByteRead(uchar channel, uchar Reg){
if(channel == 1){
*(unsigned char*)CAN1_Port = Reg;
return (*(unsigned char*)CAN1_Data);
}
else if(channel == 2){
*(unsigned char*)CAN2_Port = Reg;
return (*(unsigned char*)CAN2_Data);
}
else
DebugPrint("Err in func CAN_ByteRead() - channel is not correct!/n");
}
/******************************************************
* SJA1000的中断处理函数
******************************************************/
STATUS ISR_Can(uchar channel){
//logMsg("channel-%d ISR is active : %d/n",channel,CAN_ByteRead(channel,Reg_Int),0,0,0,0);
uchar chISR = 0 , i;
uchar chData[8];
RxMsgFrameHeader rxHeader;
chISR = CAN_ByteRead(channel,Reg_Int);
/* Transmit Interrupt */
if(chISR & IR_TI);
/* Error Warning Interrupt */
else if(chISR & IR_EI);
/* Data Overrun Interrupt */
else if(chISR & IR_DOI);
/* Wakeup Interrupt */
else if(chISR & IR_WUI);
/* Error Passive Interrupt */
else if(chISR & IR_EPI);
/* Arbitration Lost Interrupt */
else if(chISR & IR_ALI);
/* Bus Error Interrupt */
else if(chISR & IR_BEI);
/* Receive Interrupt */
else if(chISR & IR_RI)
netJobAdd((FUNCPTR)RecvInt_Can,channel,0,0,0,0);
}
//测试代码
STATUS Send_Test(){
Send_Can(2,0,0,8,0,0,0,0,0,chTestData);
}
/******************************************************
* CAN的发送程序,按照CAMS3000的CAN协议
******************************************************/
STATUS Send_Can(uchar channel,
uchar FF,uchar RTR,uchar DLC,
uchar DIR,uchar SA,uchar BBC,
uchar MA, uchar RW,
uchar* pCanSendData){
TxMsgFrameHeader txHeader;
char i=0;
if(DLC > 8) return (ERROR);
txHeader.TxFrameInfo = TX_FRAME_INFO(FF,RTR,DLC);
txHeader.TxIdentifier1= CAMS3K_TX_ID1(DIR,SA,BBC);
txHeader.TxIdentifier2= CAMS3K_TX_ID2(MA,RW);
CAN_ByteWrite(channel,Reg_TxFrameInfo, txHeader.TxFrameInfo);
CAN_ByteWrite(channel,Reg_TxIdentifier1,txHeader.TxIdentifier1);
CAN_ByteWrite(channel,Reg_TxIdentifier2,txHeader.TxIdentifier2);
for(i=0;i<DLC;i++)
CAN_ByteWrite(channel,Reg_TxDataByte1+i,pCanSendData[i]);
CAN_ByteWrite(channel,Reg_CMD,CMR_TR);
return(OK);
}
/******************************************************
* CAN的中断接收函数
******************************************************/
STATUS RecvInt_Can(uchar channel){
Recv_Can(channel,pchFrameData);
RecvHook(pchFrameData);
}
/******************************************************
* CAN的接收函数,用于轮询读取
******************************************************/
STATUS Recv_Can(uchar channel,
uchar* pCanRecvBuf){
uchar chData[8];
RxMsgFrameHeader rxHeader;
char DLC,i=0;
/* Get frame header */
rxHeader.RxFrameInfo = CAN_ByteRead(channel,Reg_TxFrameInfo);
rxHeader.RxIdentifier1 = CAN_ByteRead(channel,Reg_TxIdentifier1);
rxHeader.RxIdentifier2 = CAN_ByteRead(channel,Reg_TxIdentifier2);
/* Get frame data */
DLC = MSG_GET_DLC(rxHeader.RxFrameInfo);
for(i=0;i<DLC;i++)
chData[i] = CAN_ByteRead(channel,Reg_TxDataByte1+i);
/* Release buffer */
CAN_ByteWrite(channel,Reg_CMD,CMR_RRB);
memcpy(pCanRecvBuf , &rxHeader.RxFrameInfo,3);
memcpy(pCanRecvBuf+3, chData,DLC);
}
/******************************************************
* CAN设备打开
******************************************************/
STATUS Open_Can(uchar channel){
if((channel == 1)||(channel == 2)){
Reset_Can(channel);
SetCanParam(channel);
SetCanISR(channel);
intEnable(AT91C_ID_IRQ0+(channel-1));
}
else
DebugPrint("Err in func Open_Can() - channel is not correct!/n");
}
/******************************************************
* CAN设备关闭
******************************************************/
STATUS Close_Can(uchar channel){
Reset_Can(channel);
CAN_ByteWrite(channel,Reg_intEn,0x0);
intDisable( AT91C_ID_IRQ0+(channel-1) );
}
/******************************************************
* 设置CAN设备参数
* 采用dual filter、peliCAN模式
******************************************************/
STATUS SetCanParam(uchar channel){
CAN_ByteWrite(channel,Reg_MODE,MOD_RM);
CAN_ByteWrite(channel,Reg_ClkDivider,CDR_PELICAN_MODE);
if( CAN_ByteRead(channel,Reg_ClkDivider)& CDR_PELICAN_MODE){
/* The Acceptance Mask Register is working at the Dual filter mode */
CAN_ByteWrite( channel, Reg_AcceptMask0, 0xFF ); /* filtrate to msb */
CAN_ByteWrite( channel, Reg_AcceptMask1, 0xFF );
CAN_ByteWrite( channel, Reg_AcceptMask2, 0xFF ); /* filtrate to msb */
CAN_ByteWrite( channel, Reg_AcceptMask3, 0xFF );
CAN_ByteWrite( channel, Reg_AcceptCode0, 0x80 );
CAN_ByteWrite( channel, Reg_AcceptCode2, 0x80 );
/* Setup the Bus Timing Register 0 & 1 */
CAN_ByteWrite( channel, Reg_BusTim0, (uchar)( /*CAN_BAUT_RATE*/(0x14) >> 8 ));
CAN_ByteWrite( channel, Reg_BusTim1, (uchar)( /*CAN_BAUT_RATE*/(0x14) & 0xFF ));
/* Setup Output Control Register */
CAN_ByteWrite( channel, Reg_OutputCtrl, 0x4A );
CAN_ByteWrite( channel, Reg_intEn, 0xFD ); /* Disable transmit interrupt */
/* Exit reset mode */
CAN_ByteWrite( channel, Reg_MODE, 0x00 );
}
}
/******************************************************
* 设置CAN设备中断
******************************************************/
STATUS SetCanISR(uchar channel){
if(channel == 1){
/* Disable CAN 1 interrupt */
intDisable( AT91C_ID_IRQ0 );
/* Set intrrupt attr. & level of AT91C_ID_IRQ0 */
*((volatile unsigned int *)0xFFFFF064) = 0x20;
/* install CAN 1 ISRs */
intConnect((void *)AT91C_ID_IRQ0,(void*)ISR_Can,1 );
}
else if(channel == 2){
/* Disable CAN 2 interrupt */
intDisable( AT91C_ID_IRQ1 );
/* Set intrrupt attr. & level of AT91C_ID_IRQ1 */
*((volatile unsigned int *)0xFFFFF068) = 0x20;
/* install CAN 2 ISRs */
intConnect((void *)AT91C_ID_IRQ1,(void*)ISR_Can,2 );
}
}
STATUS Reset_Can(uchar channel){
if(channel == 1){
ClearPIOOutput(AT91C_BASE_PIOB,PIOB_PB6);
taskDelay(sysClkRateGet()/10);
SetPIOOutput(AT91C_BASE_PIOB,PIOB_PB6);
}
else if(channel == 2){
ClearPIOOutput(AT91C_BASE_PIOB,PIOB_PB7);
taskDelay(sysClkRateGet()/10);
SetPIOOutput(AT91C_BASE_PIOB,PIOB_PB7);
}
else
DebugPrint("Err in func Reset_Can() - channel is not correct!/n");
}
STATUS ClearPIOOutput(AT91S_PIO* PIO,uint bitFlag){
PIO->PIO_PER |= bitFlag;
PIO->PIO_PUER |= bitFlag;
PIO->PIO_OER |= bitFlag;
PIO->PIO_CODR |= bitFlag;
}
STATUS SetPIOOutput(AT91S_PIO* PIO,uint bitFlag){
PIO->PIO_PER |= bitFlag;
PIO->PIO_PUER |= bitFlag;
PIO->PIO_OER |= bitFlag;
PIO->PIO_SODR |= bitFlag;
}
对应的头文件
/***************************************************************************************/
#ifndef _CAN_SJA1K_H
#define _CAN_SJA1K_H
#define _DEBUG
#define CAN1_Port (0x50000000)
#define CAN1_Data (0x50000100)
#define CAN2_Port (0x50000200)
#define CAN2_Data (0x50000300)
#define AT91C_ID_IRQ0 ((unsigned int) 25) /* Advanced Interrupt Controller (IRQ0)*/
#define AT91C_ID_IRQ1 ((unsigned int) 26) /* Advanced Interrupt Controller (IRQ1)*/
/* registers */
#define Reg_MODE 0
#define Reg_CMD 1
#define Reg_Status 2
#define Reg_Int 3
#define Reg_intEn 4
#define Reg_BusTim0 6
#define Reg_BusTim1 7
#define Reg_OutputCtrl 8
#define Reg_Test 9
#define Reg_ArbiLostCap 11
#define Reg_ErrCodeCap 12
#define Reg_ErrWarnCap 13
#define Reg_RxErrCounter 14
#define Reg_TxErrCounter 15
#define Reg_AcceptCode0 16
#define Reg_AcceptCode1 17
#define Reg_AcceptCode2 18
#define Reg_AcceptCode3 19
#define Reg_AcceptMask0 20
#define Reg_AcceptMask1 21
#define Reg_AcceptMask2 22
#define Reg_AcceptMask3 23
#define Reg_ClkDivider 31
#define Reg_TxFrameInfo 16
#define Reg_TxIdentifier1 17
#define Reg_TxIdentifier2 18
#define Reg_TxDataByte1 19
/* mode register bits */
#define MOD_RM 0x01
#define MOD_LOM 0x02
#define MOD_STM 0x04
#define MOD_AFM 0x08
#define MOD_SM 0x10
/* command register bits */
#define CMR_TR 0x01
#define CMR_AT 0x02
#define CMR_RRB 0x04
#define CMR_CDO 0x08
#define CMR_SRR 0x10
/* status register bits */
#define SJA1000_SR_RBS 0x01
#define SJA1000_SR_DOS 0x02
#define SJA1000_SR_TBS 0x04
#define SJA1000_SR_TCS 0x08
#define SJA1000_SR_RS 0x10
#define SJA1000_SR_TS 0x20
#define SJA1000_SR_ES 0x40
#define SJA1000_SR_BS 0x80
/* interrupt register bits */
#define IR_RI 0x01
#define IR_TI 0x02
#define IR_EI 0x04
#define IR_DOI 0x08
#define IR_WUI 0x10
#define IR_EPI 0x20
#define IR_ALI 0x40
#define IR_BEI 0x80
/* interrupt enable register bits */
#define IER_RIE 0x01
#define IER_TIE 0x02
#define IER_EIE 0x04
#define IER_DOIE 0x08
#define IER_WUIE 0x10
#define IER_EPIE 0x20
#define IER_ALIE 0x40
#define IER_BEIE 0x80
/* error code capture register */
#define ECC_SEG0 0x01
#define ECC_SEG1 0x02
#define ECC_SEG2 0x04
#define ECC_SEG3 0x08
#define ECC_SEG4 0x10
#define ECC_DIR 0x20
#define ECC_ERRC0 0x40
#define ECC_ERCC1 0x80
/* clock divider register */
#define CDR_PELICAN_MODE 0x80
/* max number of message objects for sja1000 */
#define SJA1000_MAX_MSG_OBJ 2
/* sja1000 channel types */
#define TX_CHN_NUM 0
#define RX_CHN_NUM 1
extern const UINT g_sja1000chnType[SJA1000_MAX_MSG_OBJ];
typedef unsigned int uint;
typedef unsigned char uchar;
typedef struct _CAN_FUNCS{
FUNCPTR (*Can_Open) (void);
FUNCPTR (*Can_Close)(void);
FUNCPTR (*Can_Write)(void);
FUNCPTR (*Can_Read) (void);
FUNCPTR (*Can_Ctrl) (void);
FUNCPTR (*Can_Load) (void);
FUNCPTR (*Can_Hook_ISRRead)(void);
}CanFuncs,*pCanFuncs;
typedef struct _CAN_DEV_DESC{
int unit; /* unit number */
CanFuncs funcs;
UINT32 CanJobDoing;
}CanDevDesc,*pCanDevDesc;
/*************************************************
* Tx Msg Structure
*************************************************/
typedef struct _TxMsgFrameHeader{
UCHAR TxFrameInfo; /* Tx frame Information : FF|RTR|Reserver[2]|DLC.3|DLC.2|DLC.1|DLC.0*/
UCHAR TxIdentifier1; /* Tx Identifier1 */
UCHAR TxIdentifier2; /* Tx Identifier2 : ID.20|ID.19|ID.18| X[5] */
} TxMsgFrameHeader,*pTxMsgFrameHeader;
#define TX_FRAME_INFO(FF,RTR,DLC) (((FF&0x1)<<7) | ((RTR&0x1)<<6) | ((DLC&0xf)<<0))
#define CAMS3K_TX_ID1(DIR,SA,BBC) (((DIR&0x1)<<7)| ((SA&0x3f)<<1) | ((BBC&0x1)<<0))
#define CAMS3K_TX_ID2(MA,RW) (((MA&0x3)<<6) | ((RW &0x1)<<5))
/*************************************************
* Rx Msg Structure
*************************************************/
typedef struct _RxMsgFrameHeader{
UCHAR RxFrameInfo; /* Rx frame Information : FF|RTR|0|0|DLC.3|DLC.2|DLC.1|DLC.0*/
UCHAR RxIdentifier1; /* Rx Identifier1 */
UCHAR RxIdentifier2; /* Rx Identifier2 : ID.20|ID.19|ID.18|0|0|0|0|0 */
} RxMsgFrameHeader,*pRxMsgFrameHeader;
#define MSG_GET_DLC(RxFrameInfo) ((RxFrameInfo>>0) & 0xf)
#define MSG_GET_FF(RxFrameInfo) ((RxFrameInfo>>7) & 0x1)
#define MSG_GET_RTR(RxFrameInfo) ((RxFrameInfo>>6) & 0x1)
#define MSG_GET_DIR(RxIdentifier1) ((RxIdentifier1>>7) & 0x1)
#define MSG_GET_SA(RxIdentifier1) ((RxIdentifier1>>1) & 0x3f)
#define MSG_GET_BBC(RxIdentifier1) ((RxIdentifier1>>0) & 0x1)
#define MSG_GET_MA(RxIdentifier2) ((RxIdentifier2>>6) & 0x3)
#define MSG_GET_RW(RxIdentifier2) ((RxIdentifier2>>5) & 0x1)
/* IO Pin */
#define PIOB_PB6 (0x1<<6)
#define PIOB_PB7 (0x1<<7)
typedef volatile unsigned int AT91_REG; /* Hardware register definition*/
/* PIO structure */
typedef struct _AT91S_PIO {
AT91_REG PIO_PER; /* PIO Enable Register*/
AT91_REG PIO_PDR; /* PIO Disable Register*/
AT91_REG PIO_PSR; /* PIO Status Register*/
AT91_REG Reserved0[1]; /* */
AT91_REG PIO_OER; /* Output Enable Register*/
AT91_REG PIO_ODR; /* Output Disable Registerr*/
AT91_REG PIO_OSR; /* Output Status Register*/
AT91_REG Reserved1[1]; /* */
AT91_REG PIO_IFER; /* Input Filter Enable Register*/
AT91_REG PIO_IFDR; /* Input Filter Disable Register*/
AT91_REG PIO_IFSR; /* Input Filter Status Register*/
AT91_REG Reserved2[1]; /* */
AT91_REG PIO_SODR; /* Set Output Data Register*/
AT91_REG PIO_CODR; /* Clear Output Data Register*/
AT91_REG PIO_ODSR; /* Output Data Status Register*/
AT91_REG PIO_PDSR; /* Pin Data Status Register*/
AT91_REG PIO_IER; /* Interrupt Enable Register*/
AT91_REG PIO_IDR; /* Interrupt Disable Register*/
AT91_REG PIO_IMR; /* Interrupt Mask Register*/
AT91_REG PIO_ISR; /* Interrupt Status Register*/
AT91_REG PIO_MDER; /* Multi-driver Enable Register*/
AT91_REG PIO_MDDR; /* Multi-driver Disable Register*/
AT91_REG PIO_MDSR; /* Multi-driver Status Register*/
AT91_REG Reserved3[1]; /* */
AT91_REG PIO_PUDR; /* Pull-up Disable Register*/
AT91_REG PIO_PUER; /* Pull-up Enable Register*/
AT91_REG PIO_PUSR; /* Pad Pull-up Status Register*/
AT91_REG Reserved4[1]; /* */
AT91_REG PIO_ASR; /* Select A Register*/
AT91_REG PIO_BSR; /* Select B Register*/
AT91_REG PIO_ABSR; /* AB Select Status Register*/
AT91_REG Reserved5[9]; /* */
AT91_REG PIO_OWER; /* Output Write Enable Register*/
AT91_REG PIO_OWDR; /* Output Write Disable Register*/
AT91_REG PIO_OWSR; /* Output Write Status Register*/
} AT91S_PIO, *AT91PS_PIO;
#define AT91C_BASE_PIOB ((AT91PS_PIO) 0xFFFFF600) /* (PIOB) Base Address*/
#endif