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

📄 can_lpc2xxx.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 5 页
字号:
#define SR_ERR               0x40
#define SR_BUS_OFF           0x80


//---------------------------------------------------------------------------
// Optimize for the case of a single CAN channel, while still allowing
// multiple channels.
//
#if CYGINT_IO_CAN_CHANNELS == 1
#define CAN_CTRL_BASE(_extra_)   CAN_CTRL_SINGLETON_BASE
#define CAN_ISRVEC(_extra_)      CAN_SINGLETON_ISRVEC
#define CAN_DECLARE_INFO(_chan_)
#define CAN_DECLARE_CHAN(_data_)
#else
#define CAN_CTRL_BASE(_extra_)   ((_extra_)->base)
#define CAN_ISRVEC(_extra_)      ((_extra_)->isrvec)
#define CAN_DECLARE_INFO(_chan_) lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv;
#define CAN_DECLARE_CHAN(_data_) can_channel  *chan = (can_channel *)data;
#endif // CYGINT_IO_CAN_CHANNELS == 1 


#ifdef CYGOPT_DEVS_CAN_LPC2XXX_CAN0_ACCFILT_STARTUP_CFG_RX_ALL
#define CAN0_FLAG_STARTUP_ACCFILT_SETUP INFO_FLAG_STARTUP_RX_ALL
#else
#define CAN0_FLAG_STARTUP_ACCFILT_SETUP 0x00
#endif

#ifdef CYGOPT_DEVS_CAN_LPC2XXX_CAN1_ACCFILT_STARTUP_CFG_RX_ALL
#define CAN1_FLAG_STARTUP_ACCFILT_SETUP INFO_FLAG_STARTUP_RX_ALL
#else
#define CAN1_FLAG_STARTUP_ACCFILT_SETUP 0x00
#endif

#ifdef CYGOPT_DEVS_CAN_LPC2XXX_CAN2_ACCFILT_STARTUP_CFG_RX_ALL
#define CAN2_FLAG_STARTUP_ACCFILT_SETUP INFO_FLAG_STARTUP_RX_ALL
#else
#define CAN2_FLAG_STARTUP_ACCFILT_SETUP 0x00
#endif

#ifdef CYGOPT_DEVS_CAN_LPC2XXX_CAN3_ACCFILT_STARTUP_CFG_RX_ALL
#define CAN3_FLAG_STARTUP_ACCFILT_SETUP INFO_FLAG_STARTUP_RX_ALL
#else
#define CAN3_FLAG_STARTUP_ACCFILT_SETUP 0x00
#endif


//===========================================================================
//                              DATA TYPES
//===========================================================================
//
// Structure stores LPC2xxx CAN channel related stuff
//

// If we use Self Reception Request command instead of the Transmission Request
// we must add last transmit message id in order to reject it in rx_ISR
// There are two last_tx_id because tx interrupt (and so transmition of next 
// message) happens before rx interrupt (which uses last_tx_id for rejecting)) 

// Format of last_tx_id:
//  (bits: 28:0-ID, 29-Validation, 30-RTR, 31-EXT)
//  if last_tx_id == 0xFFFFFFFF (Validation == 1) then last id is not valid
#ifdef CYGOPT_DEVS_CAN_LPC2XXX_USE_SELF_RECEPTION
 #define LPC2XXX_CAN_INFO_LAST_TX_ID_IDMASK   0x1FFFFFFF
 #define LPC2XXX_CAN_INFO_LAST_TX_ID_FLMASK   0xC0000000
 #define LPC2XXX_CAN_INFO_LAST_TX_ID_NOVALID  0xFFFFFFFF

 #define LPC2XXX_CAN_INFO_LAST_TX_ID_DECL     cyg_uint8    last_tx_index;                 \
                                              cyg_uint32   last_tx_id[2];
 #define LPC2XXX_CAN_INFO_LAST_TX_ID_INIT     last_tx_index : 0,                          \
                                              last_tx_id    : {LPC2XXX_CAN_INFO_LAST_TX_ID_NOVALID, LPC2XXX_CAN_INFO_LAST_TX_ID_NOVALID},
