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