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