#else
 #define LPC2XXX_CAN_INFO_LAST_TX_ID_DECL
 #define LPC2XXX_CAN_INFO_LAST_TX_ID_INIT
#endif

typedef struct lpc2xxx_can_info_st
{
    cyg_interrupt      tx_interrupt;
    cyg_handle_t       tx_interrupt_handle;     
    cyg_interrupt      rx_interrupt;
    cyg_handle_t       rx_interrupt_handle; 
    cyg_can_state      state;            // state of CAN controller 
    cyg_uint32         icr;              // buffers icr register
    cyg_uint8          flags;            // flags indicating several states       
    LPC2XXX_CAN_INFO_LAST_TX_ID_DECL     // last transmited messages ids   
#if CYGINT_IO_CAN_CHANNELS > 1
    cyg_uint32         base;             // Per-bus h/w details
    cyg_uint8          isrvec;           // ISR vector (peripheral id)
#endif
} lpc2xxx_can_info_t;


#define INFO_FLAG_RX_ALL           0x01 // this bit indicates that channel receives all CAN messages - no filtering active
#define INFO_FLAG_STARTUP_RX_ALL   0x02 // this bit indicates filter state at startup


//
// lpc2xxx info initialisation
//
#define LPC2XXX_CTRL_NOT_INITIALIZED 0xFF
#if CYGINT_IO_CAN_CHANNELS > 1
#define LPC2XXX_CAN_INFO(_l, _base, _isrvec, _flags)                             \
lpc2xxx_can_info_t _l  = {                                                       \
    state             :  LPC2XXX_CTRL_NOT_INITIALIZED,                           \
    base              : (_base),                                                 \
    isrvec            : (_isrvec),                                               \
    flags             : (_flags),                                                \
    icr               : 0,                                                       \
    LPC2XXX_CAN_INFO_LAST_TX_ID_INIT                                             \
};
#else
#define LPC2XXX_CAN_INFO(_l, _flags)               \
lpc2xxx_can_info_t _l = {                          \
    state      : CYGNUM_CAN_STATE_STOPPED,         \
    flags      : (_flags),                         \
    icr        : 0,                                \
    LPC2XXX_CAN_INFO_LAST_TX_ID_INIT               \
};
#endif


//
// Acceptance filter data
//
typedef struct lpc2xxx_global_can_info_st
{
    cyg_interrupt       err_interrupt;
    cyg_handle_t        err_interrupt_handle;    
    cyg_uint16          free_filters;       // number of free message filters
    cyg_uint8           init_cnt;           // counts number of initialized channels
    can_channel*        active_channels[5]; // stores pointers to active channels - the last entry is just a delimiter
} lpc2xxx_global_can_info_t;


//
// The number of available message filters depends on the size of the
// acceptance filter RAM and on the size of one entry. The size of
// one entry is 4 byte (standard ID only 2 byte, extended groups 8 byte)
//
#define ACCFILT_COMMON_ENTRY_SIZE 4
#define LPC2XXX_CAN_MSG_FILTERS_MAX (ACCFILT_RAM_SIZE / ACCFILT_COMMON_ENTRY_SIZE)
lpc2xxx_global_can_info_t lpc2xxx_global_can_info =
{
    .free_filters     = LPC2XXX_CAN_MSG_FILTERS_MAX,
    .init_cnt         = 0,
    .active_channels  = {0, 0, 0, 0, 0},
};



//
// Data type for access of single bytes/words of an dword value
//
typedef union lsc_buf_u
{
    cyg_uint8  bytes[4];
    struct 
    {
        cyg_uint16 low;
        cyg_uint16 high;
    } words;
    
    struct
    {
        cyg_uint16 upper; // uppper column of acceptance filter ram
        cyg_uint16 lower; // lower column of acceptance filter ram
    } column;
    
    cyg_uint32 dword;
} lsc_buf_t;


