⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hard_can.c

📁 CAN 驱动程序
💻 C
字号:
/*========================================================*
 * 程序修改记录(最新的放在最前面):

    1. 2005.08.02.lejianxin modify
 */


#include "Macro.h"
#include "Variable.h"
#include "Function.h"
#include "CPU_S3C44B0x.h"
#include "CAN_SJA1000.h"
#include "Mon_Can.h"

#if( !CN_HAVE_CAN )  // 本装置上不存在CAN 硬件
#error 本装置无CAN 硬件,无法使用ISA-CAN规约!
#endif

BYTE        g_byCANMode[CN_NUM_PORT_CAN];        // CAN芯片运行模式,初始化时赋值,中断处调用


/*======================================*
 * Initialize the SJA1000 chip
 * bIsHardRst:TRUE 为硬启动,FALSE 为软启动*/
BOOLEAN Hard_Can_Init( BYTE byPortNo ,BOOLEAN bIsHardRst)
{
    tagPPortSet     ptPortSet;
    tagPPortVal     ptPortVal;
    tagPCanCtrl     ptCanCtrl;
    BYTE            byIndex, byCanIP, byBTR0, byBTR1, byTemp;
    LPSTR           pAddr;

    byIndex = byPortNo - CN_PORT_BASE_CAN;
    if( byIndex >=CN_NUM_PORT_CAN ) return FALSE;

    if( FALSE==Fun_GetPortVariable(byPortNo, &ptPortVal) ) return FALSE;
    ptPortSet  =  ptPortVal->ptPortSet;

    g_tPortVal[byPortNo].wResetTimes++;
    byCanIP = ((tagPParamCan)(ptPortSet->dwParam))->byCanIP;
    pAddr = (LPSTR)(ptPortSet->dwAddBase);

    switch( ptPortSet->byBaudRate )
    {
    case EN_CAN_BAUD_5K   :   byBTR0 = 0xBF;      byBTR1 = 0x7F;      break;      //    5k
    case EN_CAN_BAUD_10K  :   byBTR0 = 0xB1;      byBTR1 = 0x2B;      break;      //   10k
    case EN_CAN_BAUD_20K  :   byBTR0 = 0x98;      byBTR1 = 0x2B;      break;      //   20k
    case EN_CAN_BAUD_40K  :   byBTR0 = 0x89;      byBTR1 = 0X5C;      break;      //   40k
    case EN_CAN_BAUD_80K  :   byBTR0 = 0x84;      byBTR1 = 0X5C;      break;      //   80k
    case EN_CAN_BAUD_200K :   byBTR0 = 0x81;      byBTR1 = 0X5C;      break;      //  200k
    case EN_CAN_BAUD_400K :   byBTR0 = 0x80;      byBTR1 = 0x2F;      break;      //  400k
    case EN_CAN_BAUD_800K :   byBTR0 = 0x80;      byBTR1 = 0x25;      break;      //  800k
    case EN_CAN_BAUD_1000K:   byBTR0 = 0x80;      byBTR1 = 0x14;      break;      // 1000k
    default               :   byBTR0 = 0x84;      byBTR1 = 0x2F;      break;      //   80k
    }

    g_byCANMode[byIndex] = ptPortSet->byRunMode;                    // CAN芯片运行模式
    if( EN_MODE_BASIC_CAN ==ptPortSet->byRunMode )
    {
        byTemp = *( pAddr + CN_BCAN_SR );       // Clear Status Register
        byTemp = *( pAddr + CN_BCAN_IIR );      // Clear Interrupt Identify Register

        *( pAddr + CN_BCAN_CR )  = 0x21;     // 0010-0001: reset mode
        *( pAddr + CN_BCAN_CDR ) = 0x05;     // BasicCAN mode & Clock driver: 0000-0101
        *( pAddr + CN_BCAN_CMR ) = 0x0E;     // Command
        *( pAddr + CN_BCAN_ACR ) = byCanIP;  //
        *( pAddr + CN_BCAN_AMR ) = 0x00;     // 0000-0000

        *( pAddr + CN_BCAN_BTR0 ) = byBTR0;     // Bus timing register 0
        *( pAddr + CN_BCAN_BTR1 ) = byBTR1;     // Bus timing register 1
        *( pAddr + CN_BCAN_OCR )  = 0xDA;       // 1101-1010:
        *( pAddr + CN_BCAN_CR )   = 0x3E;       // Operating mode & Interrupt enabled: 0011-1110

    }else  // PeliCAN mode ( EN_MODE_PELI_CAN )
    {
        byTemp = *( pAddr + CN_PCAN_SR );       // Clear Status Register
        byTemp = *( pAddr + CN_PCAN_IIR );      // Clear Interrupt Identify Register

        *( pAddr + CN_PCAN_MODE ) = 0x21;     // Reset mode
        *( pAddr + CN_PCAN_CDR )  = 0x85;     // PeliCAN mode & Clock driver:1000-0101
        *( pAddr + CN_PCAN_CMR )  = 0x0E;     // Command Register
        *( pAddr + CN_PCAN_IER )  = 0x00;     // Interruption disabled
        *( pAddr + CN_PCAN_BTR0 ) = byBTR0;   // Bus timeing register 0
        *( pAddr + CN_PCAN_BTR1 ) = byBTR1;   // Bus timeing register 1
        *( pAddr + CN_PCAN_OCR )  = 0xDA;     // Output Control:110-110-10
        *( pAddr + CN_PCAN_RXERR )= 0x00;     // RX Error counter
        *( pAddr + CN_PCAN_TXERR )= 0x00;     // TX Error counter
        *( pAddr + CN_PCAN_RBSA ) = 0x00;     // RX Buffer Start Address

        *( pAddr + CN_PCAN_ACR0 ) = byCanIP;  //
        *( pAddr + CN_PCAN_ACR1 ) = 0x00;     //
        *( pAddr + CN_PCAN_ACR2 ) = 0x00;     //广播地址
        *( pAddr + CN_PCAN_ACR3 ) = 0x00;     //
        *( pAddr + CN_PCAN_AMR0 ) = 0x00;     //
        *( pAddr + CN_PCAN_AMR1 ) = 0xFF;     //
        *( pAddr + CN_PCAN_AMR2 ) = 0x00;     //
        *( pAddr + CN_PCAN_AMR3 ) = 0xFF;     //

        *( pAddr + CN_PCAN_IER )  = 0x7F;     // Interrupt enabled
        *( pAddr + CN_PCAN_MODE ) = 0x20;     // Normal Operating mode
    
    }

    ptCanCtrl = (tagPCanCtrl)ptPortVal->dwRes;

    if(bIsHardRst==TRUE)
        ptCanCtrl->bStopByAddrConflict = FALSE;

    return TRUE;
}


