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

📄 can_at91sam7.c

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

#ifndef CYGNUM_DEVS_CAN_AT91SAM7_CAN0_EXT_MBOXES
#define CYGNUM_DEVS_CAN_AT91SAM7_CAN0_EXT_MBOXES 0
#endif

#else  // #if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS == 1

#define CAN_PID(_extra_)            ((_extra_)->isrvec)
#define CAN_ISRVEC(_extra_)         ((_extra_)->isrvec)
#define CAN_ISRPRIO(_extra_)        ((_extra_)->isrprio)
#define CAN_BASE(_extra_)           ((_extra_)->base)
#define CAN_DECLARE_INFO(_chan_)    at91sam7_can_info_t *info = (at91sam7_can_info_t *)chan->dev_priv;
#define CAN_MBOX_TX(_extra_)        7 // normally it is always the last mailbox
#define CAN_MBOX_STD_CNT(_extra_)   ((_extra_)->mboxes_std_cnt)
#define CAN_MBOX_EXT_CNT(_extra_)   ((_extra_)->mboxes_ext_cnt)
#define CAN_MBOX_RX_ALL_CNT(_extra) ((_extra_)->mboxes_rx_all_cnt)

#endif // #if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS == 1


//===========================================================================
//                              DATA TYPES
//===========================================================================
typedef struct at91sam7_can_info_t
{
    cyg_interrupt      interrupt;
    cyg_handle_t       interrupt_handle;
    cyg_uint32         stat;             // buffers status register value between ISR and DSR
    cyg_uint8          free_mboxes;      // number of free message boxes for msg filters and rtr buffers
    bool               rx_all;           // true if reception of call can messages is active
    cyg_can_state      state;            // state of CAN controller      

#if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS > 1
    cyg_uint32         base;             // Per-bus h/w details
    cyg_uint8          isrpri;           // ISR priority
    cyg_uint8          isrvec;           // ISR vector (peripheral id)
    cyg_uint8          mboxes_std_cnt;   // contains number of standard message boxes available
    cyg_uint8          mboxes_ext_cnt;   // number of message boxes with ext id
    cyg_uint8          mboxes_rx_all_cnt;// number of all available mboxes
#endif
} at91sam7_can_info_t;


//
// at91sam7 info initialisation
//
#if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS > 1
#define AT91SAM7_CAN_INFO(_l, _base, _isrpri, _isrvec, _std_mboxes, _ext_mboxes) \
at91sam7_can_info_t _l {                                                         \
    state             : CYGNUM_CAN_STATE_STOPPED,                                \
    base              : (_base),                                                 \
    isrpri            : (_isrpri),                                               \
    isrvec            : (_isrvec),                                               \
    mboxes_std_cnt    : (_std_mboxes),                                           \
    mboxes_ext_cnt    : (_ext_mboxes),                                           \
    mboxes_rx_all_cnt : ((_std_mboxes) + (_ext_mboxes)),                         \
};
#else
#define AT91SAM7_CAN_INFO(_l)              \
at91sam7_can_info_t _l = {                 \
    state      : CYGNUM_CAN_STATE_STOPPED, \
};
#endif


//===========================================================================
//                          GLOBAL DATA
//===========================================================================
#if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS > 1
//
// ToDo - Initialisation of individual CAN channels if more than one channel
// is supported
//
#else // CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS == 1
//
// Only one single CAN channel supported by SAM7 chip
//
AT91SAM7_CAN_INFO(at91sam7_can0_info);
#endif


//===========================================================================
//                          LOCAL DATA
//===========================================================================
//
// Macro for creation of CAN_BR value for baudrate tbl
//

#define CAN_BR_TBL_ENTRY(_brp_, _propag_, _phase1_, _phase2_, _sjw_) \
   ((_brp_ << 16) | (_propag_ << 8) | (_phase2_) | (_phase1_ << 4) | (_sjw_ << 12))

//
// Table with register values for baudrates at main clock of 48 MHz
//
static const cyg_uint32 at91sam7_br_tbl[] =
{
    CAN_BR_TBL_ENTRY(0xef, 0x07, 0x07, 0x02, 0), // 10  kbaud
    CAN_BR_TBL_ENTRY(0x95, 0x04, 0x07, 0x01, 0), // 20  kbaud
    CAN_BR_TBL_ENTRY(0x3b, 0x04, 0x07, 0x01, 0), // 50  kbaud
    CAN_BR_TBL_ENTRY(0x1d, 0x04, 0x07, 0x01, 0), // 100 kbaud
    CAN_BR_TBL_ENTRY(0x17, 0x04, 0x07, 0x01, 0), // 125 kbaud
    CAN_BR_TBL_ENTRY(0x0b, 0x04, 0x07, 0x01, 0), // 250 kbaud
    CAN_BR_TBL_ENTRY(0x05, 0x04, 0x07, 0x01, 0), // 500 kbaud
    CAN_BR_TBL_ENTRY(0x03, 0x03, 0x07, 0x01, 0), // 800 kbaud
    CAN_BR_TBL_ENTRY(0x02, 0x04, 0x07, 0x01, 0), // 1000 kbaud
    CAN_BR_TBL_ENTRY(0x00, 0x00, 0x00, 0x00, 0), // Autobaud
};

//
// Macro fills baudrate register value depending on selected baudrate
// For a standard AT91 clock speed of 48 MHz we provide a pre calculated
// baudrate table. If the board uses another clock speed, then the platform 
// HAL needs to provide an own HAL_AT91SAM7_GET_CAN_BR() macro that returns 
// valid baudrate register values
//
#ifdef CYGNUM_HAL_ARM_AT91_CLOCK_SPEED_48000000
#define HAL_AT91SAM7_GET_CAN_BR(_baudrate_, _br_)                \
CYG_MACRO_START                                                  \
    _br_ = at91sam7_br_tbl[(_baudrate_) - CYGNUM_CAN_KBAUD_10];  \
CYG_MACRO_END
#endif


//===========================================================================
//                              PROTOTYPES
//===========================================================================

//--------------------------------------------------------------------------
// Device driver interface functions
//
static bool        at91sam7_can_init(struct cyg_devtab_entry* devtab_entry);
static Cyg_ErrNo   at91sam7_can_lookup(struct cyg_devtab_entry** tab, struct cyg_devtab_entry* sub_tab, const char* name);
static Cyg_ErrNo   at91sam7_can_set_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len);
static Cyg_ErrNo   at91sam7_can_get_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len);
static bool        at91sam7_can_putmsg(can_channel *priv, CYG_CAN_MSG_T *pmsg, void *pdata);
static bool        at91sam7_can_getevent(can_channel *priv, CYG_CAN_EVENT_T *pevent, void *pdata);
static void        at91sam7_can_start_xmit(can_channel* chan);
static void        at91sam7_can_stop_xmit(can_channel* chan);


//--------------------------------------------------------------------------
// ISRs and DSRs
//
static cyg_uint32 at91sam7_can_ISR(cyg_vector_t vector, cyg_addrword_t data);
static void       at91sam7_can_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);


//--------------------------------------------------------------------------
// Private utility functions
//
static bool at91sam7_can_config_channel(can_channel* chan, cyg_can_info_t* config, cyg_bool init);
static bool at91sam7_can_set_baud(can_channel *chan, cyg_can_baud_rate_t *baudrate);
static void at91sam7_can_mbox_config_rx_all(can_channel *chan);
static void at91sam7_can_setup_mbox(can_channel *chan,    // channel 
                                    cyg_uint8    mbox,    // message box number (0 -7)
                                    cyg_uint32   mid,     // message identifier
                                    cyg_uint32   mam,     // acceptance mask for this message box
                                    cyg_uint32   rxtype); // RX or RX with overwrite are valid values
static void at91sam7_enter_lowpower_mode(can_channel *chan);
static void at91sam7_start_module(can_channel *chan);
static cyg_can_state at91sam7_get_state(at91sam7_can_info_t *info);

#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
static void at91sam7_can_config_rx_none(can_channel *chan);
static Cyg_ErrNo at91sam7_can_set_config_msgbuf(can_channel *chan, cyg_can_msgbuf_cfg *buf);
#endif


                                       

//===========================================================================
//                   GENERIC CAN IO DATA INITIALISATION
//===========================================================================
CAN_LOWLEVEL_FUNS(at91sam7_can_lowlevel_funs,
                  at91sam7_can_putmsg,
                  at91sam7_can_getevent,
                  at91sam7_can_get_config,
                  at91sam7_can_set_config,
                  at91sam7_can_start_xmit,
                  at91sam7_can_stop_xmit
     );


CYG_CAN_EVENT_T  at91sam7_can0_rxbuf[CYGNUM_DEVS_CAN_AT91SAM7_CAN0_QUEUESIZE_RX]; // buffer for RX can events
CYG_CAN_MSG_T    at91sam7_can0_txbuf[CYGNUM_DEVS_CAN_AT91SAM7_CAN0_QUEUESIZE_TX]; // buffer for TX can messages


CAN_CHANNEL_USING_INTERRUPTS(at91sam7_can0_chan,
                             at91sam7_can_lowlevel_funs,
                             at91sam7_can0_info,
                             CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_AT91SAM7_CAN0_KBAUD),
                             at91sam7_can0_txbuf, CYGNUM_DEVS_CAN_AT91SAM7_CAN0_QUEUESIZE_TX,
                             at91sam7_can0_rxbuf, CYGNUM_DEVS_CAN_AT91SAM7_CAN0_QUEUESIZE_RX
    );


DEVTAB_ENTRY(at91sam7_can_devtab, 
             CYGPKG_DEVS_CAN_AT91SAM7_CAN0_NAME,
             0,                     // Does not depend on a lower level interface
             &cyg_io_can_devio, 
             at91sam7_can_init, 
             at91sam7_can_lookup,  // CAN driver may need initializing
             &at91sam7_can0_chan
    );


//===========================================================================
//                            IMPLEMENTATION
//===========================================================================



//===========================================================================
/// First initialisation and reset of CAN modul.
//===========================================================================
static bool at91sam7_can_init(struct cyg_devtab_entry* devtab_entry)
{
    can_channel          *chan    = (can_channel*)devtab_entry->priv;
    at91sam7_can_info_t *info    = (at91sam7_can_info_t *)chan->dev_priv;

#ifdef CYGDBG_IO_INIT
    diag_printf("AT91 CAN init\n");
#endif   
    cyg_drv_interrupt_create(CAN_ISRVEC(info),
                             CAN_ISRPRIO(info),        // Priority
                             (cyg_addrword_t)chan,     // Data item passed to interrupt handler
                             at91sam7_can_ISR,
                             at91sam7_can_DSR,
                             &info->interrupt_handle,
                             &info->interrupt);
    cyg_drv_interrupt_attach(info->interrupt_handle);
    cyg_drv_interrupt_unmask(CAN_ISRVEC(info));
     
    return at91sam7_can_config_channel(chan, &chan->config, true);
}


//===========================================================================
//  Lookup the device and return its handle
//===========================================================================
static Cyg_ErrNo at91sam7_can_lookup(struct cyg_devtab_entry** tab, struct cyg_devtab_entry* sub_tab, const char* name)
{
    can_channel* chan    = (can_channel*) (*tab)->priv;
    CAN_DECLARE_INFO(chan);

    chan->callbacks->can_init(chan); 
    HAL_WRITE_UINT32(CAN_IER(info), INT_DEFAULT);                  // enable wakeup and error interrupts
    HAL_WRITE_UINT32(AT91_PMC+AT91_PMC_PCER, 1 << CAN_PID(info));  // Enable the peripheral clock to the device      
     
    //
    // It is important to setup the message buffer configuration after enabling the 
    // peripheral clock. This is nowhere documented in the at91sam7 hardware manual.
    // If the message buffer configuration is set before the peripheral clock is
    // enabled, then message buffers that receive extended frames might not work
    // properly
    //
    at91sam7_can_mbox_config_rx_all(chan); 
      
    return ENOERR;
}


#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
//===========================================================================
// Setup AT91SAM7 CAN module in a state where all message boxes are disabled
// After this callit is possible to add single message buffers and filters
//===========================================================================
static void at91sam7_can_config_rx_none(can_channel *chan)
{
    at91sam7_can_info_t *info = (at91sam7_can_info_t *)chan->dev_priv;
    cyg_uint8 i;
    
    //
    // setup all RX messages moxes into a disabled state and disable all
    // interrupts - maybe we have to abort pending transfers before $$$$
    //
    HAL_WRITE_UINT32(CAN_IDR(info), INT_MB_RX);
    for (i = 0; i < CAN_MBOX_RX_CNT; ++i)
    {
        HAL_WRITE_UINT32(CAN_MB_MMR(info, i), MMR_MB_TYPE_DISABLED); // first disable message box
    }
    
    info->free_mboxes = CAN_MBOX_RX_CNT;
    info->rx_all = false;
}


//===========================================================================
// Add single message filter - setupm message box and enable interrupt
//===========================================================================
static void at91sam7_can_add_rx_filter(can_channel *chan, cyg_uint8 mbox, cyg_can_message *msg)
{   
    CAN_DECLARE_INFO(chan);
    
    if (msg->ext)
    {
        at91sam7_can_setup_mbox(chan, mbox, MID_SET_EXT(msg->id), MAM_SET_EXT, MMR_MB_TYPE_RX); 
    }
    else
    {
        at91sam7_can_setup_mbox(chan, mbox, MID_SET_STD(msg->id), MAM_SET_STD, MMR_MB_TYPE_RX);    
    } 
    HAL_WRITE_UINT32(CAN_IER(info), 0x01 << mbox);   
}
#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG


#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
//===========================================================================
// Allocate message box
// Try to find a free message box and return its ID
//===========================================================================
static cyg_int8 at91sam7_can_alloc_mbox(at91sam7_can_info_t *info)
{
    cyg_uint8     i;
    cyg_int8      res = CYGNUM_CAN_MSGBUF_NA;
    
    if (info->free_mboxes)
    {  

⌨️ 快捷键说明

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