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

📄 can_at91sam7.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 5 页
字号:
}


//===========================================================================
// Query device configuration
//===========================================================================
static Cyg_ErrNo at91sam7_can_get_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len)
{
    Cyg_ErrNo            res  = ENOERR;
    at91sam7_can_info_t *info = (at91sam7_can_info_t *)chan->dev_priv;
    
    switch(key)
    {
        //
        // query state of CAN controller
        //
        case CYG_IO_GET_CONFIG_CAN_STATE :
             {
                cyg_can_state *can_state  = (cyg_can_state*) buf;
                
                if (*len != sizeof(cyg_can_state)) 
                {
                    return -EINVAL;
                }
                *len = sizeof(cyg_can_state);
                *can_state = at91sam7_get_state(info);
             }
             break;

#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG       
        //
        // Query message box information - returns available and free message
        // boxes
        //     
        case CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO :
             {
                 cyg_can_msgbuf_info *mbox_info  = (cyg_can_msgbuf_info*) buf;
                
                 if (*len != sizeof(cyg_can_msgbuf_info)) 
                 {
                     return -EINVAL;
                 }
                *len = sizeof(cyg_can_msgbuf_info);
                
                 mbox_info->count = CAN_MBOX_RX_CNT;
                 mbox_info->free  = info->free_mboxes;
             }
             break;
#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG

        
        //
        // Query hardware description of FlexCAN device driver
        //     
        case CYG_IO_GET_CONFIG_CAN_HDI :
             {
                cyg_can_hdi *hdi = (cyg_can_hdi *)buf;
                //
                // comes from high level driver so we do not need to
                // check buffer size here
                //             
                hdi->support_flags = CYGNUM_CAN_HDI_FRAMETYPE_EXT_ACTIVE
                                   | CYGNUM_CAN_HDI_FULLCAN
                                   | CYGNUM_CAN_HDI_AUTBAUD;
#ifdef CYGOPT_IO_CAN_SUPPORT_TIMESTAMP 
                hdi->support_flags |= CYGNUM_CAN_HDI_TIMESTAMP;
#endif
             }
             break;
             
        default :
            res = -EINVAL;
    }// switch(key)
    
    return res;
}


//===========================================================================
// Send single message
//===========================================================================
static bool at91sam7_can_putmsg(can_channel *priv, CYG_CAN_MSG_T *pmsg, void *pdata)
{
    CAN_DECLARE_INFO(priv);
    cyg_uint32            msr;   
    cyg_uint32            mcr = 0;   
    
    //
    // First check if this message box is ready fro transmission or if it still transmits
    // a message - we read the MSR register to check the ready flag
    //
    HAL_READ_UINT32(CAN_MB_MSR(info, CAN_MBOX_TX(info)), msr);    
    if (!(msr & MSR_RDY))
    {
        AT91SAM7_DBG_PRINT("!MSR_RDY\n");
        return false;
    }
    
    //
    // To prevent concurrent access with the internal CAN core, the application must disable 
    // the mailbox before writing to CAN_MIDx registers - so we do this now
    // 
    HAL_WRITE_UINT32(CAN_MB_MMR(info, CAN_MBOX_TX(info)), MMR_MB_TYPE_DISABLED); 
    
    //
    // Setup the message identifier - this depends on the frame type (standard or extended)
    //
#ifdef CYGOPT_IO_CAN_EXT_CAN_ID
    if (AT91SAM7_CAN_IS_EXT(*pmsg))
    {
        HAL_WRITE_UINT32(CAN_MB_MID(info, CAN_MBOX_TX(info)), 
                         pmsg->id | MID_MIDE);                                   // set extended message id
    }
    else
#endif // CYGOPT_IO_CAN_EXT_CAN_ID
    {
#ifdef CYGOPT_IO_CAN_STD_CAN_ID
        HAL_WRITE_UINT32(CAN_MB_MID(info, CAN_MBOX_TX(info)), 
                        (pmsg->id << MID_MIDvA_SHIFTER) & MID_MIDvA_BITMASK);    // set standard message id
#endif // CYGOPT_IO_CAN_STD_CAN_ID  
    }

    HAL_WRITE_UINT32(CAN_MB_MDL(info, CAN_MBOX_TX(info)), pmsg->data.dwords[0]); // set data
    HAL_WRITE_UINT32(CAN_MB_MDH(info, CAN_MBOX_TX(info)), pmsg->data.dwords[1]); // set data
    HAL_WRITE_UINT32(CAN_MB_MMR(info, CAN_MBOX_TX(info)), MMR_MB_TYPE_TX);       // reenable the message box
    mcr = (AT91SAM7_CAN_GET_DLC(*pmsg) << MCR_DLC_SHIFTER) | MCR_TRANSFER_CMD;   // set data lengt and transfer request
    
    if (AT91SAM7_CAN_IS_RTR(*pmsg))
    {
        mcr |= MCR_RTR;
    }
    
    HAL_WRITE_UINT32(CAN_MB_MCR(info, CAN_MBOX_TX(info)), mcr);
    return true;
}


