1 //==========================================================================
3 // devs/can/arm/at91sam7x/current/src/can_at91sam7x.c
5 // CAN driver for Atmel AT91SAM7X microcontrollers
7 //==========================================================================
8 //####ECOSGPLCOPYRIGHTBEGIN####
9 // -------------------------------------------
10 // This file is part of eCos, the Embedded Configurable Operating System.
11 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12 // Copyright (C) 2003 Gary Thomas
14 // eCos is free software; you can redistribute it and/or modify it under
15 // the terms of the GNU General Public License as published by the Free
16 // Software Foundation; either version 2 or (at your option) any later version.
18 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
19 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 // You should have received a copy of the GNU General Public License along
24 // with eCos; if not, write to the Free Software Foundation, Inc.,
25 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
27 // As a special exception, if other files instantiate templates or use macros
28 // or inline functions from this file, or you compile this file and link it
29 // with other works to produce a work based on this file, this file does not
30 // by itself cause the resulting work to be covered by the GNU General Public
31 // License. However the source code for this file must still be made available
32 // in accordance with section (3) of the GNU General Public License.
34 // This exception does not invalidate any other reasons why a work based on
35 // this file might be covered by the GNU General Public License.
37 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
38 // at http://sources.redhat.com/ecos/ecos-license/
39 // -------------------------------------------
40 //####ECOSGPLCOPYRIGHTEND####
41 //==========================================================================
42 //#####DESCRIPTIONBEGIN####
44 // Author(s): Uwe Kindler
45 // Contributors: Uwe Kindler
47 // Purpose: Support at91sam7 on-chip CAN moduls
50 //####DESCRIPTIONEND####
52 //==========================================================================
55 //==========================================================================
57 //==========================================================================
58 #include <pkgconf/system.h>
59 #include <pkgconf/io_can.h>
60 #include <pkgconf/io.h>
61 #include <pkgconf/devs_can_at91sam7.h>
63 #include <cyg/infra/diag.h>
65 #include <cyg/io/io.h>
66 #include <cyg/io/devtab.h>
67 #include <cyg/io/can.h>
69 #include <cyg/hal/hal_arch.h>
70 #include <cyg/hal/hal_intr.h>
71 #include <cyg/hal/hal_io.h>
73 #include <cyg/hal/hal_diag.h>
74 #include <cyg/infra/cyg_ass.h>
77 //===========================================================================
79 //===========================================================================
82 // Support debug output if this option is enabled in CDL file
84 #ifdef CYGDBG_DEVS_CAN_AT91SAM7_DEBUG
85 #define AT91SAM7_DBG_PRINT diag_printf
87 #define AT91SAM7_DBG_PRINT( fmt, ... )
92 // we define our own set of register bits in order to be independent from
93 // platform specific names
96 //---------------------------------------------------------------------------
99 #define BIT_MB0 (0x01 << 0)
100 #define BIT_MB1 (0x01 << 1)
101 #define BIT_MB2 (0x01 << 2)
102 #define BIT_MB3 (0x01 << 3)
103 #define BIT_MB4 (0x01 << 4)
104 #define BIT_MB5 (0x01 << 5)
105 #define BIT_MB6 (0x01 << 6)
106 #define BIT_MB7 (0x01 << 7)
109 //---------------------------------------------------------------------------
110 // CAN Mode Register bits (CAN_MR)
112 #define MR_CAN_ENABLE (0x01 << 0)
113 #define MR_LOW_POWER (0x01 << 1)
114 #define MR_AUTOBAUD (0x01 << 2)
115 #define MR_OVERLOAD (0x01 << 3)
116 #define MR_TIMESTAMP_EOF (0x01 << 4)
117 #define MR_TIME_TRIG (0x01 << 5)
118 #define MR_TIMER_FREEZE (0x01 << 6)
119 #define MR_DISABLE_REPEAT (0x01 << 7)
122 //---------------------------------------------------------------------------
123 // CAN Interrupt Enable/Disable, Mask and Status Register bits (CAN_IER, CAN_IDR, CAN_IMR)
125 #define INT_ERR_ACTIVE (0x01 << 16)
126 #define INT_WARN (0x01 << 17)
127 #define INT_ERR_PASSIVE (0x01 << 18)
128 #define INT_BUS_OFF (0x01 << 19)
129 #define INT_SLEEP (0x01 << 20)
130 #define INT_WAKEUP (0x01 << 21)
131 #define INT_TMR_OVF (0x01 << 22)
132 #define INT_TIMESTAMP (0x01 << 23)
133 #define INT_CRC_ERR (0x01 << 24)
134 #define INT_STUFF_ERR (0x01 << 25)
135 #define INT_ACKN_ERR (0x01 << 26)
136 #define INT_FORM_ERR (0x01 << 27)
137 #define INT_BIT_ERR (0x01 << 28)
138 #define INT_MB 0xFF // message box intterupt (mbox 1 - 8)
139 #define INT_MB_RX 0x7F // rx message box interrupts
140 #define INT_MB_TX 0x80 // tx message box interrupts
143 // We do not enable INT_WARN by default because this flug is buggy and causes interrupts
144 // event if no counter reached warning level.
146 #define INT_ALL_ERR (INT_CRC_ERR | INT_STUFF_ERR | INT_ACKN_ERR | INT_FORM_ERR | INT_BIT_ERR)
147 #define INT_DEFAULT (INT_ERR_PASSIVE | INT_BUS_OFF | INT_SLEEP | INT_WAKEUP | INT_ALL_ERR)
151 // these bits are only in status register (CAN_SR)
153 #define SR_RX_BUSY (0x01 << 29)
154 #define SR_TX_BUSY (0x01 << 30)
155 #define SR_OVL_BUSY (0x01 << 31)
158 //---------------------------------------------------------------------------
159 // CAN Baudrate Register (CAN_BR)
161 #define BR_PHASE2_BITMASK 0x00000007
162 #define BR_PHASE1_BITMASK 0x00000070
163 #define BR_PROPAG_BITMASK 0x00000700
164 #define BR_SJW_BITMASK 0x00003000
165 #define BR_BRP_BITMASK 0x007F0000
166 #define BR_SMP_BITMASK 0x01000000
169 //---------------------------------------------------------------------------
170 // CAN Error Counter Register (CAN_ECR)
172 #define ECR_GET_TEC(_ecr_) (((_ecr_) >> 16) & 0xFF)
173 #define ECR_GET_REC(_ecr_) ((_ecr_) & 0xFF)
176 //---------------------------------------------------------------------------
177 // CAN Transfer Command Resgister (CAN_TCR)
179 #define TCR_TMR_RESET 0x80000000
182 //---------------------------------------------------------------------------
183 // CAN Message Mode Register (CAN_MMRx)
185 #define MMR_TIMEMARK_BITMASK 0x0000FFFF
186 #define MMR_PRIOR_BITMASK 0x000F0000
188 #define MMR_MB_SHIFTER 24
189 #define MMR_MB_TYPE_BITMASK (0x07 << MMR_MB_SHIFTER) // mask the mot bits
190 #define MMR_MB_TYPE_DISABLED (0x00 << MMR_MB_SHIFTER) // message box disabled
191 #define MMR_MB_TYPE_RX (0x01 << MMR_MB_SHIFTER) // rx message box
192 #define MMR_MB_TYPE_RX_OVW (0x02 << MMR_MB_SHIFTER) // rx message box with overwrite
193 #define MMR_MB_TYPE_TX (0x03 << MMR_MB_SHIFTER) // tx message box
194 #define MMR_MB_TYPE_CONSUME (0x04 << MMR_MB_SHIFTER) // consumer - receives RTR and sends its content
195 #define MMR_MB_TYPE_PRODUCE (0x05 << MMR_MB_SHIFTER) // producer - sends a RTR and waits for answer
196 #define MMR_MB_GET_TYPE(_mb_) ((_mb_) & MMR_MB_TYPE_BITMASK)
198 //---------------------------------------------------------------------------
199 // CAN Message Acceptance Mask/ID Register (CAN_MAMx, CAN_MIDx)
201 #define MID_MIDvB_BITMASK 0x0003FFFF
202 #define MID_MIDvA_BITMASK 0x1FFC0000
203 #define MID_MIDE 0x20000000
204 #define MID_MIDvA_SHIFTER 18
205 #define MID_SET_STD(_id_) (((_id_) << MID_MIDvA_SHIFTER) & MID_MIDvA_BITMASK)
206 #define MID_SET_EXT(_id_) ((_id_) | MID_MIDE)
207 #define MAM_SET_STD ((((0x7FF << MID_MIDvA_SHIFTER) & MID_MIDvA_BITMASK) | MID_MIDE))
208 #define MAM_SET_EXT 0xFFFFFFFF
209 #define MID_GET_STD(_mid_) (((_mid_) >> MID_MIDvA_SHIFTER) & CYG_CAN_STD_ID_MASK)
210 #define MID_GET_EXT(_mid_) ((_mid_) & CYG_CAN_EXT_ID_MASK)
213 //---------------------------------------------------------------------------
214 // CAN Message Status Register (CAN_MSRx)
216 #define MSR_TIMESTAMP 0x0000FFFF
217 #define MSR_DLC 0x000F0000
218 #define MSR_RTR 0x00100000
219 #define MSR_MSG_ABORT 0x00400000
220 #define MSR_RDY 0x00800000
221 #define MSR_MSG_IGNORED 0x01000000
222 #define MSR_DLC_SHIFTER 16
223 #define MSR_DLC_GET(_msr_) (((_msr_) >> 16) & 0x0F)
225 //---------------------------------------------------------------------------
226 // CAN Message Control Register (CAN_MCRx)
228 #define MCR_DLC 0x000F0000 // MDLC
229 #define MCR_RTR 0x00100000 // MRTR
230 #define MCR_MSG_ABORT 0x00400000 // MACR
231 #define MCR_TRANSFER_CMD 0x00800000 // MTCR
232 #define MCR_DLC_SHIFTER 16
233 #define MCR_DLC_CREATE(_len_) ((_len_) << MCR_DLC_SHIFTER)
235 //---------------------------------------------------------------------------
236 // CAN Module Register Layout
238 #define CANREG_MR 0x0000
239 #define CANREG_IER 0x0004
240 #define CANREG_IDR 0x0008
241 #define CANREG_IMR 0x000C
242 #define CANREG_SR 0x0010
243 #define CANREG_BR 0x0014
244 #define CANREG_TIM 0x0018
245 #define CANREG_TIMESTAMP 0x001C
246 #define CANREG_ECR 0x0020
247 #define CANREG_TCR 0x0024
248 #define CANREG_ACR 0x0028
250 #define CANREG_MB_BASE 0x0200
253 // Register layout of message box relativ to base register of a certain
256 #define CANREG_MMR 0x0000
257 #define CANREG_MAM 0x0004
258 #define CANREG_MID 0x0008
259 #define CANREG_MFID 0x000C
260 #define CANREG_MSR 0x0010
261 #define CANREG_MDL 0x0014
262 #define CANREG_MDH 0x0018
263 #define CANREG_MCR 0x001C
266 #define AT91SAM7_CAN_PERIPHERAL_ID 15
267 #define CAN_MBOX_MIN 0
268 #define CAN_MBOX_MAX 7
269 #define CAN_MBOX_CNT 8
270 #define CAN_MBOX_RX_MIN 0
271 #define CAN_MBOX_RX_MAX (CAN_MBOX_MAX - 1) // one message box is tx
272 #define CAN_MBOX_RX_CNT (CAN_MBOX_CNT - 1) // one message box is tx
274 #define CAN_MR(_extra_) (CAN_BASE(_extra_) + CANREG_MR)
275 #define CAN_IER(_extra_) (CAN_BASE(_extra_) + CANREG_IER)
276 #define CAN_IDR(_extra_) (CAN_BASE(_extra_) + CANREG_IDR)
277 #define CAN_IMR(_etxra_) (CAN_BASE(_extra_) + CANREG_IMR)
278 #define CAN_SR(_etxra_) (CAN_BASE(_extra_) + CANREG_SR)
279 #define CAN_BR(_etxra_) (CAN_BASE(_extra_) + CANREG_BR)
280 #define CAN_TIM(_etxra_) (CAN_BASE(_extra_) + CANREG_TIM)
281 #define CAN_TIMESTAMP(_etxra_) (CAN_BASE(_extra_) + CANREG_TIMESTAMP)
282 #define CAN_ECR(_etxra_) (CAN_BASE(_extra_) + CANREG_ECR)
283 #define CAN_TCR(_etxra_) (CAN_BASE(_extra_) + CANREG_TCR)
284 #define CAN_ACR(_etxra_) (CAN_BASE(_extra_) + CANREG_ACR)
287 // Message box registers
289 #define CAN_MB_BASE(_extra_) (CAN_BASE(_extra_) + CANREG_MB_BASE)
290 #define CAN_MB_MMR(_extra_, _mb_) (CAN_MB_BASE(_extra_) + 0x0020 * (_mb_) + CANREG_MMR)
291 #define CAN_MB_MAM(_extra_, _mb_) (CAN_MB_BASE(_extra_) + 0x0020 * (_mb_) + CANREG_MAM)
292 #define CAN_MB_MID(_extra_, _mb_) (CAN_MB_BASE(_extra_) + 0x0020 * (_mb_) + CANREG_MID)
293 #define CAN_MB_MFID(_extra_, _mb_) (CAN_MB_BASE(_extra_) + 0x0020 * (_mb_) + CANREG_MFID)
294 #define CAN_MB_MSR(_extra_, _mb_) (CAN_MB_BASE(_extra_) + 0x0020 * (_mb_) + CANREG_MSR)
295 #define CAN_MB_MDL(_extra_, _mb_) (CAN_MB_BASE(_extra_) + 0x0020 * (_mb_) + CANREG_MDL)
296 #define CAN_MB_MDH(_extra_, _mb_) (CAN_MB_BASE(_extra_) + 0x0020 * (_mb_) + CANREG_MDH)
297 #define CAN_MB_MCR(_extra_, _mb_) (CAN_MB_BASE(_extra_) + 0x0020 * (_mb_) + CANREG_MCR)
300 //---------------------------------------------------------------------------
301 // Optimize for the case of a single CAN channel, while still allowing
302 // multiple channels. At the moment only AT91SAM7 controllers with one
303 // CAN channel are known.
305 #if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS == 1
307 #define CAN_PID(_extra_) AT91SAM7_CAN_PERIPHERAL_ID
308 #define CAN_ISRVEC(_extra_) CAN_PID(_extra_)
309 #define CAN_ISRPRIO(_extra_) CYGNUM_DEVS_CAN_AT91SAM7_CAN0_ISR_PRIORITY
310 #define CAN_BASE(_extra_) AT91_CAN
311 #define CAN_DECLARE_INFO(_chan_)
312 #define CAN_MBOX_TX(_extra_) CYGNUM_DEVS_CAN_AT91SAM7_CAN0_DEFAULT_TX_MBOX
313 #define CAN_MBOX_STD_CNT(_extra_) CYGNUM_DEVS_CAN_AT91SAM7_CAN0_STD_MBOXES
314 #define CAN_MBOX_EXT_CNT(_extra_) CYGNUM_DEVS_CAN_AT91SAM7_CAN0_EXT_MBOXES
315 #define CAN_MBOX_RX_ALL_CNT(_extra) (CAN_MBOX_STD_CNT(_extra_) + CAN_MBOX_EXT_CNT(_extra_))
317 #ifndef CYGNUM_DEVS_CAN_AT91SAM7_CAN0_STD_MBOXES
318 #define CYGNUM_DEVS_CAN_AT91SAM7_CAN0_STD_MBOXES 0
321 #ifndef CYGNUM_DEVS_CAN_AT91SAM7_CAN0_EXT_MBOXES
322 #define CYGNUM_DEVS_CAN_AT91SAM7_CAN0_EXT_MBOXES 0
325 #else // #if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS == 1
327 #define CAN_PID(_extra_) ((_extra_)->isrvec)
328 #define CAN_ISRVEC(_extra_) ((_extra_)->isrvec)
329 #define CAN_ISRPRIO(_extra_) ((_extra_)->isrprio)
330 #define CAN_BASE(_extra_) ((_extra_)->base)
331 #define CAN_DECLARE_INFO(_chan_) at91sam7_can_info_t *info = (at91sam7_can_info_t *)chan->dev_priv;
332 #define CAN_MBOX_TX(_extra_) 7 // normally it is always the last mailbox
333 #define CAN_MBOX_STD_CNT(_extra_) ((_extra_)->mboxes_std_cnt)
334 #define CAN_MBOX_EXT_CNT(_extra_) ((_extra_)->mboxes_ext_cnt)
335 #define CAN_MBOX_RX_ALL_CNT(_extra) ((_extra_)->mboxes_rx_all_cnt)
337 #endif // #if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS == 1
340 //===========================================================================
342 //===========================================================================
343 typedef struct at91sam7_can_info_t
345 cyg_interrupt interrupt;
346 cyg_handle_t interrupt_handle;
347 cyg_uint32 stat; // buffers status register value between ISR and DSR
348 cyg_uint8 free_mboxes; // number of free message boxes for msg filters and rtr buffers
349 bool rx_all; // true if reception of call can messages is active
350 cyg_can_state state; // state of CAN controller
352 #if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS > 1
353 cyg_uint32 base; // Per-bus h/w details
354 cyg_uint8 isrpri; // ISR priority
355 cyg_uint8 isrvec; // ISR vector (peripheral id)
356 cyg_uint8 mboxes_std_cnt; // contains number of standard message boxes available
357 cyg_uint8 mboxes_ext_cnt; // number of message boxes with ext id
358 cyg_uint8 mboxes_rx_all_cnt;// number of all available mboxes
360 } at91sam7_can_info_t;
364 // at91sam7 info initialisation
366 #if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS > 1
367 #define AT91SAM7_CAN_INFO(_l, _base, _isrpri, _isrvec, _std_mboxes, _ext_mboxes) \
368 at91sam7_can_info_t _l { \
369 state : CYGNUM_CAN_STATE_STOPPED, \
371 isrpri : (_isrpri), \
372 isrvec : (_isrvec), \
373 mboxes_std_cnt : (_std_mboxes), \
374 mboxes_ext_cnt : (_ext_mboxes), \
375 mboxes_rx_all_cnt : ((_std_mboxes) + (_ext_mboxes)), \
378 #define AT91SAM7_CAN_INFO(_l) \
379 at91sam7_can_info_t _l = { \
380 state : CYGNUM_CAN_STATE_STOPPED, \
385 //===========================================================================
387 //===========================================================================
388 #if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS > 1
390 // ToDo - Initialisation of individual CAN channels if more than one channel
393 #else // CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS == 1
395 // Only one single CAN channel supported by SAM7 chip
397 AT91SAM7_CAN_INFO(at91sam7_can0_info);
401 //===========================================================================
403 //===========================================================================
405 // Macro for creation of CAN_BR value for baudrate tbl
408 #define CAN_BR_TBL_ENTRY(_brp_, _propag_, _phase1_, _phase2_, _sjw_) \
409 ((_brp_ << 16) | (_propag_ << 8) | (_phase2_) | (_phase1_ << 4) | (_sjw_ << 12))
412 // Table with register values for baudrates at main clock of 48 MHz
414 static const cyg_uint32 at91sam7_br_tbl[] =
416 CAN_BR_TBL_ENTRY(0xef, 0x07, 0x07, 0x02, 0), // 10 kbaud
417 CAN_BR_TBL_ENTRY(0x95, 0x04, 0x07, 0x01, 0), // 20 kbaud
418 CAN_BR_TBL_ENTRY(0x3b, 0x04, 0x07, 0x01, 0), // 50 kbaud
419 CAN_BR_TBL_ENTRY(0x1d, 0x04, 0x07, 0x01, 0), // 100 kbaud
420 CAN_BR_TBL_ENTRY(0x17, 0x04, 0x07, 0x01, 0), // 125 kbaud
421 CAN_BR_TBL_ENTRY(0x0b, 0x04, 0x07, 0x01, 0), // 250 kbaud
422 CAN_BR_TBL_ENTRY(0x05, 0x04, 0x07, 0x01, 0), // 500 kbaud
423 CAN_BR_TBL_ENTRY(0x03, 0x03, 0x07, 0x01, 0), // 800 kbaud
424 CAN_BR_TBL_ENTRY(0x02, 0x04, 0x07, 0x01, 0), // 1000 kbaud
425 CAN_BR_TBL_ENTRY(0x00, 0x00, 0x00, 0x00, 0), // Autobaud
429 // Macro fills baudrate register value depending on selected baudrate
430 // For a standard AT91 clock speed of 48 MHz we provide a pre calculated
431 // baudrate table. If the board uses another clock speed, then the platform
432 // HAL needs to provide an own HAL_AT91SAM7_GET_CAN_BR() macro that returns
433 // valid baudrate register values
435 #ifdef CYGNUM_HAL_ARM_AT91_CLOCK_SPEED_48000000
436 #define HAL_AT91SAM7_GET_CAN_BR(_baudrate_, _br_) \
438 _br_ = at91sam7_br_tbl[(_baudrate_) - CYGNUM_CAN_KBAUD_10]; \
443 //===========================================================================
445 //===========================================================================
447 //--------------------------------------------------------------------------
448 // Device driver interface functions
450 static bool at91sam7_can_init(struct cyg_devtab_entry* devtab_entry);
451 static Cyg_ErrNo at91sam7_can_lookup(struct cyg_devtab_entry** tab, struct cyg_devtab_entry* sub_tab, const char* name);
452 static Cyg_ErrNo at91sam7_can_set_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len);
453 static Cyg_ErrNo at91sam7_can_get_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len);
454 static bool at91sam7_can_putmsg(can_channel *priv, CYG_CAN_MSG_T *pmsg, void *pdata);
455 static bool at91sam7_can_getevent(can_channel *priv, CYG_CAN_EVENT_T *pevent, void *pdata);
456 static void at91sam7_can_start_xmit(can_channel* chan);
457 static void at91sam7_can_stop_xmit(can_channel* chan);
460 //--------------------------------------------------------------------------
463 static cyg_uint32 at91sam7_can_ISR(cyg_vector_t vector, cyg_addrword_t data);
464 static void at91sam7_can_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
467 //--------------------------------------------------------------------------
468 // Private utility functions
470 static bool at91sam7_can_config_channel(can_channel* chan, cyg_can_info_t* config, cyg_bool init);
471 static bool at91sam7_can_set_baud(can_channel *chan, cyg_can_baud_rate_t *baudrate);
472 static void at91sam7_can_mbox_config_rx_all(can_channel *chan);
473 static void at91sam7_can_setup_mbox(can_channel *chan, // channel
474 cyg_uint8 mbox, // message box number (0 -7)
475 cyg_uint32 mid, // message identifier
476 cyg_uint32 mam, // acceptance mask for this message box
477 cyg_uint32 rxtype); // RX or RX with overwrite are valid values
478 static void at91sam7_enter_lowpower_mode(can_channel *chan);
479 static void at91sam7_start_module(can_channel *chan);
480 static cyg_can_state at91sam7_get_state(at91sam7_can_info_t *info);
482 #ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
483 static void at91sam7_can_config_rx_none(can_channel *chan);
484 static Cyg_ErrNo at91sam7_can_set_config_msgbuf(can_channel *chan, cyg_can_msgbuf_cfg *buf);
490 //===========================================================================
491 // GENERIC CAN IO DATA INITIALISATION
492 //===========================================================================
493 CAN_LOWLEVEL_FUNS(at91sam7_can_lowlevel_funs,
495 at91sam7_can_getevent,
496 at91sam7_can_get_config,
497 at91sam7_can_set_config,
498 at91sam7_can_start_xmit,
499 at91sam7_can_stop_xmit
503 CYG_CAN_EVENT_T at91sam7_can0_rxbuf[CYGNUM_DEVS_CAN_AT91SAM7_CAN0_QUEUESIZE_RX]; // buffer for RX can events
504 CYG_CAN_MSG_T at91sam7_can0_txbuf[CYGNUM_DEVS_CAN_AT91SAM7_CAN0_QUEUESIZE_TX]; // buffer for TX can messages
507 CAN_CHANNEL_USING_INTERRUPTS(at91sam7_can0_chan,
508 at91sam7_can_lowlevel_funs,
510 CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_AT91SAM7_CAN0_KBAUD),
511 at91sam7_can0_txbuf, CYGNUM_DEVS_CAN_AT91SAM7_CAN0_QUEUESIZE_TX,
512 at91sam7_can0_rxbuf, CYGNUM_DEVS_CAN_AT91SAM7_CAN0_QUEUESIZE_RX
516 DEVTAB_ENTRY(at91sam7_can_devtab,
517 CYGPKG_DEVS_CAN_AT91SAM7_CAN0_NAME,
518 0, // Does not depend on a lower level interface
521 at91sam7_can_lookup, // CAN driver may need initializing
526 //===========================================================================
528 //===========================================================================
532 //===========================================================================
533 /// First initialisation and reset of CAN modul.
534 //===========================================================================
535 static bool at91sam7_can_init(struct cyg_devtab_entry* devtab_entry)
537 can_channel *chan = (can_channel*)devtab_entry->priv;
538 at91sam7_can_info_t *info = (at91sam7_can_info_t *)chan->dev_priv;
540 #ifdef CYGDBG_IO_INIT
541 diag_printf("AT91 CAN init\n");
543 cyg_drv_interrupt_create(CAN_ISRVEC(info),
544 CAN_ISRPRIO(info), // Priority
545 (cyg_addrword_t)chan, // Data item passed to interrupt handler
548 &info->interrupt_handle,
550 cyg_drv_interrupt_attach(info->interrupt_handle);
551 cyg_drv_interrupt_unmask(CAN_ISRVEC(info));
553 return at91sam7_can_config_channel(chan, &chan->config, true);
557 //===========================================================================
558 // Lookup the device and return its handle
559 //===========================================================================
560 static Cyg_ErrNo at91sam7_can_lookup(struct cyg_devtab_entry** tab, struct cyg_devtab_entry* sub_tab, const char* name)
562 can_channel* chan = (can_channel*) (*tab)->priv;
563 CAN_DECLARE_INFO(chan);
565 chan->callbacks->can_init(chan);
566 HAL_WRITE_UINT32(CAN_IER(info), INT_DEFAULT); // enable wakeup and error interrupts
567 HAL_WRITE_UINT32(AT91_PMC+AT91_PMC_PCER, 1 << CAN_PID(info)); // Enable the peripheral clock to the device
570 // It is important to setup the message buffer configuration after enabling the
571 // peripheral clock. This is nowhere documented in the at91sam7 hardware manual.
572 // If the message buffer configuration is set before the peripheral clock is
573 // enabled, then message buffers that receive extended frames might not work
576 at91sam7_can_mbox_config_rx_all(chan);
582 #ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
583 //===========================================================================
584 // Setup AT91SAM7 CAN module in a state where all message boxes are disabled
585 // After this callit is possible to add single message buffers and filters
586 //===========================================================================
587 static void at91sam7_can_config_rx_none(can_channel *chan)
589 at91sam7_can_info_t *info = (at91sam7_can_info_t *)chan->dev_priv;
593 // setup all RX messages moxes into a disabled state and disable all
594 // interrupts - maybe we have to abort pending transfers before $$$$
596 HAL_WRITE_UINT32(CAN_IDR(info), INT_MB_RX);
597 for (i = 0; i < CAN_MBOX_RX_CNT; ++i)
599 HAL_WRITE_UINT32(CAN_MB_MMR(info, i), MMR_MB_TYPE_DISABLED); // first disable message box
602 info->free_mboxes = CAN_MBOX_RX_CNT;
603 info->rx_all = false;
607 //===========================================================================
608 // Add single message filter - setupm message box and enable interrupt
609 //===========================================================================
610 static void at91sam7_can_add_rx_filter(can_channel *chan, cyg_uint8 mbox, cyg_can_message *msg)
612 CAN_DECLARE_INFO(chan);
616 at91sam7_can_setup_mbox(chan, mbox, MID_SET_EXT(msg->id), MAM_SET_EXT, MMR_MB_TYPE_RX);
620 at91sam7_can_setup_mbox(chan, mbox, MID_SET_STD(msg->id), MAM_SET_STD, MMR_MB_TYPE_RX);
622 HAL_WRITE_UINT32(CAN_IER(info), 0x01 << mbox);
624 #endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
627 #ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
628 //===========================================================================
629 // Allocate message box
630 // Try to find a free message box and return its ID
631 //===========================================================================
632 static cyg_int8 at91sam7_can_alloc_mbox(at91sam7_can_info_t *info)
635 cyg_int8 res = CYGNUM_CAN_MSGBUF_NA;
637 if (info->free_mboxes)
639 for (i = (CAN_MBOX_RX_CNT - info->free_mboxes); i <= CAN_MBOX_RX_MAX; ++i)
642 HAL_READ_UINT32(CAN_MB_MMR(info, i), mmr);
643 if ((mmr & MMR_MB_TYPE_BITMASK) == MMR_MB_TYPE_DISABLED)
650 } // if (info->free_mboxes)
654 #endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
657 #ifdef CYGOPT_IO_CAN_REMOTE_BUF
658 //===========================================================================
659 // Setup a RTR response message box
660 //===========================================================================
661 static bool at91sam7_can_setup_rtrmbox(can_channel *chan,
663 cyg_can_message *pmsg,
666 CAN_DECLARE_INFO(chan);
670 // To prevent concurrent access with the internal CAN core, the application
671 // must disable the mailbox before writing to CAN_MIDx registers - so we
678 at91sam7_can_setup_mbox(chan, mbox, MID_SET_EXT(pmsg->id), MAM_SET_EXT, MMR_MB_TYPE_PRODUCE);
682 at91sam7_can_setup_mbox(chan, mbox, MID_SET_STD(pmsg->id), MAM_SET_STD, MMR_MB_TYPE_PRODUCE);
684 HAL_WRITE_UINT32(CAN_IER(info), 0x01 << mbox); // enable interrupt
690 // Check if this message box is ready for transmission or if it still transmits
691 // a message - we read the MSR register to check the ready flag
693 HAL_READ_UINT32(CAN_MB_MSR(info, mbox), msr);
694 if (!(msr & MSR_RDY))
696 AT91SAM7_DBG_PRINT("(RTR) !MSR_RDY\n");
701 HAL_WRITE_UINT32(CAN_MB_MDL(info, mbox), pmsg->data.dwords[0]); // set data
702 HAL_WRITE_UINT32(CAN_MB_MDH(info, mbox), pmsg->data.dwords[1]); // set data
703 mcr = (pmsg->dlc << MCR_DLC_SHIFTER) | MCR_TRANSFER_CMD; // set data lengt and transfer request
704 HAL_WRITE_UINT32(CAN_MB_MCR(info, mbox), mcr); // transfer request
707 #endif // CYGOPT_IO_CAN_REMOTE_BUF
710 #ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
711 //===========================================================================
712 // Configure message buffers
713 //===========================================================================
714 static Cyg_ErrNo at91sam7_can_set_config_msgbuf(can_channel *chan, cyg_can_msgbuf_cfg *buf)
716 Cyg_ErrNo res = ENOERR;
717 at91sam7_can_info_t *info = (at91sam7_can_info_t *)chan->dev_priv;
722 // clear all message filters and remote buffers - prepare for message buffer
725 case CYGNUM_CAN_MSGBUF_RESET_ALL :
727 at91sam7_can_config_rx_none(chan);
732 // setup AT91SAM7 CAN module for reception of all standard and extended messages
734 case CYGNUM_CAN_MSGBUF_RX_FILTER_ALL :
736 if (!info->rx_all) // if rx_all is enabled we do not need to do anything
738 at91sam7_can_mbox_config_rx_all(chan); // setup RX all state
744 // add single message filter, message with filter ID will be received
746 case CYGNUM_CAN_MSGBUF_RX_FILTER_ADD :
748 cyg_can_filter *filter = (cyg_can_filter*) buf;
751 // if AT91SAM7 CAN module is configured to receive all messages then
752 // it is not allowed to add single message filters because then more
753 // than one message buffer would receive the same CAN id
761 // try to allocate a free message box - if we have a free one
762 // then we can prepare the message box for reception of the
763 // desired message id
765 filter->handle = at91sam7_can_alloc_mbox(info);
766 if (filter->handle > CYGNUM_CAN_MSGBUF_NA)
768 at91sam7_can_add_rx_filter(chan, filter->handle, &filter->msg);
771 break; //CYGNUM_CAN_MSGBUF_RX_FILTER_ADD
774 #ifdef CYGOPT_IO_CAN_REMOTE_BUF
776 // Try to add a new RTR response message buffer for automatic transmisson
777 // of data frame on reception of a remote frame
779 case CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD :
781 cyg_can_remote_buf *rtr_buf = (cyg_can_remote_buf*) buf;
782 rtr_buf->handle = at91sam7_can_alloc_mbox(info);
784 if (rtr_buf->handle > CYGNUM_CAN_MSGBUF_NA)
787 // if we have a free message buffer then we setup this buffer
788 // for remote frame reception
790 at91sam7_can_setup_rtrmbox(chan, rtr_buf->handle, &rtr_buf->msg, true);
796 // write data into remote response buffer
798 case CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE :
800 cyg_can_remote_buf *rtr_buf = (cyg_can_remote_buf*) buf;
802 // If we have a valid rtr buf handle then we can store data into
805 if ((rtr_buf->handle >= 0) && (rtr_buf->handle <= CAN_MBOX_RX_MAX))
807 if (!at91sam7_can_setup_rtrmbox(chan, rtr_buf->handle, &rtr_buf->msg, false))
818 #endif // #ifdef CYGOPT_IO_CAN_REMOTE_BUF
819 } // switch (buf->cfg_id)
823 #endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
826 //===========================================================================
827 // Read state of CAN controller
828 // The CAN state variable for each channel is modiefied by DSR so if we
829 // read the state we need to lock DSRs to protect the data access
830 //===========================================================================
831 static cyg_can_state at91sam7_get_state(at91sam7_can_info_t *info)
833 cyg_can_state result;
836 result = info->state;
837 cyg_drv_dsr_unlock();
843 //===========================================================================
844 // Enter low power mode
845 // Before stopping the CAN clock (PMC), the CAN Controller must be in
846 // Low-power Mode to complete the current transfer. After restarting the
847 // clock, the application must disable the Low-power Mode of the
848 // CAN controller. If the power mode is entered, a sleep interrupt is
850 //===========================================================================
851 static void at91sam7_enter_lowpower_mode(can_channel *chan)
853 CAN_DECLARE_INFO(chan);
857 HAL_READ_UINT32(CAN_MR(info), mr);
858 HAL_WRITE_UINT32(CAN_MR(info), mr | MR_LOW_POWER);
859 HAL_WRITE_UINT32(CAN_IER(info), INT_SLEEP);
863 //===========================================================================
864 // Start CAN module (or leave the low power mode)
865 // If the CAN module is in STANDBY state then we enable the module clock
866 // and leave the low power mode by clearing the low power flag.
867 //===========================================================================
868 static void at91sam7_start_module(can_channel *chan)
870 CAN_DECLARE_INFO(chan);
873 HAL_WRITE_UINT32(CAN_IER(info), INT_DEFAULT); // enable wakeup interrupt
874 HAL_WRITE_UINT32(AT91_PMC+AT91_PMC_PCER, 1 << CAN_PID(info)); // restart peripheral clock
875 HAL_READ_UINT32(CAN_MR(info), mr);
876 mr &= ~MR_LOW_POWER ;
877 HAL_WRITE_UINT32(CAN_MR(info), mr | MR_CAN_ENABLE); // clear the low power flag to leave standby
880 //===========================================================================
881 // Change device configuration
882 //===========================================================================
883 static Cyg_ErrNo at91sam7_can_set_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len)
885 Cyg_ErrNo res = ENOERR;
890 // Setup a new CAN configuration. This will i.e. setup a new baud rate
892 case CYG_IO_SET_CONFIG_CAN_INFO:
894 cyg_can_info_t* config = (cyg_can_info_t*) buf;
895 if (*len < sizeof(cyg_can_info_t))
899 *len = sizeof(cyg_can_info_t);
900 if (!at91sam7_can_config_channel(chan, config, false))
907 #ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
909 // configure message buffers
911 case CYG_IO_SET_CONFIG_CAN_MSGBUF :
913 cyg_can_msgbuf_cfg *msg_buf = (cyg_can_msgbuf_cfg *)buf;
915 if (*len != sizeof(cyg_can_msgbuf_cfg))
920 res = at91sam7_can_set_config_msgbuf(chan, msg_buf);
923 #endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
926 // Change CAN state of AT91SAM7 CAN module
928 case CYG_IO_SET_CONFIG_CAN_MODE :
930 cyg_can_mode *can_mode = (cyg_can_mode*) buf;
932 if (*len != sizeof(cyg_can_mode))
936 *len = sizeof(cyg_can_mode);
939 // decide what to do acording to mode
944 // The controller does not support a stopped and standby state so we
945 // simply enter the low power state here. This state is also safe for
946 // message buffer configuration
948 case CYGNUM_CAN_MODE_STOP : at91sam7_enter_lowpower_mode(chan); break;
949 case CYGNUM_CAN_MODE_START : at91sam7_start_module(chan); break;
950 case CYGNUM_CAN_MODE_STANDBY : at91sam7_enter_lowpower_mode(chan); break;
951 case CYGNUM_CAN_MODE_CONFIG : at91sam7_enter_lowpower_mode(chan); break;
954 break; // case CYG_IO_SET_CONFIG_CAN_MODE :
961 //===========================================================================
962 // Query device configuration
963 //===========================================================================
964 static Cyg_ErrNo at91sam7_can_get_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len)
966 Cyg_ErrNo res = ENOERR;
967 at91sam7_can_info_t *info = (at91sam7_can_info_t *)chan->dev_priv;
972 // query state of CAN controller
974 case CYG_IO_GET_CONFIG_CAN_STATE :
976 cyg_can_state *can_state = (cyg_can_state*) buf;
978 if (*len != sizeof(cyg_can_state))
982 *len = sizeof(cyg_can_state);
983 *can_state = at91sam7_get_state(info);
987 #ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
989 // Query message box information - returns available and free message
992 case CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO :
994 cyg_can_msgbuf_info *mbox_info = (cyg_can_msgbuf_info*) buf;
996 if (*len != sizeof(cyg_can_msgbuf_info))
1000 *len = sizeof(cyg_can_msgbuf_info);
1002 mbox_info->count = CAN_MBOX_RX_CNT;
1003 mbox_info->free = info->free_mboxes;
1006 #endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
1010 // Query hardware description of FlexCAN device driver
1012 case CYG_IO_GET_CONFIG_CAN_HDI :
1014 cyg_can_hdi *hdi = (cyg_can_hdi *)buf;
1016 // comes from high level driver so we do not need to
1017 // check buffer size here
1019 hdi->support_flags = CYGNUM_CAN_HDI_FRAMETYPE_EXT_ACTIVE
1020 | CYGNUM_CAN_HDI_FULLCAN
1021 | CYGNUM_CAN_HDI_AUTBAUD;
1022 #ifdef CYGOPT_IO_CAN_SUPPORT_TIMESTAMP
1023 hdi->support_flags |= CYGNUM_CAN_HDI_TIMESTAMP;
1036 //===========================================================================
1037 // Send single message
1038 //===========================================================================
1039 static bool at91sam7_can_putmsg(can_channel *priv, CYG_CAN_MSG_T *pmsg, void *pdata)
1041 CAN_DECLARE_INFO(priv);
1046 // First check if this message box is ready fro transmission or if it still transmits
1047 // a message - we read the MSR register to check the ready flag
1049 HAL_READ_UINT32(CAN_MB_MSR(info, CAN_MBOX_TX(info)), msr);
1050 if (!(msr & MSR_RDY))
1052 AT91SAM7_DBG_PRINT("!MSR_RDY\n");
1057 // To prevent concurrent access with the internal CAN core, the application must disable
1058 // the mailbox before writing to CAN_MIDx registers - so we do this now
1060 HAL_WRITE_UINT32(CAN_MB_MMR(info, CAN_MBOX_TX(info)), MMR_MB_TYPE_DISABLED);
1063 // Setup the message identifier - this depends on the frame type (standard or extended)
1065 #ifdef CYGOPT_IO_CAN_EXT_CAN_ID
1066 if (AT91SAM7_CAN_IS_EXT(*pmsg))
1068 HAL_WRITE_UINT32(CAN_MB_MID(info, CAN_MBOX_TX(info)),
1069 pmsg->id | MID_MIDE); // set extended message id
1072 #endif // CYGOPT_IO_CAN_EXT_CAN_ID
1074 #ifdef CYGOPT_IO_CAN_STD_CAN_ID
1075 HAL_WRITE_UINT32(CAN_MB_MID(info, CAN_MBOX_TX(info)),
1076 (pmsg->id << MID_MIDvA_SHIFTER) & MID_MIDvA_BITMASK); // set standard message id
1077 #endif // CYGOPT_IO_CAN_STD_CAN_ID
1080 HAL_WRITE_UINT32(CAN_MB_MDL(info, CAN_MBOX_TX(info)), pmsg->data.dwords[0]); // set data
1081 HAL_WRITE_UINT32(CAN_MB_MDH(info, CAN_MBOX_TX(info)), pmsg->data.dwords[1]); // set data
1082 HAL_WRITE_UINT32(CAN_MB_MMR(info, CAN_MBOX_TX(info)), MMR_MB_TYPE_TX); // reenable the message box
1083 mcr = (AT91SAM7_CAN_GET_DLC(*pmsg) << MCR_DLC_SHIFTER) | MCR_TRANSFER_CMD; // set data lengt and transfer request
1085 if (AT91SAM7_CAN_IS_RTR(*pmsg))
1090 HAL_WRITE_UINT32(CAN_MB_MCR(info, CAN_MBOX_TX(info)), mcr);
1095 //===========================================================================
1096 // Read event from device driver
1097 //===========================================================================
1098 static bool at91sam7_can_getevent(can_channel *chan, CYG_CAN_EVENT_T *pevent, void *pdata)
1100 at91sam7_can_info_t *info = (at91sam7_can_info_t *)chan->dev_priv;
1101 cyg_uint32* pstat = (cyg_uint32 *)pdata;
1102 cyg_uint8 mboxflags = (*pstat & INT_MB_RX);
1107 // First check if a message box interrupt occured if a message box interrupt
1108 // occured process the lowest message box that caused an interrupt
1116 while (!(mboxflags & 0x01))
1123 // If the message box that caused the interrupt is an PRODUCER message box,
1124 // then we received an remote request message, if not, then this is a normal
1127 HAL_READ_UINT32(CAN_MB_MMR(info, mbox), mmr);
1128 HAL_READ_UINT32(CAN_MB_MSR(info, mbox), msr);
1129 *pstat &= ~(0x01 << mbox); // clear flag
1131 if (MMR_MB_GET_TYPE(mmr) != MMR_MB_TYPE_PRODUCE)
1133 HAL_READ_UINT32(CAN_MB_MID(info, mbox), mid);
1134 pevent->flags |= CYGNUM_CAN_EVENT_RX;
1135 if (msr & MSR_MSG_IGNORED)
1137 pevent->flags |= CYGNUM_CAN_EVENT_OVERRUN_RX;
1141 // It is important to set the DLC first because this also clears the ctrl
1142 // field if extended identifiers are supported
1144 AT91SAM7_CAN_SET_DLC(pevent->msg, MSR_DLC_GET(msr));
1146 #ifdef CYGOPT_IO_CAN_EXT_CAN_ID
1149 pevent->msg.id = MID_GET_EXT(mid);
1150 AT91SAM7_CAN_SET_EXT(pevent->msg);
1153 #endif // CYGOPT_IO_CAN_EXT_CAN_ID
1155 #ifdef CYGOPT_IO_CAN_STD_CAN_ID
1156 pevent->msg.id = MID_GET_STD(mid);
1157 #endif // CYGOPT_IO_CAN_STD_CAN_ID
1162 AT91SAM7_CAN_SET_RTR(pevent->msg);
1166 HAL_READ_UINT32(CAN_MB_MDL(info, mbox), pevent->msg.data.dwords[0]);
1167 HAL_READ_UINT32(CAN_MB_MDH(info, mbox), pevent->msg.data.dwords[1]);
1169 #ifdef CYGOPT_IO_CAN_SUPPORT_TIMESTAMP
1170 pevent->timestamp = msr & MSR_TIMESTAMP;
1173 HAL_WRITE_UINT32(CAN_MB_MCR(info, mbox), MCR_TRANSFER_CMD); // transfer request
1174 AT91SAM7_DBG_PRINT("RXID: %x\n", AT91SAM7_CAN_GET_ID(pevent->msg));
1175 } // if (!(mbox & info->rtr_mboxes)
1178 HAL_WRITE_UINT32(CAN_MB_MCR(info, mbox), (msr & MSR_DLC) | MCR_TRANSFER_CMD); // transfer request
1180 // We do not need to store an event into receive queue if the stat field does
1181 // not contain any further event flags. If stat is empty we can set res
1182 // to false and no event will bestore
1184 res = !(*pstat == 0);
1187 HAL_WRITE_UINT32(CAN_IER(info), 0x01 << mbox); // enable interruptfor this message box
1191 // Now check if additional events occured
1195 if (*pstat & INT_WAKEUP)
1197 AT91SAM7_DBG_PRINT("WAKE\n");
1198 pevent->flags |= CYGNUM_CAN_EVENT_LEAVING_STANDBY;
1199 *pstat &= ~INT_WAKEUP;
1200 info->state = CYGNUM_CAN_STATE_ACTIVE;
1203 if (*pstat & INT_ERR_PASSIVE)
1205 AT91SAM7_DBG_PRINT("ERRP\n");
1206 pevent->flags |= CYGNUM_CAN_EVENT_ERR_PASSIVE;
1207 *pstat &= ~INT_ERR_PASSIVE;
1208 info->state = CYGNUM_CAN_STATE_ERR_PASSIVE;
1209 HAL_WRITE_UINT32(CAN_IER(info), INT_WAKEUP);
1212 if (*pstat & INT_WARN)
1215 // check which counter reached its warning level (> 96)
1218 HAL_READ_UINT32(CAN_ECR(info), ecr);
1219 if (ECR_GET_REC(ecr) > 96)
1221 pevent->flags |= CYGNUM_CAN_EVENT_WARNING_RX;
1222 AT91SAM7_DBG_PRINT("WARN TX\n");
1224 if (ECR_GET_TEC(ecr) > 96)
1226 pevent->flags |= CYGNUM_CAN_EVENT_WARNING_TX;
1227 AT91SAM7_DBG_PRINT("WARN RX\n");
1229 *pstat &= ~INT_WARN;
1230 info->state = CYGNUM_CAN_STATE_BUS_WARN;
1231 HAL_WRITE_UINT32(CAN_IER(info), INT_ERR_PASSIVE | INT_BUS_OFF);
1234 if (*pstat & INT_BUS_OFF)
1236 pevent->flags |= CYGNUM_CAN_EVENT_BUS_OFF;
1237 AT91SAM7_DBG_PRINT("BOFF\n");
1238 *pstat &= ~INT_BUS_OFF;
1239 info->state = CYGNUM_CAN_STATE_BUS_OFF;
1240 HAL_WRITE_UINT32(CAN_IER(info), INT_WAKEUP);
1243 if (*pstat & INT_SLEEP)
1245 pevent->flags |= CYGNUM_CAN_EVENT_ENTERING_STANDBY;
1246 AT91SAM7_DBG_PRINT("SLEEP\n");
1247 *pstat &= ~INT_SLEEP;
1248 HAL_WRITE_UINT32(AT91_PMC+AT91_PMC_PCDR, 1 << CAN_PID(info)); // disable module clock
1249 info->state = CYGNUM_CAN_STATE_STANDBY; // set state variable
1250 HAL_WRITE_UINT32(CAN_IER(info), INT_WAKEUP); // enable wakeup interrupt
1253 if (*pstat & (INT_CRC_ERR | INT_STUFF_ERR | INT_ACKN_ERR | INT_FORM_ERR | INT_BIT_ERR))
1255 pevent->flags |= CYGNUM_CAN_EVENT_CAN_ERR;
1256 AT91SAM7_DBG_PRINT("CERR\n");
1257 *pstat &= ~(INT_CRC_ERR | INT_STUFF_ERR | INT_ACKN_ERR | INT_FORM_ERR | INT_BIT_ERR);
1265 //===========================================================================
1267 //===========================================================================
1268 static void at91sam7_can_start_xmit(can_channel* chan)
1270 CAN_DECLARE_INFO(chan);
1272 AT91SAM7_DBG_PRINT("start_xmit\n");
1274 HAL_WRITE_UINT32(CAN_IER(info), 0x01 << CAN_MBOX_TX(info)); // enable tx interrupt
1275 cyg_drv_dsr_unlock();
1279 //===========================================================================
1281 //===========================================================================
1282 static void at91sam7_can_stop_xmit(can_channel* chan)
1284 CAN_DECLARE_INFO(chan);
1286 HAL_WRITE_UINT32(CAN_IDR(info), 0x01 << CAN_MBOX_TX(info)); // disable tx interrupt
1287 AT91SAM7_DBG_PRINT("stop_xmit\n");
1291 //===========================================================================
1292 // Configure can channel
1293 //===========================================================================
1294 static bool at91sam7_can_config_channel(can_channel* chan, cyg_can_info_t* config, cyg_bool init)
1296 CAN_DECLARE_INFO(chan);
1303 // If the platform that uses the driver needs to do some platform specific
1304 // initialisation steps, it can do it inside of this macro. I.e. some platforms
1305 // need to setup the CAN transceiver properly here (this is necessary for the
1306 // Atmel AT91SAM7X-EK)
1308 #if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS == 1 && defined(HAL_AT91SAM7_CAN0_PLF_INIT)
1309 HAL_AT91SAM7_CAN0_PLF_INIT();
1310 #else // CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS > 1
1311 #if defined(CYGPKG_DEVS_CAN_AT91SAM7_CAN0) && defined(HAL_AT91SAM7_CAN0_PLF_INIT)
1312 if (info == &at91sam7_can0_info) {
1313 HAL_AT91SAM7_CAN0_PLF_INIT();
1315 #endif // defined(CYGPKG_DEVS_CAN_AT91SAM7_CAN0) && defined(HAL_AT91SAM7_CAN0_PLF_INIT)
1316 #if defined(CYGPKG_DEVS_CAN_AT91SAM7_CAN1) && defined(HAL_AT91SAM7_CAN1_PLF_INIT)
1317 if (info == &at91sam7_can1_info) {
1318 HAL_AT91SAM7_CAN1_PLF_INIT();
1320 #endif // defined(CYGPKG_DEVS_CAN_AT91SAM7_CAN0) && defined(HAL_AT91SAM7_CAN0_PLF_INIT)
1321 #endif // CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS == 1
1323 HAL_WRITE_UINT32(CAN_IDR(info), 0xFFFFFFFF); // disable all interrupts
1324 HAL_WRITE_UINT32(CAN_MR(info), 0x00); // disable CAN module
1325 HAL_ARM_AT91_PIO_CFG(AT91_CAN_CANRX); // Enable the CAN module to drive the CAN port pins
1326 HAL_ARM_AT91_PIO_CFG(AT91_CAN_CANTX);
1328 HAL_WRITE_UINT32(CAN_MB_MMR(info, CAN_MBOX_TX(info)), MMR_MB_TYPE_DISABLED); // first disable tx message box
1329 HAL_WRITE_UINT32(CAN_MB_MAM(info, CAN_MBOX_TX(info)), 0x00000000); // set acceptance mask once
1330 HAL_WRITE_UINT32(CAN_MB_MMR(info, CAN_MBOX_TX(info)), MMR_MB_TYPE_TX); // setup as tx message box
1332 HAL_WRITE_UINT32(CAN_MR(info), MR_CAN_ENABLE); // enable CAN module
1335 // The device should go into error active state right after enabling it
1337 HAL_READ_UINT32(CAN_SR(info), temp32);
1338 if (!(temp32 & INT_ERR_ACTIVE))
1344 res = at91sam7_can_set_baud(chan, &config->baud); // set baudrate
1347 // store new config values
1349 if (config != &chan->config)
1351 chan->config = *config;
1358 //===========================================================================
1359 // Low level interrupt handler
1360 //===========================================================================
1361 static cyg_uint32 at91sam7_can_ISR(cyg_vector_t vector, cyg_addrword_t data)
1363 can_channel *chan = (can_channel *)data;
1364 at91sam7_can_info_t * const info = (at91sam7_can_info_t *)chan->dev_priv;
1369 HAL_READ_UINT32(CAN_IMR(info), imr);
1370 HAL_READ_UINT32(CAN_SR(info), sr);
1371 AT91SAM7_DBG_PRINT("CAN_ISR SR %x\n", sr);
1373 HAL_WRITE_UINT32(CAN_IDR(info), sr);
1376 cyg_drv_interrupt_acknowledge(vector);
1377 return CYG_ISR_CALL_DSR;
1381 //===========================================================================
1382 // High level interrupt handler
1383 //===========================================================================
1384 static void at91sam7_can_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
1386 can_channel *chan = (can_channel *)data;
1387 at91sam7_can_info_t * const info = (at91sam7_can_info_t *)chan->dev_priv;
1388 cyg_uint32 stat = 0;
1393 // If a number of events occured then we process all events now in
1394 // in this DSR the get_event() function clears the flags in the stat
1399 if (stat & (0x01 << CAN_MBOX_TX(info)))
1401 AT91SAM7_DBG_PRINT("TX_DSR\n");
1402 chan->callbacks->xmt_msg(chan, 0); // send next message
1403 stat &= ~INT_MB_TX; // clear flag
1407 AT91SAM7_DBG_PRINT("EVENT_DSR\n");
1408 chan->callbacks->rcv_event(chan, &stat);
1413 // We check, if a new event occured while we processed other events. If new events
1414 // occured, then we process the new events
1416 cyg_drv_interrupt_mask(vector);
1419 cyg_drv_interrupt_unmask(vector);
1424 //===========================================================================
1425 // Set baudrate of certain can channel
1426 //===========================================================================
1427 static bool at91sam7_can_set_baud(can_channel *chan, cyg_can_baud_rate_t *baudrate)
1432 CAN_DECLARE_INFO(chan);
1435 #ifdef CYGOPT_IO_CAN_AUTOBAUD
1436 if (CYGNUM_CAN_KBAUD_AUTO == *baudrate)
1438 cyg_can_baud_rate_t i;
1443 for (i = CYGNUM_CAN_KBAUD_10; i <= CYGNUM_CAN_KBAUD_1000; ++i)
1445 HAL_AT91SAM7_GET_CAN_BR(i, canbr);
1451 HAL_READ_UINT32(CAN_SR(info), sr);
1452 HAL_WRITE_UINT32(CAN_MR(info), 0); // disable the module
1453 HAL_WRITE_UINT32(CAN_BR(info), canbr); // write baudrate register
1454 HAL_WRITE_UINT32(CAN_MR(info), MR_CAN_ENABLE | MR_AUTOBAUD); // enable controller in auto aud mode
1455 for(j = 0; j < 200; ++j)
1457 HAL_DELAY_US(1000); // wait at least 11 bit times for synchronization
1459 HAL_READ_UINT32(CAN_SR(info), sr); // read status register
1460 if (!(sr & INT_ALL_ERR) && (sr & INT_WAKEUP))
1462 HAL_WRITE_UINT32(CAN_MR(info), 0); // disable the module
1463 HAL_WRITE_UINT32(CAN_MR(info), MR_CAN_ENABLE); // enable controller
1464 *baudrate = i; // store baudrate
1466 } // if (!(sr & INT_ALL_ERR))
1470 #endif // CYGOPT_IO_CAN_AUTOBAUD
1473 // Get bit timings from HAL because bit timings depend on sysclock
1474 // For main clock of 48 MHz this macro is implemented in this device
1475 // driver. If the macro fills the canbr value with 0 then the baudrate
1476 // is not supported and the function returns false
1478 HAL_AT91SAM7_GET_CAN_BR(*baudrate, canbr);
1485 // Any modificatons to the baudrate register must be done while CAN
1486 // module is disabled. So we first disable CAN module, then we set
1487 // baudrate and then we reenable the CAN module by setting the CAN enable
1490 HAL_READ_UINT32(CAN_MR(info), mrbck); // backup value of mode register
1491 HAL_WRITE_UINT32(CAN_MR(info), mrbck &~MR_CAN_ENABLE); // disable controller
1492 HAL_WRITE_UINT32(CAN_BR(info), canbr); // write baudrate register
1495 // Now restore the previous state - if the module was started then
1496 // it will no be started again, if it was stopped, then it remains stopped
1498 HAL_WRITE_UINT32(CAN_MR(info), mrbck);
1505 //===========================================================================
1506 // Setup one single message box for reception of can message
1507 //===========================================================================
1508 static void at91sam7_can_setup_mbox(can_channel *chan, cyg_uint8 mbox, cyg_uint32 mid, cyg_uint32 mam, cyg_uint32 rxtype)
1510 CAN_DECLARE_INFO(chan);
1511 CYG_ASSERT(mbox < 7, "invalid rx mbox number");
1515 // To prevent concurrent access with the internal CAN core, the application
1516 // must disable the mailbox before writing to CAN_MIDx registers - so we
1519 HAL_WRITE_UINT32(CAN_MB_MMR(info, mbox), MMR_MB_TYPE_DISABLED); // first disable message box
1520 HAL_WRITE_UINT32(CAN_MB_MAM(info, mbox), mam); // set acceptance mask
1521 HAL_WRITE_UINT32(CAN_MB_MID(info, mbox), mid); // set message identifier
1522 HAL_WRITE_UINT32(CAN_MB_MMR(info, mbox), rxtype); // setup message box as rx message box (with or without overwrite)
1523 HAL_WRITE_UINT32(CAN_MB_MCR(info, mbox), MCR_TRANSFER_CMD); // transfer request - we do not enable interrupts here
1527 //===========================================================================
1528 // Configure message boxes for reception of any CAN message
1529 //===========================================================================
1530 static void at91sam7_can_mbox_config_rx_all(can_channel *chan)
1532 at91sam7_can_info_t * const info = (at91sam7_can_info_t *)chan->dev_priv;
1534 cyg_uint8 mbox_int_mask = 0;
1535 cyg_uint8 mbox_rx_all_cnt = CAN_MBOX_RX_ALL_CNT(info);
1536 #ifdef CYGOPT_IO_CAN_STD_CAN_ID
1537 cyg_uint8 last_std_rx_mbox = CAN_MBOX_STD_CNT(info) - 1;
1538 #endif // CYGOPT_IO_CAN_STD_CAN_ID
1539 #ifdef CYGOPT_IO_CAN_EXT_CAN_ID
1540 cyg_uint8 last_ext_rx_mbox = mbox_rx_all_cnt - 1;
1541 #endif// CYGOPT_IO_CAN_EXT_CAN_ID
1544 // Now setup all rx message boxes. One message box (the last one - no 8) is
1545 // used for transmission so we have 7 message boxes for reception of can messages
1546 // We setup the message boxes 0 - 5 as RX mboxes and message box 6 as RX mbox with
1549 for (i = 0; i < mbox_rx_all_cnt; ++i)
1551 #ifdef CYGOPT_IO_CAN_STD_CAN_ID
1552 if (i < CAN_MBOX_STD_CNT(info))
1555 // setup message boxes for standard frames
1557 if (i < last_std_rx_mbox)
1559 at91sam7_can_setup_mbox(chan, i, 0, MID_MIDE, MMR_MB_TYPE_RX);
1563 at91sam7_can_setup_mbox(chan, i, 0, MID_MIDE, MMR_MB_TYPE_RX_OVW);
1567 #endif // CYGOPT_IO_CAN_STD_CAN_ID
1569 #ifdef CYGOPT_IO_CAN_EXT_CAN_ID
1571 // setup message boxes for extended frames
1573 if (i < last_ext_rx_mbox)
1575 at91sam7_can_setup_mbox(chan, i, MID_MIDE, MID_MIDE, MMR_MB_TYPE_RX);
1579 at91sam7_can_setup_mbox(chan, i, MID_MIDE, MID_MIDE, MMR_MB_TYPE_RX_OVW);
1581 #endif// CYGOPT_IO_CAN_EXT_CAN_ID
1582 } // if (i < CAN_MBOX_STD_CNT(info))
1584 mbox_int_mask = (mbox_int_mask << 1) | 0x01; // enable interrupt
1585 } // for (i = 0; i < CAN_MBOX_RX_CNT; ++i)*/
1587 info->free_mboxes = CAN_MBOX_RX_CNT - mbox_rx_all_cnt;
1588 info->rx_all = true;
1589 HAL_WRITE_UINT32(CAN_IER(info), mbox_int_mask); // Now finally enable the interrupts for als RX mboxes
1593 //---------------------------------------------------------------------------
1594 // EOF can_at91am7.c