/*=======================================================*
 *  Read only ONE frame from can buffer each times
 */
BYTE Hard_Can_Message_Read( BYTE byIndex )
{
    tagPRecvCtrl    ptRecvCtrl;
    tagPPortSet     ptPortSet;
    WORD            wWrite, wRead;
    BYTE            byPortNo, *pbyRecvBuf, bySR, byLen, byLoop;
    LPSTR           pAddr;

    if( byIndex >=CN_NUM_PORT_CAN ) return 0;
    byPortNo = CN_PORT_BASE_CAN + byIndex;

    ptPortSet = g_ptPortSet[byPortNo];
    pAddr = (LPSTR)(ptPortSet->dwAddBase);

    ptRecvCtrl = &g_tPortVal[byPortNo].tRecvCtrl;
    if( ptRecvCtrl->wRecvWrite >=CN_NUM_CAN_FRAME )
    {
        ptRecvCtrl->wRecvWrite = 0;
        ptRecvCtrl->wRecvRead  = 0;
    }

    byLen = 0;
    wRead = ptRecvCtrl->wRecvRead;              // 保存的是帧指针
  //for( wCounter=0; wCounter<1; wCounter++ )
    {
        wWrite = ptRecvCtrl->wRecvWrite;
        pbyRecvBuf = &(ptRecvCtrl->byRecvQue[ wWrite*11] );
        bySR = *( pAddr + CN_CAN_SR );      // CN_BCAN_SR=CN_PCAN_SR
        if( 0 ==(bySR & 0x01) ) return( byLen );                // RBS is empty
      //Time_TimerBReset( &ptRecvCtrl->tTimerRecv );            // clear the timer

        if( g_byCANMode[byIndex] == EN_MODE_BASIC_CAN )
        {
            byLen = ((*( pAddr + CN_BCAN_RX_LEN )) & 0x0F) + 2;
            if( 10 <byLen ) byLen = 10;
            for( byLoop=0; byLoop<byLen; byLoop++)
            {
                pbyRecvBuf[byLoop] = *( pAddr + CN_BCAN_RXD+byLoop ) ;
            }
            *( pAddr + CN_BCAN_CMR ) = 0xEC;    // 1110-1100
        }else //                  EN_MODE_PELI_CAN
        {
            byLen = ((*( pAddr + CN_PCAN_RX_LEN )) & 0x0F) + 3;
            if( 11 <byLen ) byLen = 11;
            for( byLoop=0; byLoop<byLen; byLoop++ )
            {
                pbyRecvBuf[byLoop] = *( pAddr + CN_PCAN_RXD+byLoop );
            }
            *( pAddr + CN_PCAN_CMR ) = 0xEC;    // 1110-1100
        }

        wWrite++;            // 保存的是帧指针
        if( wWrite >=CN_NUM_CAN_FRAME ) wWrite = 0;
        ptRecvCtrl->wRecvWrite = wWrite;
        if( wWrite ==wRead ) // receive buffer overflow!!!
        {
            wRead++;         // 保存的是帧指针
            if( wRead >=CN_NUM_CAN_FRAME ) wRead = 0;
            ptRecvCtrl->wRecvRead = wRead;
        }

        // message-watching
        if( M_Dbg_RawDataRecv( byPortNo ))
        {
            Dbg_SavePortMsg( byPortNo, EN_DBG_DATA_RECV, byLen, pbyRecvBuf );
        }
    }

    return( byLen );
}