//===========================================================================
// Read event from device driver
//===========================================================================
static bool at91sam7_can_getevent(can_channel *chan, CYG_CAN_EVENT_T *pevent, void *pdata)
{
    at91sam7_can_info_t  *info       = (at91sam7_can_info_t *)chan->dev_priv;
    cyg_uint32*           pstat      = (cyg_uint32 *)pdata;
    cyg_uint8             mboxflags  = (*pstat & INT_MB_RX);
    cyg_uint8             mbox       = 0;
    bool                  res        = true;
    
    //
    // First check if a message box interrupt occured if a message box interrupt
    // occured process the lowest message box that caused an interrupt
    //
    if (mboxflags)
    {
        cyg_uint32 msr;
        cyg_uint32 mid;
        cyg_uint32 mmr;
        
        while (!(mboxflags & 0x01))
        {
            mboxflags >>= 1;
            mbox++;
        }
        
        //
        // If the message box that caused the interrupt is an PRODUCER message box,
        // then we received an remote request message, if not, then this is a normal
        // RX message
        //
        HAL_READ_UINT32(CAN_MB_MMR(info, mbox), mmr);
        HAL_READ_UINT32(CAN_MB_MSR(info, mbox), msr);   
       *pstat &= ~(0x01 << mbox);                                 // clear flag
        
        if (MMR_MB_GET_TYPE(mmr) != MMR_MB_TYPE_PRODUCE)
        {
            HAL_READ_UINT32(CAN_MB_MID(info, mbox), mid);
            pevent->flags |= CYGNUM_CAN_EVENT_RX; 
            if (msr & MSR_MSG_IGNORED)
            {
                pevent->flags |= CYGNUM_CAN_EVENT_OVERRUN_RX;
            }
            
            //
            // It is important to set the DLC first because this also clears the ctrl
            // field if extended identifiers are supported
            //
            AT91SAM7_CAN_SET_DLC(pevent->msg, MSR_DLC_GET(msr));  
            
#ifdef CYGOPT_IO_CAN_EXT_CAN_ID     
            if (mid & MID_MIDE)
            {  
                pevent->msg.id = MID_GET_EXT(mid);
                AT91SAM7_CAN_SET_EXT(pevent->msg);
            }
            else
#endif // CYGOPT_IO_CAN_EXT_CAN_ID
            {
#ifdef CYGOPT_IO_CAN_STD_CAN_ID
                pevent->msg.id = MID_GET_STD(mid);
#endif // CYGOPT_IO_CAN_STD_CAN_ID
            }
            
            if (msr & MSR_RTR)
            {
                AT91SAM7_CAN_SET_RTR(pevent->msg);
            }
            else
            {
                HAL_READ_UINT32(CAN_MB_MDL(info, mbox), pevent->msg.data.dwords[0]);
                HAL_READ_UINT32(CAN_MB_MDH(info, mbox), pevent->msg.data.dwords[1]);
            }
#ifdef CYGOPT_IO_CAN_SUPPORT_TIMESTAMP 
            pevent->timestamp = msr & MSR_TIMESTAMP;
#endif
      
            HAL_WRITE_UINT32(CAN_MB_MCR(info, mbox), MCR_TRANSFER_CMD);                  // transfer request        
            AT91SAM7_DBG_PRINT("RXID: %x\n", AT91SAM7_CAN_GET_ID(pevent->msg));
        } // if (!(mbox & info->rtr_mboxes)
        else
        {
            HAL_WRITE_UINT32(CAN_MB_MCR(info, mbox), (msr & MSR_DLC) | MCR_TRANSFER_CMD); // transfer request 
            //
            // We do not need to store an event into receive queue if the stat field does
            // not contain any further event flags. If stat is empty we can set res
            // to false and no event will bestore
            //
            res = !(*pstat == 0);
        }
        
        HAL_WRITE_UINT32(CAN_IER(info), 0x01 << mbox);                  // enable interruptfor this message box
    } // if (mboxflags)
    
    //
    // Now check if additional events occured
    //
    if (*pstat)
    {
        if (*pstat & INT_WAKEUP)
        {
            AT91SAM7_DBG_PRINT("WAKE\n");
            pevent->flags |= CYGNUM_CAN_EVENT_LEAVING_STANDBY;
            *pstat &= ~INT_WAKEUP;
            info->state = CYGNUM_CAN_STATE_ACTIVE;       
        }
    
        if (*pstat & INT_ERR_PASSIVE)
        {
            AT91SAM7_DBG_PRINT("ERRP\n");
            pevent->flags |= CYGNUM_CAN_EVENT_ERR_PASSIVE;  
            *pstat &= ~INT_ERR_PASSIVE;
            info->state = CYGNUM_CAN_STATE_ERR_PASSIVE; 
            HAL_WRITE_UINT32(CAN_IER(info), INT_WAKEUP); 
        }
        
        if (*pstat & INT_WARN)
        {
            //
            // check which counter reached its warning level (> 96)
            //
            cyg_uint8 ecr;
            HAL_READ_UINT32(CAN_ECR(info), ecr);
            if (ECR_GET_REC(ecr) > 96)
            {
                pevent->flags |= CYGNUM_CAN_EVENT_WARNING_RX;
                AT91SAM7_DBG_PRINT("WARN TX\n");    
            }
            if (ECR_GET_TEC(ecr) > 96)
            {
                pevent->flags |= CYGNUM_CAN_EVENT_WARNING_TX;
                AT91SAM7_DBG_PRINT("WARN RX\n"); 
            }
            *pstat &= ~INT_WARN;
            info->state = CYGNUM_CAN_STATE_BUS_WARN;
            HAL_WRITE_UINT32(CAN_IER(info), INT_ERR_PASSIVE | INT_BUS_OFF); 
        }
        
        if (*pstat & INT_BUS_OFF)
        {
            pevent->flags |= CYGNUM_CAN_EVENT_BUS_OFF;  
            AT91SAM7_DBG_PRINT("BOFF\n");
            *pstat &= ~INT_BUS_OFF;
            info->state = CYGNUM_CAN_STATE_BUS_OFF;
            HAL_WRITE_UINT32(CAN_IER(info), INT_WAKEUP); 
        }
        
        if (*pstat & INT_SLEEP)
        {
            pevent->flags |= CYGNUM_CAN_EVENT_ENTERING_STANDBY;
            AT91SAM7_DBG_PRINT("SLEEP\n");
            *pstat &= ~INT_SLEEP;
            HAL_WRITE_UINT32(AT91_PMC+AT91_PMC_PCDR, 1 << CAN_PID(info)); // disable module clock
            info->state = CYGNUM_CAN_STATE_STANDBY;                       // set state variable
            HAL_WRITE_UINT32(CAN_IER(info), INT_WAKEUP);                  // enable wakeup interrupt
        }
        
        if (*pstat & (INT_CRC_ERR | INT_STUFF_ERR | INT_ACKN_ERR | INT_FORM_ERR | INT_BIT_ERR))
        {
            pevent->flags |= CYGNUM_CAN_EVENT_CAN_ERR;
            AT91SAM7_DBG_PRINT("CERR\n");
            *pstat &= ~(INT_CRC_ERR | INT_STUFF_ERR | INT_ACKN_ERR | INT_FORM_ERR | INT_BIT_ERR);  
        }
    } // if (*pstat)
      
    return res;
}


//===========================================================================
// Kick transmitter
//===========================================================================
static void at91sam7_can_start_xmit(can_channel* chan)
{
    CAN_DECLARE_INFO(chan);
    
    AT91SAM7_DBG_PRINT("start_xmit\n");
    cyg_drv_dsr_lock();
    HAL_WRITE_UINT32(CAN_IER(info), 0x01 << CAN_MBOX_TX(info)); // enable tx interrupt
    cyg_drv_dsr_unlock();
}

⌨️ 快捷键说明

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