]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/devs/can/arm/at91/at91sam7/v2_0/src/can_at91sam7.c
Initial revision
[karo-tx-redboot.git] / packages / devs / can / arm / at91 / at91sam7 / v2_0 / src / can_at91sam7.c
1 //==========================================================================
2 //
3 //      devs/can/arm/at91sam7x/current/src/can_at91sam7x.c
4 //
5 //      CAN driver for Atmel AT91SAM7X microcontrollers
6 //
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
13 //
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.
17 //
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
21 // for more details.
22 //
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.
26 //
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.
33 //
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.
36 //
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####
43 //
44 // Author(s):    Uwe Kindler
45 // Contributors: Uwe Kindler
46 // Date:         2007-01-06
47 // Purpose:      Support at91sam7 on-chip CAN moduls
48 // Description: 
49 //
50 //####DESCRIPTIONEND####
51 //
52 //==========================================================================
53
54
55 //==========================================================================
56 //                              INCLUDES
57 //==========================================================================
58 #include <pkgconf/system.h>
59 #include <pkgconf/io_can.h>
60 #include <pkgconf/io.h>
61 #include <pkgconf/devs_can_at91sam7.h>
62
63 #include <cyg/infra/diag.h>
64
65 #include <cyg/io/io.h>
66 #include <cyg/io/devtab.h>
67 #include <cyg/io/can.h>
68
69 #include <cyg/hal/hal_arch.h>
70 #include <cyg/hal/hal_intr.h>
71 #include <cyg/hal/hal_io.h>
72
73 #include <cyg/hal/hal_diag.h>
74 #include <cyg/infra/cyg_ass.h>
75
76
77 //===========================================================================
78 //                                DEFINES  
79 //===========================================================================
80
81 //
82 // Support debug output if this option is enabled in CDL file
83 //
84 #ifdef CYGDBG_DEVS_CAN_AT91SAM7_DEBUG
85 #define AT91SAM7_DBG_PRINT diag_printf
86 #else
87 #define AT91SAM7_DBG_PRINT( fmt, ... )
88 #endif
89
90
91 //
92 // we define our own set of register bits in order to be independent from
93 // platform specific names
94 //
95
96 //---------------------------------------------------------------------------
97 // Mailbox bits
98 //
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)
107
108
109 //---------------------------------------------------------------------------
110 // CAN Mode Register bits (CAN_MR)
111 //
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)
120
121
122 //---------------------------------------------------------------------------
123 // CAN Interrupt Enable/Disable, Mask and Status Register bits (CAN_IER, CAN_IDR, CAN_IMR)
124 //
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
141
142 //
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.
145 //
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)
148
149
150 //
151 // these bits are only in status register (CAN_SR)
152 //
153 #define SR_RX_BUSY         (0x01 << 29)
154 #define SR_TX_BUSY         (0x01 << 30)
155 #define SR_OVL_BUSY        (0x01 << 31)
156
157
158 //---------------------------------------------------------------------------
159 // CAN Baudrate Register (CAN_BR)
160 //
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
167
168
169 //---------------------------------------------------------------------------
170 // CAN Error Counter Register (CAN_ECR)
171 //
172 #define ECR_GET_TEC(_ecr_) (((_ecr_) >> 16) & 0xFF)
173 #define ECR_GET_REC(_ecr_) ((_ecr_) & 0xFF)
174
175
176 //---------------------------------------------------------------------------
177 // CAN Transfer Command Resgister (CAN_TCR)
178 //
179 #define TCR_TMR_RESET      0x80000000
180
181
182 //---------------------------------------------------------------------------
183 // CAN Message Mode Register (CAN_MMRx)
184 //
185 #define MMR_TIMEMARK_BITMASK 0x0000FFFF
186 #define MMR_PRIOR_BITMASK    0x000F0000
187
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)
197
198 //---------------------------------------------------------------------------
199 // CAN Message Acceptance Mask/ID Register (CAN_MAMx, CAN_MIDx)
200 //
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)
211
212
213 //---------------------------------------------------------------------------
214 // CAN Message Status Register (CAN_MSRx)
215 //
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)
224
225 //---------------------------------------------------------------------------
226 // CAN Message Control Register (CAN_MCRx)
227 //
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)
234
235 //---------------------------------------------------------------------------
236 // CAN Module Register Layout
237 //
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
249
250 #define CANREG_MB_BASE    0x0200
251
252 //
253 // Register layout of message box relativ to base register of a certain
254 // message box
255 //
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
264
265
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 
273
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) 
285
286 //
287 // Message box registers
288 //
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)
298
299
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.
304 //
305 #if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS == 1
306
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_))
316
317 #ifndef CYGNUM_DEVS_CAN_AT91SAM7_CAN0_STD_MBOXES
318 #define CYGNUM_DEVS_CAN_AT91SAM7_CAN0_STD_MBOXES 0
319 #endif
320
321 #ifndef CYGNUM_DEVS_CAN_AT91SAM7_CAN0_EXT_MBOXES
322 #define CYGNUM_DEVS_CAN_AT91SAM7_CAN0_EXT_MBOXES 0
323 #endif
324
325 #else  // #if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS == 1
326
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)
336
337 #endif // #if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS == 1
338
339
340 //===========================================================================
341 //                              DATA TYPES
342 //===========================================================================
343 typedef struct at91sam7_can_info_t
344 {
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      
351
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
359 #endif
360 } at91sam7_can_info_t;
361
362
363 //
364 // at91sam7 info initialisation
365 //
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,                                \
370     base              : (_base),                                                 \
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)),                         \
376 };
377 #else
378 #define AT91SAM7_CAN_INFO(_l)              \
379 at91sam7_can_info_t _l = {                 \
380     state      : CYGNUM_CAN_STATE_STOPPED, \
381 };
382 #endif
383
384
385 //===========================================================================
386 //                          GLOBAL DATA
387 //===========================================================================
388 #if CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS > 1
389 //
390 // ToDo - Initialisation of individual CAN channels if more than one channel
391 // is supported
392 //
393 #else // CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS == 1
394 //
395 // Only one single CAN channel supported by SAM7 chip
396 //
397 AT91SAM7_CAN_INFO(at91sam7_can0_info);
398 #endif
399
400
401 //===========================================================================
402 //                          LOCAL DATA
403 //===========================================================================
404 //
405 // Macro for creation of CAN_BR value for baudrate tbl
406 //
407
408 #define CAN_BR_TBL_ENTRY(_brp_, _propag_, _phase1_, _phase2_, _sjw_) \
409    ((_brp_ << 16) | (_propag_ << 8) | (_phase2_) | (_phase1_ << 4) | (_sjw_ << 12))
410
411 //
412 // Table with register values for baudrates at main clock of 48 MHz
413 //
414 static const cyg_uint32 at91sam7_br_tbl[] =
415 {
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
426 };
427
428 //
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
434 //
435 #ifdef CYGNUM_HAL_ARM_AT91_CLOCK_SPEED_48000000
436 #define HAL_AT91SAM7_GET_CAN_BR(_baudrate_, _br_)                \
437 CYG_MACRO_START                                                  \
438     _br_ = at91sam7_br_tbl[(_baudrate_) - CYGNUM_CAN_KBAUD_10];  \
439 CYG_MACRO_END
440 #endif
441
442
443 //===========================================================================
444 //                              PROTOTYPES
445 //===========================================================================
446
447 //--------------------------------------------------------------------------
448 // Device driver interface functions
449 //
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);
458
459
460 //--------------------------------------------------------------------------
461 // ISRs and DSRs
462 //
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);
465
466
467 //--------------------------------------------------------------------------
468 // Private utility functions
469 //
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);
481
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);
485 #endif
486
487
488                                        
489
490 //===========================================================================
491 //                   GENERIC CAN IO DATA INITIALISATION
492 //===========================================================================
493 CAN_LOWLEVEL_FUNS(at91sam7_can_lowlevel_funs,
494                   at91sam7_can_putmsg,
495                   at91sam7_can_getevent,
496                   at91sam7_can_get_config,
497                   at91sam7_can_set_config,
498                   at91sam7_can_start_xmit,
499                   at91sam7_can_stop_xmit
500      );
501
502
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
505
506
507 CAN_CHANNEL_USING_INTERRUPTS(at91sam7_can0_chan,
508                              at91sam7_can_lowlevel_funs,
509                              at91sam7_can0_info,
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
513     );
514
515
516 DEVTAB_ENTRY(at91sam7_can_devtab, 
517              CYGPKG_DEVS_CAN_AT91SAM7_CAN0_NAME,
518              0,                     // Does not depend on a lower level interface
519              &cyg_io_can_devio, 
520              at91sam7_can_init, 
521              at91sam7_can_lookup,  // CAN driver may need initializing
522              &at91sam7_can0_chan
523     );
524
525
526 //===========================================================================
527 //                            IMPLEMENTATION
528 //===========================================================================
529
530
531
532 //===========================================================================
533 /// First initialisation and reset of CAN modul.
534 //===========================================================================
535 static bool at91sam7_can_init(struct cyg_devtab_entry* devtab_entry)
536 {
537     can_channel          *chan    = (can_channel*)devtab_entry->priv;
538     at91sam7_can_info_t *info    = (at91sam7_can_info_t *)chan->dev_priv;
539
540 #ifdef CYGDBG_IO_INIT
541     diag_printf("AT91 CAN init\n");
542 #endif   
543     cyg_drv_interrupt_create(CAN_ISRVEC(info),
544                              CAN_ISRPRIO(info),        // Priority
545                              (cyg_addrword_t)chan,     // Data item passed to interrupt handler
546                              at91sam7_can_ISR,
547                              at91sam7_can_DSR,
548                              &info->interrupt_handle,
549                              &info->interrupt);
550     cyg_drv_interrupt_attach(info->interrupt_handle);
551     cyg_drv_interrupt_unmask(CAN_ISRVEC(info));
552      
553     return at91sam7_can_config_channel(chan, &chan->config, true);
554 }
555
556
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)
561 {
562     can_channel* chan    = (can_channel*) (*tab)->priv;
563     CAN_DECLARE_INFO(chan);
564
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      
568      
569     //
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
574     // properly
575     //
576     at91sam7_can_mbox_config_rx_all(chan); 
577       
578     return ENOERR;
579 }
580
581
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)
588 {
589     at91sam7_can_info_t *info = (at91sam7_can_info_t *)chan->dev_priv;
590     cyg_uint8 i;
591     
592     //
593     // setup all RX messages moxes into a disabled state and disable all
594     // interrupts - maybe we have to abort pending transfers before $$$$
595     //
596     HAL_WRITE_UINT32(CAN_IDR(info), INT_MB_RX);
597     for (i = 0; i < CAN_MBOX_RX_CNT; ++i)
598     {
599         HAL_WRITE_UINT32(CAN_MB_MMR(info, i), MMR_MB_TYPE_DISABLED); // first disable message box
600     }
601     
602     info->free_mboxes = CAN_MBOX_RX_CNT;
603     info->rx_all = false;
604 }
605
606
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)
611 {   
612     CAN_DECLARE_INFO(chan);
613     
614     if (msg->ext)
615     {
616         at91sam7_can_setup_mbox(chan, mbox, MID_SET_EXT(msg->id), MAM_SET_EXT, MMR_MB_TYPE_RX); 
617     }
618     else
619     {
620         at91sam7_can_setup_mbox(chan, mbox, MID_SET_STD(msg->id), MAM_SET_STD, MMR_MB_TYPE_RX);    
621     } 
622     HAL_WRITE_UINT32(CAN_IER(info), 0x01 << mbox);   
623 }
624 #endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
625
626
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)
633 {
634     cyg_uint8     i;
635     cyg_int8      res = CYGNUM_CAN_MSGBUF_NA;
636     
637     if (info->free_mboxes)
638     {  
639         for (i = (CAN_MBOX_RX_CNT - info->free_mboxes); i <= CAN_MBOX_RX_MAX; ++i)
640         {
641             cyg_uint32 mmr;
642             HAL_READ_UINT32(CAN_MB_MMR(info, i), mmr);
643             if ((mmr & MMR_MB_TYPE_BITMASK) == MMR_MB_TYPE_DISABLED)
644             {
645                 info->free_mboxes--;
646                 res = i;
647                 break;
648             }             
649         }
650     } // if (info->free_mboxes)
651     
652     return res;
653 }
654 #endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
655
656
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,
662                                        cyg_uint32        mbox,
663                                        cyg_can_message  *pmsg,
664                                        bool              init)
665 {
666     CAN_DECLARE_INFO(chan);
667     cyg_uint32 mcr;
668
669     //
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
672     // do this here
673     //
674     if (init)
675     {
676         if (pmsg->ext)
677         {
678             at91sam7_can_setup_mbox(chan, mbox, MID_SET_EXT(pmsg->id), MAM_SET_EXT, MMR_MB_TYPE_PRODUCE); 
679         }
680         else
681         {
682             at91sam7_can_setup_mbox(chan, mbox, MID_SET_STD(pmsg->id), MAM_SET_STD, MMR_MB_TYPE_PRODUCE);    
683         }   
684         HAL_WRITE_UINT32(CAN_IER(info), 0x01 << mbox); // enable interrupt
685     }
686     else
687     {
688         cyg_uint32 msr;
689         //
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
692         //
693         HAL_READ_UINT32(CAN_MB_MSR(info, mbox), msr);    
694         if (!(msr & MSR_RDY))
695         {
696             AT91SAM7_DBG_PRINT("(RTR) !MSR_RDY\n");
697             return false;
698         }
699     }
700     
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    
705     return true;
706 }
707 #endif // CYGOPT_IO_CAN_REMOTE_BUF
708
709
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)
715 {
716     Cyg_ErrNo             res  = ENOERR;
717     at91sam7_can_info_t *info = (at91sam7_can_info_t *)chan->dev_priv;
718
719     switch (buf->cfg_id)
720     {
721         //
722         // clear all message filters and remote buffers - prepare for message buffer
723         // configuration
724         //
725         case CYGNUM_CAN_MSGBUF_RESET_ALL :
726              {
727                  at91sam7_can_config_rx_none(chan);
728              }
729              break;
730
731         //
732         // setup AT91SAM7 CAN module for reception of all standard and extended messages
733         //
734         case CYGNUM_CAN_MSGBUF_RX_FILTER_ALL :
735              {
736                  if (!info->rx_all) // if rx_all is enabled we do not need to do anything
737                  {
738                     at91sam7_can_mbox_config_rx_all(chan);  // setup RX all state
739                  }
740              }
741              break;
742         
743         //
744         // add single message filter, message with filter ID will be received
745         //     
746         case CYGNUM_CAN_MSGBUF_RX_FILTER_ADD :
747              {
748                  cyg_can_filter *filter   = (cyg_can_filter*) buf;
749                  
750                  //
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
754                  //
755                  if (info->rx_all)
756                  {
757                     return -EPERM;
758                  }
759                  
760                  //
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
764                  //
765                  filter->handle = at91sam7_can_alloc_mbox(info);
766                  if (filter->handle > CYGNUM_CAN_MSGBUF_NA)
767                  {
768                      at91sam7_can_add_rx_filter(chan, filter->handle, &filter->msg);
769                  }
770              }
771              break; //CYGNUM_CAN_MSGBUF_RX_FILTER_ADD
772
773
774 #ifdef CYGOPT_IO_CAN_REMOTE_BUF
775         //
776         // Try to add a new RTR response message buffer for automatic transmisson
777         // of data frame on reception of a remote frame
778         //
779         case CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD :
780              {
781                  cyg_can_remote_buf *rtr_buf    = (cyg_can_remote_buf*) buf;
782                  rtr_buf->handle = at91sam7_can_alloc_mbox(info);
783                      
784                  if (rtr_buf->handle > CYGNUM_CAN_MSGBUF_NA)
785                  {
786                      //
787                      // if we have a free message buffer then we setup this buffer
788                      // for remote frame reception
789                      //
790                      at91sam7_can_setup_rtrmbox(chan, rtr_buf->handle, &rtr_buf->msg, true);
791                  }
792              }
793              break;
794                      
795         //
796         // write data into remote response buffer
797         //
798         case CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE :
799              {
800                  cyg_can_remote_buf *rtr_buf    = (cyg_can_remote_buf*) buf;
801                  //
802                  // If we have a valid rtr buf handle then we can store data into
803                  // rtr message box
804                  // 
805                  if ((rtr_buf->handle >= 0) && (rtr_buf->handle <= CAN_MBOX_RX_MAX))
806                  {
807                       if (!at91sam7_can_setup_rtrmbox(chan, rtr_buf->handle, &rtr_buf->msg, false))
808                       {
809                           res = -EAGAIN;
810                       }
811                  }
812                  else
813                  {
814                     res = -EINVAL;
815                  }  
816              }
817              break;
818 #endif // #ifdef CYGOPT_IO_CAN_REMOTE_BUF
819     } // switch (buf->cfg_id)
820     
821     return res;
822 }
823 #endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
824
825
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)
832 {
833     cyg_can_state result;
834     
835     cyg_drv_dsr_lock();
836     result = info->state;
837     cyg_drv_dsr_unlock();
838     
839     return result;
840 }
841
842
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 
849 // generated.
850 //===========================================================================
851 static void at91sam7_enter_lowpower_mode(can_channel *chan)
852 {
853     CAN_DECLARE_INFO(chan);
854     
855     
856     cyg_uint32 mr;
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);
860 }
861
862
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)
869 {
870     CAN_DECLARE_INFO(chan);
871     cyg_uint32           mr;
872     
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     
878 }
879
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)
884 {
885     Cyg_ErrNo  res = ENOERR;
886     
887     switch (key)
888     {   
889         //
890         // Setup a new CAN configuration. This will i.e. setup a new baud rate
891         //
892         case CYG_IO_SET_CONFIG_CAN_INFO:
893              {
894                  cyg_can_info_t*  config = (cyg_can_info_t*) buf;
895                  if (*len < sizeof(cyg_can_info_t))
896                  {
897                      return -EINVAL;
898                  }
899                  *len = sizeof(cyg_can_info_t);
900                  if (!at91sam7_can_config_channel(chan, config, false))
901                  {
902                      return -EINVAL;
903                  }
904              }
905              break;
906
907 #ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG            
908         //
909         // configure message buffers
910         //
911         case CYG_IO_SET_CONFIG_CAN_MSGBUF :
912              {
913                 cyg_can_msgbuf_cfg *msg_buf = (cyg_can_msgbuf_cfg *)buf;
914
915                 if (*len != sizeof(cyg_can_msgbuf_cfg))
916                 {
917                     return -EINVAL;
918                 }
919                 
920                 res = at91sam7_can_set_config_msgbuf(chan, msg_buf);
921              }
922              break;
923 #endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
924              
925         //
926         // Change CAN state of AT91SAM7 CAN module
927         //    
928         case CYG_IO_SET_CONFIG_CAN_MODE :
929              {
930                 cyg_can_mode   *can_mode  = (cyg_can_mode*) buf;
931                 
932                 if (*len != sizeof(cyg_can_mode)) 
933                 {
934                     return -EINVAL;
935                 }
936                 *len = sizeof(cyg_can_mode);
937                 
938                 //
939                 // decide what to do acording to mode
940                 //
941                 switch (*can_mode)
942                 {
943                     //
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
947                     //
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;
952                 }
953              }
954              break; // case CYG_IO_SET_CONFIG_CAN_MODE :         
955     } // switch (key)
956     
957     return res;
958 }
959
960
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)
965 {
966     Cyg_ErrNo            res  = ENOERR;
967     at91sam7_can_info_t *info = (at91sam7_can_info_t *)chan->dev_priv;
968     
969     switch(key)
970     {
971         //
972         // query state of CAN controller
973         //
974         case CYG_IO_GET_CONFIG_CAN_STATE :
975              {
976                 cyg_can_state *can_state  = (cyg_can_state*) buf;
977                 
978                 if (*len != sizeof(cyg_can_state)) 
979                 {
980                     return -EINVAL;
981                 }
982                 *len = sizeof(cyg_can_state);
983                 *can_state = at91sam7_get_state(info);
984              }
985              break;
986
987 #ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG       
988         //
989         // Query message box information - returns available and free message
990         // boxes
991         //     
992         case CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO :
993              {
994                  cyg_can_msgbuf_info *mbox_info  = (cyg_can_msgbuf_info*) buf;
995                 
996                  if (*len != sizeof(cyg_can_msgbuf_info)) 
997                  {
998                      return -EINVAL;
999                  }
1000                 *len = sizeof(cyg_can_msgbuf_info);
1001                 
1002                  mbox_info->count = CAN_MBOX_RX_CNT;
1003                  mbox_info->free  = info->free_mboxes;
1004              }
1005              break;
1006 #endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG
1007
1008         
1009         //
1010         // Query hardware description of FlexCAN device driver
1011         //     
1012         case CYG_IO_GET_CONFIG_CAN_HDI :
1013              {
1014                 cyg_can_hdi *hdi = (cyg_can_hdi *)buf;
1015                 //
1016                 // comes from high level driver so we do not need to
1017                 // check buffer size here
1018                 //             
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;
1024 #endif
1025              }
1026              break;
1027              
1028         default :
1029             res = -EINVAL;
1030     }// switch(key)
1031     
1032     return res;
1033 }
1034
1035
1036 //===========================================================================
1037 // Send single message
1038 //===========================================================================
1039 static bool at91sam7_can_putmsg(can_channel *priv, CYG_CAN_MSG_T *pmsg, void *pdata)
1040 {
1041     CAN_DECLARE_INFO(priv);
1042     cyg_uint32            msr;   
1043     cyg_uint32            mcr = 0;   
1044     
1045     //
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
1048     //
1049     HAL_READ_UINT32(CAN_MB_MSR(info, CAN_MBOX_TX(info)), msr);    
1050     if (!(msr & MSR_RDY))
1051     {
1052         AT91SAM7_DBG_PRINT("!MSR_RDY\n");
1053         return false;
1054     }
1055     
1056     //
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
1059     // 
1060     HAL_WRITE_UINT32(CAN_MB_MMR(info, CAN_MBOX_TX(info)), MMR_MB_TYPE_DISABLED); 
1061     
1062     //
1063     // Setup the message identifier - this depends on the frame type (standard or extended)
1064     //
1065 #ifdef CYGOPT_IO_CAN_EXT_CAN_ID
1066     if (AT91SAM7_CAN_IS_EXT(*pmsg))
1067     {
1068         HAL_WRITE_UINT32(CAN_MB_MID(info, CAN_MBOX_TX(info)), 
1069                          pmsg->id | MID_MIDE);                                   // set extended message id
1070     }
1071     else
1072 #endif // CYGOPT_IO_CAN_EXT_CAN_ID
1073     {
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  
1078     }
1079
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
1084     
1085     if (AT91SAM7_CAN_IS_RTR(*pmsg))
1086     {
1087         mcr |= MCR_RTR;
1088     }
1089     
1090     HAL_WRITE_UINT32(CAN_MB_MCR(info, CAN_MBOX_TX(info)), mcr);
1091     return true;
1092 }
1093
1094
1095 //===========================================================================
1096 // Read event from device driver
1097 //===========================================================================
1098 static bool at91sam7_can_getevent(can_channel *chan, CYG_CAN_EVENT_T *pevent, void *pdata)
1099 {
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);
1103     cyg_uint8             mbox       = 0;
1104     bool                  res        = true;
1105     
1106     //
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
1109     //
1110     if (mboxflags)
1111     {
1112         cyg_uint32 msr;
1113         cyg_uint32 mid;
1114         cyg_uint32 mmr;
1115         
1116         while (!(mboxflags & 0x01))
1117         {
1118             mboxflags >>= 1;
1119             mbox++;
1120         }
1121         
1122         //
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
1125         // RX message
1126         //
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
1130         
1131         if (MMR_MB_GET_TYPE(mmr) != MMR_MB_TYPE_PRODUCE)
1132         {
1133             HAL_READ_UINT32(CAN_MB_MID(info, mbox), mid);
1134             pevent->flags |= CYGNUM_CAN_EVENT_RX; 
1135             if (msr & MSR_MSG_IGNORED)
1136             {
1137                 pevent->flags |= CYGNUM_CAN_EVENT_OVERRUN_RX;
1138             }
1139             
1140             //
1141             // It is important to set the DLC first because this also clears the ctrl
1142             // field if extended identifiers are supported
1143             //
1144             AT91SAM7_CAN_SET_DLC(pevent->msg, MSR_DLC_GET(msr));  
1145             
1146 #ifdef CYGOPT_IO_CAN_EXT_CAN_ID     
1147             if (mid & MID_MIDE)
1148             {  
1149                 pevent->msg.id = MID_GET_EXT(mid);
1150                 AT91SAM7_CAN_SET_EXT(pevent->msg);
1151             }
1152             else
1153 #endif // CYGOPT_IO_CAN_EXT_CAN_ID
1154             {
1155 #ifdef CYGOPT_IO_CAN_STD_CAN_ID
1156                 pevent->msg.id = MID_GET_STD(mid);
1157 #endif // CYGOPT_IO_CAN_STD_CAN_ID
1158             }
1159             
1160             if (msr & MSR_RTR)
1161             {
1162                 AT91SAM7_CAN_SET_RTR(pevent->msg);
1163             }
1164             else
1165             {
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]);
1168             }
1169 #ifdef CYGOPT_IO_CAN_SUPPORT_TIMESTAMP 
1170             pevent->timestamp = msr & MSR_TIMESTAMP;
1171 #endif
1172       
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)
1176         else
1177         {
1178             HAL_WRITE_UINT32(CAN_MB_MCR(info, mbox), (msr & MSR_DLC) | MCR_TRANSFER_CMD); // transfer request 
1179             //
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
1183             //
1184             res = !(*pstat == 0);
1185         }
1186         
1187         HAL_WRITE_UINT32(CAN_IER(info), 0x01 << mbox);                  // enable interruptfor this message box
1188     } // if (mboxflags)
1189     
1190     //
1191     // Now check if additional events occured
1192     //
1193     if (*pstat)
1194     {
1195         if (*pstat & INT_WAKEUP)
1196         {
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;       
1201         }
1202     
1203         if (*pstat & INT_ERR_PASSIVE)
1204         {
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); 
1210         }
1211         
1212         if (*pstat & INT_WARN)
1213         {
1214             //
1215             // check which counter reached its warning level (> 96)
1216             //
1217             cyg_uint8 ecr;
1218             HAL_READ_UINT32(CAN_ECR(info), ecr);
1219             if (ECR_GET_REC(ecr) > 96)
1220             {
1221                 pevent->flags |= CYGNUM_CAN_EVENT_WARNING_RX;
1222                 AT91SAM7_DBG_PRINT("WARN TX\n");    
1223             }
1224             if (ECR_GET_TEC(ecr) > 96)
1225             {
1226                 pevent->flags |= CYGNUM_CAN_EVENT_WARNING_TX;
1227                 AT91SAM7_DBG_PRINT("WARN RX\n"); 
1228             }
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); 
1232         }
1233         
1234         if (*pstat & INT_BUS_OFF)
1235         {
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); 
1241         }
1242         
1243         if (*pstat & INT_SLEEP)
1244         {
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
1251         }
1252         
1253         if (*pstat & (INT_CRC_ERR | INT_STUFF_ERR | INT_ACKN_ERR | INT_FORM_ERR | INT_BIT_ERR))
1254         {
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);  
1258         }
1259     } // if (*pstat)
1260       
1261     return res;
1262 }
1263
1264
1265 //===========================================================================
1266 // Kick transmitter
1267 //===========================================================================
1268 static void at91sam7_can_start_xmit(can_channel* chan)
1269 {
1270     CAN_DECLARE_INFO(chan);
1271     
1272     AT91SAM7_DBG_PRINT("start_xmit\n");
1273     cyg_drv_dsr_lock();
1274     HAL_WRITE_UINT32(CAN_IER(info), 0x01 << CAN_MBOX_TX(info)); // enable tx interrupt
1275     cyg_drv_dsr_unlock();
1276 }
1277
1278
1279 //===========================================================================
1280 // Stop transmitter
1281 //===========================================================================
1282 static void at91sam7_can_stop_xmit(can_channel* chan)
1283 {
1284      CAN_DECLARE_INFO(chan);
1285     
1286      HAL_WRITE_UINT32(CAN_IDR(info), 0x01 << CAN_MBOX_TX(info)); // disable tx interrupt 
1287      AT91SAM7_DBG_PRINT("stop_xmit\n");   
1288 }
1289
1290
1291 //===========================================================================
1292 // Configure can channel
1293 //===========================================================================
1294 static bool at91sam7_can_config_channel(can_channel* chan, cyg_can_info_t* config, cyg_bool init)
1295 {
1296     CAN_DECLARE_INFO(chan);
1297     cyg_uint32 temp32;
1298     bool       res = true;
1299     
1300     if (init)
1301     {
1302         //
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)
1307         //
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();
1314         }
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();
1319         }
1320 #endif // defined(CYGPKG_DEVS_CAN_AT91SAM7_CAN0) && defined(HAL_AT91SAM7_CAN0_PLF_INIT)
1321 #endif // CYGINT_DEVS_CAN_AT91SAM7_CAN_CHANNELS == 1
1322
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);      
1327             
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
1331         
1332         HAL_WRITE_UINT32(CAN_MR(info), MR_CAN_ENABLE); // enable CAN module  
1333         
1334         //
1335         // The device should go into error active state right after enabling it
1336         //
1337         HAL_READ_UINT32(CAN_SR(info), temp32);
1338         if (!(temp32 & INT_ERR_ACTIVE))
1339         {
1340             res = false;
1341         }   
1342     } // if (init)
1343     
1344     res = at91sam7_can_set_baud(chan, &config->baud);        // set baudrate
1345             
1346     //
1347     // store new config values
1348     //
1349     if (config != &chan->config) 
1350     {
1351         chan->config = *config;
1352     }   
1353     
1354     return res;
1355 }
1356
1357
1358 //===========================================================================
1359 // Low level interrupt handler
1360 //===========================================================================
1361 static cyg_uint32 at91sam7_can_ISR(cyg_vector_t vector, cyg_addrword_t data)
1362 {
1363     can_channel                 *chan    = (can_channel *)data;
1364     at91sam7_can_info_t * const info = (at91sam7_can_info_t *)chan->dev_priv;
1365     cyg_uint32                   sr;
1366     cyg_uint32                   imr;
1367     
1368     
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);   
1372     sr &= imr;
1373     HAL_WRITE_UINT32(CAN_IDR(info), sr);
1374    
1375     info->stat |= sr;
1376     cyg_drv_interrupt_acknowledge(vector);
1377     return CYG_ISR_CALL_DSR;
1378 }
1379
1380
1381 //===========================================================================
1382 // High level interrupt handler
1383 //===========================================================================
1384 static void at91sam7_can_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
1385 {
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;
1389        
1390     do
1391     {   
1392         //
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
1395         // field
1396         //
1397         while (stat)
1398         {
1399             if (stat & (0x01 << CAN_MBOX_TX(info)))
1400             {
1401                 AT91SAM7_DBG_PRINT("TX_DSR\n");    
1402                 chan->callbacks->xmt_msg(chan, 0);   // send next message 
1403                 stat &= ~INT_MB_TX;                  // clear flag
1404             }
1405             else if (stat)
1406             {
1407                 AT91SAM7_DBG_PRINT("EVENT_DSR\n");   
1408                 chan->callbacks->rcv_event(chan, &stat);
1409             }
1410         }
1411         
1412         //
1413         // We check, if a new event occured while we processed other events. If new events
1414         // occured, then we process the new events
1415         //
1416         cyg_drv_interrupt_mask(vector);
1417         stat = info->stat;
1418         info->stat = 0;
1419         cyg_drv_interrupt_unmask(vector);
1420     } while (stat);
1421 }
1422
1423
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)
1428 {
1429     bool                  res = true;
1430     cyg_uint32            mrbck;
1431     cyg_uint32            canbr;
1432     CAN_DECLARE_INFO(chan);
1433
1434
1435 #ifdef CYGOPT_IO_CAN_AUTOBAUD  
1436     if (CYGNUM_CAN_KBAUD_AUTO == *baudrate)
1437     {   
1438         cyg_can_baud_rate_t   i;
1439         cyg_uint8             j;
1440         cyg_uint32            sr;
1441         
1442         res = false;
1443         for (i = CYGNUM_CAN_KBAUD_10; i <= CYGNUM_CAN_KBAUD_1000; ++i)
1444         {
1445             HAL_AT91SAM7_GET_CAN_BR(i, canbr);
1446             if (0 == canbr)
1447             {
1448                 continue;
1449             }  
1450                       
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)
1456             {
1457                 HAL_DELAY_US(1000);                                       // wait at least 11 bit times for synchronization
1458             }
1459             HAL_READ_UINT32(CAN_SR(info), sr);                            // read status register
1460             if (!(sr & INT_ALL_ERR) && (sr & INT_WAKEUP))
1461             {
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
1465                 return true;
1466             } // if (!(sr & INT_ALL_ERR))         
1467         }
1468     }
1469     else
1470 #endif // CYGOPT_IO_CAN_AUTOBAUD 
1471     { 
1472         //
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
1477         //
1478         HAL_AT91SAM7_GET_CAN_BR(*baudrate, canbr);   
1479         if (0 == canbr)
1480         {
1481             return false;
1482         }
1483         
1484         //
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
1488         // flag
1489         //
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
1493         
1494         //
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
1497         //
1498         HAL_WRITE_UINT32(CAN_MR(info), mrbck);
1499     }
1500     
1501     return res;
1502 }
1503
1504
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)
1509 {
1510     CAN_DECLARE_INFO(chan);
1511     CYG_ASSERT(mbox < 7, "invalid rx mbox number");
1512     
1513   
1514     //
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
1517     // do this here
1518     //
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
1524 }
1525
1526
1527 //===========================================================================
1528 // Configure message boxes for reception of any CAN message
1529 //===========================================================================
1530 static void at91sam7_can_mbox_config_rx_all(can_channel *chan)
1531 {
1532     at91sam7_can_info_t * const info = (at91sam7_can_info_t *)chan->dev_priv;
1533     cyg_uint8  i;
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 
1542
1543     //
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
1547     // overwrite. 
1548     //    
1549     for (i = 0; i < mbox_rx_all_cnt; ++i)
1550     { 
1551 #ifdef CYGOPT_IO_CAN_STD_CAN_ID     
1552         if (i < CAN_MBOX_STD_CNT(info))
1553         {
1554             //
1555             // setup message boxes for standard frames
1556             //
1557             if (i < last_std_rx_mbox) 
1558             {
1559                 at91sam7_can_setup_mbox(chan, i, 0, MID_MIDE, MMR_MB_TYPE_RX);
1560             }
1561             else
1562             {
1563                 at91sam7_can_setup_mbox(chan, i, 0, MID_MIDE, MMR_MB_TYPE_RX_OVW);
1564             }
1565         }
1566         else
1567 #endif // CYGOPT_IO_CAN_STD_CAN_ID 
1568         {
1569 #ifdef CYGOPT_IO_CAN_EXT_CAN_ID
1570             //
1571             // setup message boxes for extended frames
1572             //
1573             if (i < last_ext_rx_mbox)
1574             {
1575                 at91sam7_can_setup_mbox(chan, i, MID_MIDE, MID_MIDE, MMR_MB_TYPE_RX);
1576             }
1577             else
1578             {
1579                 at91sam7_can_setup_mbox(chan, i, MID_MIDE, MID_MIDE, MMR_MB_TYPE_RX_OVW);
1580             }
1581 #endif// CYGOPT_IO_CAN_EXT_CAN_ID 
1582         } // if (i < CAN_MBOX_STD_CNT(info))
1583         
1584         mbox_int_mask = (mbox_int_mask << 1) | 0x01; // enable interrupt 
1585     } // for (i = 0; i < CAN_MBOX_RX_CNT; ++i)*/
1586     
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
1590 }
1591
1592
1593 //---------------------------------------------------------------------------
1594 // EOF can_at91am7.c