//===========================================================================
//                          GLOBAL DATA
//===========================================================================
#if CYGINT_IO_CAN_CHANNELS > 1
#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN0
LPC2XXX_CAN_INFO(lpc2xxx_can0_info,
                 CAN_CTRL_1_REG_BASE,
                 CYGNUM_HAL_INTERRUPT_CAN1_TX,
                 CAN0_FLAG_STARTUP_ACCFILT_SETUP);
#endif

#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN1
LPC2XXX_CAN_INFO(lpc2xxx_can1_info, 
                 CAN_CTRL_2_REG_BASE, 
                 CYGNUM_HAL_INTERRUPT_CAN2_TX,
                 CAN1_FLAG_STARTUP_ACCFILT_SETUP);
#endif

#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN2
LPC2XXX_CAN_INFO(lpc2xxx_can2_info, 
                 CAN_CTRL_3_REG_BASE, 
                 CYGNUM_HAL_INTERRUPT_CAN3_TX,
                 CAN2_FLAG_STARTUP_ACCFILT_SETUP);
#endif

#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN3
LPC2XXX_CAN_INFO(lpc2xxx_can3_info, 
                 CAN_CTRL_4_REG_BASE, 
                 CYGNUM_HAL_INTERRUPT_CAN4_TX,
                 CAN3_FLAG_STARTUP_ACCFILT_SETUP);
#endif
#else // CYGINT_IO_CAN_CHANNELS == 1
#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN0
LPC2XXX_CAN_INFO(lpc2xxx_can0_info, CAN0_FLAG_STARTUP_ACCFILT_SETUP);
#define CAN_CTRL_SINGLETON_BASE   CAN_CTRL_1_REG_BASE
#define CAN_SINGLETON_ISRVEC      CYGNUM_HAL_INTERRUPT_CAN1_TX
#endif

#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN1
LPC2XXX_CAN_INFO(lpc2xxx_can1_info, CAN1_FLAG_STARTUP_ACCFILT_SETUP);
#define CAN_CTRL_SINGLETON_BASE   CAN_CTRL_2_REG_BASE
#define CAN_SINGLETON_ISRVEC      CYGNUM_HAL_INTERRUPT_CAN2_TX
#endif

#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN2
LPC2XXX_CAN_INFO(lpc2xxx_can2_info, CAN2_FLAG_STARTUP_ACCFILT_SETUP);
#define CAN_CTRL_SINGLETON_BASE   CAN_CTRL_3_REG_BASE
#define CAN_SINGLETON_ISRVEC      CYGNUM_HAL_INTERRUPT_CAN3_TX
#endif

#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN3
LPC2XXX_CAN_INFO(lpc2xxx_can3_info, CAN3_FLAG_STARTUP_ACCFILT_SETUP);
#define CAN_CTRL_SINGLETON_BASE   CAN_CTRL_4_REG_BASE
#define CAN_SINGLETON_ISRVEC      CYGNUM_HAL_INTERRUPT_CAN4_TX
#endif

#endif // #if CYGINT_IO_CAN_CHANNELS > 1


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

//--------------------------------------------------------------------------
// Device driver interface functions
//
static bool        lpc2xxx_can_init(struct cyg_devtab_entry* devtab_entry);
static Cyg_ErrNo   lpc2xxx_can_lookup(struct cyg_devtab_entry** tab, struct cyg_devtab_entry* sub_tab, const char* name);
static Cyg_ErrNo   lpc2xxx_can_set_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len);
static Cyg_ErrNo   lpc2xxx_can_get_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len);
static bool        lpc2xxx_can_putmsg(can_channel *priv, CYG_CAN_MSG_T *pmsg, void *pdata);
static bool        lpc2xxx_can_getevent(can_channel *priv, CYG_CAN_EVENT_T *pevent, void *pdata);
static void        lpc2xxx_can_start_xmit(can_channel* chan);
static void        lpc2xxx_can_stop_xmit(can_channel* chan);


//--------------------------------------------------------------------------
// ISRs and DSRs
//
static cyg_uint32 lpc2xxx_can_tx_ISR(cyg_vector_t vector, cyg_addrword_t data);
static void       lpc2xxx_can_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
static cyg_uint32 lpc2xxx_can_rx_ISR(cyg_vector_t vector, cyg_addrword_t data);
static void       lpc2xxx_can_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
static cyg_uint32 lpc2xxx_can_err_ISR(cyg_vector_t vector, cyg_addrword_t data);
static void       lpc2xxx_can_err_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);


//--------------------------------------------------------------------------
// Private utility functions
//
static bool lpc2xxx_can_config_channel(can_channel* chan, cyg_can_info_t* config, cyg_bool init);
static bool lpc2xxx_can_set_baud(can_channel *chan, cyg_can_baud_rate_t *baudrate);
static Cyg_ErrNo lpc2xxx_enter_lowpower_mode(can_channel *chan);
static void lpc2xxx_start_module(can_channel *chan);
static cyg_can_state lpc2xxx_get_state(lpc2xxx_can_info_t *info);
static void lpc2xxx_set_state(lpc2xxx_can_info_t *info, cyg_can_state state);


//--------------------------------------------------------------------------
// Message box configuration
//
static void lpc2xxx_can_config_rx_all(can_channel *chan);
#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
static void lpc2xxx_can_config_rx_none(can_channel *chan);
static bool lpc2xxx_can_add_rx_filter(lpc2xxx_can_info_t *info, cyg_can_filter *filter);
#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG


#include "can_accfilt_lpc2xxx.c"

//===========================================================================
//                   GENERIC CAN IO DATA INITIALISATION
//===========================================================================
CAN_LOWLEVEL_FUNS(lpc2xxx_can_lowlevel_funs,
                  lpc2xxx_can_putmsg,
                  lpc2xxx_can_getevent,
                  lpc2xxx_can_get_config,
                  lpc2xxx_can_set_config,
                  lpc2xxx_can_start_xmit,
                  lpc2xxx_can_stop_xmit
     );


//---------------------------------------------------------------------------
// CAN channel 0
//
#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN0
CYG_CAN_EVENT_T  lpc2xxx_can0_rxbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN0_QUEUESIZE_RX]; // buffer for RX can events
CYG_CAN_MSG_T    lpc2xxx_can0_txbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN0_QUEUESIZE_TX]; // buffer for TX can messages


CAN_CHANNEL_USING_INTERRUPTS(lpc2xxx_can0_chan,
                             lpc2xxx_can_lowlevel_funs,
                             lpc2xxx_can0_info,
                             CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_LPC2XXX_CAN0_KBAUD),
                             lpc2xxx_can0_txbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN0_QUEUESIZE_TX,
                             lpc2xxx_can0_rxbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN0_QUEUESIZE_RX
    );


DEVTAB_ENTRY(lpc2xxx_can0_devtab, 
             CYGPKG_DEVS_CAN_LPC2XXX_CAN0_NAME,
             0,                     // Does not depend on a lower level interface
             &cyg_io_can_devio, 
             lpc2xxx_can_init, 
             lpc2xxx_can_lookup,    // CAN driver may need initializing
             &lpc2xxx_can0_chan
    );
#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN0


//---------------------------------------------------------------------------
// CAN channel 1
//
#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN1
CYG_CAN_EVENT_T  lpc2xxx_can1_rxbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN1_QUEUESIZE_RX]; // buffer for RX can events
CYG_CAN_MSG_T    lpc2xxx_can1_txbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN1_QUEUESIZE_TX]; // buffer for TX can messages


CAN_CHANNEL_USING_INTERRUPTS(lpc2xxx_can1_chan,
                             lpc2xxx_can_lowlevel_funs,
                             lpc2xxx_can1_info,
                             CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_LPC2XXX_CAN1_KBAUD),
                             lpc2xxx_can1_txbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN1_QUEUESIZE_TX,
                             lpc2xxx_can1_rxbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN1_QUEUESIZE_RX
    );

⌨️ 快捷键说明

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