/*========================================*
 *  Write ONE frame to SJA1000            */
BYTE Hard_Can_Message_Write( BYTE byIndex )
{
    tagPSendCtrl    ptSendCtrl;
    tagPPortSet     ptPortSet;
    LPSTR           pAddr;
    BYTE            byPortNo, *pbySendBuf;
    BYTE            byUnitNo, byFrameNo, bySR, byLen, byLoop;
    WORD            wRead;

    if( byIndex >=CN_NUM_PORT_CAN ) return 0;
    byPortNo = CN_PORT_BASE_CAN + byIndex;

    ptPortSet = g_ptPortSet[byPortNo];
    pAddr = (LPSTR)(ptPortSet->dwAddBase);

    bySR = *( pAddr + CN_CAN_SR );

    if( 0 ==(bySR & 0x04) ) return 0;     // TBS not empty

    ptSendCtrl = &g_tPortVal[byPortNo].tSendCtrl;
    if( ptSendCtrl->wSendFlag !=CN_STATUS_SEND_BUSY ) return 0;
    wRead = ptSendCtrl->wSendRead;
    if( (wRead >=CN_VOL_BUF_SEND) || (wRead >=ptSendCtrl->wSendLen) )    // ERROR
    {
        ptSendCtrl->wSendLen  = 0;
        ptSendCtrl->wSendRead = 0;
        ptSendCtrl->wSendFlag = CN_STATUS_SEND_IDLE;
        Time_TimerBStop ( &ptSendCtrl->tTimerAbandon );
        Time_TimerBStart( &ptSendCtrl->tTimerLineIdle, CN_INTERVAL_BUS_IDLE, EN_TIMERB_TYPE_MS);
        return 0;
    }

    byUnitNo   =  ptSendCtrl->wUnitAddr;        // 发送函数中必须注明该参数
    pbySendBuf = &ptSendCtrl->bySendBuf[wRead]; // the start position to be sent
    if( g_byCANMode[byIndex] == EN_MODE_BASIC_CAN )
    {
        byFrameNo = wRead / 7;
        if( (wRead+7) >=ptSendCtrl->wSendLen )
        {
            byLen = ptSendCtrl->wSendLen - wRead;

            ptSendCtrl->wSendLen  = 0;
            ptSendCtrl->wSendRead = 0;
            ptSendCtrl->wSendFlag = CN_STATUS_SEND_IDLE;
          //Time_TimerBStop ( &ptSendCtrl->tTimerAbandon );
          //Time_TimerBStart( &ptSendCtrl->TimerLineIdle, CN_INTERVAL_BUS_IDLE, EN_TIMERB_TYPE_MS);

            *( pAddr + CN_BCAN_DSCR0 )   = byUnitNo;
            *( pAddr + CN_BCAN_DSCR1 )   = (0x60 | (byLen+1));
            *( pAddr + CN_BCAN_FRAMENO ) = byFrameNo;
        }else
        {
            byLen = 7;
            ptSendCtrl->wSendRead = wRead + 7;
          //Time_TimerBRestart( &ptSendCtrl->tTimerAbandon );

            *( pAddr + CN_BCAN_DSCR0 )   = byUnitNo;
            *( pAddr + CN_BCAN_DSCR1 )   = 0x48;
            *( pAddr + CN_BCAN_FRAMENO ) = byFrameNo;
        }

        for( byLoop=0; byLoop<byLen; byLoop++ )
            *( pAddr + (CN_BCAN_TXD+byLoop) )   = pbySendBuf[byLoop];
        *( pAddr + CN_BCAN_CMR )   = 0x01;    // sending request

    }else  //                 EN_MODE_PELI_CAN
    {
        byFrameNo = wRead / 7;                  // max 7 Byte per frame
        if( (wRead+7) >=ptSendCtrl->wSendLen )
        {
            byLen = ptSendCtrl->wSendLen - wRead;

            ptSendCtrl->wSendLen  = 0;
            ptSendCtrl->wSendRead = 0;
            ptSendCtrl->wSendFlag = CN_STATUS_SEND_IDLE;
          //Time_TimerBStop ( &ptSendCtrl->tTimerAbandon );
          //Time_TimerBStart( &ptSendCtrl->TimerLineIdle, CN_INTERVAL_BUS_IDLE, EN_TIMERB_TYPE_MS);

            *( pAddr + CN_PCAN_DSCR0 )   = (byLen+1);
            *( pAddr + CN_PCAN_DSCR1 )   = byUnitNo;
            *( pAddr + CN_PCAN_DSCR2 )   = 0x20;
            *( pAddr + CN_PCAN_FRAMENO ) = byFrameNo;
        }else
        {
            byLen = 7;
            ptSendCtrl->wSendRead = wRead + 7;
          //Time_TimerBRestart( &ptSendCtrl->tTimerAbandon );

            *( pAddr + CN_PCAN_DSCR0 )   = 0x08;
            *( pAddr + CN_PCAN_DSCR1 )   = byUnitNo;
            *( pAddr + CN_PCAN_DSCR2 )   = 0x00;
            *( pAddr + CN_PCAN_FRAMENO ) = byFrameNo;
        }

        for( byLoop=0; byLoop<byLen; byLoop++ )
            *( pAddr + (CN_PCAN_TXD+byLoop) )   = pbySendBuf[byLoop];
        *( pAddr + CN_PCAN_CMR )   = 0x01;    // sending request

    }

    // message-watching
    if( M_Dbg_RawDataSend( byPortNo) )
    {
        Dbg_SavePortMsg( byPortNo, EN_DBG_DATA_SEND, byLen, pbySendBuf );
    }

    return byLen;
}


