📄 can_lpc2xxx.c
字号:
#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 + -