/*==================================================*
 * Start the CAN Transmit                           */
BOOLEAN Hard_Can_TxStartup( BYTE byPortNo ,BOOLEAN bIsReSend)
{
    tagPSendCtrl    ptSendCtrl;
    BYTE    byIndex, byLenSend;
    WORD    wMsgLen;

    byIndex = byPortNo - CN_PORT_BASE_CAN;
    if( byIndex >=CN_NUM_PORT_CAN ) return FALSE;

    ptSendCtrl = &g_tPortVal[byPortNo].tSendCtrl;

    if( ptSendCtrl->wSendRead !=0 ) return FALSE;
    wMsgLen = ptSendCtrl->wSendLen;

//    intDisable( CN_CPU_INT_LVL_EINT0 );  // INT CAN-0
//    intDisable( CN_CPU_INT_LVL_EINT1 );  // INT CAN-1

    byLenSend = Hard_Can_Message_Write( byIndex );

//    intEnable( CN_CPU_INT_LVL_EINT0 );   // INT CAN-0
//    intEnable( CN_CPU_INT_LVL_EINT1 );   // INT CAN-1

    if(( M_Dbg_MsgDataSend( byPortNo ) ) && (!bIsReSend))
    { // message-watching
        ptSendCtrl = &g_tPortVal[byPortNo].tSendCtrl;
        Dbg_SavePortMsg( byPortNo, EN_DBG_MSG_SEND, wMsgLen, ptSendCtrl->bySendBuf );
    }// 重发的报文可能显示两次

    return TRUE;
}




//void Hard_Can_IntProcess( BYTE byIndex )
void ISR_Can( BYTE byIndex )
{
    BYTE            byIIR, byPortNo, byINTSource, byTemp;
    tagPPortSet     ptPortSet;
    LPSTR           pAddr;

    if( byIndex >=CN_NUM_PORT_CAN ) return ;
    byPortNo = CN_PORT_BASE_CAN + byIndex;

    ptPortSet = g_ptPortSet[byPortNo];
    pAddr = (LPSTR)(ptPortSet->dwAddBase);

    if( g_byCANMode[byIndex] == EN_MODE_BASIC_CAN )   // CAN芯片运行模式
        byINTSource = 0x1C;     // Error: 0001-1100
    else //                   EN_MODE_PELI_CAN
        byINTSource = 0x7C;     // Error: 0111-1100

    byIIR = *( pAddr + CN_CAN_IIR );
//    printf("\nbyIIR: %d",byIIR);

    if( byIIR & byINTSource )
    {
        byTemp = *( pAddr + CN_CAN_SR );
        Hard_Can_Init( byPortNo , FALSE);
    }else
    {
        if( byIIR & 0x02 )      // TI
            Hard_Can_Message_Write( byIndex );
        if( byIIR & 0x01 )      // RI
            Hard_Can_Message_Read( byIndex );
    }

    // Clear the INT pending flag
//    *(PUI32)(CN_CPU_I_ISPC) = *(PUI32)(CN_CPU_I_ISPR);

    return;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -