Mercurial > ecos-v3_0-branch
changeset 2409:e8eaf852a606
2007-07-07 Alexey Shusharin <mrfinch@mail.ru>
* cdl/can_lpx2xxx.cdl: Option
CYGOPT_DEVS_CAN_LPC2XXX_USE_SELF_RECEPTION added for enabling
self reception requests instead of transmission requests.
* src/can_lpc2xxx.c: Some small bugs fixed. Added support for LUT
error. Support for self transmission request added. Debug output
improved.
* src/can_accfilt_lpc2xxx.c: Added support for baudrates of 10kbaud
and 20 kbaud at clock speed of 60 MHz
* DOS2UNIX everything, which makes the diff a bit useles...
| author | asl |
|---|---|
| date | Tue, 31 Jul 2007 07:53:36 +0000 |
| parents | 16f728931a36 |
| children | 87cd3c9ced46 |
| files | packages/devs/can/arm/lpc2xxx/current/ChangeLog packages/devs/can/arm/lpc2xxx/current/cdl/can_lpc2xxx.cdl packages/devs/can/arm/lpc2xxx/current/include/can_lpc2xxx.h packages/devs/can/arm/lpc2xxx/current/include/can_lpc2xxx_baudrates.h packages/devs/can/arm/lpc2xxx/current/src/can_accfilt_lpc2xxx.c packages/devs/can/arm/lpc2xxx/current/src/can_lpc2xxx.c packages/devs/can/arm/lpc2xxx/current/tests/can_test_aux.inl |
| diffstat | 7 files changed, 3547 insertions(+), 3342 deletions(-) [+] |
line wrap: on
line diff
--- a/packages/devs/can/arm/lpc2xxx/current/ChangeLog +++ b/packages/devs/can/arm/lpc2xxx/current/ChangeLog @@ -1,3 +1,16 @@ +2007-07-07 Alexey Shusharin <mrfinch@mail.ru> + + * cdl/can_lpx2xxx.cdl: Option + CYGOPT_DEVS_CAN_LPC2XXX_USE_SELF_RECEPTION added for enabling + self reception requests instead of transmission requests. + + * src/can_lpc2xxx.c: Some small bugs fixed. Added support for LUT + error. Support for self transmission request added. Debug output + improved. + + * src/can_accfilt_lpc2xxx.c: Added support for baudrates of 10kbaud + and 20 kbaud at clock speed of 60 MHz + 2007-07-01 Uwe Kindler <uwe_kindler@web.de> * LPC2xxx CAN driver package created @@ -5,6 +18,7 @@ 2007-07-01 Uwe Kindler <uwe_kindler@we * include/can_lpc2xxx.h * include/can_lpc2xxx_baudrates.h * src/can_lpc2xxx.c + * src/can_accfilt_lpc2xxx.c //=========================================================================== //####ECOSGPLCOPYRIGHTBEGIN####
--- a/packages/devs/can/arm/lpc2xxx/current/cdl/can_lpc2xxx.cdl +++ b/packages/devs/can/arm/lpc2xxx/current/cdl/can_lpc2xxx.cdl @@ -71,37 +71,77 @@ cdl_package CYGPKG_DEVS_CAN_LPC2XXX { flavor bool implements CYGINT_IO_CAN_RUNTIME_MBOX_CFG description " - The LPC2xxx CAN module supports a global acceptance filter. Enabling this - option provides support for runtime configuration of this acceptance filter. - If each CAN channel should receive all CAN messages and individual message - filtering is not required then disable this option to eleminate almost - the complete acceptance filter code and to decrease codesize. If this - option is disabled the option CYGOPT_IO_CAN_RUNTIME_MBOX_CFG is not - available and the configuration key CYG_IO_SET_CONFIG_CAN_MSGBUF is - not supported by this driver." - + The LPC2xxx CAN module supports a global acceptance + filter. Enabling this option provides support for runtime + configuration of this acceptance filter. If each CAN + channel should receive all CAN messages and individual + message filtering is not required then disable this option + to eleminate almost the complete acceptance filter code + and to decrease codesize. If this option is disabled the + option CYGOPT_IO_CAN_RUNTIME_MBOX_CFG is not available and + the configuration key CYG_IO_SET_CONFIG_CAN_MSGBUF is not + supported by this driver." + cdl_option CYGOPT_DEVS_CAN_LPC2XXX_EXTENDED_CFG_KEYS { display "Extended acceptance filtering" flavor bool default_value 0 description " - The common CAN I/O layer supports setup of single message filters for - reception of single CAN messages. The global LPC2xxx acceptance filter - supports not only single message filters but also message groups. - A message group is defined by a lower bound CAN identifier and an upper - bound CAN identifier. The acceptance filter will accept all messages within - this range of CAN identifiers. The acceptance filter supports a number of - message groups for each CAN channel. The support of message filter groups - is not conform to the standard API of the CAN I/O layer and should only - be used for application where portability is not important." + The common CAN I/O layer supports setup of single + message filters for reception of single CAN + messages. The global LPC2xxx acceptance filter + supports not only single message filters but also + message groups. A message group is defined by a + lower bound CAN identifier and an upper bound CAN + identifier. The acceptance filter will accept all + messages within this range of CAN identifiers. The + acceptance filter supports a number of message + groups for each CAN channel. The support of + message filter groups is not conform to the + standard API of the CAN I/O layer and should only + be used for application where portability is not + important." } } + + cdl_option CYGOPT_DEVS_CAN_LPC2XXX_USE_SELF_RECEPTION { + display "Use Self Reception Request command" + flavor bool + default_value 0 + description " + Enable this option for using work-around of problem with + reciving messages while arbitration is lost. If this work + around is used each transmitted CAN message will be + received. This will produce additional RX interrupts an + requires additional time for processing these interrupts + and for filtering of received messages. + + The errata sheet tells the following about this issue: + Introduction: The CAN module can lose arbitration to + another CAN node during an attempt to transmit a CAN + message. The message of the CAN node the arbitration was + lost to is supposed to be received correctly by the CAN + module. + + Problem: Messages might not be received correctly if + during a CAN Transmission the CAN bus arbitration is lost + to another CAN node. + + Work-around: Use the Self Reception Request command + instead of the Transmission Request command. However, it + has to be taken into account that now all transmitted + messages may be received if not prevented by appropriate + Acceptance Filter settings. (Don't set up Acceptance + Filter Message Identifiers for the messages you are + transmitting yourself.)." + } cdl_option CYGDBG_DEVS_CAN_LPC2XXX_DEBUG { display "Support printing debug information" default_value 0 description " - Check this box to turn ON debug options for AT91SAM7 CAN device driver." + Check this box to turn ON debug options for LPC2XXXX + CAN device driver." } # Support up to 4 on-chip CAN modules. The number may vary between @@ -124,8 +164,9 @@ cdl_package CYGPKG_DEVS_CAN_LPC2XXX { default_value 1 implements CYGINT_IO_CAN_CHANNELS description " - If the application needs to access the on-chip CAN module [set ::channel] - via an eCos CAN driver then this option should be enabled." + If the application needs to access the on-chip CAN + module [set ::channel] via an eCos CAN driver then + this option should be enabled." cdl_option CYGPKG_DEVS_CAN_LPC2XXX_CAN[set ::channel]_NAME { display "Device name for CAN module [set ::channel]" @@ -143,8 +184,9 @@ cdl_package CYGPKG_DEVS_CAN_LPC2XXX { flavor data default_value 100 legal_values { 10 20 50 100 125 250 500 800 1000 "AUTO"} - description "This option determines the initial baud rate in KBaud for - CAN module [set ::channel]" + description " + This option determines the initial baud rate in + KBaud for CAN module [set ::channel]" } cdl_option CYGNUM_DEVS_CAN_LPC2XXX_CAN[set ::channel]_QUEUESIZE_TX { @@ -153,9 +195,10 @@ cdl_package CYGPKG_DEVS_CAN_LPC2XXX { default_value 32 legal_values 1 to 1024 description " - The CAN device driver will run in interrupt mode and will - perform buffering of outgoing data. This option controls the number - of CAN messages the TX queue can store." + The CAN device driver will run in interrupt mode + and will perform buffering of outgoing data. This + option controls the number of CAN messages the TX + queue can store." } cdl_option CYGNUM_DEVS_CAN_LPC2XXX_CAN[set ::channel]_QUEUESIZE_RX { @@ -164,9 +207,10 @@ cdl_package CYGPKG_DEVS_CAN_LPC2XXX { default_value 64 legal_values 8 to 4096 description " - The CAN device driver will run in interrupt mode and will - perform buffering of incoming data. This option controls the number - of CAN events the RX queue can store." + The CAN device driver will run in interrupt mode + and will perform buffering of incoming data. This + option controls the number of CAN events the RX + queue can store." } cdl_option CYGOPT_DEVS_CAN_LPC2XXX_CAN[set ::channel]_ACCFILT_STARTUP_CFG { @@ -176,11 +220,13 @@ cdl_package CYGPKG_DEVS_CAN_LPC2XXX { default_value {"RX_ALL"} active_if CYGOPT_DEVS_CAN_LPC2XXX_RUNTIME_ACCFILT description " - Normally the acceptance filter will be configured at startup time to - receive all available CAN messages. The application can setup single - message filters during runtime later. If RX_NONE is selected then the - acceptance filter for this channel is configured to receive no CAN - message identifier." + Normally the acceptance filter will be configured + at startup time to receive all available CAN + messages. The application can setup single message + filters during runtime later. If RX_NONE is + selected then the acceptance filter for this + channel is configured to receive no CAN message + identifier." } } @@ -192,7 +238,8 @@ cdl_package CYGPKG_DEVS_CAN_LPC2XXX { no_define calculated { "tests/can_busload tests/can_rx_tx" } description " - This option specifies the set of tests for the LPC2xxx CAN device driver." + This option specifies the set of tests for the LPC2xxx + CAN device driver." } cdl_option CYGBLD_DEVS_CAN_LPC2XXX_EXTRA_TESTS {
--- a/packages/devs/can/arm/lpc2xxx/current/include/can_lpc2xxx.h +++ b/packages/devs/can/arm/lpc2xxx/current/include/can_lpc2xxx.h @@ -1,93 +1,93 @@ -#ifndef CYGONCE_CAN_LPC2XXX_H -#define CYGONCE_CAN_LPC2XXX_H -//========================================================================== -// -// devs/can/arm/lpc2xxx/current/include/can_lpc2xxx.h -// -// Extended configuration option for LPC2xxx CAN driver -// -//========================================================================== -//####ECOSGPLCOPYRIGHTBEGIN#### -// ------------------------------------------- -// This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -// Copyright (C) 2003 Gary Thomas -// -// eCos is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 or (at your option) any later version. -// -// eCos is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. -// -// You should have received a copy of the GNU General Public License along -// with eCos; if not, write to the Free Software Foundation, Inc., -// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -// -// As a special exception, if other files instantiate templates or use macros -// or inline functions from this file, or you compile this file and link it -// with other works to produce a work based on this file, this file does not -// by itself cause the resulting work to be covered by the GNU General Public -// License. However the source code for this file must still be made available -// in accordance with section (3) of the GNU General Public License. -// -// This exception does not invalidate any other reasons why a work based on -// this file might be covered by the GNU General Public License. -// -// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. -// at http://sources.redhat.com/ecos/ecos-license/ -// ------------------------------------------- -//####ECOSGPLCOPYRIGHTEND#### -//========================================================================== -//#####DESCRIPTIONBEGIN#### -// -// Author(s): Uwe Kindler -// Contributors: Uwe Kindler -// Date: 2007-02-08 -// Purpose: Extended configuration options for LPC2xxx CAN driver -// Description: -// -//####DESCRIPTIONEND#### -// -//========================================================================== - - -//========================================================================== -// DEFINES -//========================================================================== -// -// The LPC2XXX supports enhanced configuration options that are not supported -// be the generic CAN I/O layer. Be careful with using this extension -// because they may reduce portability of your pplication -// - -//-------------------------------------------------------------------------- -// Message filter configuration -// -#define CYG_IO_SET_CONFIG_LPC2XXX_ACCFILT_GROUP CYG_IO_SET_CONFIG_CAN_ABORT + 0x10 // add message filter group - - -//-------------------------------------------------------------------------- -// Mode setup of LPC2XXX -// -#define CYGNUM_CAN_MODE_LPC2XXX_LISTEN_ONLY 0x80 // set controller in listen only mode - - -//========================================================================== -// DATA TYPES -//========================================================================== -// -// structure for configuration of message filter groups -// -typedef struct cyg_can_filtergroup_cfg_st -{ - cyg_can_id_type ext; - cyg_uint32 lower_id_bound; - cyg_uint32 upper_id_bound; -} cyg_can_filtergroup_cfg; - - -//--------------------------------------------------------------------------- -#endif // CYGONCE_CAN_LPC2XXX_H +#ifndef CYGONCE_CAN_LPC2XXX_H +#define CYGONCE_CAN_LPC2XXX_H +//========================================================================== +// +// devs/can/arm/lpc2xxx/current/include/can_lpc2xxx.h +// +// Extended configuration option for LPC2xxx CAN driver +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2003 Gary Thomas +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Uwe Kindler +// Contributors: Uwe Kindler +// Date: 2007-02-08 +// Purpose: Extended configuration options for LPC2xxx CAN driver +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + + +//========================================================================== +// DEFINES +//========================================================================== +// +// The LPC2XXX supports enhanced configuration options that are not supported +// be the generic CAN I/O layer. Be careful with using this extension +// because they may reduce portability of your pplication +// + +//-------------------------------------------------------------------------- +// Message filter configuration +// +#define CYG_IO_SET_CONFIG_LPC2XXX_ACCFILT_GROUP CYG_IO_SET_CONFIG_CAN_ABORT + 0x10 // add message filter group + + +//-------------------------------------------------------------------------- +// Mode setup of LPC2XXX +// +#define CYGNUM_CAN_MODE_LPC2XXX_LISTEN_ONLY 0x80 // set controller in listen only mode + + +//========================================================================== +// DATA TYPES +//========================================================================== +// +// structure for configuration of message filter groups +// +typedef struct cyg_can_filtergroup_cfg_st +{ + cyg_can_id_type ext; + cyg_uint32 lower_id_bound; + cyg_uint32 upper_id_bound; +} cyg_can_filtergroup_cfg; + + +//--------------------------------------------------------------------------- +#endif // CYGONCE_CAN_LPC2XXX_H
--- a/packages/devs/can/arm/lpc2xxx/current/include/can_lpc2xxx_baudrates.h +++ b/packages/devs/can/arm/lpc2xxx/current/include/can_lpc2xxx_baudrates.h @@ -1,216 +1,216 @@ -#ifndef CYGONCE_CAN_LPC2XXX_BAUDRATES_H -#define CYGONCE_CAN_LPC2XXX_BAUDRATES_H -//========================================================================== -// -// devs/can/arm/lpc2xxx/current/include/can_lpc2xxx_baudrates.h -// -// Precalculated values for bit timing register -// -//========================================================================== -//####ECOSGPLCOPYRIGHTBEGIN#### -// ------------------------------------------- -// This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -// Copyright (C) 2003 Gary Thomas -// -// eCos is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 or (at your option) any later version. -// -// eCos is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. -// -// You should have received a copy of the GNU General Public License along -// with eCos; if not, write to the Free Software Foundation, Inc., -// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -// -// As a special exception, if other files instantiate templates or use macros -// or inline functions from this file, or you compile this file and link it -// with other works to produce a work based on this file, this file does not -// by itself cause the resulting work to be covered by the GNU General Public -// License. However the source code for this file must still be made available -// in accordance with section (3) of the GNU General Public License. -// -// This exception does not invalidate any other reasons why a work based on -// this file might be covered by the GNU General Public License. -// -// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. -// at http://sources.redhat.com/ecos/ecos-license/ -// ------------------------------------------- -//####ECOSGPLCOPYRIGHTEND#### -//========================================================================== -//#####DESCRIPTIONBEGIN#### -// -// Author(s): Uwe Kindler -// Contributors: Uwe Kindler -// Date: 2007-07-01 -// Purpose: Precalculated bit timing values for various baudrates -// Description: -// -//####DESCRIPTIONEND#### -// -//========================================================================== - - -// -// Peripheral clock speed -// -#define CYGNUM_CAN_LPC2XXX_VPB_CLK (CYGNUM_HAL_ARM_LPC2XXX_CLOCK_SPEED / CYGNUM_HAL_ARM_LPC2XXX_VPBDIV) - -// -// Macro for creation of CAN_BR value for baudrate tbl -// -#define CAN_BR_TBL_ENTRY(_brp_, _tseg1_, _tseg2_, _sjw_, _sam_) \ - ((_sam_ << 23) | (_tseg2_ << 20) | (_tseg1_ << 16) | (_sjw_ << 14) | (_brp_)) - - -//========================================================================== -// BAUDRATES -//========================================================================== -#if CYGNUM_CAN_LPC2XXX_VPB_CLK == 60000000 -// -// Table with register values for baudrates at peripheral clock of 60 MHz -// -static const cyg_uint32 lpc2xxx_br_tbl[] = -{ - CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // 10 kbaud - not supported - CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // 20 kbaud - not supported - CAN_BR_TBL_ENTRY(59, 15, 02, 0, 1), // 50 kbaud - CAN_BR_TBL_ENTRY(39, 11, 01, 0, 1), // 100 kbaud - CAN_BR_TBL_ENTRY(29, 12, 01, 0, 1), // 125 kbaud - CAN_BR_TBL_ENTRY(14, 12, 01, 0, 1), // 250 kbaud - CAN_BR_TBL_ENTRY(07, 11, 01, 0, 0), // 500 kbaud - CAN_BR_TBL_ENTRY(04, 11, 01, 0, 0), // 800 kbaud - CAN_BR_TBL_ENTRY(03, 11, 01, 0, 0), // 1000 kbaud - CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // Autobaud - not supported -}; -#define HAL_LPC2XXX_BAUD_TBL_DEFINED 1 -#endif // CYGNUM_CAN_LPC2XXX_VPB_CLK == 60000000 - -#if CYGNUM_CAN_LPC2XXX_VPB_CLK == 30000000 -// -// Table with register values for baudrates at peripheral clock of 30 MHz -// -static const cyg_uint32 lpc2xxx_br_tbl[] = -{ - CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // 10 kbaud - not supported - CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // 20 kbaud - not supported - CAN_BR_TBL_ENTRY(59, 15, 02, 0, 1), // 50 kbaud - CAN_BR_TBL_ENTRY(39, 11, 01, 0, 1), // 100 kbaud - CAN_BR_TBL_ENTRY(29, 12, 01, 0, 1), // 125 kbaud - CAN_BR_TBL_ENTRY(14, 12, 01, 0, 1), // 250 kbaud - CAN_BR_TBL_ENTRY(07, 11, 01, 0, 0), // 500 kbaud - CAN_BR_TBL_ENTRY(04, 11, 01, 0, 0), // 800 kbaud - CAN_BR_TBL_ENTRY(03, 11, 01, 0, 0), // 1000 kbaud - CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // Autobaud - not supported -}; -#define HAL_LPC2XXX_BAUD_TBL_DEFINED 1 -#endif // CYGNUM_CAN_LPC2XXX_VPB_CLK == 30000000 - -#if CYGNUM_CAN_LPC2XXX_VPB_CLK == 15000000 -// -// Table with register values for baudrates at peripheral clock of 15 MHz -// -static const cyg_uint32 lpc2xxx_br_tbl[] = -{ - CAN_BR_TBL_ENTRY(59, 15, 07, 0, 1), // 10 kbaud - CAN_BR_TBL_ENTRY(49, 11, 01, 0, 1), // 20 kbaud - CAN_BR_TBL_ENTRY(19, 11, 01, 0, 1), // 50 kbaud - CAN_BR_TBL_ENTRY(09, 11, 01, 0, 1), // 100 kbaud - CAN_BR_TBL_ENTRY(07, 11, 01, 0, 1), // 125 kbaud - CAN_BR_TBL_ENTRY(03, 11, 01, 0, 1), // 250 kbaud - CAN_BR_TBL_ENTRY(01, 11, 01, 0, 0), // 500 kbaud - CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // 800 kbaud - not supported - CAN_BR_TBL_ENTRY(00, 11, 01, 0, 0), // 1000 kbaud - CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // Autobaud - not supported -}; -#define HAL_LPC2XXX_BAUD_TBL_DEFINED 1 -#endif // CYGNUM_CAN_LPC2XXX_VPB_CLK == 15000000 - -#if CYGNUM_CAN_LPC2XXX_VPB_CLK == 48000000 -// -// Table with register values for baudrates at peripheral clock of 48 MHz -// -static const cyg_uint32 lpc2xxx_br_tbl[] = -{ - CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // 10 kbaud - not supported - CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // 20 kbaud - not supported - CAN_BR_TBL_ENTRY(59, 12, 01, 0, 1), // 50 kbaud - CAN_BR_TBL_ENTRY(29, 12, 01, 0, 1), // 100 kbaud - CAN_BR_TBL_ENTRY(23, 12, 01, 0, 1), // 125 kbaud - CAN_BR_TBL_ENTRY(11, 12, 01, 0, 1), // 250 kbaud - CAN_BR_TBL_ENTRY(05, 12, 01, 0, 0), // 500 kbaud - CAN_BR_TBL_ENTRY(03, 11, 01, 0, 0), // 800 kbaud - CAN_BR_TBL_ENTRY(02, 12, 01, 0, 0), // 1000 kbaud - CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // Autobaud - not supported -}; -#define HAL_LPC2XXX_BAUD_TBL_DEFINED 1 -#endif // CYGNUM_CAN_LPC2XXX_VPB_CLK == 48000000 - -#if CYGNUM_CAN_LPC2XXX_VPB_CLK == 24000000 -// -// Table with register values for baudrates at peripheral clock of 24 MHz -// -static const cyg_uint32 lpc2xxx_br_tbl[] = -{ - CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // 10 kbaud - not supported - CAN_BR_TBL_ENTRY(59, 15, 02, 0, 1), // 20 kbaud - CAN_BR_TBL_ENTRY(29, 12, 01, 0, 1), // 50 kbaud - CAN_BR_TBL_ENTRY(14, 12, 01, 0, 1), // 100 kbaud - CAN_BR_TBL_ENTRY(11, 12, 01, 0, 1), // 125 kbaud - CAN_BR_TBL_ENTRY(05, 12, 01, 0, 1), // 250 kbaud - CAN_BR_TBL_ENTRY(02, 12, 01, 0, 0), // 500 kbaud - CAN_BR_TBL_ENTRY(01, 11, 01, 0, 0), // 800 kbaud - CAN_BR_TBL_ENTRY(01, 05, 00, 0, 0), // 1000 kbaud - CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // Autobaud - not supported -}; -#define HAL_LPC2XXX_BAUD_TBL_DEFINED 1 -#endif // CYGNUM_CAN_LPC2XXX_VPB_CLK == 24000000 - -#if CYGNUM_CAN_LPC2XXX_VPB_CLK == 12000000 -// -// Table with register values for baudrates at peripheral clock of 12 MHz -// -static const cyg_uint32 lpc2xxx_br_tbl[] = -{ - CAN_BR_TBL_ENTRY(59, 15, 02, 0, 1), // 10 kbaud - not supported - CAN_BR_TBL_ENTRY(39, 11, 01, 0, 1), // 20 kbaud - CAN_BR_TBL_ENTRY(14, 12, 01, 0, 1), // 50 kbaud - CAN_BR_TBL_ENTRY(07, 11, 01, 0, 1), // 100 kbaud - CAN_BR_TBL_ENTRY(05, 12, 01, 0, 1), // 125 kbaud - CAN_BR_TBL_ENTRY(02, 12, 01, 0, 1), // 250 kbaud - CAN_BR_TBL_ENTRY(02, 05, 00, 0, 0), // 500 kbaud - CAN_BR_TBL_ENTRY(00, 11, 01, 0, 0), // 800 kbaud - CAN_BR_TBL_ENTRY(00, 09, 00, 0, 0), // 1000 kbaud - CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // Autobaud - not supported -}; -#define HAL_LPC2XXX_BAUD_TBL_DEFINED 1 -#endif // CYGNUM_CAN_LPC2XXX_VPB_CLK == 12000000 - - -//========================================================================== -// BIT TIMING MACRO -//========================================================================== -// -// Macro fills baudrate register value depending on selected baudrate -// For several LPC2XXX peripheral clock speeds we provide a pre calculated -// baudrate table. If the board uses another clock speed, then the platform -// HAL needs to provide an own HAL_LPC2XXX_GET_CAN_BR() macro that returns -// valid baudrate register values or it needs to patch this file with -// an additional table for the desired clock speed -// -// -// If a certain baudrate is not supported, then this macro shall return -// 0 as the baudrate register value -// -#ifdef HAL_LPC2XXX_BAUD_TBL_DEFINED -#define HAL_LPC2XXX_GET_CAN_BR(_baudrate_, _br_) \ -CYG_MACRO_START \ - _br_ = lpc2xxx_br_tbl[(_baudrate_) - CYGNUM_CAN_KBAUD_10]; \ -CYG_MACRO_END -#endif // HAL_LPC2XXX_BAUD_TBL_DEFINED - -//------------------------------------------------------------------------- -#endif // #ifndef CYGONCE_CAN_LPC2XXX_BAUDRATES_H +#ifndef CYGONCE_CAN_LPC2XXX_BAUDRATES_H +#define CYGONCE_CAN_LPC2XXX_BAUDRATES_H +//========================================================================== +// +// devs/can/arm/lpc2xxx/current/include/can_lpc2xxx_baudrates.h +// +// Precalculated values for bit timing register +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2003 Gary Thomas +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Uwe Kindler +// Contributors: Uwe Kindler +// Date: 2007-07-01 +// Purpose: Precalculated bit timing values for various baudrates +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + + +// +// Peripheral clock speed +// +#define CYGNUM_CAN_LPC2XXX_VPB_CLK (CYGNUM_HAL_ARM_LPC2XXX_CLOCK_SPEED / CYGNUM_HAL_ARM_LPC2XXX_VPBDIV) + +// +// Macro for creation of CAN_BR value for baudrate tbl +// +#define CAN_BR_TBL_ENTRY(_brp_, _tseg1_, _tseg2_, _sjw_, _sam_) \ + ((_sam_ << 23) | (_tseg2_ << 20) | (_tseg1_ << 16) | (_sjw_ << 14) | (_brp_)) + + +//========================================================================== +// BAUDRATES +//========================================================================== +#if CYGNUM_CAN_LPC2XXX_VPB_CLK == 60000000 +// +// Table with register values for baudrates at peripheral clock of 60 MHz +// +static const cyg_uint32 lpc2xxx_br_tbl[] = +{ + CAN_BR_TBL_ENTRY(300, 15, 02, 0, 1), // 10 kbaud + CAN_BR_TBL_ENTRY(150, 15, 02, 0, 1), // 20 kbaud + CAN_BR_TBL_ENTRY(59, 15, 02, 0, 1), // 50 kbaud + CAN_BR_TBL_ENTRY(39, 11, 01, 0, 1), // 100 kbaud + CAN_BR_TBL_ENTRY(29, 12, 01, 0, 1), // 125 kbaud + CAN_BR_TBL_ENTRY(14, 12, 01, 0, 1), // 250 kbaud + CAN_BR_TBL_ENTRY(07, 11, 01, 0, 0), // 500 kbaud + CAN_BR_TBL_ENTRY(04, 11, 01, 0, 0), // 800 kbaud + CAN_BR_TBL_ENTRY(03, 11, 01, 0, 0), // 1000 kbaud + CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // Autobaud - not supported +}; +#define HAL_LPC2XXX_BAUD_TBL_DEFINED 1 +#endif // CYGNUM_CAN_LPC2XXX_VPB_CLK == 60000000 + +#if CYGNUM_CAN_LPC2XXX_VPB_CLK == 30000000 +// +// Table with register values for baudrates at peripheral clock of 30 MHz +// +static const cyg_uint32 lpc2xxx_br_tbl[] = +{ + CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // 10 kbaud - not supported + CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // 20 kbaud - not supported + CAN_BR_TBL_ENTRY(59, 15, 02, 0, 1), // 50 kbaud + CAN_BR_TBL_ENTRY(39, 11, 01, 0, 1), // 100 kbaud + CAN_BR_TBL_ENTRY(29, 12, 01, 0, 1), // 125 kbaud + CAN_BR_TBL_ENTRY(14, 12, 01, 0, 1), // 250 kbaud + CAN_BR_TBL_ENTRY(07, 11, 01, 0, 0), // 500 kbaud + CAN_BR_TBL_ENTRY(04, 11, 01, 0, 0), // 800 kbaud + CAN_BR_TBL_ENTRY(03, 11, 01, 0, 0), // 1000 kbaud + CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // Autobaud - not supported +}; +#define HAL_LPC2XXX_BAUD_TBL_DEFINED 1 +#endif // CYGNUM_CAN_LPC2XXX_VPB_CLK == 30000000 + +#if CYGNUM_CAN_LPC2XXX_VPB_CLK == 15000000 +// +// Table with register values for baudrates at peripheral clock of 15 MHz +// +static const cyg_uint32 lpc2xxx_br_tbl[] = +{ + CAN_BR_TBL_ENTRY(59, 15, 07, 0, 1), // 10 kbaud + CAN_BR_TBL_ENTRY(49, 11, 01, 0, 1), // 20 kbaud + CAN_BR_TBL_ENTRY(19, 11, 01, 0, 1), // 50 kbaud + CAN_BR_TBL_ENTRY(09, 11, 01, 0, 1), // 100 kbaud + CAN_BR_TBL_ENTRY(07, 11, 01, 0, 1), // 125 kbaud + CAN_BR_TBL_ENTRY(03, 11, 01, 0, 1), // 250 kbaud + CAN_BR_TBL_ENTRY(01, 11, 01, 0, 0), // 500 kbaud + CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // 800 kbaud - not supported + CAN_BR_TBL_ENTRY(00, 11, 01, 0, 0), // 1000 kbaud + CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // Autobaud - not supported +}; +#define HAL_LPC2XXX_BAUD_TBL_DEFINED 1 +#endif // CYGNUM_CAN_LPC2XXX_VPB_CLK == 15000000 + +#if CYGNUM_CAN_LPC2XXX_VPB_CLK == 48000000 +// +// Table with register values for baudrates at peripheral clock of 48 MHz +// +static const cyg_uint32 lpc2xxx_br_tbl[] = +{ + CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // 10 kbaud - not supported + CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // 20 kbaud - not supported + CAN_BR_TBL_ENTRY(59, 12, 01, 0, 1), // 50 kbaud + CAN_BR_TBL_ENTRY(29, 12, 01, 0, 1), // 100 kbaud + CAN_BR_TBL_ENTRY(23, 12, 01, 0, 1), // 125 kbaud + CAN_BR_TBL_ENTRY(11, 12, 01, 0, 1), // 250 kbaud + CAN_BR_TBL_ENTRY(05, 12, 01, 0, 0), // 500 kbaud + CAN_BR_TBL_ENTRY(03, 11, 01, 0, 0), // 800 kbaud + CAN_BR_TBL_ENTRY(02, 12, 01, 0, 0), // 1000 kbaud + CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // Autobaud - not supported +}; +#define HAL_LPC2XXX_BAUD_TBL_DEFINED 1 +#endif // CYGNUM_CAN_LPC2XXX_VPB_CLK == 48000000 + +#if CYGNUM_CAN_LPC2XXX_VPB_CLK == 24000000 +// +// Table with register values for baudrates at peripheral clock of 24 MHz +// +static const cyg_uint32 lpc2xxx_br_tbl[] = +{ + CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // 10 kbaud - not supported + CAN_BR_TBL_ENTRY(59, 15, 02, 0, 1), // 20 kbaud + CAN_BR_TBL_ENTRY(29, 12, 01, 0, 1), // 50 kbaud + CAN_BR_TBL_ENTRY(14, 12, 01, 0, 1), // 100 kbaud + CAN_BR_TBL_ENTRY(11, 12, 01, 0, 1), // 125 kbaud + CAN_BR_TBL_ENTRY(05, 12, 01, 0, 1), // 250 kbaud + CAN_BR_TBL_ENTRY(02, 12, 01, 0, 0), // 500 kbaud + CAN_BR_TBL_ENTRY(01, 11, 01, 0, 0), // 800 kbaud + CAN_BR_TBL_ENTRY(01, 05, 00, 0, 0), // 1000 kbaud + CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // Autobaud - not supported +}; +#define HAL_LPC2XXX_BAUD_TBL_DEFINED 1 +#endif // CYGNUM_CAN_LPC2XXX_VPB_CLK == 24000000 + +#if CYGNUM_CAN_LPC2XXX_VPB_CLK == 12000000 +// +// Table with register values for baudrates at peripheral clock of 12 MHz +// +static const cyg_uint32 lpc2xxx_br_tbl[] = +{ + CAN_BR_TBL_ENTRY(59, 15, 02, 0, 1), // 10 kbaud - not supported + CAN_BR_TBL_ENTRY(39, 11, 01, 0, 1), // 20 kbaud + CAN_BR_TBL_ENTRY(14, 12, 01, 0, 1), // 50 kbaud + CAN_BR_TBL_ENTRY(07, 11, 01, 0, 1), // 100 kbaud + CAN_BR_TBL_ENTRY(05, 12, 01, 0, 1), // 125 kbaud + CAN_BR_TBL_ENTRY(02, 12, 01, 0, 1), // 250 kbaud + CAN_BR_TBL_ENTRY(02, 05, 00, 0, 0), // 500 kbaud + CAN_BR_TBL_ENTRY(00, 11, 01, 0, 0), // 800 kbaud + CAN_BR_TBL_ENTRY(00, 09, 00, 0, 0), // 1000 kbaud + CAN_BR_TBL_ENTRY(00, 00, 00, 0, 0), // Autobaud - not supported +}; +#define HAL_LPC2XXX_BAUD_TBL_DEFINED 1 +#endif // CYGNUM_CAN_LPC2XXX_VPB_CLK == 12000000 + + +//========================================================================== +// BIT TIMING MACRO +//========================================================================== +// +// Macro fills baudrate register value depending on selected baudrate +// For several LPC2XXX peripheral clock speeds we provide a pre calculated +// baudrate table. If the board uses another clock speed, then the platform +// HAL needs to provide an own HAL_LPC2XXX_GET_CAN_BR() macro that returns +// valid baudrate register values or it needs to patch this file with +// an additional table for the desired clock speed +// +// +// If a certain baudrate is not supported, then this macro shall return +// 0 as the baudrate register value +// +#ifdef HAL_LPC2XXX_BAUD_TBL_DEFINED +#define HAL_LPC2XXX_GET_CAN_BR(_baudrate_, _br_) \ +CYG_MACRO_START \ + _br_ = lpc2xxx_br_tbl[(_baudrate_) - CYGNUM_CAN_KBAUD_10]; \ +CYG_MACRO_END +#endif // HAL_LPC2XXX_BAUD_TBL_DEFINED + +//------------------------------------------------------------------------- +#endif // #ifndef CYGONCE_CAN_LPC2XXX_BAUDRATES_H
--- a/packages/devs/can/arm/lpc2xxx/current/src/can_accfilt_lpc2xxx.c +++ b/packages/devs/can/arm/lpc2xxx/current/src/can_accfilt_lpc2xxx.c @@ -1,987 +1,988 @@ -//========================================================================== -// -// devs/can/arm/lpc2xxx/current/src/can_accfilt_lpc2xxx.c -// -// Acceptance filter management for LPC2xxx CAN driver -// -//========================================================================== -//####ECOSGPLCOPYRIGHTBEGIN#### -// ------------------------------------------- -// This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -// Copyright (C) 2003 Gary Thomas -// -// eCos is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 or (at your option) any later version. -// -// eCos is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. -// -// You should have received a copy of the GNU General Public License along -// with eCos; if not, write to the Free Software Foundation, Inc., -// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -// -// As a special exception, if other files instantiate templates or use macros -// or inline functions from this file, or you compile this file and link it -// with other works to produce a work based on this file, this file does not -// by itself cause the resulting work to be covered by the GNU General Public -// License. However the source code for this file must still be made available -// in accordance with section (3) of the GNU General Public License. -// -// This exception does not invalidate any other reasons why a work based on -// this file might be covered by the GNU General Public License. -// -// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. -// at http://sources.redhat.com/ecos/ecos-license/ -// ------------------------------------------- -//####ECOSGPLCOPYRIGHTEND#### -//========================================================================== -//#####DESCRIPTIONBEGIN#### -// -// Author(s): Uwe Kindler -// Contributors: Uwe Kindler -// Date: 2007-05-28 -// Purpose: Support LPC2xxx on-chip CAN acceptance filters -// Description: -// -//####DESCRIPTIONEND#### -// -//========================================================================== - - -//=========================================================================== -// Data types -//=========================================================================== -// -// Acceptance filter entry -// -typedef struct lpc2xxx_accfilt_entry -{ - cyg_uint32 data; // the value inclusive channel number - cyg_uint32 id; - cyg_uint32 lower_id_bound; - cyg_uint32 upper_id_bound; - cyg_uint8 channel_no; -} lpc2xxx_accfilt_entry_t; - - -//=========================================================================== -// Declarations -//=========================================================================== -//-------------------------------------------------------------------------- -// Lowlevel acceptance filter access -// -#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG -static bool lpc2xxx_can_accfilt_add(lpc2xxx_can_info_t *info, - cyg_uint32 lower_id, - cyg_uint32 upper_id, - cyg_can_id_type ext); -void lpc2xxx_can_accfilt_ram_insert_entry(cyg_uint32 TableAddress, cyg_uint16 EntryNo); -void lpc2xxx_can_accfilt_ram_remove_entry(cyg_uint32 TableAddress, cyg_uint16 EntryNo); -void lpc2xxx_can_accfilt_remove_all_ctrl_entries(lpc2xxx_can_info_t *info); -#else -static void lpc2xxx_can_accfilt_simple_rx_all(void); -#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG -void lpc2xxx_can_accfilt_reset(void); - -#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG -void lpc2xxx_can_accfilt_dbg_dump(void); -void lpc2xxx_can_reg_dump(struct cyg_devtab_entry* devtab_entry); -#endif - - -#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG -//=========================================================================== -// Calculate address of entry in certain table -//=========================================================================== -static cyg_uint32 lpc2xxx_can_accfilt_calc_entry_address(cyg_uint32 TableAddressRegister, cyg_uint16 EntryNo) -{ - cyg_uint32 EntryAddress = 0xFFFFFFFF; - cyg_uint32 TableAddress; - - HAL_READ_UINT32(TableAddressRegister, TableAddress); - switch (TableAddressRegister) - { -#ifdef CYGOPT_IO_CAN_STD_CAN_ID - case CAN_ACCFILT_SFF_SA: - EntryAddress = ((EntryNo / 2) << 2) + TableAddress; - break; - - case CAN_ACCFILT_SFF_GRP_SA: - EntryAddress = TableAddress + (EntryNo << 2); - break; -#endif // CYGOPT_IO_CAN_STD_CAN_ID - -#ifdef CYGOPT_IO_CAN_EXT_CAN_ID - case CAN_ACCFILT_EFF_SA: - EntryAddress = TableAddress + (EntryNo << 2); - break; - - case CAN_ACCFILT_EFF_GRP_SA: - EntryAddress = TableAddress + (EntryNo << 3); - break; -#endif // CYGOPT_IO_CAN_EXT_CAN_ID - default: - CYG_ASSERT(0, "Wrong TableAddressRegister"); - } - - return EntryAddress; -} - - -//=========================================================================== -// Remove one single entry from acceptance filter table -//=========================================================================== -void lpc2xxx_can_accfilt_ram_remove_entry(cyg_uint32 Table, cyg_uint16 EntryNo) -{ - cyg_int32 remove_address = lpc2xxx_can_accfilt_calc_entry_address(Table, EntryNo); - cyg_int32 entry_address; - lsc_buf_t lsc_val; - cyg_uint8 entry_size = sizeof(cyg_uint32); - cyg_uint32 sff_sa; - cyg_uint32 sff_grp_sa; - cyg_uint32 eff_sa; - cyg_uint32 eff_grp_sa; - cyg_int32 end_of_table; - - HAL_READ_UINT32(CAN_ACCFILT_SFF_SA, sff_sa); - HAL_READ_UINT32(CAN_ACCFILT_SFF_GRP_SA, sff_grp_sa); - HAL_READ_UINT32(CAN_ACCFILT_EFF_SA, eff_sa); - HAL_READ_UINT32(CAN_ACCFILT_EFF_GRP_SA, eff_grp_sa); - HAL_READ_UINT32(CAN_ACCFILT_ENDOFTABLE, end_of_table); - - // - // Do not try to remove from an empty table - // - if (!end_of_table) - { - return; - } - - entry_address = remove_address; - - if ((remove_address < eff_grp_sa) && (CAN_ACCFILT_EFF_GRP_SA != Table)) - { - if ((remove_address < eff_sa) && (CAN_ACCFILT_EFF_SA != Table)) - { - if ((remove_address < sff_grp_sa) && (CAN_ACCFILT_SFF_GRP_SA != Table)) - { - lsc_buf_t nextval; - - if (EntryNo % 2) - { - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + remove_address, lsc_val.dword); - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + remove_address + sizeof(cyg_uint32), nextval.dword); - lsc_val.column.upper = nextval.column.lower; - entry_address += sizeof(cyg_uint32); - } - - // - // Start copy immediatelly after removed entry - // - while (entry_address < sff_grp_sa) - { - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + entry_address, lsc_val.dword); - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + entry_address + sizeof(cyg_uint32), nextval.dword); - lsc_val.column.lower = lsc_val.column.upper; - lsc_val.column.upper = nextval.column.lower; - HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + entry_address, lsc_val.dword); - entry_address += sizeof(cyg_uint32); - } - - // - // now check if the lower identifier is disabled - if it is disabled, then - // also the upper identifier is invalid and we can remove the entry completely - // if the lower identifier is not disabled, then it is valid and we need - // to disable the upper identifier because it contains an invalid entry - // - if (lsc_val.column.lower & ACCFILT_STD_DIS) - { - sff_grp_sa -= sizeof(cyg_uint32); - entry_address = sff_grp_sa; - } - else - { - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + sff_grp_sa - sizeof(cyg_uint32), lsc_val.dword); - lsc_val.column.upper = 0xffff; - HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + sff_grp_sa - sizeof(cyg_uint32), lsc_val.dword); - entry_size = 0; // we do not need to remove anything - } - } // if (pLine < pStdGrpStart) - - eff_sa -= entry_size; - } // if (pLine < pExtIdStart) - - eff_grp_sa -= entry_size; - } // if (pLine < pExtGrpStart) - - // - // If no entry was removed then we can leave immediatelly without changing any - // table pointers because we only did a change inside the sff table - // - if (!entry_size) - { -#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG - lpc2xxx_can_accfilt_dbg_dump(); -#endif - return; - } - - if (CAN_ACCFILT_EFF_GRP_SA == Table) - { - // - // If we are in the area of extended groups then we need to remove - // 2 lines because lower and upper identifier need 1 line each - // - entry_size += sizeof(cyg_uint32); - } - - end_of_table -= entry_size; - - // - // Move alle entries one or two dword downwads - that means we remove a line - // - while (entry_address < end_of_table) - { - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + entry_address + entry_size, lsc_val.dword); - HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + entry_address, lsc_val.dword); - entry_address += sizeof(cyg_uint32); - } - - HAL_WRITE_UINT32(CAN_ACCFILT_SFF_SA, sff_sa); - HAL_WRITE_UINT32(CAN_ACCFILT_SFF_GRP_SA, sff_grp_sa); - HAL_WRITE_UINT32(CAN_ACCFILT_EFF_SA, eff_sa); - HAL_WRITE_UINT32(CAN_ACCFILT_EFF_GRP_SA, eff_grp_sa); - HAL_WRITE_UINT32(CAN_ACCFILT_ENDOFTABLE, end_of_table); - -#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG - lpc2xxx_can_accfilt_dbg_dump(); -#endif -} - -//=========================================================================== -// Insert one empty line into ram - all entries behind this line will be -// moved one entry upwards -//=========================================================================== -void lpc2xxx_can_accfilt_ram_insert_entry(cyg_uint32 Table, cyg_uint16 EntryNo) -{ - cyg_int16 insert_address = lpc2xxx_can_accfilt_calc_entry_address(Table, EntryNo); - cyg_int16 entry_address; - cyg_int16 copy_start = insert_address; - lsc_buf_t lsc_val; - cyg_uint8 entry_size = sizeof(cyg_uint32); - cyg_uint32 sff_sa; - cyg_uint32 sff_grp_sa; - cyg_uint32 eff_sa; - cyg_uint32 eff_grp_sa; - cyg_uint32 end_of_table; - - - HAL_READ_UINT32(CAN_ACCFILT_SFF_SA, sff_sa); - HAL_READ_UINT32(CAN_ACCFILT_SFF_GRP_SA, sff_grp_sa); - HAL_READ_UINT32(CAN_ACCFILT_EFF_SA, eff_sa); - HAL_READ_UINT32(CAN_ACCFILT_EFF_GRP_SA, eff_grp_sa); - HAL_READ_UINT32(CAN_ACCFILT_ENDOFTABLE, end_of_table); - - if ((insert_address <= eff_grp_sa) && (CAN_ACCFILT_EFF_GRP_SA != Table)) - { - if ((insert_address <= eff_sa) && (CAN_ACCFILT_EFF_SA != Table)) - { - if ((insert_address <= sff_grp_sa) && (CAN_ACCFILT_SFF_GRP_SA != Table)) - { - // - // If we are in the range of standard identifiers then we need to - // do some special copy procedure for this area because a standard entry - // is only 2 byte long. Copy only til start of area with standard groups - // - if (sff_grp_sa) - { - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + sff_grp_sa - sizeof(cyg_uint32), lsc_val.dword); // read last entry - // - // now check if the upper identifier is disabled - if it is disabled, then - // we have an odd number of std ids in the list. Then we do not need to - // insert a new line - we simply need to copy all entries 2 bytes upwards - // that meeans we only need to change the std id area and do not need to touch - // any other filter id area. - // If the last entry is not disabled, then we have a valid filter here. - // Then we need to insert a complete new line, that means we also have to mave - // all following entries and filter tables one dword upwards. - // - if (lsc_val.words.low & ACCFILT_STD_DIS) - { - copy_start = end_of_table + sizeof(cyg_uint32); // we do not need to insert a new line and do not copy anything - entry_size = 0; - } - } - - if (entry_size) - { - copy_start = sff_grp_sa; // copy everything behind std id group - sff_grp_sa += entry_size; - } - } // if (pLine < pStdGrpStart) - - eff_sa += entry_size; - } // if (pLine < pExtIdStart) - - eff_grp_sa += entry_size; - } // if (pLine < pExtGrpStart) - - if (CAN_ACCFILT_EFF_GRP_SA == Table) - { - // - // If we are in the area of extended groups then we need to insert - // 2 lines because lower and upper identifier need 1 line each - // - entry_size += sizeof(cyg_uint32); // one entry is 2 dword long - } - - entry_address = end_of_table - sizeof(cyg_uint32); - end_of_table += entry_size; // add one additional entry - - // - // Move alle entries one or two dwords upwards - that means we insert a new empty line - // - while (entry_address >= copy_start) - { - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + (cyg_uint32)entry_address, lsc_val.dword); - HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + (cyg_uint32)entry_address + entry_size, lsc_val.dword); - entry_address -= sizeof(cyg_uint32); - } - - // - // For the std ID area we need a special pocedure - // - if (CAN_ACCFILT_SFF_SA == Table) - { - lsc_buf_t preval; - // - // Start copy with last entry of std id table - // - entry_address = sff_grp_sa - sizeof(cyg_uint32); - - while (entry_address > insert_address) - { - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + (cyg_uint32)entry_address, lsc_val.dword); - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + (cyg_uint32)entry_address - sizeof(cyg_uint32), preval.dword); - lsc_val.column.upper = lsc_val.column.lower; - lsc_val.column.lower = preval.column.upper; - HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + (cyg_uint32)entry_address, lsc_val.dword); - entry_address -= sizeof(cyg_uint32); - } - - // - // If we insert an entry into the lower colum, then we need to move the - // content of the lower column into the upper column - // - if (!(EntryNo % 2)) - { - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + (cyg_uint32)insert_address, lsc_val.dword); - lsc_val.column.upper = lsc_val.column.lower; - HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + (cyg_uint32)insert_address, lsc_val.dword); - } - - // - // If we inserted a new line, then we have an odd number of identifiers now - // and need to disable the last (the upper) entry - // - if (entry_size) - { - lsc_val.column.upper = 0xFFFF; // disable the entry - HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + sff_grp_sa - sizeof(cyg_uint32) , lsc_val.dword); - } - } - - HAL_WRITE_UINT32(CAN_ACCFILT_SFF_SA, sff_sa); - HAL_WRITE_UINT32(CAN_ACCFILT_SFF_GRP_SA, sff_grp_sa); - HAL_WRITE_UINT32(CAN_ACCFILT_EFF_SA, eff_sa); - HAL_WRITE_UINT32(CAN_ACCFILT_EFF_GRP_SA, eff_grp_sa); - HAL_WRITE_UINT32(CAN_ACCFILT_ENDOFTABLE, end_of_table); -} - - -//=========================================================================== -// Query number of entries in a certain table -//=========================================================================== -static cyg_uint16 lpc2xxx_can_accfilt_get_table_entries(cyg_uint32 TableStartAddress) -{ - cyg_uint32 start; - cyg_uint32 end; - - switch (TableStartAddress) - { -#ifdef CYGOPT_IO_CAN_STD_CAN_ID - case CAN_ACCFILT_SFF_SA: - HAL_READ_UINT32(CAN_ACCFILT_SFF_SA, start); - HAL_READ_UINT32(CAN_ACCFILT_SFF_GRP_SA, end); - if (end - start) - { - lsc_buf_t data; - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + end - sizeof(cyg_uint32), data.dword); - if (data.column.upper & ACCFILT_STD_DIS) - { - return (((end - start) >> 1) - 1); - } - } - return (end - start) >> 1; - - case CAN_ACCFILT_SFF_GRP_SA: - HAL_READ_UINT32(CAN_ACCFILT_SFF_GRP_SA, start); - HAL_READ_UINT32(CAN_ACCFILT_EFF_SA, end); - return (end - start) >> 2; -#endif // CYGOPT_IO_CAN_STD_CAN_ID - -#ifdef CYGOPT_IO_CAN_EXT_CAN_ID - case CAN_ACCFILT_EFF_SA: - HAL_READ_UINT32(CAN_ACCFILT_EFF_SA, start); - HAL_READ_UINT32(CAN_ACCFILT_EFF_GRP_SA, end); - return (end - start) >> 2; - - case CAN_ACCFILT_EFF_GRP_SA: - HAL_READ_UINT32(CAN_ACCFILT_EFF_GRP_SA, start); - HAL_READ_UINT32(CAN_ACCFILT_ENDOFTABLE, end); - return (end - start) >> 3; -#endif // CYGOPT_IO_CAN_EXT_CAN_ID - default: - CYG_FAIL("Invalid identifier table address"); - return 0; - } // switch (TableStartAddress) -} - -//=========================================================================== -// Query certain entry from table -//=========================================================================== -static void lpc2xxx_can_accfilt_get_entry(cyg_uint32 TableStartAddress, cyg_uint16 EntryNo, lpc2xxx_accfilt_entry_t *pEntry) -{ - cyg_uint32 EntryAddress = lpc2xxx_can_accfilt_calc_entry_address(TableStartAddress, EntryNo); - lsc_buf_t Data; - - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + EntryAddress, Data.dword); - pEntry->data = Data.dword; - switch (TableStartAddress) - { -#ifdef CYGOPT_IO_CAN_STD_CAN_ID - case CAN_ACCFILT_SFF_SA: - { - cyg_uint16 column; - if (EntryNo % 2) - { - column = Data.column.upper; - } - else - { - column = Data.column.lower; - } - pEntry->id = ACCFILT_STD_GET_ID(column); - pEntry->channel_no = ACCFILT_STD_GET_CTRL(column); - } - break; - - case CAN_ACCFILT_SFF_GRP_SA: - pEntry->lower_id_bound = ACCFILT_STD_GET_ID(Data.column.lower); - pEntry->upper_id_bound = ACCFILT_STD_GET_ID(Data.column.upper); - pEntry->channel_no = ACCFILT_STD_GET_CTRL(Data.column.lower); - break; -#endif // #ifdef CYGOPT_IO_CAN_STD_CAN_ID - -#ifdef CYGOPT_IO_CAN_EXT_CAN_ID - case CAN_ACCFILT_EFF_SA: - pEntry->id = ACCFILT_EXT_GET_ID(Data.dword); - pEntry->channel_no = ACCFILT_EXT_GET_CTRL(Data.dword); - break; - - case CAN_ACCFILT_EFF_GRP_SA: - pEntry->lower_id_bound = ACCFILT_EXT_GET_ID(Data.dword); - pEntry->channel_no = ACCFILT_EXT_GET_CTRL(Data.dword); - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE+ EntryAddress + sizeof(cyg_uint32), Data.dword); - pEntry->upper_id_bound = ACCFILT_EXT_GET_ID(Data.dword); - break; -#endif // #ifedf CYGOPT_IO_CAN_EXT_CAN_ID - default: - CYG_FAIL("Invalid identifier table address"); - } // switch () -} - - -//=========================================================================== -// Set certain entry in table -//=========================================================================== -static void lpc2xxx_can_accfilt_set_entry(cyg_uint32 TableStartAddress, cyg_uint16 EntryNo, lpc2xxx_accfilt_entry_t *pEntry) -{ - cyg_uint32 EntryAddress = lpc2xxx_can_accfilt_calc_entry_address(TableStartAddress, EntryNo); - lsc_buf_t Data; - - switch (TableStartAddress) - { -#ifdef CYGOPT_IO_CAN_STD_CAN_ID - case CAN_ACCFILT_SFF_SA: - { - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + EntryAddress, Data.dword); - if (EntryNo % 2) - { - Data.column.upper = (pEntry->channel_no << 13) | (pEntry->id & ACCFILT_STD_ID_MASK); - } - else - { - Data.column.lower = (pEntry->channel_no << 13) | (pEntry->id & ACCFILT_STD_ID_MASK); - } - } - break; - - case CAN_ACCFILT_SFF_GRP_SA: - Data.column.lower = (pEntry->channel_no << 13) | (pEntry->lower_id_bound & ACCFILT_STD_ID_MASK); - Data.column.upper = (pEntry->channel_no << 13) | (pEntry->upper_id_bound & ACCFILT_STD_ID_MASK); - break; -#endif // #ifdef CYGOPT_IO_CAN_STD_CAN_ID - -#ifdef CYGOPT_IO_CAN_EXT_CAN_ID - case CAN_ACCFILT_EFF_SA: - Data.dword = (pEntry->channel_no << 29) | (pEntry->id & ACCFILT_EXT_ID_MASK); - break; - - case CAN_ACCFILT_EFF_GRP_SA: - { - lsc_buf_t Data2; - - Data.dword = (pEntry->channel_no << 29) | (pEntry->lower_id_bound & ACCFILT_EXT_ID_MASK); - Data2.dword = (pEntry->channel_no << 29) | (pEntry->upper_id_bound & ACCFILT_EXT_ID_MASK); - HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + EntryAddress + sizeof(cyg_uint32), Data2.dword); - } - break; -#endif // #ifdef CYGOPT_IO_CAN_EXT_CAN_ID - - default: - CYG_FAIL("Invalid identifier table address"); - } // switch () - - HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + EntryAddress, Data.dword); -} - - -//=========================================================================== -// Add one entry to acceptance filter RAM -// If upper ID is > lower ID then we have to add a group filter - else we -// have to add a single message filter here -//=========================================================================== -static bool lpc2xxx_can_accfilt_add(lpc2xxx_can_info_t *info, - cyg_uint32 lower_id, - cyg_uint32 upper_id, - cyg_can_id_type ext) -{ - cyg_uint32 accfilt_bck; // acceptance filter backup - cyg_uint32 end_of_table; - cyg_uint32 table; - lpc2xxx_accfilt_entry_t entry; - lpc2xxx_accfilt_entry_t new_entry; - - - // - // first step: disable acceptance filter and prepare it for modification - // - HAL_READ_UINT32(CAN_ACCFILT_AFMR, accfilt_bck); - HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, AFMR_OFF | AFMR_BYPASS); - - // - // Check if table is full - // - HAL_READ_UINT32(CAN_ACCFILT_ENDOFTABLE, end_of_table); - if (end_of_table >= ACCFILT_RAM_SIZE) - { - return false; - } - - new_entry.id = lower_id; - new_entry.lower_id_bound = lower_id; - new_entry.upper_id_bound = upper_id; - - // - // Here we rely on the ISR vector ordering for calculaion of of channel number - // Maybe this is not the right way for newer LPC parts - // - new_entry.channel_no = (CAN_ISRVEC(info) - CYGNUM_HAL_INTERRUPT_CAN1_TX) + 1; - - // - // If lower_id == upper_id then we know that we have to setup a single message filter - // here. If it is not equal the it is group of identifiers to receive - // - if ((lower_id == upper_id) || (lower_id > upper_id)) - { - // - // setup single message filter (standard or extended) here - // -#ifdef CYGOPT_IO_CAN_EXT_CAN_ID - if (ext) - { - table = CAN_ACCFILT_EFF_SA; - } - else -#endif // #ifdef CYGOPT_IO_CAN_EXT_CAN_ID - { -#ifdef CYGOPT_IO_CAN_STD_CAN_ID - table = CAN_ACCFILT_SFF_SA; -#endif // CYGOPT_IO_CAN_STD_CAN_ID - } - } - else - { - // - // setup single message filter (standard or extended) here - // -#ifdef CYGOPT_IO_CAN_EXT_CAN_ID - if (ext) - { - table = CAN_ACCFILT_EFF_GRP_SA; - } - else -#endif // #ifdef CYGOPT_IO_CAN_EXT_CAN_ID - { -#ifdef CYGOPT_IO_CAN_STD_CAN_ID - table = CAN_ACCFILT_SFF_GRP_SA; -#endif // #ifdef CYGOPT_IO_CAN_STD_CAN_ID - } - } - - cyg_uint16 entries = lpc2xxx_can_accfilt_get_table_entries(table); - cyg_uint16 i; - - - for (i = 0; i < entries; ++i) - { - lpc2xxx_can_accfilt_get_entry(table, i, &entry); - - if (entry.channel_no > new_entry.channel_no) - { - break; - } - - if ((entry.channel_no == new_entry.channel_no) - && (entry.id > new_entry.id)) - { - break; - } - } // for (i = 0; i < entries; ++i) - - lpc2xxx_can_accfilt_ram_insert_entry(table, i); - lpc2xxx_can_accfilt_set_entry(table, i, &new_entry); - - // - // finally restore the prvious state of the acceptance filter - // - HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, accfilt_bck); - return true; -} - - -//=========================================================================== -// Remove all entries from a certain controller -//=========================================================================== -void lpc2xxx_can_accfilt_remove_all_ctrl_entries(lpc2xxx_can_info_t *info) -{ - cyg_uint32 accfilt_bck; // acceptance filter backup - cyg_uint16 i; - cyg_uint16 entries; - cyg_uint32 TableStartAddress = CAN_ACCFILT_SFF_SA; - lpc2xxx_accfilt_entry_t Entry; - cyg_uint8 channel_no = (CAN_ISRVEC(info) - CYGNUM_HAL_INTERRUPT_CAN1_TX) + 1; - cyg_uint16 entry_idx; - - // - // first step: disable acceptance filter and prepare it for modification - // - HAL_READ_UINT32(CAN_ACCFILT_AFMR, accfilt_bck); - HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, AFMR_OFF | AFMR_BYPASS); - - // - // now remove all entries for a certain controller - // - for (TableStartAddress = CAN_ACCFILT_SFF_SA; TableStartAddress < CAN_ACCFILT_ENDOFTABLE; TableStartAddress += 4) - { - entries = lpc2xxx_can_accfilt_get_table_entries(TableStartAddress); - entry_idx = 0; - for (i = 0; i < entries; ++i) - { - lpc2xxx_can_accfilt_get_entry(TableStartAddress, entry_idx, &Entry); - if (Entry.channel_no == channel_no) - { - lpc2xxx_can_accfilt_ram_remove_entry(TableStartAddress, entry_idx); - } - else - { - entry_idx++; - } - } // for (i = 0; i < entries; ++i) - } // for (TableStartAddress = CAN_ACCFILT_SFF_SA ... - - // - // finally restore the prvious state of the acceptance filter - // - HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, accfilt_bck); -} -#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG - - -#ifndef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG -//=========================================================================== -// Setup reception of all CAN identifiers -// If runtime acceptance filter configuration is not required then we simply -// setup the acceptance filter here to receive all CAN identifiers -//=========================================================================== -static void lpc2xxx_can_accfilt_simple_rx_all(void) -{ - cyg_uint32 regval; - - // - // First check if it is really necessary to setup filters. If end of table is - // != 0 then the acceptance filter is already setup properly - // - HAL_READ_UINT32(CAN_ACCFILT_ENDOFTABLE, regval); - if (regval) - { - return; - } - - cyg_uint32 accfilt_bck; // acceptance filter backup - cyg_uint8 i = 0; // loop counter - lsc_buf_t accfilt_entry; // std group entry -#ifdef CYGOPT_IO_CAN_STD_CAN_ID - cyg_uint8 std_address = 0; // std group entry address -#ifdef CYGOPT_IO_CAN_EXT_CAN_ID - cyg_uint8 ext_address = lpc2xxx_global_can_info.init_cnt << 2; -#endif -#else - cyg_uint8 ext_address = 0; -#endif - - // - // first step: disable acceptance filter and prepare it for modification - // - HAL_READ_UINT32(CAN_ACCFILT_AFMR, accfilt_bck); - HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, AFMR_OFF | AFMR_BYPASS); - - // - // Write table start adresses - we use only standard group and extended filter - // group - // - HAL_WRITE_UINT32(CAN_ACCFILT_SFF_SA, 0); - HAL_WRITE_UINT32(CAN_ACCFILT_SFF_GRP_SA, 0); - HAL_WRITE_UINT32(CAN_ACCFILT_EFF_SA, ext_address); - HAL_WRITE_UINT32(CAN_ACCFILT_EFF_GRP_SA, ext_address); - - // - // Now loop through all active CAN channels and setup the acceptance filter for - // each channel to receive all standard and extended CAN identifiers - // - while (lpc2xxx_global_can_info.active_channels[i]) - { - lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)lpc2xxx_global_can_info.active_channels[i++]->dev_priv; - cyg_uint8 channel_no = (CAN_ISRVEC(info) - CYGNUM_HAL_INTERRUPT_CAN1_TX) + 1; - -#ifdef CYGOPT_IO_CAN_STD_CAN_ID - accfilt_entry.column.lower = (channel_no << 13) | (0x000 & ACCFILT_STD_ID_MASK); - accfilt_entry.column.upper = (channel_no << 13) | (0x7FF & ACCFILT_STD_ID_MASK); - HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + std_address, accfilt_entry.dword); - std_address += sizeof(cyg_uint32); -#endif // CYGOPT_IO_CAN_STD_CAN_ID - -#ifdef CYGOPT_IO_CAN_EXT_CAN_ID - accfilt_entry.dword = (channel_no << 29) | (0x00000000 & ACCFILT_EXT_ID_MASK); - HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + ext_address, accfilt_entry.dword); - ext_address += sizeof(cyg_uint32); - accfilt_entry.dword = (channel_no << 29) | (0x1FFFFFFF & ACCFILT_EXT_ID_MASK); - HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + ext_address, accfilt_entry.dword); - ext_address += sizeof(cyg_uint32); -#endif // CYGOPT_IO_CAN_EXT_CAN_ID - } // while (lpc2xxx_global_can_info.active_channels[i]) - - // - // finally store end of table value and restore the previous state of the - // acceptance filter - // - HAL_WRITE_UINT32(CAN_ACCFILT_ENDOFTABLE, ext_address); - HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, accfilt_bck); -} -#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG - - -//=========================================================================== -// Reset acceptance filter to poweron defaults -//=========================================================================== -void lpc2xxx_can_accfilt_reset(void) -{ - cyg_uint32 accfilt_bck; // acceptance filter backup - // - // first step: disable acceptance filter and prepare it for modification - // - HAL_READ_UINT32(CAN_ACCFILT_AFMR, accfilt_bck); - HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, AFMR_OFF | AFMR_BYPASS); - - // - // Now write zero to all addresses of acceptance filter table - // - HAL_WRITE_UINT32(CAN_ACCFILT_SFF_SA, 0); - HAL_WRITE_UINT32(CAN_ACCFILT_SFF_GRP_SA, 0); - HAL_WRITE_UINT32(CAN_ACCFILT_EFF_SA, 0); - HAL_WRITE_UINT32(CAN_ACCFILT_EFF_GRP_SA, 0); - HAL_WRITE_UINT32(CAN_ACCFILT_ENDOFTABLE, 0); - - // - // finally restore the prvious state of the acceptance filter - // - HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, accfilt_bck); -} - - -//=========================================================================== -// Dump content of acceptance filter lookup table -//=========================================================================== -#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG -void lpc2xxx_can_accfilt_dbg_dump(void) -{ - cyg_uint32 sff_sa; - cyg_uint32 sff_grp_sa; - cyg_uint32 eff_sa; - cyg_uint32 eff_grp_sa; - cyg_uint32 end_of_table; - cyg_uint32 entry_address; - lsc_buf_t data; - - - HAL_READ_UINT32(CAN_ACCFILT_SFF_SA, sff_sa); - HAL_READ_UINT32(CAN_ACCFILT_SFF_GRP_SA, sff_grp_sa); - HAL_READ_UINT32(CAN_ACCFILT_EFF_SA, eff_sa); - HAL_READ_UINT32(CAN_ACCFILT_EFF_GRP_SA, eff_grp_sa); - HAL_READ_UINT32(CAN_ACCFILT_ENDOFTABLE, end_of_table); - - entry_address = sff_sa; - - // - // Print lookup table registers - // - diag_printf("\n\nDUMP CAN ACCEPTANCE FILTER REGISTERS\n"); - diag_printf("----------------------------------------\n"); - diag_printf("SFF_sa:\t\t0x%08x\n", sff_sa); - diag_printf("SFF_GRP_sa:\t0x%08x\n", sff_grp_sa); - diag_printf("EFF_sa:\t\t0x%08x\n", eff_sa); - diag_printf("EFF_GRP_sa:\t0x%08x\n", eff_grp_sa); - diag_printf("EOT:\t\t0x%08x\n", end_of_table); - - // - // Print table of standard identifiers - // - diag_printf("\n\nDUMP CAN LOOKUP TABLE RAM"); - diag_printf("\nSFF_sa\t\tcolumn_lower\tcolumn_upper\traw_data\n"); - diag_printf("----------------------------------------------------------\n"); - while (entry_address < sff_grp_sa) - { - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + entry_address, data.dword); - diag_printf("0x%04x:\t\t0x%x\t\t0x%x\t\t0x%x\n", entry_address, data.column.lower, data.column.upper, data.dword); - entry_address += sizeof(cyg_uint32); - } - - // - // Print table of standard identifier groups - // - diag_printf("\nSFF_GRP_sa\tcolumn_lower\tcolumn_upper\traw_data\n"); - diag_printf("----------------------------------------------------------\n"); - while (entry_address < eff_sa) - { - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + entry_address, data.dword); - diag_printf("0x%04x:\t\t0x%x\t\t0x%x\t\t0x%x\n", entry_address, data.column.lower, data.column.upper, data.dword); - entry_address += sizeof(cyg_uint32); - } - - // - // Print table of extended identifiers - // - diag_printf("\nEFF_sa\t\t-\t\t-\t\traw_data\n"); - diag_printf("----------------------------------------------------------\n"); - while (entry_address < eff_grp_sa) - { - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + entry_address, data.dword); - diag_printf("0x%04x:\t\t\t\t\t\t0x%x\n", entry_address, data.dword); - entry_address += sizeof(cyg_uint32); - } - - // - // Print table of extended identifier groups - // - diag_printf("\nEFF_GRP_sa\t-\t\t-\t\traw_data\n"); - diag_printf("----------------------------------------------------------\n"); - while (entry_address < end_of_table) - { - HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + entry_address, data.dword); - diag_printf("0x%04x:\t\t\t\t\t\t0x%x\n", entry_address, data.dword); - entry_address += sizeof(cyg_uint32); - } -} -#endif // CYGDBG_DEVS_CAN_LPC2XXX_DEBUG - -//=========================================================================== -// Dump content of acceptance filter lookup table -//=========================================================================== -#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG -void lpc2xxx_can_reg_dump(struct cyg_devtab_entry* devtab_entry) -{ - can_channel *chan = (can_channel*)devtab_entry->priv; - cyg_uint32 reg_val; - CAN_DECLARE_INFO(chan); - - chan = chan; // avoid compiler warnings for unused variables - // - // Print table of extended identifier groups - // - diag_printf("\n\nCAN REGISTER DUMP\n"); - diag_printf("\nRegister\tValue\n"); - diag_printf("----------------------------------------------------------\n"); - HAL_READ_UINT32(CAN_CTRL_MOD(info), reg_val); - diag_printf("CANMOD\t\t0x%08x\n", reg_val); - HAL_READ_UINT32(CAN_CTRL_CMR(info), reg_val); - diag_printf("CANCMR\t\t0x%08x\n", reg_val); - HAL_READ_UINT32(CAN_CTRL_GSR(info), reg_val); - diag_printf("CANGSR\t\t0x%08x\n", reg_val); - HAL_READ_UINT32(CAN_CTRL_ICR(info), reg_val); - diag_printf("CANICR\t\t0x%08x\n", reg_val); - HAL_READ_UINT32(CAN_CTRL_IER(info), reg_val); - diag_printf("CANIER\t\t0x%08x\n", reg_val); - HAL_READ_UINT32(CAN_CTRL_BTR(info), reg_val); - diag_printf("CANBTR\t\t0x%08x\n", reg_val); - HAL_READ_UINT32(CAN_CTRL_EWL(info), reg_val); - diag_printf("CANEWL\t\t0x%08x\n", reg_val); - HAL_READ_UINT32(CAN_CTRL_SR(info), reg_val); - diag_printf("CANSR\t\t0x%08x\n", reg_val); - HAL_READ_UINT32(CAN_CTRL_RFS(info), reg_val); - diag_printf("CANRFS\t\t0x%08x\n", reg_val); - HAL_READ_UINT32(CAN_CTRL_RID(info), reg_val); - diag_printf("CANRID\t\t0x%08x\n", reg_val); - HAL_READ_UINT32(CAN_CTRL_RDA(info), reg_val); - diag_printf("CANRDA\t\t0x%08x\n", reg_val); - HAL_READ_UINT32(CAN_CTRL_RDB(info), reg_val); - diag_printf("CANRDB\t\t0x%08x\n", reg_val); - - diag_printf("\n\nCAN CENTRAL REGISTER DUMP\n"); - diag_printf("\nRegister\tValue\n"); - diag_printf("----------------------------------------------------------\n"); - HAL_READ_UINT32(CAN_CENTRAL_TXSR, reg_val); - diag_printf("CANTxSR\t\t0x%08x\n", reg_val); - HAL_READ_UINT32(CAN_CENTRAL_RXSR, reg_val); - diag_printf("CANRxSR\t\t0x%08x\n", reg_val); - HAL_READ_UINT32(CAN_CENTRAL_MSR, reg_val); - diag_printf("CANMSR\t\t0x%08x\n", reg_val); - - diag_printf("\n\nCAN ACCEPTANCE FILTER REGISTER DUMP\n"); - diag_printf("\nRegister\tValue\n"); - diag_printf("----------------------------------------------------------\n"); - HAL_READ_UINT32(CAN_ACCFILT_AFMR, reg_val); - diag_printf("AFMR\t\t0x%08x\n", reg_val); - HAL_READ_UINT32(CAN_ACCFILT_LUT_ERR, reg_val); - diag_printf("LUTERR\t\t0x%08x\n", reg_val); - HAL_READ_UINT32(CAN_ACCFILT_LUT_ERR_ADDR, reg_val); - diag_printf("LUTERRADDR\t0x%08x\n", reg_val); -} -#endif // #ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG - -//--------------------------------------------------------------------------- -// EOF can_accfilt_lpc2xxx.c +//========================================================================== +// +// devs/can/arm/lpc2xxx/current/src/can_accfilt_lpc2xxx.c +// +// Acceptance filter management for LPC2xxx CAN driver +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2003 Gary Thomas +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Uwe Kindler +// Contributors: Uwe Kindler +// Date: 2007-05-28 +// Purpose: Support LPC2xxx on-chip CAN acceptance filters +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + + +//=========================================================================== +// Data types +//=========================================================================== +// +// Acceptance filter entry +// +typedef struct lpc2xxx_accfilt_entry +{ + cyg_uint32 data; // the value inclusive channel number + cyg_uint32 id; + cyg_uint32 lower_id_bound; + cyg_uint32 upper_id_bound; + cyg_uint8 channel_no; +} lpc2xxx_accfilt_entry_t; + + +//=========================================================================== +// Declarations +//=========================================================================== +//-------------------------------------------------------------------------- +// Lowlevel acceptance filter access +// +#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG +static bool lpc2xxx_can_accfilt_add(lpc2xxx_can_info_t *info, + cyg_uint32 lower_id, + cyg_uint32 upper_id, + cyg_can_id_type ext); +void lpc2xxx_can_accfilt_ram_insert_entry(cyg_uint32 TableAddress, cyg_uint16 EntryNo); +void lpc2xxx_can_accfilt_ram_remove_entry(cyg_uint32 TableAddress, cyg_uint16 EntryNo); +void lpc2xxx_can_accfilt_remove_all_ctrl_entries(lpc2xxx_can_info_t *info); +#else +static void lpc2xxx_can_accfilt_simple_rx_all(void); +#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG +void lpc2xxx_can_accfilt_reset(void); + +#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG +void lpc2xxx_can_accfilt_dbg_dump(void); +void lpc2xxx_can_reg_dump(struct cyg_devtab_entry* devtab_entry); +#endif + + +#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG +//=========================================================================== +// Calculate address of entry in certain table +//=========================================================================== +static cyg_uint32 lpc2xxx_can_accfilt_calc_entry_address(cyg_uint32 TableAddressRegister, cyg_uint16 EntryNo) +{ + cyg_uint32 EntryAddress = 0xFFFFFFFF; + cyg_uint32 TableAddress; + + HAL_READ_UINT32(TableAddressRegister, TableAddress); + switch (TableAddressRegister) + { +#ifdef CYGOPT_IO_CAN_STD_CAN_ID + case CAN_ACCFILT_SFF_SA: + EntryAddress = ((EntryNo / 2) << 2) + TableAddress; + break; + + case CAN_ACCFILT_SFF_GRP_SA: + EntryAddress = TableAddress + (EntryNo << 2); + break; +#endif // CYGOPT_IO_CAN_STD_CAN_ID + +#ifdef CYGOPT_IO_CAN_EXT_CAN_ID + case CAN_ACCFILT_EFF_SA: + EntryAddress = TableAddress + (EntryNo << 2); + break; + + case CAN_ACCFILT_EFF_GRP_SA: + EntryAddress = TableAddress + (EntryNo << 3); + break; +#endif // CYGOPT_IO_CAN_EXT_CAN_ID + default: + CYG_ASSERT(0, "Wrong TableAddressRegister"); + } + + return EntryAddress; +} + + +//=========================================================================== +// Remove one single entry from acceptance filter table +//=========================================================================== +void lpc2xxx_can_accfilt_ram_remove_entry(cyg_uint32 Table, cyg_uint16 EntryNo) +{ + cyg_int32 remove_address = lpc2xxx_can_accfilt_calc_entry_address(Table, EntryNo); + cyg_int32 entry_address; + lsc_buf_t lsc_val; + cyg_uint8 entry_size = sizeof(cyg_uint32); + cyg_uint32 sff_sa; + cyg_uint32 sff_grp_sa; + cyg_uint32 eff_sa; + cyg_uint32 eff_grp_sa; + cyg_int32 end_of_table; + + HAL_READ_UINT32(CAN_ACCFILT_SFF_SA, sff_sa); + HAL_READ_UINT32(CAN_ACCFILT_SFF_GRP_SA, sff_grp_sa); + HAL_READ_UINT32(CAN_ACCFILT_EFF_SA, eff_sa); + HAL_READ_UINT32(CAN_ACCFILT_EFF_GRP_SA, eff_grp_sa); + HAL_READ_UINT32(CAN_ACCFILT_ENDOFTABLE, end_of_table); + + // + // Do not try to remove from an empty table + // + if (!end_of_table) + { + return; + } + + entry_address = remove_address; + + if ((remove_address < eff_grp_sa) && (CAN_ACCFILT_EFF_GRP_SA != Table)) + { + if ((remove_address < eff_sa) && (CAN_ACCFILT_EFF_SA != Table)) + { + if ((remove_address < sff_grp_sa) && (CAN_ACCFILT_SFF_GRP_SA != Table)) + { + lsc_buf_t nextval; + + if (EntryNo % 2) + { + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + remove_address, lsc_val.dword); + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + remove_address + sizeof(cyg_uint32), nextval.dword); + lsc_val.column.upper = nextval.column.lower; + entry_address += sizeof(cyg_uint32); + } + + // + // Start copy immediatelly after removed entry + // + while (entry_address < sff_grp_sa) + { + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + entry_address, lsc_val.dword); + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + entry_address + sizeof(cyg_uint32), nextval.dword); + lsc_val.column.lower = lsc_val.column.upper; + lsc_val.column.upper = nextval.column.lower; + HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + entry_address, lsc_val.dword); + entry_address += sizeof(cyg_uint32); + } + + // + // now check if the lower identifier is disabled - if it is disabled, then + // also the upper identifier is invalid and we can remove the entry completely + // if the lower identifier is not disabled, then it is valid and we need + // to disable the upper identifier because it contains an invalid entry + // + if (lsc_val.column.lower & ACCFILT_STD_DIS) + { + sff_grp_sa -= sizeof(cyg_uint32); + entry_address = sff_grp_sa; + } + else + { + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + sff_grp_sa - sizeof(cyg_uint32), lsc_val.dword); + lsc_val.column.upper = 0xffff; + HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + sff_grp_sa - sizeof(cyg_uint32), lsc_val.dword); + entry_size = 0; // we do not need to remove anything + } + } // if (pLine < pStdGrpStart) + + eff_sa -= entry_size; + } // if (pLine < pExtIdStart) + + eff_grp_sa -= entry_size; + } // if (pLine < pExtGrpStart) + + // + // If no entry was removed then we can leave immediatelly without changing any + // table pointers because we only did a change inside the sff table + // + if (!entry_size) + { +#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG + lpc2xxx_can_accfilt_dbg_dump(); +#endif + return; + } + + if (CAN_ACCFILT_EFF_GRP_SA == Table) + { + // + // If we are in the area of extended groups then we need to remove + // 2 lines because lower and upper identifier need 1 line each + // + entry_size += sizeof(cyg_uint32); + } + + end_of_table -= entry_size; + + // + // Move alle entries one or two dword downwads - that means we remove a line + // + while (entry_address < end_of_table) + { + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + entry_address + entry_size, lsc_val.dword); + HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + entry_address, lsc_val.dword); + entry_address += sizeof(cyg_uint32); + } + + HAL_WRITE_UINT32(CAN_ACCFILT_SFF_SA, sff_sa); + HAL_WRITE_UINT32(CAN_ACCFILT_SFF_GRP_SA, sff_grp_sa); + HAL_WRITE_UINT32(CAN_ACCFILT_EFF_SA, eff_sa); + HAL_WRITE_UINT32(CAN_ACCFILT_EFF_GRP_SA, eff_grp_sa); + HAL_WRITE_UINT32(CAN_ACCFILT_ENDOFTABLE, end_of_table); + +#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG + lpc2xxx_can_accfilt_dbg_dump(); +#endif +} + +//=========================================================================== +// Insert one empty line into ram - all entries behind this line will be +// moved one entry upwards +//=========================================================================== +void lpc2xxx_can_accfilt_ram_insert_entry(cyg_uint32 Table, cyg_uint16 EntryNo) +{ + cyg_int16 insert_address = lpc2xxx_can_accfilt_calc_entry_address(Table, EntryNo); + cyg_int16 entry_address; + cyg_int16 copy_start = insert_address; + lsc_buf_t lsc_val; + cyg_uint8 entry_size = sizeof(cyg_uint32); + cyg_uint32 sff_sa; + cyg_uint32 sff_grp_sa; + cyg_uint32 eff_sa; + cyg_uint32 eff_grp_sa; + cyg_uint32 end_of_table; + + + HAL_READ_UINT32(CAN_ACCFILT_SFF_SA, sff_sa); + HAL_READ_UINT32(CAN_ACCFILT_SFF_GRP_SA, sff_grp_sa); + HAL_READ_UINT32(CAN_ACCFILT_EFF_SA, eff_sa); + HAL_READ_UINT32(CAN_ACCFILT_EFF_GRP_SA, eff_grp_sa); + HAL_READ_UINT32(CAN_ACCFILT_ENDOFTABLE, end_of_table); + + if ((insert_address <= eff_grp_sa) && (CAN_ACCFILT_EFF_GRP_SA != Table)) + { + if ((insert_address <= eff_sa) && (CAN_ACCFILT_EFF_SA != Table)) + { + if ((insert_address <= sff_grp_sa) && (CAN_ACCFILT_SFF_GRP_SA != Table)) + { + // + // If we are in the range of standard identifiers then we need to + // do some special copy procedure for this area because a standard entry + // is only 2 byte long. Copy only til start of area with standard groups + // + if (sff_grp_sa) + { + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + sff_grp_sa - sizeof(cyg_uint32), lsc_val.dword); // read last entry + // + // now check if the upper identifier is disabled - if it is disabled, then + // we have an odd number of std ids in the list. Then we do not need to + // insert a new line - we simply need to copy all entries 2 bytes upwards + // that meeans we only need to change the std id area and do not need to touch + // any other filter id area. + // If the last entry is not disabled, then we have a valid filter here. + // Then we need to insert a complete new line, that means we also have to mave + // all following entries and filter tables one dword upwards. + // + if (lsc_val.words.low & ACCFILT_STD_DIS) + { + copy_start = end_of_table + sizeof(cyg_uint32); // we do not need to insert a new line and do not copy anything + entry_size = 0; + } + } + + if (entry_size) + { + copy_start = sff_grp_sa; // copy everything behind std id group + sff_grp_sa += entry_size; + } + } // if (pLine < pStdGrpStart) + + eff_sa += entry_size; + } // if (pLine < pExtIdStart) + + eff_grp_sa += entry_size; + } // if (pLine < pExtGrpStart) + + if (CAN_ACCFILT_EFF_GRP_SA == Table) + { + // + // If we are in the area of extended groups then we need to insert + // 2 lines because lower and upper identifier need 1 line each + // + entry_size += sizeof(cyg_uint32); // one entry is 2 dword long + } + + entry_address = end_of_table - sizeof(cyg_uint32); + end_of_table += entry_size; // add one additional entry + + // + // Move alle entries one or two dwords upwards - that means we insert a new empty line + // + while (entry_address >= copy_start) + { + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + (cyg_uint32)entry_address, lsc_val.dword); + HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + (cyg_uint32)entry_address + entry_size, lsc_val.dword); + entry_address -= sizeof(cyg_uint32); + } + + // + // For the std ID area we need a special pocedure + // + if (CAN_ACCFILT_SFF_SA == Table) + { + lsc_buf_t preval; + // + // Start copy with last entry of std id table + // + entry_address = sff_grp_sa - sizeof(cyg_uint32); + + while (entry_address > insert_address) + { + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + (cyg_uint32)entry_address, lsc_val.dword); + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + (cyg_uint32)entry_address - sizeof(cyg_uint32), preval.dword); + lsc_val.column.upper = lsc_val.column.lower; + lsc_val.column.lower = preval.column.upper; + HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + (cyg_uint32)entry_address, lsc_val.dword); + entry_address -= sizeof(cyg_uint32); + } + + // + // If we insert an entry into the lower colum, then we need to move the + // content of the lower column into the upper column + // + if (!(EntryNo % 2)) + { + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + (cyg_uint32)insert_address, lsc_val.dword); + lsc_val.column.upper = lsc_val.column.lower; + HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + (cyg_uint32)insert_address, lsc_val.dword); + } + + // + // If we inserted a new line, then we have an odd number of identifiers now + // and need to disable the last (the upper) entry + // + if (entry_size) + { + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + sff_grp_sa - sizeof(cyg_uint32) , lsc_val.dword); + lsc_val.column.upper = 0xFFFF; // disable the entry + HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + sff_grp_sa - sizeof(cyg_uint32) , lsc_val.dword); + } + } + + HAL_WRITE_UINT32(CAN_ACCFILT_SFF_SA, sff_sa); + HAL_WRITE_UINT32(CAN_ACCFILT_SFF_GRP_SA, sff_grp_sa); + HAL_WRITE_UINT32(CAN_ACCFILT_EFF_SA, eff_sa); + HAL_WRITE_UINT32(CAN_ACCFILT_EFF_GRP_SA, eff_grp_sa); + HAL_WRITE_UINT32(CAN_ACCFILT_ENDOFTABLE, end_of_table); +} + + +//=========================================================================== +// Query number of entries in a certain table +//=========================================================================== +static cyg_uint16 lpc2xxx_can_accfilt_get_table_entries(cyg_uint32 TableStartAddress) +{ + cyg_uint32 start; + cyg_uint32 end; + + switch (TableStartAddress) + { +#ifdef CYGOPT_IO_CAN_STD_CAN_ID + case CAN_ACCFILT_SFF_SA: + HAL_READ_UINT32(CAN_ACCFILT_SFF_SA, start); + HAL_READ_UINT32(CAN_ACCFILT_SFF_GRP_SA, end); + if (end - start) + { + lsc_buf_t data; + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + end - sizeof(cyg_uint32), data.dword); + if (data.column.upper & ACCFILT_STD_DIS) + { + return (((end - start) >> 1) - 1); + } + } + return (end - start) >> 1; + + case CAN_ACCFILT_SFF_GRP_SA: + HAL_READ_UINT32(CAN_ACCFILT_SFF_GRP_SA, start); + HAL_READ_UINT32(CAN_ACCFILT_EFF_SA, end); + return (end - start) >> 2; +#endif // CYGOPT_IO_CAN_STD_CAN_ID + +#ifdef CYGOPT_IO_CAN_EXT_CAN_ID + case CAN_ACCFILT_EFF_SA: + HAL_READ_UINT32(CAN_ACCFILT_EFF_SA, start); + HAL_READ_UINT32(CAN_ACCFILT_EFF_GRP_SA, end); + return (end - start) >> 2; + + case CAN_ACCFILT_EFF_GRP_SA: + HAL_READ_UINT32(CAN_ACCFILT_EFF_GRP_SA, start); + HAL_READ_UINT32(CAN_ACCFILT_ENDOFTABLE, end); + return (end - start) >> 3; +#endif // CYGOPT_IO_CAN_EXT_CAN_ID + default: + CYG_FAIL("Invalid identifier table address"); + return 0; + } // switch (TableStartAddress) +} + +//=========================================================================== +// Query certain entry from table +//=========================================================================== +static void lpc2xxx_can_accfilt_get_entry(cyg_uint32 TableStartAddress, cyg_uint16 EntryNo, lpc2xxx_accfilt_entry_t *pEntry) +{ + cyg_uint32 EntryAddress = lpc2xxx_can_accfilt_calc_entry_address(TableStartAddress, EntryNo); + lsc_buf_t Data; + + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + EntryAddress, Data.dword); + pEntry->data = Data.dword; + switch (TableStartAddress) + { +#ifdef CYGOPT_IO_CAN_STD_CAN_ID + case CAN_ACCFILT_SFF_SA: + { + cyg_uint16 column; + if (EntryNo % 2) + { + column = Data.column.upper; + } + else + { + column = Data.column.lower; + } + pEntry->id = ACCFILT_STD_GET_ID(column); + pEntry->channel_no = ACCFILT_STD_GET_CTRL(column); + } + break; + + case CAN_ACCFILT_SFF_GRP_SA: + pEntry->lower_id_bound = ACCFILT_STD_GET_ID(Data.column.lower); + pEntry->upper_id_bound = ACCFILT_STD_GET_ID(Data.column.upper); + pEntry->channel_no = ACCFILT_STD_GET_CTRL(Data.column.lower); + break; +#endif // #ifdef CYGOPT_IO_CAN_STD_CAN_ID + +#ifdef CYGOPT_IO_CAN_EXT_CAN_ID + case CAN_ACCFILT_EFF_SA: + pEntry->id = ACCFILT_EXT_GET_ID(Data.dword); + pEntry->channel_no = ACCFILT_EXT_GET_CTRL(Data.dword); + break; + + case CAN_ACCFILT_EFF_GRP_SA: + pEntry->lower_id_bound = ACCFILT_EXT_GET_ID(Data.dword); + pEntry->channel_no = ACCFILT_EXT_GET_CTRL(Data.dword); + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE+ EntryAddress + sizeof(cyg_uint32), Data.dword); + pEntry->upper_id_bound = ACCFILT_EXT_GET_ID(Data.dword); + break; +#endif // #ifedf CYGOPT_IO_CAN_EXT_CAN_ID + default: + CYG_FAIL("Invalid identifier table address"); + } // switch () +} + + +//=========================================================================== +// Set certain entry in table +//=========================================================================== +static void lpc2xxx_can_accfilt_set_entry(cyg_uint32 TableStartAddress, cyg_uint16 EntryNo, lpc2xxx_accfilt_entry_t *pEntry) +{ + cyg_uint32 EntryAddress = lpc2xxx_can_accfilt_calc_entry_address(TableStartAddress, EntryNo); + lsc_buf_t Data; + + switch (TableStartAddress) + { +#ifdef CYGOPT_IO_CAN_STD_CAN_ID + case CAN_ACCFILT_SFF_SA: + { + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + EntryAddress, Data.dword); + if (EntryNo % 2) + { + Data.column.upper = (pEntry->channel_no << 13) | (pEntry->id & ACCFILT_STD_ID_MASK); + } + else + { + Data.column.lower = (pEntry->channel_no << 13) | (pEntry->id & ACCFILT_STD_ID_MASK); + } + } + break; + + case CAN_ACCFILT_SFF_GRP_SA: + Data.column.lower = (pEntry->channel_no << 13) | (pEntry->lower_id_bound & ACCFILT_STD_ID_MASK); + Data.column.upper = (pEntry->channel_no << 13) | (pEntry->upper_id_bound & ACCFILT_STD_ID_MASK); + break; +#endif // #ifdef CYGOPT_IO_CAN_STD_CAN_ID + +#ifdef CYGOPT_IO_CAN_EXT_CAN_ID + case CAN_ACCFILT_EFF_SA: + Data.dword = (pEntry->channel_no << 29) | (pEntry->id & ACCFILT_EXT_ID_MASK); + break; + + case CAN_ACCFILT_EFF_GRP_SA: + { + lsc_buf_t Data2; + + Data.dword = (pEntry->channel_no << 29) | (pEntry->lower_id_bound & ACCFILT_EXT_ID_MASK); + Data2.dword = (pEntry->channel_no << 29) | (pEntry->upper_id_bound & ACCFILT_EXT_ID_MASK); + HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + EntryAddress + sizeof(cyg_uint32), Data2.dword); + } + break; +#endif // #ifdef CYGOPT_IO_CAN_EXT_CAN_ID + + default: + CYG_FAIL("Invalid identifier table address"); + } // switch () + + HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + EntryAddress, Data.dword); +} + + +//=========================================================================== +// Add one entry to acceptance filter RAM +// If upper ID is > lower ID then we have to add a group filter - else we +// have to add a single message filter here +//=========================================================================== +static bool lpc2xxx_can_accfilt_add(lpc2xxx_can_info_t *info, + cyg_uint32 lower_id, + cyg_uint32 upper_id, + cyg_can_id_type ext) +{ + cyg_uint32 accfilt_bck; // acceptance filter backup + cyg_uint32 end_of_table; + cyg_uint32 table; + lpc2xxx_accfilt_entry_t entry; + lpc2xxx_accfilt_entry_t new_entry; + + + // + // first step: disable acceptance filter and prepare it for modification + // + HAL_READ_UINT32(CAN_ACCFILT_AFMR, accfilt_bck); + HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, AFMR_OFF | AFMR_BYPASS); + + // + // Check if table is full + // + HAL_READ_UINT32(CAN_ACCFILT_ENDOFTABLE, end_of_table); + if (end_of_table >= ACCFILT_RAM_SIZE) + { + return false; + } + + new_entry.id = lower_id; + new_entry.lower_id_bound = lower_id; + new_entry.upper_id_bound = upper_id; + + // + // Here we rely on the ISR vector ordering for calculaion of of channel number + // Maybe this is not the right way for newer LPC parts + // + new_entry.channel_no = (CAN_ISRVEC(info) - CYGNUM_HAL_INTERRUPT_CAN1_TX) + 1; + + // + // If lower_id == upper_id then we know that we have to setup a single message filter + // here. If it is not equal the it is group of identifiers to receive + // + if ((lower_id == upper_id) || (lower_id > upper_id)) + { + // + // setup single message filter (standard or extended) here + // +#ifdef CYGOPT_IO_CAN_EXT_CAN_ID + if (ext) + { + table = CAN_ACCFILT_EFF_SA; + } + else +#endif // #ifdef CYGOPT_IO_CAN_EXT_CAN_ID + { +#ifdef CYGOPT_IO_CAN_STD_CAN_ID + table = CAN_ACCFILT_SFF_SA; +#endif // CYGOPT_IO_CAN_STD_CAN_ID + } + } + else + { + // + // setup single message filter (standard or extended) here + // +#ifdef CYGOPT_IO_CAN_EXT_CAN_ID + if (ext) + { + table = CAN_ACCFILT_EFF_GRP_SA; + } + else +#endif // #ifdef CYGOPT_IO_CAN_EXT_CAN_ID + { +#ifdef CYGOPT_IO_CAN_STD_CAN_ID + table = CAN_ACCFILT_SFF_GRP_SA; +#endif // #ifdef CYGOPT_IO_CAN_STD_CAN_ID + } + } + + cyg_uint16 entries = lpc2xxx_can_accfilt_get_table_entries(table); + cyg_uint16 i; + + + for (i = 0; i < entries; ++i) + { + lpc2xxx_can_accfilt_get_entry(table, i, &entry); + + if (entry.channel_no > new_entry.channel_no) + { + break; + } + + if ((entry.channel_no == new_entry.channel_no) + && (entry.id > new_entry.id)) + { + break; + } + } // for (i = 0; i < entries; ++i) + + lpc2xxx_can_accfilt_ram_insert_entry(table, i); + lpc2xxx_can_accfilt_set_entry(table, i, &new_entry); + + // + // finally restore the prvious state of the acceptance filter + // + HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, accfilt_bck); + return true; +} + + +//=========================================================================== +// Remove all entries from a certain controller +//=========================================================================== +void lpc2xxx_can_accfilt_remove_all_ctrl_entries(lpc2xxx_can_info_t *info) +{ + cyg_uint32 accfilt_bck; // acceptance filter backup + cyg_uint16 i; + cyg_uint16 entries; + cyg_uint32 TableStartAddress = CAN_ACCFILT_SFF_SA; + lpc2xxx_accfilt_entry_t Entry; + cyg_uint8 channel_no = (CAN_ISRVEC(info) - CYGNUM_HAL_INTERRUPT_CAN1_TX) + 1; + cyg_uint16 entry_idx; + + // + // first step: disable acceptance filter and prepare it for modification + // + HAL_READ_UINT32(CAN_ACCFILT_AFMR, accfilt_bck); + HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, AFMR_OFF | AFMR_BYPASS); + + // + // now remove all entries for a certain controller + // + for (TableStartAddress = CAN_ACCFILT_SFF_SA; TableStartAddress < CAN_ACCFILT_ENDOFTABLE; TableStartAddress += 4) + { + entries = lpc2xxx_can_accfilt_get_table_entries(TableStartAddress); + entry_idx = 0; + for (i = 0; i < entries; ++i) + { + lpc2xxx_can_accfilt_get_entry(TableStartAddress, entry_idx, &Entry); + if (Entry.channel_no == channel_no) + { + lpc2xxx_can_accfilt_ram_remove_entry(TableStartAddress, entry_idx); + } + else + { + entry_idx++; + } + } // for (i = 0; i < entries; ++i) + } // for (TableStartAddress = CAN_ACCFILT_SFF_SA ... + + // + // finally restore the prvious state of the acceptance filter + // + HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, accfilt_bck); +} +#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + + +#ifndef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG +//=========================================================================== +// Setup reception of all CAN identifiers +// If runtime acceptance filter configuration is not required then we simply +// setup the acceptance filter here to receive all CAN identifiers +//=========================================================================== +static void lpc2xxx_can_accfilt_simple_rx_all(void) +{ + cyg_uint32 regval; + + // + // First check if it is really necessary to setup filters. If end of table is + // != 0 then the acceptance filter is already setup properly + // + HAL_READ_UINT32(CAN_ACCFILT_ENDOFTABLE, regval); + if (regval) + { + return; + } + + cyg_uint32 accfilt_bck; // acceptance filter backup + cyg_uint8 i = 0; // loop counter + lsc_buf_t accfilt_entry; // std group entry +#ifdef CYGOPT_IO_CAN_STD_CAN_ID + cyg_uint8 std_address = 0; // std group entry address +#ifdef CYGOPT_IO_CAN_EXT_CAN_ID + cyg_uint8 ext_address = lpc2xxx_global_can_info.init_cnt << 2; +#endif +#else + cyg_uint8 ext_address = 0; +#endif + + // + // first step: disable acceptance filter and prepare it for modification + // + HAL_READ_UINT32(CAN_ACCFILT_AFMR, accfilt_bck); + HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, AFMR_OFF | AFMR_BYPASS); + + // + // Write table start adresses - we use only standard group and extended filter + // group + // + HAL_WRITE_UINT32(CAN_ACCFILT_SFF_SA, 0); + HAL_WRITE_UINT32(CAN_ACCFILT_SFF_GRP_SA, 0); + HAL_WRITE_UINT32(CAN_ACCFILT_EFF_SA, ext_address); + HAL_WRITE_UINT32(CAN_ACCFILT_EFF_GRP_SA, ext_address); + + // + // Now loop through all active CAN channels and setup the acceptance filter for + // each channel to receive all standard and extended CAN identifiers + // + while (lpc2xxx_global_can_info.active_channels[i]) + { + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)lpc2xxx_global_can_info.active_channels[i++]->dev_priv; + cyg_uint8 channel_no = (CAN_ISRVEC(info) - CYGNUM_HAL_INTERRUPT_CAN1_TX) + 1; + +#ifdef CYGOPT_IO_CAN_STD_CAN_ID + accfilt_entry.column.lower = (channel_no << 13) | (0x000 & ACCFILT_STD_ID_MASK); + accfilt_entry.column.upper = (channel_no << 13) | (0x7FF & ACCFILT_STD_ID_MASK); + HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + std_address, accfilt_entry.dword); + std_address += sizeof(cyg_uint32); +#endif // CYGOPT_IO_CAN_STD_CAN_ID + +#ifdef CYGOPT_IO_CAN_EXT_CAN_ID + accfilt_entry.dword = (channel_no << 29) | (0x00000000 & ACCFILT_EXT_ID_MASK); + HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + ext_address, accfilt_entry.dword); + ext_address += sizeof(cyg_uint32); + accfilt_entry.dword = (channel_no << 29) | (0x1FFFFFFF & ACCFILT_EXT_ID_MASK); + HAL_WRITE_UINT32(CAN_ACCFILT_RAM_BASE + ext_address, accfilt_entry.dword); + ext_address += sizeof(cyg_uint32); +#endif // CYGOPT_IO_CAN_EXT_CAN_ID + } // while (lpc2xxx_global_can_info.active_channels[i]) + + // + // finally store end of table value and restore the previous state of the + // acceptance filter + // + HAL_WRITE_UINT32(CAN_ACCFILT_ENDOFTABLE, ext_address); + HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, accfilt_bck); +} +#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + + +//=========================================================================== +// Reset acceptance filter to poweron defaults +//=========================================================================== +void lpc2xxx_can_accfilt_reset(void) +{ + cyg_uint32 accfilt_bck; // acceptance filter backup + // + // first step: disable acceptance filter and prepare it for modification + // + HAL_READ_UINT32(CAN_ACCFILT_AFMR, accfilt_bck); + HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, AFMR_OFF | AFMR_BYPASS); + + // + // Now write zero to all addresses of acceptance filter table + // + HAL_WRITE_UINT32(CAN_ACCFILT_SFF_SA, 0); + HAL_WRITE_UINT32(CAN_ACCFILT_SFF_GRP_SA, 0); + HAL_WRITE_UINT32(CAN_ACCFILT_EFF_SA, 0); + HAL_WRITE_UINT32(CAN_ACCFILT_EFF_GRP_SA, 0); + HAL_WRITE_UINT32(CAN_ACCFILT_ENDOFTABLE, 0); + + // + // finally restore the prvious state of the acceptance filter + // + HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, accfilt_bck); +} + + +//=========================================================================== +// Dump content of acceptance filter lookup table +//=========================================================================== +#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG +void lpc2xxx_can_accfilt_dbg_dump(void) +{ + cyg_uint32 sff_sa; + cyg_uint32 sff_grp_sa; + cyg_uint32 eff_sa; + cyg_uint32 eff_grp_sa; + cyg_uint32 end_of_table; + cyg_uint32 entry_address; + lsc_buf_t data; + + + HAL_READ_UINT32(CAN_ACCFILT_SFF_SA, sff_sa); + HAL_READ_UINT32(CAN_ACCFILT_SFF_GRP_SA, sff_grp_sa); + HAL_READ_UINT32(CAN_ACCFILT_EFF_SA, eff_sa); + HAL_READ_UINT32(CAN_ACCFILT_EFF_GRP_SA, eff_grp_sa); + HAL_READ_UINT32(CAN_ACCFILT_ENDOFTABLE, end_of_table); + + entry_address = sff_sa; + + // + // Print lookup table registers + // + diag_printf("\n\nDUMP CAN ACCEPTANCE FILTER REGISTERS\n"); + diag_printf("----------------------------------------\n"); + diag_printf("SFF_sa:\t\t0x%08x\n", sff_sa); + diag_printf("SFF_GRP_sa:\t0x%08x\n", sff_grp_sa); + diag_printf("EFF_sa:\t\t0x%08x\n", eff_sa); + diag_printf("EFF_GRP_sa:\t0x%08x\n", eff_grp_sa); + diag_printf("EOT:\t\t0x%08x\n", end_of_table); + + // + // Print table of standard identifiers + // + diag_printf("\n\nDUMP CAN LOOKUP TABLE RAM"); + diag_printf("\nSFF_sa\t\tcolumn_lower\tcolumn_upper\traw_data\n"); + diag_printf("----------------------------------------------------------\n"); + while (entry_address < sff_grp_sa) + { + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + entry_address, data.dword); + diag_printf("0x%04x:\t\t0x%x\t\t0x%x\t\t0x%x\n", entry_address, data.column.lower, data.column.upper, data.dword); + entry_address += sizeof(cyg_uint32); + } + + // + // Print table of standard identifier groups + // + diag_printf("\nSFF_GRP_sa\tcolumn_lower\tcolumn_upper\traw_data\n"); + diag_printf("----------------------------------------------------------\n"); + while (entry_address < eff_sa) + { + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + entry_address, data.dword); + diag_printf("0x%04x:\t\t0x%x\t\t0x%x\t\t0x%x\n", entry_address, data.column.lower, data.column.upper, data.dword); + entry_address += sizeof(cyg_uint32); + } + + // + // Print table of extended identifiers + // + diag_printf("\nEFF_sa\t\t-\t\t-\t\traw_data\n"); + diag_printf("----------------------------------------------------------\n"); + while (entry_address < eff_grp_sa) + { + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + entry_address, data.dword); + diag_printf("0x%04x:\t\t\t\t\t\t0x%x\n", entry_address, data.dword); + entry_address += sizeof(cyg_uint32); + } + + // + // Print table of extended identifier groups + // + diag_printf("\nEFF_GRP_sa\t-\t\t-\t\traw_data\n"); + diag_printf("----------------------------------------------------------\n"); + while (entry_address < end_of_table) + { + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + entry_address, data.dword); + diag_printf("0x%04x:\t\t\t\t\t\t0x%x\n", entry_address, data.dword); + entry_address += sizeof(cyg_uint32); + } +} +#endif // CYGDBG_DEVS_CAN_LPC2XXX_DEBUG + +//=========================================================================== +// Dump content of acceptance filter lookup table +//=========================================================================== +#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG +void lpc2xxx_can_reg_dump(struct cyg_devtab_entry* devtab_entry) +{ + can_channel *chan = (can_channel*)devtab_entry->priv; + cyg_uint32 reg_val; + CAN_DECLARE_INFO(chan); + + chan = chan; // avoid compiler warnings for unused variables + // + // Print table of extended identifier groups + // + diag_printf("\n\nCAN REGISTER DUMP\n"); + diag_printf("\nRegister\tValue\n"); + diag_printf("----------------------------------------------------------\n"); + HAL_READ_UINT32(CAN_CTRL_MOD(info), reg_val); + diag_printf("CANMOD\t\t0x%08x\n", reg_val); + HAL_READ_UINT32(CAN_CTRL_CMR(info), reg_val); + diag_printf("CANCMR\t\t0x%08x\n", reg_val); + HAL_READ_UINT32(CAN_CTRL_GSR(info), reg_val); + diag_printf("CANGSR\t\t0x%08x\n", reg_val); + HAL_READ_UINT32(CAN_CTRL_ICR(info), reg_val); + diag_printf("CANICR\t\t0x%08x\n", reg_val); + HAL_READ_UINT32(CAN_CTRL_IER(info), reg_val); + diag_printf("CANIER\t\t0x%08x\n", reg_val); + HAL_READ_UINT32(CAN_CTRL_BTR(info), reg_val); + diag_printf("CANBTR\t\t0x%08x\n", reg_val); + HAL_READ_UINT32(CAN_CTRL_EWL(info), reg_val); + diag_printf("CANEWL\t\t0x%08x\n", reg_val); + HAL_READ_UINT32(CAN_CTRL_SR(info), reg_val); + diag_printf("CANSR\t\t0x%08x\n", reg_val); + HAL_READ_UINT32(CAN_CTRL_RFS(info), reg_val); + diag_printf("CANRFS\t\t0x%08x\n", reg_val); + HAL_READ_UINT32(CAN_CTRL_RID(info), reg_val); + diag_printf("CANRID\t\t0x%08x\n", reg_val); + HAL_READ_UINT32(CAN_CTRL_RDA(info), reg_val); + diag_printf("CANRDA\t\t0x%08x\n", reg_val); + HAL_READ_UINT32(CAN_CTRL_RDB(info), reg_val); + diag_printf("CANRDB\t\t0x%08x\n", reg_val); + + diag_printf("\n\nCAN CENTRAL REGISTER DUMP\n"); + diag_printf("\nRegister\tValue\n"); + diag_printf("----------------------------------------------------------\n"); + HAL_READ_UINT32(CAN_CENTRAL_TXSR, reg_val); + diag_printf("CANTxSR\t\t0x%08x\n", reg_val); + HAL_READ_UINT32(CAN_CENTRAL_RXSR, reg_val); + diag_printf("CANRxSR\t\t0x%08x\n", reg_val); + HAL_READ_UINT32(CAN_CENTRAL_MSR, reg_val); + diag_printf("CANMSR\t\t0x%08x\n", reg_val); + + diag_printf("\n\nCAN ACCEPTANCE FILTER REGISTER DUMP\n"); + diag_printf("\nRegister\tValue\n"); + diag_printf("----------------------------------------------------------\n"); + HAL_READ_UINT32(CAN_ACCFILT_AFMR, reg_val); + diag_printf("AFMR\t\t0x%08x\n", reg_val); + HAL_READ_UINT32(CAN_ACCFILT_LUT_ERR, reg_val); + diag_printf("LUTERR\t\t0x%08x\n", reg_val); + HAL_READ_UINT32(CAN_ACCFILT_LUT_ERR_ADDR, reg_val); + diag_printf("LUTERRADDR\t0x%08x\n", reg_val); +} +#endif // #ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG + +//--------------------------------------------------------------------------- +// EOF can_accfilt_lpc2xxx.c
--- a/packages/devs/can/arm/lpc2xxx/current/src/can_lpc2xxx.c +++ b/packages/devs/can/arm/lpc2xxx/current/src/can_lpc2xxx.c @@ -1,1863 +1,2006 @@ -//========================================================================== -// -// devs/can/arm/lpc2xxx/current/src/can_lpc2xxx.c -// -// CAN driver for LPC2xxx microcontrollers -// -//========================================================================== -//####ECOSGPLCOPYRIGHTBEGIN#### -// ------------------------------------------- -// This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -// Copyright (C) 2003 Gary Thomas -// -// eCos is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 or (at your option) any later version. -// -// eCos is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. -// -// You should have received a copy of the GNU General Public License along -// with eCos; if not, write to the Free Software Foundation, Inc., -// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -// -// As a special exception, if other files instantiate templates or use macros -// or inline functions from this file, or you compile this file and link it -// with other works to produce a work based on this file, this file does not -// by itself cause the resulting work to be covered by the GNU General Public -// License. However the source code for this file must still be made available -// in accordance with section (3) of the GNU General Public License. -// -// This exception does not invalidate any other reasons why a work based on -// this file might be covered by the GNU General Public License. -// -// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. -// at http://sources.redhat.com/ecos/ecos-license/ -// ------------------------------------------- -//####ECOSGPLCOPYRIGHTEND#### -//========================================================================== -//#####DESCRIPTIONBEGIN#### -// -// Author(s): Uwe Kindler -// Contributors: Uwe Kindler -// Date: 2007-04-09 -// Purpose: Support LPC2xxx on-chip CAN moduls -// Description: -// -//####DESCRIPTIONEND#### -// -//========================================================================== - - -//========================================================================== -// INCLUDES -//========================================================================== -#include <pkgconf/system.h> -#include <pkgconf/io_can.h> -#include <pkgconf/io.h> -#include <pkgconf/devs_can_lpc2xxx.h> - -#include <cyg/infra/diag.h> - -#include <cyg/io/io.h> -#include <cyg/io/devtab.h> -#include <cyg/io/can.h> -#include <cyg/io/can_lpc2xxx.h> -#include <cyg/io/can_lpc2xxx_baudrates.h> - -#include <cyg/hal/hal_arch.h> -#include <cyg/hal/hal_intr.h> -#include <cyg/hal/hal_io.h> - -#include <cyg/hal/hal_diag.h> -#include <cyg/infra/cyg_ass.h> - - -//=========================================================================== -// DEFINES -//=========================================================================== -// -// Check if the macro HAL_LPC2XXX_GET_CAN_BR is provided -// -#ifndef HAL_LPC2XXX_GET_CAN_BR -#error "Macro HAL_LPC2XXX_GET_CAN_BR() missing" -#endif - -// -// Support debug output if this option is enabled in CDL file -// -#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG -#define LPC2XXX_DBG_PRINT diag_printf -#else -#define LPC2XXX_DBG_PRINT( fmt, ... ) -#endif - - -//--------------------------------------------------------------------------- -// we define our own set of register bits in order to be independent from -// platform specific names -// - -//--------------------------------------------------------------------------- -// Memory map of CAN block -// -#define CAN_ACCFILT_RAM_BASE 0xE0038000 -#define CAN_ACCFILT_REG_BASE 0xE003C000 -#define CAN_CENTRAL_REG_BASE 0xE0040000 -#define CAN_CTRL_1_REG_BASE 0xE0044000 -#define CAN_CTRL_2_REG_BASE 0xE0048000 -#define CAN_CTRL_3_REG_BASE 0xE004C000 -#define CAN_CTRL_4_REG_BASE 0xE0050000 - - -//--------------------------------------------------------------------------- -// CAN Acceptance Filter register layout -// -#define CAN_ACCFILT_AFMR (CAN_ACCFILT_REG_BASE + 0x0000) -#define CAN_ACCFILT_SFF_SA (CAN_ACCFILT_REG_BASE + 0x0004) -#define CAN_ACCFILT_SFF_GRP_SA (CAN_ACCFILT_REG_BASE + 0x0008) -#define CAN_ACCFILT_EFF_SA (CAN_ACCFILT_REG_BASE + 0x000C) -#define CAN_ACCFILT_EFF_GRP_SA (CAN_ACCFILT_REG_BASE + 0x0010) -#define CAN_ACCFILT_ENDOFTABLE (CAN_ACCFILT_REG_BASE + 0x0014) -#define CAN_ACCFILT_LUT_ERR_ADDR (CAN_ACCFILT_REG_BASE + 0x0018) -#define CAN_ACCFILT_LUT_ERR (CAN_ACCFILT_REG_BASE + 0x001C) - -//--------------------------------------------------------------------------- -// CAN_ACCFILT_AFMR Bits -// -#define AFMR_OFF 0x00000001 // 1 = Acceptance filter is not operational -#define AFMR_BYPASS 0x00000002 // 1 = all Rx messages are accepted on enabled CAN controllers. -#define AFMR_FULLCAN 0x00000004 // 1 = FullCAN mode -#define AFMR_ON 0x00000000 // Acceptance filter on -#define ACCFILT_RAM_SIZE 2048 // size of acceptance filter ram - - -//--------------------------------------------------------------------------- -// Acceptance filter tool macros -// -#define ACCFILT_STD_ID_MASK 0x7FF -#define ACCFILT_EXT_ID_MASK 0x1FFFFFFF -#define ACCFILT_STD_DIS 0x1000 -#define ACCFILT_STD_CTRL_MASK 0xE000 -#define ACCFILT_EXT_CTRL_MASK 0xE0000000 -#define ACCFILT_STD_GET_CTRL(_entry_) (((_entry_) >> 13) & 0x7) -#define ACCFILT_STD_GET_CTRL_LOWER(_entry_) (((_entry_) >> 29) & 0x7) -#define ACCFILT_STD_GET_CTRL_UPPER(_entry_) (((_entry_) >> 13) & 0x7) -#define ACCFILT_STD_GET_ID(_entry_) ((_entry_) & ACCFILT_STD_ID_MASK) -#define ACCFILT_EXT_GET_ID(_entry_) ((_entry_) & ACCFILT_EXT_ID_MASK) -#define ACCFILT_EXT_GET_CTRL(_entry_) (((_entry_) >> 29) & 0x7) -#define ACCFILT_EXT_SET_CTRL(_entry_, _ctrl_) ((_entry_ & 0xE0000000) | ((_ctrl_) << 29)) - - -//--------------------------------------------------------------------------- -// CAN Central CAN Registers register layout -// -#define CAN_CENTRAL_TXSR (CAN_CENTRAL_REG_BASE + 0x0000) -#define CAN_CENTRAL_RXSR (CAN_CENTRAL_REG_BASE + 0x0004) -#define CAN_CENTRAL_MSR (CAN_CENTRAL_REG_BASE + 0x0008) - - -//--------------------------------------------------------------------------- -// CAN Controller register offsets -// Registers are offsets from base CAN module control register -// -#define CANREG_MOD 0x0000 -#define CANREG_CMR 0x0004 -#define CANREG_GSR 0x0008 -#define CANREG_ICR 0x000C -#define CANREG_IER 0x0010 -#define CANREG_BTR 0x0014 -#define CANREG_EWL 0x0018 -#define CANREG_SR 0x001C -#define CANREG_RFS 0x0020 -#define CANREG_RID 0x0024 -#define CANREG_RDA 0x0028 -#define CANREG_RDB 0x002C -#define CANREG_TFI1 0x0030 -#define CANREG_TID1 0x0034 -#define CANREG_TDA1 0x0038 -#define CANREG_TDB1 0x003C -#define CANREG_TFI2 0x0040 -#define CANREG_TID2 0x0044 -#define CANREG_TDA2 0x0048 -#define CANREG_TDB2 0x004C -#define CANREG_TFI3 0x0050 -#define CANREG_TID3 0x0054 -#define CANREG_TDA3 0x0058 -#define CANREG_TDB3 0x005C - - -//--------------------------------------------------------------------------- -// CAN Controller register layout -// -#define CAN_CTRL_MOD(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_MOD) -#define CAN_CTRL_CMR(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_CMR) -#define CAN_CTRL_GSR(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_GSR) -#define CAN_CTRL_ICR(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_ICR) -#define CAN_CTRL_IER(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_IER) -#define CAN_CTRL_BTR(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_BTR) -#define CAN_CTRL_EWL(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_EWL) -#define CAN_CTRL_SR(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_SR) -#define CAN_CTRL_RFS(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_RFS) -#define CAN_CTRL_RID(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_RID) -#define CAN_CTRL_RDA(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_RDA) -#define CAN_CTRL_RDB(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_RDB) -#define CAN_CTRL_TFI1(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TFI1) -#define CAN_CTRL_TID1(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TID1) -#define CAN_CTRL_TDA1(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TDA1) -#define CAN_CTRL_TDB1(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TDB1) -#define CAN_CTRL_TFI2(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TFI2) -#define CAN_CTRL_TID2(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TID2) -#define CAN_CTRL_TDA2(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TDA2) -#define CAN_CTRL_TDB2(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TDB2) -#define CAN_CTRL_TFI3(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TFI3) -#define CAN_CTRL_TID3(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TID3) -#define CAN_CTRL_TDA3(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TDA3) -#define CAN_CTRL_TDB3(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TDB3) - - -//--------------------------------------------------------------------------- -// CAN_CTRL_ICR register bits -// -#define ICR_RX 0x00000001 -#define ICR_TX1 0x00000002 -#define ICR_ERR_WARN 0x00000004 -#define ICR_DATA_OVR 0x00000008 -#define ICR_WAKE_UP 0x00000010 -#define ICR_ERR_PASSIVE 0x00000020 -#define ICR_ARBITR_LOST 0x00000040 -#define ICR_BUS_ERR 0x00000080 -#define ICR_ID_READY 0x00000100 -#define ICR_TX2 0x00000200 -#define ICR_TX3 0x00000400 -#define ICR_GET_ERRBIT(_icr_) (((_icr_) >> 16) & 0x1F) -#define ICR_ERR_DIRECTION 0x00200000 -#define ICR_GET_ERRCODE(_icr_) (((_icr_) >> 22) & 0x03) -#define ICR_GET_ALCBIT(_icr_) (((_icr_) >> 24) & 0x1F) - -#define CAN_ALL_ERR_INT (ICR_ERR_PASSIVE | ICR_ARBITR_LOST | ICR_BUS_ERR | ICR_ERR_WARN) -#define CAN_MISC_INT (CAN_ALL_ERR_INT | ICR_WAKE_UP) - - -//--------------------------------------------------------------------------- -// CAN_CTRL_ICR register bits -// -#define ICR_ERRCODE_BIT_ERR 0x00 -#define ICR_ERRCODE_FORM_ERR 0x01 -#define ICR_ERRCODE_STUFF_ERR 0x02 -#define ICR_ERRCODE_OTHER_ERR 0x03 - - -//--------------------------------------------------------------------------- -// CAN_CTRL_RFS register bits -// -#define RFS_ACCFILT_INDEX_MASK 0x000003FF -#define RFS_RECEIVED_IN_BYPASS_MODE 0x00000400 -#define RFS_DLC_MASK 0x000F0000 -#define RFS_RTR 0x40000000 -#define RFS_EXT 0x80000000 -#define RFS_GET_DLC(_regval_) (((_regval_) >> 16) & 0xF) - -//--------------------------------------------------------------------------- -// CAN_CTRL_CMR register bits -// -#define CMR_TX_REQ 0x00000001 -#define CMR_TX_ABORT 0x00000002 -#define CMR_RX_RELEASE_BUF 0x00000004 -#define CMR_CLEAR_DATA_OVR 0x00000008 -#define CMR_SELF_RX_REQ 0x00000010 -#define CMR_SEND_TX_BUF1 0x00000020 -#define CMR_SEND_TX_BUF2 0x00000040 -#define CMR_SEND_TX_BUF3 0x00000080 - - -//--------------------------------------------------------------------------- -// CAN_CTRL_TFI register bits -// -#define TFI_PRIO_MASK 0x000000FF -#define TFI_DLC_MASK 0x000F0000 -#define TFI_DLC_RTR 0x40000000 -#define TFI_DLC_EXT 0x80000000 - - -//--------------------------------------------------------------------------- -// CAN_CTRL_MOD register bits -// -#define CANMOD_OPERATIONAL 0x00000000 -#define CANMOD_RESET 0x00000001 -#define CANMOD_LISTEN_ONLY 0x00000002 -#define CANMOD_SELF_TEST 0x00000004 -#define CANMOD_TX_BUF_CFG 0x00000008 -#define CANMOD_SLEEP 0x00000010 -#define CANMOD_REV_POLARITY 0x00000020 -#define CANMOD_TEST 0x00000040 - - -//--------------------------------------------------------------------------- -// CAN_CTRL_IER register bits -// -#define IER_RX 0x00000001 -#define IER_TX1 0x00000002 -#define IER_ERR_WARN 0x00000004 -#define IER_DATA_OVR 0x00000008 -#define IER_WAKE_UP 0x00000010 -#define IER_ERR_PASSIVE 0x00000020 -#define IER_ARBITR_LOST 0x00000040 -#define IER_BUS_ERR 0x00000080 -#define IER_ID_READY 0x00000100 -#define IER_TX2 0x00000200 -#define IER_TX3 0x00000400 - - -//--------------------------------------------------------------------------- -// CAN_CTRL_GSR register bits -// -#define GSR_RX_MSG_AVAILABLE 0x00000001 -#define GSR_DATA_OVR 0x00000002 -#define GSR_TX_NOT_PENDING 0x00000004 -#define GSR_ALL_TX_COMPLETE 0x00000008 -#define GSR_RECEIVING_ACTIVE 0x00000010 -#define GSR_SENDING_ACTIVE 0x00000020 -#define GSR_ERR 0x00000040 -#define GSR_BUS_OFF 0x00000080 -#define GSR_RXERR_CNT(_reg_) (((_reg_) >> 16) & 0xFF) -#define GSR_TXERR_CNT(_reg_) (((_reg_) >> 24) & 0xFF) - - -//--------------------------------------------------------------------------- -// CAN_CTRL_SR register bits -// -#define SR_RX_MSG_AVAILABLE 0x01 -#define SR_DATA_OVR 0x02 -#define SR_TX_BUF_WRITE_OK 0x04 // TBS1, TBS2, TBS3 (Bit 2, 10, 18) -#define SR_TX_COMPLETE 0x08 // TCS1, TCS2, TCS3 (Bit 3, 11, 19) -#define SR_RECEIVING_ACTIVE 0x10 -#define SR_SENDING_ACTIVE 0x20 // TS1, TS2, TS3 (5, 13, 21) -#define SR_ERR 0x40 -#define SR_BUS_OFF 0x80 - - -//--------------------------------------------------------------------------- -// Optimize for the case of a single CAN channel, while still allowing -// multiple channels. -// -#if CYGINT_IO_CAN_CHANNELS == 1 -#define CAN_CTRL_BASE(_extra_) CAN_CTRL_SINGLETON_BASE -#define CAN_ISRVEC(_extra_) CAN_SINGLETON_ISRVEC -#define CAN_DECLARE_INFO(_chan_) -#define CAN_DECLARE_CHAN(_data_) -#else -#define CAN_CTRL_BASE(_extra_) ((_extra_)->base) -#define CAN_ISRVEC(_extra_) ((_extra_)->isrvec) -#define CAN_DECLARE_INFO(_chan_) lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; -#define CAN_DECLARE_CHAN(_data_) can_channel *chan = (can_channel *)data; -#endif // CYGINT_IO_CAN_CHANNELS == 1 - - -#ifdef CYGOPT_DEVS_CAN_LPC2XXX_CAN0_ACCFILT_STARTUP_CFG_RX_ALL -#define CAN0_FLAG_STARTUP_ACCFILT_SETUP INFO_FLAG_STARTUP_RX_ALL -#else -#define CAN0_FLAG_STARTUP_ACCFILT_SETUP 0x00 -#endif - -#ifdef CYGOPT_DEVS_CAN_LPC2XXX_CAN1_ACCFILT_STARTUP_CFG_RX_ALL -#define CAN1_FLAG_STARTUP_ACCFILT_SETUP INFO_FLAG_STARTUP_RX_ALL -#else -#define CAN1_FLAG_STARTUP_ACCFILT_SETUP 0x00 -#endif - -#ifdef CYGOPT_DEVS_CAN_LPC2XXX_CAN2_ACCFILT_STARTUP_CFG_RX_ALL -#define CAN2_FLAG_STARTUP_ACCFILT_SETUP INFO_FLAG_STARTUP_RX_ALL -#else -#define CAN2_FLAG_STARTUP_ACCFILT_SETUP 0x00 -#endif - -#ifdef CYGOPT_DEVS_CAN_LPC2XXX_CAN3_ACCFILT_STARTUP_CFG_RX_ALL -#define CAN3_FLAG_STARTUP_ACCFILT_SETUP INFO_FLAG_STARTUP_RX_ALL -#else -#define CAN3_FLAG_STARTUP_ACCFILT_SETUP 0x00 -#endif - - -//=========================================================================== -// DATA TYPES -//=========================================================================== -// -// Structure stores LPC2xxx CAN channel related stuff -// -typedef struct lpc2xxx_can_info_st -{ - cyg_interrupt tx_interrupt; - cyg_handle_t tx_interrupt_handle; - cyg_interrupt rx_interrupt; - cyg_handle_t rx_interrupt_handle; - cyg_can_state state; // state of CAN controller - cyg_uint32 icr; // buffers icr register - cyg_uint8 flags; // flags indicating several states -#if CYGINT_IO_CAN_CHANNELS > 1 - cyg_uint32 base; // Per-bus h/w details - cyg_uint8 isrvec; // ISR vector (peripheral id) -#endif -} lpc2xxx_can_info_t; - - -#define INFO_FLAG_RX_ALL 0x01 // this bit indicates that channel receives all CAN messages - no filtering active -#define INFO_FLAG_STARTUP_RX_ALL 0x02 // this bit indicates filter state at startup - - -// -// lpc2xxx info initialisation -// -#define LPC2XXX_CTRL_NOT_INITIALIZED 0xFF -#if CYGINT_IO_CAN_CHANNELS > 1 -#define LPC2XXX_CAN_INFO(_l, _base, _isrvec, _flags) \ -lpc2xxx_can_info_t _l = { \ - state : LPC2XXX_CTRL_NOT_INITIALIZED, \ - base : (_base), \ - isrvec : (_isrvec), \ - flags : (_flags), \ - icr : 0, \ -}; -#else -#define LPC2XXX_CAN_INFO(_l, _flags) \ -lpc2xxx_can_info_t _l = { \ - state : CYGNUM_CAN_STATE_STOPPED, \ - flags : (_flags), \ -}; -#endif - - -// -// Acceptance filter data -// -typedef struct lpc2xxx_global_can_info_st -{ - cyg_interrupt err_interrupt; - cyg_handle_t err_interrupt_handle; - cyg_uint16 free_filters; // number of free message filters - cyg_uint8 init_cnt; // counts number of initialized channels - can_channel* active_channels[5]; // stores pointers to active channels - the last entry is just a delimiter -} lpc2xxx_global_can_info_t; - - -// -// The number of available message filters depends on the size of the -// acceptance filter RAM and on the size of one entry. The size of -// one entry is 4 byte (standard ID only 2 byte, extended groups 8 byte) -// -#define ACCFILT_COMMON_ENTRY_SIZE 4 -#define LPC2XXX_CAN_MSG_FILTERS_MAX (ACCFILT_RAM_SIZE / ACCFILT_COMMON_ENTRY_SIZE) -lpc2xxx_global_can_info_t lpc2xxx_global_can_info = -{ - .free_filters = LPC2XXX_CAN_MSG_FILTERS_MAX, - .init_cnt = 0, - .active_channels = {0, 0, 0, 0, 0}, -}; - - - -// -// Data type for access of single bytes/words of an dword value -// -typedef union lsc_buf_u -{ - cyg_uint8 bytes[4]; - struct - { - cyg_uint16 low; - cyg_uint16 high; - } words; - - struct - { - cyg_uint16 upper; // uppper column of acceptance filter ram - cyg_uint16 lower; // lower column of acceptance filter ram - } column; - - cyg_uint32 dword; -} lsc_buf_t; - - -//=========================================================================== -// GLOBAL DATA -//=========================================================================== -#if CYGINT_IO_CAN_CHANNELS > 1 -#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN0 -LPC2XXX_CAN_INFO(lpc2xxx_can0_info, - CAN_CTRL_1_REG_BASE, - CYGNUM_HAL_INTERRUPT_CAN1_TX, - CAN0_FLAG_STARTUP_ACCFILT_SETUP); -#endif - -#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN1 -LPC2XXX_CAN_INFO(lpc2xxx_can1_info, - CAN_CTRL_2_REG_BASE, - CYGNUM_HAL_INTERRUPT_CAN2_TX, - CAN1_FLAG_STARTUP_ACCFILT_SETUP); -#endif - -#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN2 -LPC2XXX_CAN_INFO(lpc2xxx_can2_info, - CAN_CTRL_3_REG_BASE, - CYGNUM_HAL_INTERRUPT_CAN3_TX, - CAN2_FLAG_STARTUP_ACCFILT_SETUP); -#endif - -#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN3 -LPC2XXX_CAN_INFO(lpc2xxx_can3_info, - CAN_CTRL_4_REG_BASE, - CYGNUM_HAL_INTERRUPT_CAN4_TX, - CAN3_FLAG_STARTUP_ACCFILT_SETUP); -#endif -#else // CYGINT_IO_CAN_CHANNELS == 1 -#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN0 -LPC2XXX_CAN_INFO(lpc2xxx_can0_info, CAN0_FLAG_STARTUP_ACCFILT_SETUP); -#define CAN_CTRL_SINGLETON_BASE CAN_CTRL_1_REG_BASE -#define CAN_SINGLETON_ISRVEC CYGNUM_HAL_INTERRUPT_CAN1_TX -#endif - -#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN1 -LPC2XXX_CAN_INFO(lpc2xxx_can1_info, CAN1_FLAG_STARTUP_ACCFILT_SETUP); -#define CAN_CTRL_SINGLETON_BASE CAN_CTRL_2_REG_BASE -#define CAN_SINGLETON_ISRVEC CYGNUM_HAL_INTERRUPT_CAN2_TX -#endif - -#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN2 -LPC2XXX_CAN_INFO(lpc2xxx_can2_info, CAN2_FLAG_STARTUP_ACCFILT_SETUP); -#define CAN_CTRL_SINGLETON_BASE CAN_CTRL_3_REG_BASE -#define CAN_SINGLETON_ISRVEC CYGNUM_HAL_INTERRUPT_CAN3_TX -#endif - -#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN3 -LPC2XXX_CAN_INFO(lpc2xxx_can3_info, CAN3_FLAG_STARTUP_ACCFILT_SETUP); -#define CAN_CTRL_SINGLETON_BASE CAN_CTRL_4_REG_BASE -#define CAN_SINGLETON_ISRVEC CYGNUM_HAL_INTERRUPT_CAN4_TX -#endif - -#endif // #if CYGINT_IO_CAN_CHANNELS > 1 - - -//=========================================================================== -// PROTOTYPES -//=========================================================================== - -//-------------------------------------------------------------------------- -// Device driver interface functions -// -static bool lpc2xxx_can_init(struct cyg_devtab_entry* devtab_entry); -static Cyg_ErrNo lpc2xxx_can_lookup(struct cyg_devtab_entry** tab, struct cyg_devtab_entry* sub_tab, const char* name); -static Cyg_ErrNo lpc2xxx_can_set_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len); -static Cyg_ErrNo lpc2xxx_can_get_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len); -static bool lpc2xxx_can_putmsg(can_channel *priv, CYG_CAN_MSG_T *pmsg, void *pdata); -static bool lpc2xxx_can_getevent(can_channel *priv, CYG_CAN_EVENT_T *pevent, void *pdata); -static void lpc2xxx_can_start_xmit(can_channel* chan); -static void lpc2xxx_can_stop_xmit(can_channel* chan); - - -//-------------------------------------------------------------------------- -// ISRs and DSRs -// -static cyg_uint32 lpc2xxx_can_tx_ISR(cyg_vector_t vector, cyg_addrword_t data); -static void lpc2xxx_can_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data); -static cyg_uint32 lpc2xxx_can_rx_ISR(cyg_vector_t vector, cyg_addrword_t data); -static void lpc2xxx_can_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data); -static cyg_uint32 lpc2xxx_can_err_ISR(cyg_vector_t vector, cyg_addrword_t data); -static void lpc2xxx_can_err_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data); - - -//-------------------------------------------------------------------------- -// Private utility functions -// -static bool lpc2xxx_can_config_channel(can_channel* chan, cyg_can_info_t* config, cyg_bool init); -static bool lpc2xxx_can_set_baud(can_channel *chan, cyg_can_baud_rate_t *baudrate); -static Cyg_ErrNo lpc2xxx_enter_lowpower_mode(can_channel *chan); -static void lpc2xxx_start_module(can_channel *chan); -static cyg_can_state lpc2xxx_get_state(lpc2xxx_can_info_t *info); -static void lpc2xxx_set_state(lpc2xxx_can_info_t *info, cyg_can_state state); - - -//-------------------------------------------------------------------------- -// Message box configuration -// -static void lpc2xxx_can_config_rx_all(can_channel *chan); -#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG -static void lpc2xxx_can_config_rx_none(can_channel *chan); -static bool lpc2xxx_can_add_rx_filter(lpc2xxx_can_info_t *info, cyg_can_filter *filter); -#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG - - -#include "can_accfilt_lpc2xxx.c" - -//=========================================================================== -// GENERIC CAN IO DATA INITIALISATION -//=========================================================================== -CAN_LOWLEVEL_FUNS(lpc2xxx_can_lowlevel_funs, - lpc2xxx_can_putmsg, - lpc2xxx_can_getevent, - lpc2xxx_can_get_config, - lpc2xxx_can_set_config, - lpc2xxx_can_start_xmit, - lpc2xxx_can_stop_xmit - ); - - -//--------------------------------------------------------------------------- -// CAN channel 0 -// -#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN0 -CYG_CAN_EVENT_T lpc2xxx_can0_rxbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN0_QUEUESIZE_RX]; // buffer for RX can events -CYG_CAN_MSG_T lpc2xxx_can0_txbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN0_QUEUESIZE_TX]; // buffer for TX can messages - - -CAN_CHANNEL_USING_INTERRUPTS(lpc2xxx_can0_chan, - lpc2xxx_can_lowlevel_funs, - lpc2xxx_can0_info, - CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_LPC2XXX_CAN0_KBAUD), - lpc2xxx_can0_txbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN0_QUEUESIZE_TX, - lpc2xxx_can0_rxbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN0_QUEUESIZE_RX - ); - - -DEVTAB_ENTRY(lpc2xxx_can0_devtab, - CYGPKG_DEVS_CAN_LPC2XXX_CAN0_NAME, - 0, // Does not depend on a lower level interface - &cyg_io_can_devio, - lpc2xxx_can_init, - lpc2xxx_can_lookup, // CAN driver may need initializing - &lpc2xxx_can0_chan - ); -#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN0 - - -//--------------------------------------------------------------------------- -// CAN channel 1 -// -#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN1 -CYG_CAN_EVENT_T lpc2xxx_can1_rxbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN1_QUEUESIZE_RX]; // buffer for RX can events -CYG_CAN_MSG_T lpc2xxx_can1_txbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN1_QUEUESIZE_TX]; // buffer for TX can messages - - -CAN_CHANNEL_USING_INTERRUPTS(lpc2xxx_can1_chan, - lpc2xxx_can_lowlevel_funs, - lpc2xxx_can1_info, - CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_LPC2XXX_CAN1_KBAUD), - lpc2xxx_can1_txbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN1_QUEUESIZE_TX, - lpc2xxx_can1_rxbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN1_QUEUESIZE_RX - ); - - -DEVTAB_ENTRY(lpc2xxx_can1_devtab, - CYGPKG_DEVS_CAN_LPC2XXX_CAN1_NAME, - 0, // Does not depend on a lower level interface - &cyg_io_can_devio, - lpc2xxx_can_init, - lpc2xxx_can_lookup, // CAN driver may need initializing - &lpc2xxx_can1_chan - ); -#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN1 - - -//--------------------------------------------------------------------------- -// CAN channel 2 -// -#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN2 -CYG_CAN_EVENT_T lpc2xxx_can2_rxbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN2_QUEUESIZE_RX]; // buffer for RX can events -CYG_CAN_MSG_T lpc2xxx_can2_txbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN2_QUEUESIZE_TX]; // buffer for TX can messages - - -CAN_CHANNEL_USING_INTERRUPTS(lpc2xxx_can2_chan, - lpc2xxx_can_lowlevel_funs, - lpc2xxx_can2_info, - CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_LPC2XXX_CAN2_KBAUD), - lpc2xxx_can2_txbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN2_QUEUESIZE_TX, - lpc2xxx_can2_rxbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN2_QUEUESIZE_RX - ); - - -DEVTAB_ENTRY(lpc2xxx_can2_devtab, - CYGPKG_DEVS_CAN_LPC2XXX_CAN2_NAME, - 0, // Does not depend on a lower level interface - &cyg_io_can_devio, - lpc2xxx_can_init, - lpc2xxx_can_lookup, // CAN driver may need initializing - &lpc2xxx_can2_chan - ); -#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN2 - - -//--------------------------------------------------------------------------- -// CAN channel 3 -// -#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN3 -CYG_CAN_EVENT_T lpc2xxx_can3_rxbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN3_QUEUESIZE_RX]; // buffer for RX can events -CYG_CAN_MSG_T lpc2xxx_can3_txbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN3_QUEUESIZE_TX]; // buffer for TX can messages - - -CAN_CHANNEL_USING_INTERRUPTS(lpc2xxx_can3_chan, - lpc2xxx_can_lowlevel_funs, - lpc2xxx_can3_info, - CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_LPC2XXX_CAN3_KBAUD), - lpc2xxx_can3_txbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN3_QUEUESIZE_TX, - lpc2xxx_can3_rxbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN3_QUEUESIZE_RX - ); - - -DEVTAB_ENTRY(lpc2xxx_can3_devtab, - CYGPKG_DEVS_CAN_LPC2XXX_CAN3_NAME, - 0, // Does not depend on a lower level interface - &cyg_io_can_devio, - lpc2xxx_can_init, - lpc2xxx_can_lookup, // CAN driver may need initializing - &lpc2xxx_can3_chan - ); -#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN3 - - -//=========================================================================== -// IMPLEMENTATION -//=========================================================================== - - - -//=========================================================================== -/// First initialisation and reset of CAN modul. -//=========================================================================== -static bool lpc2xxx_can_init(struct cyg_devtab_entry* devtab_entry) -{ - can_channel *chan = (can_channel*)devtab_entry->priv; - lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; - bool res; - -#ifdef CYGDBG_IO_INIT - diag_printf("LPC2XXX CAN init\n"); -#endif - - // - // Create TX interrupt - // - cyg_drv_interrupt_create(CAN_ISRVEC(info), - 0, // Priority does not matter LPC2xxx - (cyg_addrword_t)chan, // Data item passed to interrupt handler - lpc2xxx_can_tx_ISR, - lpc2xxx_can_tx_DSR, - &info->tx_interrupt_handle, - &info->tx_interrupt); - cyg_drv_interrupt_attach(info->tx_interrupt_handle); - cyg_drv_interrupt_unmask(CAN_ISRVEC(info)); - - // - // Create RX interrupt - // - cyg_drv_interrupt_create(CAN_ISRVEC(info) + 6, - 0, // Priority does not matter for LPC2xxx - (cyg_addrword_t)chan, // Data item passed to interrupt handler - lpc2xxx_can_rx_ISR, - lpc2xxx_can_rx_DSR, - &info->rx_interrupt_handle, - &info->rx_interrupt); - cyg_drv_interrupt_attach(info->rx_interrupt_handle); - cyg_drv_interrupt_unmask(CAN_ISRVEC(info) + 6); - - // - // Now create and enable error interrupt. This interrupt is global for all channels - // and so we need to call it only one times - when the first channel is - // initialized - // - if (!lpc2xxx_global_can_info.init_cnt) - { - // - // Create err interrupt - // - cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_CAN, - 0, // Priority does not matter for LPX2xxx - 0, // Data item passed to interrupt handler - lpc2xxx_can_err_ISR, - lpc2xxx_can_err_DSR, - &lpc2xxx_global_can_info.err_interrupt_handle, - &lpc2xxx_global_can_info.err_interrupt); - cyg_drv_interrupt_attach(lpc2xxx_global_can_info.err_interrupt_handle); - cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_CAN); - } - - res = lpc2xxx_can_config_channel(chan, &chan->config, true); - lpc2xxx_global_can_info.active_channels[lpc2xxx_global_can_info.init_cnt++] = chan; - return res; -} - - -//=========================================================================== -// Configure can channel -//=========================================================================== -static bool lpc2xxx_can_config_channel(can_channel* chan, cyg_can_info_t* config, cyg_bool init) -{ - CAN_DECLARE_INFO(chan); - cyg_uint32 temp32; - bool res = true; - - if (init) - { - // - // In case platform needs extra initialization (i.e. setup of CAN transcievers) - // it should implement this macro - // -#ifdef CYGPRI_IO_CAN_LPC2XXX_PLF_INIT_HOOK - CYGPRI_IO_CAN_LPC2XXX_PLF_INIT_HOOK(chan, config); -#endif - - HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, AFMR_OFF); // Acceptance Filter Mode Register = off - HAL_WRITE_UINT32(CAN_CTRL_MOD(info), CANMOD_RESET); // Go into reset mode - HAL_WRITE_UINT32(CAN_CTRL_IER(info), 0); // disable all interrupts - HAL_WRITE_UINT32(CAN_CTRL_GSR(info), 0); // Clear Status register - clears error counters - - // - // If this is the first channel to initialize then we reset the CAN registers - // and setup the CAN I/O pins - // - if (!lpc2xxx_global_can_info.init_cnt) - { - lpc2xxx_can_accfilt_reset(); -#if defined(CYGPKG_DEVS_CAN_LPC2XXX_CAN0) || defined(CYGPKG_DEVS_CAN_LPC2XXX_CAN1) || defined(CYGPKG_DEVS_CAN_LPC2XXX_CAN3) - HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_PIN_BASE + CYGARC_HAL_LPC2XXX_REG_PINSEL1, temp32); -#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN0 - temp32 |= 0x00040000L; // Set bit 18 -#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN0 -#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN1 - temp32 |= 0x00014000L; // Set bits 14 and 16 -#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN1 -#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN2 - temp32 |= 0x00001800L; // Set bits 11 and 12 -#endif - HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_PIN_BASE + CYGARC_HAL_LPC2XXX_REG_PINSEL1, temp32); -#endif // defined(CYGPKG_DEVS_CAN_LPC2XXX_CAN0) || defined(CYGPKG_DEVS_CAN_LPC2XXX_CAN1) - - -#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN3 - HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_PIN_BASE + CYGARC_HAL_LPC2XXX_REG_PINSEL0, temp32); - temp32 |= 0x0F000000L; - HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_PIN_BASE + CYGARC_HAL_LPC2XXX_REG_PINSEL0, temp32); -#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN3 - } - } // if (init) - - res = lpc2xxx_can_set_baud(chan, &config->baud); // set baudrate - // $$$$ enable receive interrupt? - HAL_WRITE_UINT32(CAN_CTRL_MOD(info), CANMOD_OPERATIONAL); // enter normal operating mode - - // - // store new config values - // - if (config != &chan->config) - { - chan->config = *config; - } - - return res; -} - - -//=========================================================================== -// Set baudrate of certain can channel -//=========================================================================== -static bool lpc2xxx_can_set_baud(can_channel *chan, cyg_can_baud_rate_t *baudrate) -{ - bool res = true; - cyg_uint32 canbtr; - cyg_uint32 canmod; - CAN_DECLARE_INFO(chan); - - // - // Get bit timings from HAL because bit timings depend on sysclock - // If the macro fills the canbtr value with 0 then the baudrate - // is not supported and the function returns false - // - HAL_LPC2XXX_GET_CAN_BR(*baudrate, canbtr); - if (0 == canbtr) - { - return false; - } - - // - // Any modificatons to the baudrate register must be done while CAN - // module is in reset mode. So we first set the CAN moduel in reset - // mode, then we set baudrate and then we restore content of CANMOD - // register - // - HAL_READ_UINT32(CAN_CTRL_MOD(info), canmod); // backup canmod register - HAL_WRITE_UINT32(CAN_CTRL_MOD(info), CANMOD_RESET); // Go into reset mode - HAL_WRITE_UINT32(CAN_CTRL_BTR(info), canbtr); // write baudrate value - HAL_WRITE_UINT32(CAN_CTRL_MOD(info), canmod); // restore previous value - - return res; -} - - -//=========================================================================== -// Lookup the device and return its handle -//=========================================================================== -static Cyg_ErrNo lpc2xxx_can_lookup(struct cyg_devtab_entry** tab, struct cyg_devtab_entry* sub_tab, const char* name) -{ - can_channel* chan = (can_channel*) (*tab)->priv; - CAN_DECLARE_INFO(chan); - cyg_uint32 regval; - - chan->callbacks->can_init(chan); - - // - // If runtime acceptance filter configuration is supported then we only - // configure RX ALL if the user selected the RX ALL setup in config utility - // -#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG - if (info->flags & INFO_FLAG_STARTUP_RX_ALL) -#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG - { - lpc2xxx_can_config_rx_all(chan); - } - - HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, AFMR_ON); // Activate acceptance filter - HAL_READ_UINT32(CAN_CTRL_IER(info), regval); - regval = regval | IER_RX | CAN_MISC_INT; // enable all interrupts - HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); - - return ENOERR; -} - - -#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG -//=========================================================================== -// Setup AT91SAM7 CAN module in a state where all message boxes are disabled -// After this call it is possible to add single message buffers and filters -//=========================================================================== -static void lpc2xxx_can_config_rx_none(can_channel *chan) -{ - lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; - - // - // Remove all acceptance filters - // $$$$ maybe we should also abort any pending transfers and - // disable receive interrupts ? - // - lpc2xxx_can_accfilt_remove_all_ctrl_entries(info); - info->flags &= ~INFO_FLAG_RX_ALL; -#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG - lpc2xxx_can_accfilt_dbg_dump(); -#endif -} - - -//=========================================================================== -// Add one single message filter to acceptance filter -//=========================================================================== -static bool lpc2xxx_can_add_rx_filter(lpc2xxx_can_info_t *info, cyg_can_filter *filter) -{ - bool res; - - res = lpc2xxx_can_accfilt_add(info, filter->msg.id, 0, filter->msg.ext); - if (!res) - { - filter->handle = CYGNUM_CAN_MSGBUF_NA; - } -#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG - lpc2xxx_can_accfilt_dbg_dump(); -#endif - return res; -} -#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG - - - -#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG -//=========================================================================== -// Configure message buffers -//=========================================================================== -static Cyg_ErrNo lpc2xxx_can_config_msgbuf(can_channel *chan, const void* buf, cyg_uint32* len) -{ - Cyg_ErrNo res = ENOERR; - lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; - cyg_can_msgbuf_cfg *msg_buf = (cyg_can_msgbuf_cfg *)buf; - - if (*len != sizeof(cyg_can_msgbuf_cfg)) - { - return -EINVAL; - } - - switch (msg_buf->cfg_id) - { - // - // clear all message filters and remote buffers - prepare for message buffer - // configuration - // - case CYGNUM_CAN_MSGBUF_RESET_ALL : - { - lpc2xxx_can_config_rx_none(chan); - } - break; - - // - // setup driver for reception of all standard and extended messages - // - case CYGNUM_CAN_MSGBUF_RX_FILTER_ALL : - { - if (!(info->flags & INFO_FLAG_RX_ALL)) // if rx_all is enabled we do not need to do anything - { - lpc2xxx_can_config_rx_all(chan); // setup RX all state - } - } - break; - - // - // add single message filter, message with filter ID will be received - // - case CYGNUM_CAN_MSGBUF_RX_FILTER_ADD : - { - cyg_can_filter *filter = (cyg_can_filter*) buf; - - // - // if the acceptance filter is configured to receive all messages then - // it is not allowed to add single message filters because then more - // than one acceptance filter would receive the same CAN id - // - if (info->flags & INFO_FLAG_RX_ALL) - { - return -EPERM; - } - - // - // try to allocate a free acceptance filter entry - if we have a free one - // then we can prepare the acceptance filter table for reception of - // this message - // - if (!lpc2xxx_can_add_rx_filter(info, filter)) - { - return -EPERM; - } - } - break; //CYGNUM_CAN_MSGBUF_RX_FILTER_ADD - - -#ifdef CYGOPT_IO_CAN_REMOTE_BUF - // - // Try to add a new RTR response message buffer for automatic transmisson - // of data frame on reception of a remote frame - // - case CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD : - { - // $$$$ TODO implement remote repsonse buffers in software - return -ENOSUPP; - } - break; - - // - // write data into remote response buffer - // - case CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE : - { - // $$$$ TODO implement remote response buffers in software - return -ENOSUPP; - } - break; -#endif // #ifdef CYGOPT_IO_CAN_REMOTE_BUF - default: - return -EINVAL; - } // switch (buf->cfg_id) - - return res; -} -#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG - - -//=========================================================================== -// Read state of CAN controller -// The CAN state variable for each channel is modiefied by DSR so if we -// read the state we need to lock DSRs to protect the data access -//=========================================================================== -static cyg_can_state lpc2xxx_get_state(lpc2xxx_can_info_t *info) -{ - cyg_can_state result; - - cyg_drv_dsr_lock(); - result = info->state; - cyg_drv_dsr_unlock(); - - return result; -} - - -//=========================================================================== -// Set state of CAN controller -// The CAN state variable for each channel is modiefied by DSR so if we -// write the state we need to lock DSRs to protect the data access -//=========================================================================== -static void lpc2xxx_set_state(lpc2xxx_can_info_t *info, cyg_can_state state) -{ - cyg_drv_dsr_lock(); - info->state = state; - cyg_drv_dsr_unlock(); -} - - -//=========================================================================== -// Enter low power mode -//=========================================================================== -static Cyg_ErrNo lpc2xxx_enter_lowpower_mode(can_channel *chan) -{ - cyg_uint32 regval; - lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; - - // - // Before we enter low power mode, we have to enable wake up interrupt - // Normally this interrupt is always enabled so we do not need to do - // anything here - // - HAL_READ_UINT32(CAN_CTRL_MOD(info), regval); - - // - // Software can only set SM when RM in the CAN Mode register is 0 - // - if (regval & CANMOD_RESET) - { - return -EPERM; - } - - //regval &= CANMOD_SLEEP; - lpc2xxx_set_state(info, CYGNUM_CAN_STATE_STANDBY); - HAL_WRITE_UINT32(CAN_CTRL_MOD(info), CANMOD_SLEEP); - return ENOERR; -} - - -//=========================================================================== -// Start CAN module - set CANMOD operational and enable all interrupts -//=========================================================================== -static void lpc2xxx_start_module(can_channel *chan) -{ - cyg_uint32 regval; - lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; - - HAL_WRITE_UINT32(CAN_CTRL_MOD(info), CANMOD_OPERATIONAL); - // - // The interrupt enable register is also modified by ISR and DSR so - // we need to protect acces here - // - cyg_drv_isr_lock(); - HAL_READ_UINT32(CAN_CTRL_IER(info), regval); - regval = regval | IER_RX | CAN_MISC_INT; // enable all interrupts - HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); - info->state = CYGNUM_CAN_STATE_ACTIVE; - cyg_drv_isr_unlock(); -} - - -//=========================================================================== -// Enter reset mode -//=========================================================================== -static void lpc2xx_enter_reset_mode(can_channel *chan) -{ - lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; - - info->state = CYGNUM_CAN_STATE_STOPPED; - HAL_WRITE_UINT32(CAN_CTRL_MOD(info), CANMOD_RESET); -} - - -#ifdef CYGOPT_DEVS_CAN_LPC2XXX_EXTENDED_CFG_KEYS -//=========================================================================== -// Add message filter group -//=========================================================================== -static Cyg_ErrNo lpc2xxx_can_config_accfilt_group(can_channel *chan, const void* buf, cyg_uint32* len) -{ - bool res; - cyg_can_filtergroup_cfg *filter_grp = (cyg_can_filtergroup_cfg *)buf; - lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; - - - if (*len != sizeof(cyg_can_filtergroup_cfg)) - { - return -EINVAL; - } - - if (filter_grp->lower_id_bound >= filter_grp->upper_id_bound) - { - return -EINVAL; - } - - // - // if the acceptance filter is configured to receive all messages then - // it is not allowed to add single message filter groups because then more - // than one acceptance filter would receive the same CAN id - // - if (info->flags & INFO_FLAG_RX_ALL) - { - return -EPERM; - } - - res = lpc2xxx_can_accfilt_add(info, - filter_grp->lower_id_bound, - filter_grp->upper_id_bound, - filter_grp->ext); - - - return res ? ENOERR : -EPERM; -} -#endif // CYGOPT_DEVS_CAN_LPC2XXX_EXTENDED_CFG_KEYS - - -//=========================================================================== -// Change device configuration -//=========================================================================== -static Cyg_ErrNo lpc2xxx_can_set_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len) -{ - Cyg_ErrNo res = ENOERR; - - switch (key) - { - // - // Setup a new CAN configuration. This will i.e. setup a new baud rate - // - case CYG_IO_SET_CONFIG_CAN_INFO: - { - cyg_can_info_t* config = (cyg_can_info_t*) buf; - if (*len < sizeof(cyg_can_info_t)) - { - return -EINVAL; - } - *len = sizeof(cyg_can_info_t); - if (!lpc2xxx_can_config_channel(chan, config, false)) - { - return -EINVAL; - } - } - break; - -#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG - // - // configure message buffers - // - case CYG_IO_SET_CONFIG_CAN_MSGBUF : - { - res = lpc2xxx_can_config_msgbuf(chan, buf, len); - } - break; -#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG - -#ifdef CYGOPT_DEVS_CAN_LPC2XXX_EXTENDED_CFG_KEYS - // - // Add message filter group to acceptance filter - // - case CYG_IO_SET_CONFIG_LPC2XXX_ACCFILT_GROUP : - { - return lpc2xxx_can_config_accfilt_group(chan, buf, len); - } - break; -#endif // CYGOPT_DEVS_CAN_LPC2XXX_EXTENDED_CFG_KEYS - - // - // Change CAN state of CAN module - // - case CYG_IO_SET_CONFIG_CAN_MODE : - { - cyg_can_mode *can_mode = (cyg_can_mode*) buf; - - if (*len != sizeof(cyg_can_mode)) - { - return -EINVAL; - } - *len = sizeof(cyg_can_mode); - - // - // decide what to do acording to mode - // - switch (*can_mode) - { - // - // The controller does not support a stopped and standby state so we - // simply enter the low power state here. This state is also safe for - // message buffer configuration - // - case CYGNUM_CAN_MODE_STOP : lpc2xx_enter_reset_mode(chan); break; - case CYGNUM_CAN_MODE_START : lpc2xxx_start_module(chan); break; - case CYGNUM_CAN_MODE_STANDBY : lpc2xxx_enter_lowpower_mode(chan); break; - case CYGNUM_CAN_MODE_CONFIG : lpc2xx_enter_reset_mode(chan); break; - } - } - break; // case CYG_IO_SET_CONFIG_CAN_MODE : - // - // Unknown config key - indicate this by returning -EINVAL - // - default: - return -EINVAL; - } // switch (key) - - return res; -} - - -//=========================================================================== -// Query device configuration -//=========================================================================== -static Cyg_ErrNo lpc2xxx_can_get_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len) -{ - Cyg_ErrNo res = ENOERR; - lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; - - switch(key) - { - // - // query state of CAN controller - // - case CYG_IO_GET_CONFIG_CAN_STATE : - { - cyg_can_state *can_state = (cyg_can_state*) buf; - - if (*len != sizeof(cyg_can_state)) - { - return -EINVAL; - } - *len = sizeof(cyg_can_state); - *can_state = lpc2xxx_get_state(info); - } - break; - -#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG - // - // Query message box information - returns available and free message - // boxes - // - case CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO : - { - cyg_can_msgbuf_info *mbox_info = (cyg_can_msgbuf_info*) buf; - - if (*len != sizeof(cyg_can_msgbuf_info)) - { - return -EINVAL; - } - cyg_uint32 end_of_table; - *len = sizeof(cyg_can_msgbuf_info); - - HAL_READ_UINT32(CAN_ACCFILT_ENDOFTABLE, end_of_table); - mbox_info->count = LPC2XXX_CAN_MSG_FILTERS_MAX; - mbox_info->free = (ACCFILT_RAM_SIZE - end_of_table) / ACCFILT_COMMON_ENTRY_SIZE; - } - break; -#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG - - - // - // Query hardware description of FlexCAN device driver - // - case CYG_IO_GET_CONFIG_CAN_HDI : - { - cyg_can_hdi *hdi = (cyg_can_hdi *)buf; - // - // comes from high level driver so we do not need to - // check buffer size here - // - hdi->support_flags = CYGNUM_CAN_HDI_FRAMETYPE_EXT_ACTIVE - | CYGNUM_CAN_HDI_FULLCAN; - } - break; - - default : - res = -EINVAL; - }// switch(key) - - return res; -} - - -//=========================================================================== -// Send single message -//=========================================================================== -static bool lpc2xxx_can_putmsg(can_channel *chan, CYG_CAN_MSG_T *pmsg, void *pdata) -{ - cyg_uint32 regval; - CAN_DECLARE_INFO(priv); - - // - // We use only one single transmit buffer of the three available buffers - // We use buffer 1 (buffer 2 and 3 are unused) - // - // The errata sheet tells the following about the transmit buffers: - // Problem: The Triple Transmit Buffer function cannot be used. - // Work-around: Use any one Transmit buffer only (Use either Transmit Buffer 1, - // Transmit Buffer 2 or Transmit Buffer 3 exclusively). The buffer you decided - // to use should be loaded only when there is no pending transmission. - // - HAL_READ_UINT32(CAN_CTRL_SR(info), regval); - if (!(regval & SR_TX_BUF_WRITE_OK)) - { - return false; - } - - regval = pmsg->dlc << 16; - if (pmsg->rtr) - { - regval |= TFI_DLC_RTR; - } - -#ifdef CYGOPT_IO_CAN_EXT_CAN_ID - if (pmsg->ext) - { - regval |= TFI_DLC_EXT; - } -#endif // #define CYGOPT_IO_CAN_EXT_CAN_ID - HAL_WRITE_UINT32(CAN_CTRL_TFI1(info), regval); // write DLC - HAL_WRITE_UINT32(CAN_CTRL_TID1(info), pmsg->id); // write ID - HAL_WRITE_UINT32(CAN_CTRL_TDA1(info), pmsg->data.dwords[0]); // write first 4 data bytes - HAL_WRITE_UINT32(CAN_CTRL_TDB1(info), pmsg->data.dwords[1]); // write second 4 data bytes - - // - // Request transmission of message - // The errata sheet tells the following about tx request: - // Introduction: The CAN module can lose arbitration to another CAN node during an - // attempt to transmit a CAN message. The message of the CAN node the arbitration was - // lost to is supposed to be received correctly by the CAN module. - // Problem: Messages might not be received correctly if during a CAN Transmission the - // CAN bus arbitration is lost to another CAN node. - // Work-around: Use the Self Reception Request command instead of the Transmission - // Request command. However, it has to be taken into account that now all transmitted - // messages may be received if not prevented by appropriate Acceptance Filter settings. - // (Don't set up Acceptance Filter Message Identifiers for the messages you are - // transmitting yourself.) - // - HAL_WRITE_UINT32(CAN_CTRL_CMR(info), CMR_TX_REQ | CMR_SEND_TX_BUF1); // Write transmission request - //HAL_WRITE_UINT32(CAN_CTRL_CMR(info), CMR_SELF_RX_REQ | CMR_SEND_TX_BUF1); // Write self transmission request - - return true; -} - - -//=========================================================================== -// Read event from device driver -//=========================================================================== -static bool lpc2xxx_can_getevent(can_channel *chan, CYG_CAN_EVENT_T *pevent, void *pdata) -{ - lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; - bool res = true; - cyg_uint32 regval; - cyg_uint32 event = *((cyg_uint32*)pdata); - lsc_buf_t data; - - // - // Handle RX event - // - if (event & ICR_RX) - { - cyg_uint32 id; - - pevent->flags |= CYGNUM_CAN_EVENT_RX; - HAL_READ_UINT32(CAN_CTRL_RFS(info), regval); - HAL_READ_UINT32(CAN_CTRL_RID(info), id); - -#ifdef CYGOPT_IO_CAN_EXT_CAN_ID - if (regval & RFS_EXT) - { - pevent->msg.ext = CYGNUM_CAN_ID_EXT; - pevent->msg.id = id & 0x1FFFFFFF; - } - else -#endif // #define CYGOPT_IO_CAN_EXT_CAN_ID - { -#ifdef CYGOPT_IO_CAN_STD_CAN_ID - pevent->msg.ext = CYGNUM_CAN_ID_STD; - pevent->msg.id = id & 0x7FF; -#endif // #ifdef CYGOPT_IO_CAN_STD_CAN_ID - } // if (regval & RFS_EXT) - - if (regval & RFS_RTR) - { - pevent->msg.rtr = CYGNUM_CAN_FRAME_RTR; - } - else - { - pevent->msg.rtr = CYGNUM_CAN_FRAME_DATA; - HAL_READ_UINT32(CAN_CTRL_RDA(info), pevent->msg.data.dwords[0]); - HAL_READ_UINT32(CAN_CTRL_RDB(info), pevent->msg.data.dwords[1]); - } //if (regval & RFS_RTR) - pevent->msg.dlc = RFS_GET_DLC(regval); - - // - // Now check if an data overrun occured - a message was lost because the - // preceeding message to this CAN controller was not read and released - // quickly enough. After reading the status we clear the overrun bit - // - HAL_READ_UINT32(CAN_CTRL_GSR(info), regval); - if (regval & GSR_DATA_OVR) - { - pevent->flags |= CYGNUM_CAN_EVENT_OVERRUN_RX; - HAL_WRITE_UINT32(CAN_CTRL_CMR(info), CMR_CLEAR_DATA_OVR); - } - } - - // - // Handle TX events - // - if (event & ICR_TX1) - { - } - - // - // Handle all other events - // - if (event & CAN_MISC_INT) - { - HAL_READ_UINT32(CAN_CTRL_GSR(info), data.dword); - - // - // 1: Error Warning Interrupt -- this bit is set on every change (set or clear) of the Error - // Status or Bus Status bit in CANSR, if the EIE bit in CAN is 1 at the time of the - // change. - // - if (event & ICR_ERR_WARN) - { - // - // If one of the warning counters is above 96 then the controller is in bus warning - // state. If both counters are below 96 the this interrupt indicates that the - // controller has left the bus warning state and is error active again - // - if (data.bytes[2] >= 96) - { - pevent->flags |= CYGNUM_CAN_EVENT_WARNING_RX; - info->state = CYGNUM_CAN_STATE_BUS_WARN; - } - else if (data.bytes[3] >= 96) - { - pevent->flags |= CYGNUM_CAN_EVENT_WARNING_TX; - info->state = CYGNUM_CAN_STATE_BUS_WARN; - } - else - { - info->state = CYGNUM_CAN_STATE_ACTIVE; - } - LPC2XXX_DBG_PRINT("ICR_ERR_WARN\n"); - } - - // - // 1: Wake-Up Interrupt: this bit is set if the CAN controller is sleeping and bus activity - // is detected, if the WUIE bit in CANIE is 1. - // - if (event & ICR_WAKE_UP) - { - pevent->flags |= CYGNUM_CAN_EVENT_LEAVING_STANDBY; - info->state = CYGNUM_CAN_STATE_ACTIVE; - LPC2XXX_DBG_PRINT("ICR_WAKE_UP\n"); - } - - // - // Error Passive Interrupt -- this bit is set if the EPIE bit in CANIE is 1, and the CAN - // controller switches between Error Passive and Error Active mode in either - // direction. We have to check if the ERR bit is set in global status register. - // If it is set, then it is a switch to error passive else it is a switch to - // error active state - // - if (event & ICR_ERR_PASSIVE) - { - if (data.dword & GSR_ERR) - { - pevent->flags |= CYGNUM_CAN_EVENT_ERR_PASSIVE; - info->state = CYGNUM_CAN_STATE_ERR_PASSIVE; - } - else - { - info->state = CYGNUM_CAN_STATE_ACTIVE; - } - LPC2XXX_DBG_PRINT("ICR_ERR_PASSIVE\n"); - } - - // - // Arbitration Lost Interrupt -- this bit is set if the ALIE bit in CANIE is 1, and the - // CAN controller loses arbitration while attempting to transmit. - // - if (event & ICR_ARBITR_LOST) - { - pevent->flags |= CYGNUM_CAN_EVENT_ARBITRATION_LOST; - LPC2XXX_DBG_PRINT("ICR_ARBITR_LOST\n"); - } - - // - // 1: Bus Error Interrupt -- this bit is set if the BEIE bit in CANIE is 1, and the CAN - // controller detects an error on the bus. - // - if (event & ICR_BUS_ERR) - { - pevent->flags |= CYGNUM_CAN_EVENT_BUS_OFF; - LPC2XXX_DBG_PRINT("ICR_BUS_ERR\n"); - } - } // if (event & CAN_MISC_INT) - - return res; -} - - -//=========================================================================== -// Kick transmitter -//=========================================================================== -static void lpc2xxx_can_start_xmit(can_channel* chan) -{ - cyg_uint32 regval; - CAN_DECLARE_INFO(chan); - - LPC2XXX_DBG_PRINT("start_xmit\n"); - - cyg_drv_dsr_lock(); - HAL_READ_UINT32(CAN_CTRL_IER(info), regval); - regval |= IER_TX1; // enable tx interrupt for tx buf 1 - HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); - cyg_drv_dsr_unlock(); - - // - // kick transmitter - // - chan->callbacks->xmt_msg(chan, 0); // Kick transmitter (if necessary) -} - - -//=========================================================================== -// Stop transmitter -//=========================================================================== -static void lpc2xxx_can_stop_xmit(can_channel* chan) -{ - cyg_uint32 regval; - CAN_DECLARE_INFO(chan); - - LPC2XXX_DBG_PRINT("stop_xmit\n"); - - cyg_drv_dsr_lock(); - HAL_READ_UINT32(CAN_CTRL_IER(info), regval); - regval &= ~IER_TX1; // disable tx interrupt for tx buf 1 - HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); - cyg_drv_dsr_unlock(); -} - - -//=========================================================================== -// Low level transmit interrupt handler -//=========================================================================== -static cyg_uint32 lpc2xxx_can_tx_ISR(cyg_vector_t vector, cyg_addrword_t data) -{ - can_channel *chan = (can_channel *)data; - cyg_uint32 regval; - lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; - - // - // The ISR only disables and acknowledges the TX interrupt - // any further processing is done by DSR - // - HAL_READ_UINT32(CAN_CTRL_IER(info), regval); - regval &= ~IER_TX1; // disable tx interrupt for tx buf 1 - HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); - - // - // Now read iput capture register - this clears all interrupt bits in this - // register and also acknowledges the interrupt. We then store the ICR value into - // the icr buffer in the channel info data - // - HAL_READ_UINT32(CAN_CTRL_ICR(info), regval); - info->icr |= (regval &~ ICR_RX); // do not handle RX events - this is done by RX ISR - cyg_drv_interrupt_acknowledge(vector); - LPC2XXX_DBG_PRINT("tx_ISR\n"); - return CYG_ISR_CALL_DSR; -} - - -//=========================================================================== -// High level transmit interrupt handler -//=========================================================================== -static void lpc2xxx_can_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) -{ - can_channel *chan = (can_channel *)data; - cyg_uint32 regval; - lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; - - // - // now receive the event - the events are stored in ICR field of CAN info - // we need to disable ISRs here because the ICR field will be accessed from - // several ISRs (TX ISR and global error ISR) - // - cyg_drv_isr_lock(); // disable ISR s - regval = info->icr; // read the event field - info->icr = 0; // clear the event fields - all events processed in getevent() - cyg_drv_isr_unlock(); // renable ISRs - -#ifdef CYGOPT_IO_CAN_TX_EVENT_SUPPORT - if (regval & (ICR_TX1 & CAN_MISC_INT)) -#else - if (regval & CAN_MISC_INT) -#endif - { - // - // Now receive the events - pass the event field to the getevent function - // - chan->callbacks->rcv_event(chan, ®val); - } - - // - // Now transmit next message and reenable interrupts - // - chan->callbacks->xmt_msg(chan, 0); // send next message - HAL_READ_UINT32(CAN_CTRL_IER(info), regval); - regval |= IER_TX1; // reenable interrupts for the message box that caused the DSR to run - HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); - - LPC2XXX_DBG_PRINT("tx_DSR\n"); -} - - -//=========================================================================== -// Low level receive interrupt handler -//=========================================================================== -static cyg_uint32 lpc2xxx_can_rx_ISR(cyg_vector_t vector, cyg_addrword_t data) -{ - cyg_uint32 regval; - CAN_DECLARE_CHAN(data); // declares chan pointer if required - CAN_DECLARE_INFO(chan); // declares info pointer if reuired - - // - // The ISR only disables and acknowledges the RX interrupt - // any further processing is done by DSR - // - HAL_READ_UINT32(CAN_CTRL_IER(info), regval); - regval &= ~IER_RX; // disable rx interrupt for rx buf 1 - HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); - cyg_drv_interrupt_acknowledge(vector); - LPC2XXX_DBG_PRINT("rx_ISR\n"); - - return CYG_ISR_CALL_DSR; -} - - -//=========================================================================== -// High level receive interrupt handler -//=========================================================================== -static void lpc2xxx_can_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) -{ - can_channel *chan = (can_channel *)data; - cyg_uint32 regval; - CAN_DECLARE_INFO(chan); - - // - // Read the event, release the receive buffer and then reenable the - // receive interrupt for next message - // - regval = ICR_RX; // indicate RX event to getevent() function - chan->callbacks->rcv_event(chan, ®val); - HAL_WRITE_UINT32(CAN_CTRL_CMR(info), CMR_RX_RELEASE_BUF); - HAL_READ_UINT32(CAN_CTRL_IER(info), regval); - regval |= IER_RX; - HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); -} - - -//=========================================================================== -// Err ISR handler -//=========================================================================== -static cyg_uint32 lpc2xxx_can_err_ISR(cyg_vector_t vector, cyg_addrword_t data) -{ - cyg_uint8 i = 0; - LPC2XXX_DBG_PRINT("err_ISR\n"); - - while (lpc2xxx_global_can_info.active_channels[i]) - { - cyg_uint32 regval; - lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)lpc2xxx_global_can_info.active_channels[i++]->dev_priv; - - HAL_READ_UINT32(CAN_CTRL_IER(info), regval); - regval &= ~CAN_MISC_INT; // disable all interrupt sources that may cause this int - HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); - HAL_READ_UINT32(CAN_CTRL_ICR(info), regval); - info->icr |= (regval &~ ICR_RX); // do not handle RX intrupts - this is done by RX isr - } - - cyg_drv_interrupt_acknowledge(vector); - return CYG_ISR_CALL_DSR; -} - -//=========================================================================== -// Err ISR handler -//=========================================================================== -static void lpc2xxx_can_err_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) -{ - cyg_uint8 i = 0; - LPC2XXX_DBG_PRINT("err_DSR\n"); - - while (lpc2xxx_global_can_info.active_channels[i]) - { - cyg_uint32 regval; - can_channel *chan = (can_channel *)lpc2xxx_global_can_info.active_channels[i++]; - lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; - - // - // now receive the event - the events are stored in ICR field of CAN info - // - cyg_drv_isr_lock(); // disable ISR s - regval = info->icr; // read the event field - info->icr = 0; // clear the event fields - all events processed in getevent() - cyg_drv_isr_unlock(); // renable ISRs - -#ifdef CYGOPT_IO_CAN_TX_EVENT_SUPPORT - if (regval & (ICR_TX1 & CAN_MISC_INT)) -#else - if (regval & CAN_MISC_INT) -#endif - { - chan->callbacks->rcv_event(chan, ®val); - } - // - // Now reenable interrupts - // - HAL_READ_UINT32(CAN_CTRL_IER(info), regval); - regval |= CAN_MISC_INT; // reenable interrupts for the message box that caused the DSR to run - HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); - } // while (lpc2xxx_global_can_info.active_channels[i]) -} - - -#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG -//=========================================================================== -// Configure message boxes for reception of any CAN message -//=========================================================================== -static void lpc2xxx_can_config_rx_all(can_channel *chan) -{ - lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; - // - // First clear all acceptance filter entries and then insert the - // two RX all groups - // - lpc2xxx_can_config_rx_none(chan); -#ifdef CYGOPT_IO_CAN_STD_CAN_ID - lpc2xxx_can_accfilt_add(info, 0x000, 0x7FF, CYGNUM_CAN_ID_STD); -#endif // CYGOPT_IO_CAN_STD_CAN_ID -#ifdef CYGOPT_IO_CAN_EXT_CAN_ID - lpc2xxx_can_accfilt_add(info, 0x000, 0x1FFFFFFF, CYGNUM_CAN_ID_EXT); -#endif // CYGOPT_IO_CAN_EXT_CAN_ID - - info->flags |= INFO_FLAG_RX_ALL; -#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG - lpc2xxx_can_accfilt_dbg_dump(); -#endif // CYGDBG_DEVS_CAN_LPC2XXX_DEBUG -} -#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG - - -#ifndef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG -//=========================================================================== -// Configure message boxes for reception of any CAN message -//=========================================================================== -static void lpc2xxx_can_config_rx_all(can_channel *chan) -{ - lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; - - lpc2xxx_can_accfilt_simple_rx_all(); - info->flags |= INFO_FLAG_RX_ALL; - -#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG - lpc2xxx_can_accfilt_dbg_dump(); -#endif // CYGDBG_DEVS_CAN_LPC2XXX_DEBUG -} -#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG - - -//--------------------------------------------------------------------------- -// EOF can_lpc2xxx.c +//========================================================================== +// +// devs/can/arm/lpc2xxx/current/src/can_lpc2xxx.c +// +// CAN driver for LPC2xxx microcontrollers +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// Copyright (C) 2003 Gary Thomas +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Uwe Kindler +// Contributors: Uwe Kindler +// Date: 2007-04-09 +// Purpose: Support LPC2xxx on-chip CAN moduls +// Description: +// +//####DESCRIPTIONEND#### +// +//========================================================================== + + +//========================================================================== +// INCLUDES +//========================================================================== +#include <pkgconf/system.h> +#include <pkgconf/io_can.h> +#include <pkgconf/io.h> +#include <pkgconf/devs_can_lpc2xxx.h> + +#include <cyg/infra/diag.h> + +#include <cyg/io/io.h> +#include <cyg/io/devtab.h> +#include <cyg/io/can.h> +#include <cyg/io/can_lpc2xxx.h> +#include <cyg/io/can_lpc2xxx_baudrates.h> + +#include <cyg/hal/hal_arch.h> +#include <cyg/hal/hal_intr.h> +#include <cyg/hal/hal_io.h> + +#include <cyg/hal/hal_diag.h> +#include <cyg/infra/cyg_ass.h> + + +//=========================================================================== +// DEFINES +//=========================================================================== +// +// Check if the macro HAL_LPC2XXX_GET_CAN_BR is provided +// +#ifndef HAL_LPC2XXX_GET_CAN_BR +#error "Macro HAL_LPC2XXX_GET_CAN_BR() missing" +#endif + +// +// Support debug output if this option is enabled in CDL file +// +#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG +#define LPC2XXX_DBG_PRINT diag_printf +#else +#define LPC2XXX_DBG_PRINT( fmt, ... ) +#endif + + +//--------------------------------------------------------------------------- +// we define our own set of register bits in order to be independent from +// platform specific names +// + +//--------------------------------------------------------------------------- +// Memory map of CAN block +// +#define CAN_ACCFILT_RAM_BASE 0xE0038000 +#define CAN_ACCFILT_REG_BASE 0xE003C000 +#define CAN_CENTRAL_REG_BASE 0xE0040000 +#define CAN_CTRL_1_REG_BASE 0xE0044000 +#define CAN_CTRL_2_REG_BASE 0xE0048000 +#define CAN_CTRL_3_REG_BASE 0xE004C000 +#define CAN_CTRL_4_REG_BASE 0xE0050000 + + +//--------------------------------------------------------------------------- +// CAN Acceptance Filter register layout +// +#define CAN_ACCFILT_AFMR (CAN_ACCFILT_REG_BASE + 0x0000) +#define CAN_ACCFILT_SFF_SA (CAN_ACCFILT_REG_BASE + 0x0004) +#define CAN_ACCFILT_SFF_GRP_SA (CAN_ACCFILT_REG_BASE + 0x0008) +#define CAN_ACCFILT_EFF_SA (CAN_ACCFILT_REG_BASE + 0x000C) +#define CAN_ACCFILT_EFF_GRP_SA (CAN_ACCFILT_REG_BASE + 0x0010) +#define CAN_ACCFILT_ENDOFTABLE (CAN_ACCFILT_REG_BASE + 0x0014) +#define CAN_ACCFILT_LUT_ERR_ADDR (CAN_ACCFILT_REG_BASE + 0x0018) +#define CAN_ACCFILT_LUT_ERR (CAN_ACCFILT_REG_BASE + 0x001C) + +//--------------------------------------------------------------------------- +// CAN_ACCFILT_AFMR Bits +// +#define AFMR_OFF 0x00000001 // 1 = Acceptance filter is not operational +#define AFMR_BYPASS 0x00000002 // 1 = all Rx messages are accepted on enabled CAN controllers. +#define AFMR_FULLCAN 0x00000004 // 1 = FullCAN mode +#define AFMR_ON 0x00000000 // Acceptance filter on +#define ACCFILT_RAM_SIZE 2048 // size of acceptance filter ram + + +//--------------------------------------------------------------------------- +// Acceptance filter tool macros +// +#define ACCFILT_STD_ID_MASK 0x7FF +#define ACCFILT_EXT_ID_MASK 0x1FFFFFFF +#define ACCFILT_STD_DIS 0x1000 +#define ACCFILT_STD_CTRL_MASK 0xE000 +#define ACCFILT_EXT_CTRL_MASK 0xE0000000 +#define ACCFILT_STD_GET_CTRL(_entry_) (((_entry_) >> 13) & 0x7) +#define ACCFILT_STD_GET_CTRL_LOWER(_entry_) (((_entry_) >> 29) & 0x7) +#define ACCFILT_STD_GET_CTRL_UPPER(_entry_) (((_entry_) >> 13) & 0x7) +#define ACCFILT_STD_GET_ID(_entry_) ((_entry_) & ACCFILT_STD_ID_MASK) +#define ACCFILT_EXT_GET_ID(_entry_) ((_entry_) & ACCFILT_EXT_ID_MASK) +#define ACCFILT_EXT_GET_CTRL(_entry_) (((_entry_) >> 29) & 0x7) +#define ACCFILT_EXT_SET_CTRL(_entry_, _ctrl_) ((_entry_ & 0xE0000000) | ((_ctrl_) << 29)) + + +//--------------------------------------------------------------------------- +// CAN Central CAN Registers register layout +// +#define CAN_CENTRAL_TXSR (CAN_CENTRAL_REG_BASE + 0x0000) +#define CAN_CENTRAL_RXSR (CAN_CENTRAL_REG_BASE + 0x0004) +#define CAN_CENTRAL_MSR (CAN_CENTRAL_REG_BASE + 0x0008) + + +//--------------------------------------------------------------------------- +// CAN Controller register offsets +// Registers are offsets from base CAN module control register +// +#define CANREG_MOD 0x0000 +#define CANREG_CMR 0x0004 +#define CANREG_GSR 0x0008 +#define CANREG_ICR 0x000C +#define CANREG_IER 0x0010 +#define CANREG_BTR 0x0014 +#define CANREG_EWL 0x0018 +#define CANREG_SR 0x001C +#define CANREG_RFS 0x0020 +#define CANREG_RID 0x0024 +#define CANREG_RDA 0x0028 +#define CANREG_RDB 0x002C +#define CANREG_TFI1 0x0030 +#define CANREG_TID1 0x0034 +#define CANREG_TDA1 0x0038 +#define CANREG_TDB1 0x003C +#define CANREG_TFI2 0x0040 +#define CANREG_TID2 0x0044 +#define CANREG_TDA2 0x0048 +#define CANREG_TDB2 0x004C +#define CANREG_TFI3 0x0050 +#define CANREG_TID3 0x0054 +#define CANREG_TDA3 0x0058 +#define CANREG_TDB3 0x005C + + +//--------------------------------------------------------------------------- +// CAN Controller register layout +// +#define CAN_CTRL_MOD(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_MOD) +#define CAN_CTRL_CMR(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_CMR) +#define CAN_CTRL_GSR(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_GSR) +#define CAN_CTRL_ICR(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_ICR) +#define CAN_CTRL_IER(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_IER) +#define CAN_CTRL_BTR(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_BTR) +#define CAN_CTRL_EWL(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_EWL) +#define CAN_CTRL_SR(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_SR) +#define CAN_CTRL_RFS(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_RFS) +#define CAN_CTRL_RID(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_RID) +#define CAN_CTRL_RDA(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_RDA) +#define CAN_CTRL_RDB(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_RDB) +#define CAN_CTRL_TFI1(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TFI1) +#define CAN_CTRL_TID1(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TID1) +#define CAN_CTRL_TDA1(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TDA1) +#define CAN_CTRL_TDB1(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TDB1) +#define CAN_CTRL_TFI2(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TFI2) +#define CAN_CTRL_TID2(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TID2) +#define CAN_CTRL_TDA2(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TDA2) +#define CAN_CTRL_TDB2(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TDB2) +#define CAN_CTRL_TFI3(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TFI3) +#define CAN_CTRL_TID3(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TID3) +#define CAN_CTRL_TDA3(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TDA3) +#define CAN_CTRL_TDB3(_extra_) (CAN_CTRL_BASE(_extra_) + CANREG_TDB3) + + +//--------------------------------------------------------------------------- +// CAN_CTRL_ICR register bits +// +#define ICR_RX 0x00000001 +#define ICR_TX1 0x00000002 +#define ICR_ERR_WARN 0x00000004 +#define ICR_DATA_OVR 0x00000008 +#define ICR_WAKE_UP 0x00000010 +#define ICR_ERR_PASSIVE 0x00000020 +#define ICR_ARBITR_LOST 0x00000040 +#define ICR_BUS_ERR 0x00000080 +#define ICR_ID_READY 0x00000100 +#define ICR_TX2 0x00000200 +#define ICR_TX3 0x00000400 +#define ICR_LUT_ERR 0x00000800 +#define ICR_GET_ERRBIT(_icr_) (((_icr_) >> 16) & 0x1F) +#define ICR_ERR_DIRECTION 0x00200000 +#define ICR_GET_ERRCODE(_icr_) (((_icr_) >> 22) & 0x03) +#define ICR_GET_ALCBIT(_icr_) (((_icr_) >> 24) & 0x1F) + +#define CAN_ALL_ERR_INT (ICR_ERR_PASSIVE | ICR_ARBITR_LOST | ICR_BUS_ERR | ICR_ERR_WARN) +#define CAN_MISC_INT (CAN_ALL_ERR_INT | ICR_WAKE_UP) + + +//--------------------------------------------------------------------------- +// CAN_CTRL_ICR register bits +// +#define ICR_ERRCODE_BIT_ERR 0x00 +#define ICR_ERRCODE_FORM_ERR 0x01 +#define ICR_ERRCODE_STUFF_ERR 0x02 +#define ICR_ERRCODE_OTHER_ERR 0x03 + + +//--------------------------------------------------------------------------- +// CAN_CTRL_RFS register bits +// +#define RFS_ACCFILT_INDEX_MASK 0x000003FF +#define RFS_RECEIVED_IN_BYPASS_MODE 0x00000400 +#define RFS_DLC_MASK 0x000F0000 +#define RFS_RTR 0x40000000 +#define RFS_EXT 0x80000000 +#define RFS_GET_DLC(_regval_) (((_regval_) >> 16) & 0xF) + +//--------------------------------------------------------------------------- +// CAN_CTRL_CMR register bits +// +#define CMR_TX_REQ 0x00000001 +#define CMR_TX_ABORT 0x00000002 +#define CMR_RX_RELEASE_BUF 0x00000004 +#define CMR_CLEAR_DATA_OVR 0x00000008 +#define CMR_SELF_RX_REQ 0x00000010 +#define CMR_SEND_TX_BUF1 0x00000020 +#define CMR_SEND_TX_BUF2 0x00000040 +#define CMR_SEND_TX_BUF3 0x00000080 + + +//--------------------------------------------------------------------------- +// CAN_CTRL_TFI register bits +// +#define TFI_PRIO_MASK 0x000000FF +#define TFI_DLC_MASK 0x000F0000 +#define TFI_DLC_RTR 0x40000000 +#define TFI_DLC_EXT 0x80000000 + + +//--------------------------------------------------------------------------- +// CAN_CTRL_MOD register bits +// +#define CANMOD_OPERATIONAL 0x00000000 +#define CANMOD_RESET 0x00000001 +#define CANMOD_LISTEN_ONLY 0x00000002 +#define CANMOD_SELF_TEST 0x00000004 +#define CANMOD_TX_BUF_CFG 0x00000008 +#define CANMOD_SLEEP 0x00000010 +#define CANMOD_REV_POLARITY 0x00000020 +#define CANMOD_TEST 0x00000040 + + +//--------------------------------------------------------------------------- +// CAN_CTRL_IER register bits +// +#define IER_RX 0x00000001 +#define IER_TX1 0x00000002 +#define IER_ERR_WARN 0x00000004 +#define IER_DATA_OVR 0x00000008 +#define IER_WAKE_UP 0x00000010 +#define IER_ERR_PASSIVE 0x00000020 +#define IER_ARBITR_LOST 0x00000040 +#define IER_BUS_ERR 0x00000080 +#define IER_ID_READY 0x00000100 +#define IER_TX2 0x00000200 +#define IER_TX3 0x00000400 + + +//--------------------------------------------------------------------------- +// CAN_CTRL_GSR register bits +// +#define GSR_RX_MSG_AVAILABLE 0x00000001 +#define GSR_DATA_OVR 0x00000002 +#define GSR_TX_NOT_PENDING 0x00000004 +#define GSR_ALL_TX_COMPLETE 0x00000008 +#define GSR_RECEIVING_ACTIVE 0x00000010 +#define GSR_SENDING_ACTIVE 0x00000020 +#define GSR_ERR 0x00000040 +#define GSR_BUS_OFF 0x00000080 +#define GSR_RXERR_CNT(_reg_) (((_reg_) >> 16) & 0xFF) +#define GSR_TXERR_CNT(_reg_) (((_reg_) >> 24) & 0xFF) + + +//--------------------------------------------------------------------------- +// CAN_CTRL_SR register bits +// +#define SR_RX_MSG_AVAILABLE 0x01 +#define SR_DATA_OVR 0x02 +#define SR_TX_BUF_WRITE_OK 0x04 // TBS1, TBS2, TBS3 (Bit 2, 10, 18) +#define SR_TX_COMPLETE 0x08 // TCS1, TCS2, TCS3 (Bit 3, 11, 19) +#define SR_RECEIVING_ACTIVE 0x10 +#define SR_SENDING_ACTIVE 0x20 // TS1, TS2, TS3 (5, 13, 21) +#define SR_ERR 0x40 +#define SR_BUS_OFF 0x80 + + +//--------------------------------------------------------------------------- +// Optimize for the case of a single CAN channel, while still allowing +// multiple channels. +// +#if CYGINT_IO_CAN_CHANNELS == 1 +#define CAN_CTRL_BASE(_extra_) CAN_CTRL_SINGLETON_BASE +#define CAN_ISRVEC(_extra_) CAN_SINGLETON_ISRVEC +#define CAN_DECLARE_INFO(_chan_) +#define CAN_DECLARE_CHAN(_data_) +#else +#define CAN_CTRL_BASE(_extra_) ((_extra_)->base) +#define CAN_ISRVEC(_extra_) ((_extra_)->isrvec) +#define CAN_DECLARE_INFO(_chan_) lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; +#define CAN_DECLARE_CHAN(_data_) can_channel *chan = (can_channel *)data; +#endif // CYGINT_IO_CAN_CHANNELS == 1 + + +#ifdef CYGOPT_DEVS_CAN_LPC2XXX_CAN0_ACCFILT_STARTUP_CFG_RX_ALL +#define CAN0_FLAG_STARTUP_ACCFILT_SETUP INFO_FLAG_STARTUP_RX_ALL +#else +#define CAN0_FLAG_STARTUP_ACCFILT_SETUP 0x00 +#endif + +#ifdef CYGOPT_DEVS_CAN_LPC2XXX_CAN1_ACCFILT_STARTUP_CFG_RX_ALL +#define CAN1_FLAG_STARTUP_ACCFILT_SETUP INFO_FLAG_STARTUP_RX_ALL +#else +#define CAN1_FLAG_STARTUP_ACCFILT_SETUP 0x00 +#endif + +#ifdef CYGOPT_DEVS_CAN_LPC2XXX_CAN2_ACCFILT_STARTUP_CFG_RX_ALL +#define CAN2_FLAG_STARTUP_ACCFILT_SETUP INFO_FLAG_STARTUP_RX_ALL +#else +#define CAN2_FLAG_STARTUP_ACCFILT_SETUP 0x00 +#endif + +#ifdef CYGOPT_DEVS_CAN_LPC2XXX_CAN3_ACCFILT_STARTUP_CFG_RX_ALL +#define CAN3_FLAG_STARTUP_ACCFILT_SETUP INFO_FLAG_STARTUP_RX_ALL +#else +#define CAN3_FLAG_STARTUP_ACCFILT_SETUP 0x00 +#endif + + +//=========================================================================== +// DATA TYPES +//=========================================================================== +// +// Structure stores LPC2xxx CAN channel related stuff +// + +// If we use Self Reception Request command instead of the Transmission Request +// we must add last transmit message id in order to reject it in rx_ISR +// There are two last_tx_id because tx interrupt (and so transmition of next +// message) happens before rx interrupt (which uses last_tx_id for rejecting)) + +// Format of last_tx_id: +// (bits: 28:0-ID, 29-Validation, 30-RTR, 31-EXT) +// if last_tx_id == 0xFFFFFFFF (Validation == 1) then last id is not valid +#ifdef CYGOPT_DEVS_CAN_LPC2XXX_USE_SELF_RECEPTION + #define LPC2XXX_CAN_INFO_LAST_TX_ID_IDMASK 0x1FFFFFFF + #define LPC2XXX_CAN_INFO_LAST_TX_ID_FLMASK 0xC0000000 + #define LPC2XXX_CAN_INFO_LAST_TX_ID_NOVALID 0xFFFFFFFF + + #define LPC2XXX_CAN_INFO_LAST_TX_ID_DECL cyg_uint8 last_tx_index; \ + cyg_uint32 last_tx_id[2]; + #define LPC2XXX_CAN_INFO_LAST_TX_ID_INIT last_tx_index : 0, \ + last_tx_id : {LPC2XXX_CAN_INFO_LAST_TX_ID_NOVALID, LPC2XXX_CAN_INFO_LAST_TX_ID_NOVALID}, +#else + #define LPC2XXX_CAN_INFO_LAST_TX_ID_DECL + #define LPC2XXX_CAN_INFO_LAST_TX_ID_INIT +#endif + +typedef struct lpc2xxx_can_info_st +{ + cyg_interrupt tx_interrupt; + cyg_handle_t tx_interrupt_handle; + cyg_interrupt rx_interrupt; + cyg_handle_t rx_interrupt_handle; + cyg_can_state state; // state of CAN controller + cyg_uint32 icr; // buffers icr register + cyg_uint8 flags; // flags indicating several states + LPC2XXX_CAN_INFO_LAST_TX_ID_DECL // last transmited messages ids +#if CYGINT_IO_CAN_CHANNELS > 1 + cyg_uint32 base; // Per-bus h/w details + cyg_uint8 isrvec; // ISR vector (peripheral id) +#endif +} lpc2xxx_can_info_t; + + +#define INFO_FLAG_RX_ALL 0x01 // this bit indicates that channel receives all CAN messages - no filtering active +#define INFO_FLAG_STARTUP_RX_ALL 0x02 // this bit indicates filter state at startup + + +// +// lpc2xxx info initialisation +// +#define LPC2XXX_CTRL_NOT_INITIALIZED 0xFF +#if CYGINT_IO_CAN_CHANNELS > 1 +#define LPC2XXX_CAN_INFO(_l, _base, _isrvec, _flags) \ +lpc2xxx_can_info_t _l = { \ + state : LPC2XXX_CTRL_NOT_INITIALIZED, \ + base : (_base), \ + isrvec : (_isrvec), \ + flags : (_flags), \ + icr : 0, \ + LPC2XXX_CAN_INFO_LAST_TX_ID_INIT \ +}; +#else +#define LPC2XXX_CAN_INFO(_l, _flags) \ +lpc2xxx_can_info_t _l = { \ + state : CYGNUM_CAN_STATE_STOPPED, \ + flags : (_flags), \ + icr : 0, \ + LPC2XXX_CAN_INFO_LAST_TX_ID_INIT \ +}; +#endif + + +// +// Acceptance filter data +// +typedef struct lpc2xxx_global_can_info_st +{ + cyg_interrupt err_interrupt; + cyg_handle_t err_interrupt_handle; + cyg_uint16 free_filters; // number of free message filters + cyg_uint8 init_cnt; // counts number of initialized channels + can_channel* active_channels[5]; // stores pointers to active channels - the last entry is just a delimiter +} lpc2xxx_global_can_info_t; + + +// +// The number of available message filters depends on the size of the +// acceptance filter RAM and on the size of one entry. The size of +// one entry is 4 byte (standard ID only 2 byte, extended groups 8 byte) +// +#define ACCFILT_COMMON_ENTRY_SIZE 4 +#define LPC2XXX_CAN_MSG_FILTERS_MAX (ACCFILT_RAM_SIZE / ACCFILT_COMMON_ENTRY_SIZE) +lpc2xxx_global_can_info_t lpc2xxx_global_can_info = +{ + .free_filters = LPC2XXX_CAN_MSG_FILTERS_MAX, + .init_cnt = 0, + .active_channels = {0, 0, 0, 0, 0}, +}; + + + +// +// Data type for access of single bytes/words of an dword value +// +typedef union lsc_buf_u +{ + cyg_uint8 bytes[4]; + struct + { + cyg_uint16 low; + cyg_uint16 high; + } words; + + struct + { + cyg_uint16 upper; // uppper column of acceptance filter ram + cyg_uint16 lower; // lower column of acceptance filter ram + } column; + + cyg_uint32 dword; +} lsc_buf_t; + + +//=========================================================================== +// GLOBAL DATA +//=========================================================================== +#if CYGINT_IO_CAN_CHANNELS > 1 +#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN0 +LPC2XXX_CAN_INFO(lpc2xxx_can0_info, + CAN_CTRL_1_REG_BASE, + CYGNUM_HAL_INTERRUPT_CAN1_TX, + CAN0_FLAG_STARTUP_ACCFILT_SETUP); +#endif + +#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN1 +LPC2XXX_CAN_INFO(lpc2xxx_can1_info, + CAN_CTRL_2_REG_BASE, + CYGNUM_HAL_INTERRUPT_CAN2_TX, + CAN1_FLAG_STARTUP_ACCFILT_SETUP); +#endif + +#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN2 +LPC2XXX_CAN_INFO(lpc2xxx_can2_info, + CAN_CTRL_3_REG_BASE, + CYGNUM_HAL_INTERRUPT_CAN3_TX, + CAN2_FLAG_STARTUP_ACCFILT_SETUP); +#endif + +#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN3 +LPC2XXX_CAN_INFO(lpc2xxx_can3_info, + CAN_CTRL_4_REG_BASE, + CYGNUM_HAL_INTERRUPT_CAN4_TX, + CAN3_FLAG_STARTUP_ACCFILT_SETUP); +#endif +#else // CYGINT_IO_CAN_CHANNELS == 1 +#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN0 +LPC2XXX_CAN_INFO(lpc2xxx_can0_info, CAN0_FLAG_STARTUP_ACCFILT_SETUP); +#define CAN_CTRL_SINGLETON_BASE CAN_CTRL_1_REG_BASE +#define CAN_SINGLETON_ISRVEC CYGNUM_HAL_INTERRUPT_CAN1_TX +#endif + +#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN1 +LPC2XXX_CAN_INFO(lpc2xxx_can1_info, CAN1_FLAG_STARTUP_ACCFILT_SETUP); +#define CAN_CTRL_SINGLETON_BASE CAN_CTRL_2_REG_BASE +#define CAN_SINGLETON_ISRVEC CYGNUM_HAL_INTERRUPT_CAN2_TX +#endif + +#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN2 +LPC2XXX_CAN_INFO(lpc2xxx_can2_info, CAN2_FLAG_STARTUP_ACCFILT_SETUP); +#define CAN_CTRL_SINGLETON_BASE CAN_CTRL_3_REG_BASE +#define CAN_SINGLETON_ISRVEC CYGNUM_HAL_INTERRUPT_CAN3_TX +#endif + +#ifdef CYGINT_DEVS_CAN_LPC2XXX_CAN3 +LPC2XXX_CAN_INFO(lpc2xxx_can3_info, CAN3_FLAG_STARTUP_ACCFILT_SETUP); +#define CAN_CTRL_SINGLETON_BASE CAN_CTRL_4_REG_BASE +#define CAN_SINGLETON_ISRVEC CYGNUM_HAL_INTERRUPT_CAN4_TX +#endif + +#endif // #if CYGINT_IO_CAN_CHANNELS > 1 + + +//=========================================================================== +// PROTOTYPES +//=========================================================================== + +//-------------------------------------------------------------------------- +// Device driver interface functions +// +static bool lpc2xxx_can_init(struct cyg_devtab_entry* devtab_entry); +static Cyg_ErrNo lpc2xxx_can_lookup(struct cyg_devtab_entry** tab, struct cyg_devtab_entry* sub_tab, const char* name); +static Cyg_ErrNo lpc2xxx_can_set_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len); +static Cyg_ErrNo lpc2xxx_can_get_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len); +static bool lpc2xxx_can_putmsg(can_channel *priv, CYG_CAN_MSG_T *pmsg, void *pdata); +static bool lpc2xxx_can_getevent(can_channel *priv, CYG_CAN_EVENT_T *pevent, void *pdata); +static void lpc2xxx_can_start_xmit(can_channel* chan); +static void lpc2xxx_can_stop_xmit(can_channel* chan); + + +//-------------------------------------------------------------------------- +// ISRs and DSRs +// +static cyg_uint32 lpc2xxx_can_tx_ISR(cyg_vector_t vector, cyg_addrword_t data); +static void lpc2xxx_can_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data); +static cyg_uint32 lpc2xxx_can_rx_ISR(cyg_vector_t vector, cyg_addrword_t data); +static void lpc2xxx_can_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data); +static cyg_uint32 lpc2xxx_can_err_ISR(cyg_vector_t vector, cyg_addrword_t data); +static void lpc2xxx_can_err_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data); + + +//-------------------------------------------------------------------------- +// Private utility functions +// +static bool lpc2xxx_can_config_channel(can_channel* chan, cyg_can_info_t* config, cyg_bool init); +static bool lpc2xxx_can_set_baud(can_channel *chan, cyg_can_baud_rate_t *baudrate); +static Cyg_ErrNo lpc2xxx_enter_lowpower_mode(can_channel *chan); +static void lpc2xxx_start_module(can_channel *chan); +static cyg_can_state lpc2xxx_get_state(lpc2xxx_can_info_t *info); +static void lpc2xxx_set_state(lpc2xxx_can_info_t *info, cyg_can_state state); + + +//-------------------------------------------------------------------------- +// Message box configuration +// +static void lpc2xxx_can_config_rx_all(can_channel *chan); +#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG +static void lpc2xxx_can_config_rx_none(can_channel *chan); +static bool lpc2xxx_can_add_rx_filter(lpc2xxx_can_info_t *info, cyg_can_filter *filter); +#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + + +#include "can_accfilt_lpc2xxx.c" + +//=========================================================================== +// GENERIC CAN IO DATA INITIALISATION +//=========================================================================== +CAN_LOWLEVEL_FUNS(lpc2xxx_can_lowlevel_funs, + lpc2xxx_can_putmsg, + lpc2xxx_can_getevent, + lpc2xxx_can_get_config, + lpc2xxx_can_set_config, + lpc2xxx_can_start_xmit, + lpc2xxx_can_stop_xmit + ); + + +//--------------------------------------------------------------------------- +// CAN channel 0 +// +#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN0 +CYG_CAN_EVENT_T lpc2xxx_can0_rxbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN0_QUEUESIZE_RX]; // buffer for RX can events +CYG_CAN_MSG_T lpc2xxx_can0_txbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN0_QUEUESIZE_TX]; // buffer for TX can messages + + +CAN_CHANNEL_USING_INTERRUPTS(lpc2xxx_can0_chan, + lpc2xxx_can_lowlevel_funs, + lpc2xxx_can0_info, + CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_LPC2XXX_CAN0_KBAUD), + lpc2xxx_can0_txbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN0_QUEUESIZE_TX, + lpc2xxx_can0_rxbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN0_QUEUESIZE_RX + ); + + +DEVTAB_ENTRY(lpc2xxx_can0_devtab, + CYGPKG_DEVS_CAN_LPC2XXX_CAN0_NAME, + 0, // Does not depend on a lower level interface + &cyg_io_can_devio, + lpc2xxx_can_init, + lpc2xxx_can_lookup, // CAN driver may need initializing + &lpc2xxx_can0_chan + ); +#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN0 + + +//--------------------------------------------------------------------------- +// CAN channel 1 +// +#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN1 +CYG_CAN_EVENT_T lpc2xxx_can1_rxbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN1_QUEUESIZE_RX]; // buffer for RX can events +CYG_CAN_MSG_T lpc2xxx_can1_txbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN1_QUEUESIZE_TX]; // buffer for TX can messages + + +CAN_CHANNEL_USING_INTERRUPTS(lpc2xxx_can1_chan, + lpc2xxx_can_lowlevel_funs, + lpc2xxx_can1_info, + CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_LPC2XXX_CAN1_KBAUD), + lpc2xxx_can1_txbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN1_QUEUESIZE_TX, + lpc2xxx_can1_rxbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN1_QUEUESIZE_RX + ); + + +DEVTAB_ENTRY(lpc2xxx_can1_devtab, + CYGPKG_DEVS_CAN_LPC2XXX_CAN1_NAME, + 0, // Does not depend on a lower level interface + &cyg_io_can_devio, + lpc2xxx_can_init, + lpc2xxx_can_lookup, // CAN driver may need initializing + &lpc2xxx_can1_chan + ); +#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN1 + + +//--------------------------------------------------------------------------- +// CAN channel 2 +// +#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN2 +CYG_CAN_EVENT_T lpc2xxx_can2_rxbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN2_QUEUESIZE_RX]; // buffer for RX can events +CYG_CAN_MSG_T lpc2xxx_can2_txbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN2_QUEUESIZE_TX]; // buffer for TX can messages + + +CAN_CHANNEL_USING_INTERRUPTS(lpc2xxx_can2_chan, + lpc2xxx_can_lowlevel_funs, + lpc2xxx_can2_info, + CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_LPC2XXX_CAN2_KBAUD), + lpc2xxx_can2_txbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN2_QUEUESIZE_TX, + lpc2xxx_can2_rxbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN2_QUEUESIZE_RX + ); + + +DEVTAB_ENTRY(lpc2xxx_can2_devtab, + CYGPKG_DEVS_CAN_LPC2XXX_CAN2_NAME, + 0, // Does not depend on a lower level interface + &cyg_io_can_devio, + lpc2xxx_can_init, + lpc2xxx_can_lookup, // CAN driver may need initializing + &lpc2xxx_can2_chan + ); +#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN2 + + +//--------------------------------------------------------------------------- +// CAN channel 3 +// +#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN3 +CYG_CAN_EVENT_T lpc2xxx_can3_rxbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN3_QUEUESIZE_RX]; // buffer for RX can events +CYG_CAN_MSG_T lpc2xxx_can3_txbuf[CYGNUM_DEVS_CAN_LPC2XXX_CAN3_QUEUESIZE_TX]; // buffer for TX can messages + + +CAN_CHANNEL_USING_INTERRUPTS(lpc2xxx_can3_chan, + lpc2xxx_can_lowlevel_funs, + lpc2xxx_can3_info, + CYG_CAN_BAUD_RATE(CYGNUM_DEVS_CAN_LPC2XXX_CAN3_KBAUD), + lpc2xxx_can3_txbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN3_QUEUESIZE_TX, + lpc2xxx_can3_rxbuf, CYGNUM_DEVS_CAN_LPC2XXX_CAN3_QUEUESIZE_RX + ); + + +DEVTAB_ENTRY(lpc2xxx_can3_devtab, + CYGPKG_DEVS_CAN_LPC2XXX_CAN3_NAME, + 0, // Does not depend on a lower level interface + &cyg_io_can_devio, + lpc2xxx_can_init, + lpc2xxx_can_lookup, // CAN driver may need initializing + &lpc2xxx_can3_chan + ); +#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN3 + + +//=========================================================================== +// IMPLEMENTATION +//=========================================================================== + + + +//=========================================================================== +/// First initialisation and reset of CAN modul. +//=========================================================================== +static bool lpc2xxx_can_init(struct cyg_devtab_entry* devtab_entry) +{ + can_channel *chan = (can_channel*)devtab_entry->priv; + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; + bool res; + +#ifdef CYGDBG_IO_INIT + diag_printf("LPC2XXX CAN init\n"); +#endif + + // + // Create TX interrupt + // + cyg_drv_interrupt_create(CAN_ISRVEC(info), + 0, // Priority does not matter LPC2xxx + (cyg_addrword_t)chan, // Data item passed to interrupt handler + lpc2xxx_can_tx_ISR, + lpc2xxx_can_tx_DSR, + &info->tx_interrupt_handle, + &info->tx_interrupt); + cyg_drv_interrupt_attach(info->tx_interrupt_handle); + cyg_drv_interrupt_unmask(CAN_ISRVEC(info)); + + // + // Create RX interrupt + // + cyg_drv_interrupt_create(CAN_ISRVEC(info) + 6, + 0, // Priority does not matter for LPC2xxx + (cyg_addrword_t)chan, // Data item passed to interrupt handler + lpc2xxx_can_rx_ISR, + lpc2xxx_can_rx_DSR, + &info->rx_interrupt_handle, + &info->rx_interrupt); + cyg_drv_interrupt_attach(info->rx_interrupt_handle); + cyg_drv_interrupt_unmask(CAN_ISRVEC(info) + 6); + + // + // Now create and enable error interrupt. This interrupt is global for all channels + // and so we need to call it only one times - when the first channel is + // initialized + // + if (!lpc2xxx_global_can_info.init_cnt) + { + // + // Create err interrupt + // + cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_CAN, + 0, // Priority does not matter for LPX2xxx + 0, // Data item passed to interrupt handler + lpc2xxx_can_err_ISR, + lpc2xxx_can_err_DSR, + &lpc2xxx_global_can_info.err_interrupt_handle, + &lpc2xxx_global_can_info.err_interrupt); + cyg_drv_interrupt_attach(lpc2xxx_global_can_info.err_interrupt_handle); + cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_CAN); + } + + res = lpc2xxx_can_config_channel(chan, &chan->config, true); + lpc2xxx_global_can_info.active_channels[lpc2xxx_global_can_info.init_cnt++] = chan; + return res; +} + + +//=========================================================================== +// Configure can channel +//=========================================================================== +static bool lpc2xxx_can_config_channel(can_channel* chan, cyg_can_info_t* config, cyg_bool init) +{ + CAN_DECLARE_INFO(chan); + cyg_uint32 temp32; + bool res = true; + + if (init) + { + // + // In case platform needs extra initialization (i.e. setup of CAN transcievers) + // it should implement this macro + // +#ifdef CYGPRI_IO_CAN_LPC2XXX_PLF_INIT_HOOK + CYGPRI_IO_CAN_LPC2XXX_PLF_INIT_HOOK(chan, config); +#endif + + HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, AFMR_OFF); // Acceptance Filter Mode Register = off + HAL_WRITE_UINT32(CAN_CTRL_MOD(info), CANMOD_RESET); // Go into reset mode + HAL_WRITE_UINT32(CAN_CTRL_IER(info), 0); // disable all interrupts + HAL_WRITE_UINT32(CAN_CTRL_GSR(info), 0); // Clear Status register - clears error counters + + // + // If this is the first channel to initialize then we reset the CAN registers + // and setup the CAN I/O pins + // + if (!lpc2xxx_global_can_info.init_cnt) + { + lpc2xxx_can_accfilt_reset(); +#if defined(CYGPKG_DEVS_CAN_LPC2XXX_CAN0) || defined(CYGPKG_DEVS_CAN_LPC2XXX_CAN1) || defined(CYGPKG_DEVS_CAN_LPC2XXX_CAN3) + HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_PIN_BASE + CYGARC_HAL_LPC2XXX_REG_PINSEL1, temp32); +#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN0 + temp32 |= 0x00040000L; // Set bit 18 +#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN0 +#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN1 + temp32 |= 0x00014000L; // Set bits 14 and 16 +#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN1 +#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN2 + temp32 |= 0x00001800L; // Set bits 11 and 12 +#endif + HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_PIN_BASE + CYGARC_HAL_LPC2XXX_REG_PINSEL1, temp32); +#endif // defined(CYGPKG_DEVS_CAN_LPC2XXX_CAN0) || defined(CYGPKG_DEVS_CAN_LPC2XXX_CAN1) + + +#ifdef CYGPKG_DEVS_CAN_LPC2XXX_CAN3 + HAL_READ_UINT32(CYGARC_HAL_LPC2XXX_REG_PIN_BASE + CYGARC_HAL_LPC2XXX_REG_PINSEL0, temp32); + temp32 |= 0x0F000000L; + HAL_WRITE_UINT32(CYGARC_HAL_LPC2XXX_REG_PIN_BASE + CYGARC_HAL_LPC2XXX_REG_PINSEL0, temp32); +#endif // CYGPKG_DEVS_CAN_LPC2XXX_CAN3 + } + } // if (init) + + res = lpc2xxx_can_set_baud(chan, &config->baud); // set baudrate + // $$$$ enable receive interrupt? + HAL_WRITE_UINT32(CAN_CTRL_MOD(info), CANMOD_OPERATIONAL); // enter normal operating mode + + // + // store new config values + // + if (config != &chan->config) + { + chan->config = *config; + } + + return res; +} + + +//=========================================================================== +// Set baudrate of certain can channel +//=========================================================================== +static bool lpc2xxx_can_set_baud(can_channel *chan, cyg_can_baud_rate_t *baudrate) +{ + bool res = true; + cyg_uint32 canbtr; + cyg_uint32 canmod; + CAN_DECLARE_INFO(chan); + + // + // Get bit timings from HAL because bit timings depend on sysclock + // If the macro fills the canbtr value with 0 then the baudrate + // is not supported and the function returns false + // + HAL_LPC2XXX_GET_CAN_BR(*baudrate, canbtr); + if (0 == canbtr) + { + return false; + } + + // + // Any modificatons to the baudrate register must be done while CAN + // module is in reset mode. So we first set the CAN moduel in reset + // mode, then we set baudrate and then we restore content of CANMOD + // register + // + HAL_READ_UINT32(CAN_CTRL_MOD(info), canmod); // backup canmod register + HAL_WRITE_UINT32(CAN_CTRL_MOD(info), CANMOD_RESET); // Go into reset mode + HAL_WRITE_UINT32(CAN_CTRL_BTR(info), canbtr); // write baudrate value + HAL_WRITE_UINT32(CAN_CTRL_MOD(info), canmod); // restore previous value + + return res; +} + + +//=========================================================================== +// Lookup the device and return its handle +//=========================================================================== +static Cyg_ErrNo lpc2xxx_can_lookup(struct cyg_devtab_entry** tab, struct cyg_devtab_entry* sub_tab, const char* name) +{ + can_channel* chan = (can_channel*) (*tab)->priv; + CAN_DECLARE_INFO(chan); + cyg_uint32 regval; + + chan->callbacks->can_init(chan); + + // + // If runtime acceptance filter configuration is supported then we only + // configure RX ALL if the user selected the RX ALL setup in config utility + // +#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + if (info->flags & INFO_FLAG_STARTUP_RX_ALL) +#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + { + lpc2xxx_can_config_rx_all(chan); + } + + HAL_WRITE_UINT32(CAN_ACCFILT_AFMR, AFMR_ON); // Activate acceptance filter + HAL_READ_UINT32(CAN_CTRL_IER(info), regval); + regval = regval | IER_RX | CAN_MISC_INT; // enable all interrupts + HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); + + return ENOERR; +} + + +#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG +//=========================================================================== +// Setup LPC2XXX CAN module in a state where all message boxes are disabled +// After this call it is possible to add single message buffers and filters +//=========================================================================== +static void lpc2xxx_can_config_rx_none(can_channel *chan) +{ + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; + + // + // Remove all acceptance filters + // $$$$ maybe we should also abort any pending transfers and + // disable receive interrupts ? + // + lpc2xxx_can_accfilt_remove_all_ctrl_entries(info); + info->flags &= ~INFO_FLAG_RX_ALL; +#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG + lpc2xxx_can_accfilt_dbg_dump(); +#endif +} + + +//=========================================================================== +// Add one single message filter to acceptance filter +//=========================================================================== +static bool lpc2xxx_can_add_rx_filter(lpc2xxx_can_info_t *info, cyg_can_filter *filter) +{ + bool res; + + res = lpc2xxx_can_accfilt_add(info, filter->msg.id, 0, filter->msg.ext); + if (!res) + { + filter->handle = CYGNUM_CAN_MSGBUF_NA; + } +#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG + lpc2xxx_can_accfilt_dbg_dump(); +#endif + return res; +} +#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + + + +#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG +//=========================================================================== +// Configure message buffers +//=========================================================================== +static Cyg_ErrNo lpc2xxx_can_config_msgbuf(can_channel *chan, const void* buf, cyg_uint32* len) +{ + Cyg_ErrNo res = ENOERR; + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; + cyg_can_msgbuf_cfg *msg_buf = (cyg_can_msgbuf_cfg *)buf; + + if (*len != sizeof(cyg_can_msgbuf_cfg)) + { + return -EINVAL; + } + + switch (msg_buf->cfg_id) + { + // + // clear all message filters and remote buffers - prepare for message buffer + // configuration + // + case CYGNUM_CAN_MSGBUF_RESET_ALL : + { + lpc2xxx_can_config_rx_none(chan); + } + break; + + // + // setup driver for reception of all standard and extended messages + // + case CYGNUM_CAN_MSGBUF_RX_FILTER_ALL : + { + if (!(info->flags & INFO_FLAG_RX_ALL)) // if rx_all is enabled we do not need to do anything + { + lpc2xxx_can_config_rx_all(chan); // setup RX all state + } + } + break; + + // + // add single message filter, message with filter ID will be received + // + case CYGNUM_CAN_MSGBUF_RX_FILTER_ADD : + { + cyg_can_filter *filter = (cyg_can_filter*) buf; + + // + // if the acceptance filter is configured to receive all messages then + // it is not allowed to add single message filters because then more + // than one acceptance filter would receive the same CAN id + // + if (info->flags & INFO_FLAG_RX_ALL) + { + return -EPERM; + } + + // + // try to allocate a free acceptance filter entry - if we have a free one + // then we can prepare the acceptance filter table for reception of + // this message + // + if (!lpc2xxx_can_add_rx_filter(info, filter)) + { + return -EPERM; + } + } + break; //CYGNUM_CAN_MSGBUF_RX_FILTER_ADD + + +#ifdef CYGOPT_IO_CAN_REMOTE_BUF + // + // Try to add a new RTR response message buffer for automatic transmisson + // of data frame on reception of a remote frame + // + case CYGNUM_CAN_MSGBUF_REMOTE_BUF_ADD : + { + // $$$$ TODO implement remote repsonse buffers in software + return -ENOSUPP; + } + break; + + // + // write data into remote response buffer + // + case CYGNUM_CAN_MSGBUF_REMOTE_BUF_WRITE : + { + // $$$$ TODO implement remote response buffers in software + return -ENOSUPP; + } + break; +#endif // #ifdef CYGOPT_IO_CAN_REMOTE_BUF + default: + return -EINVAL; + } // switch (buf->cfg_id) + + return res; +} +#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + + +//=========================================================================== +// Read state of CAN controller +// The CAN state variable for each channel is modiefied by DSR so if we +// read the state we need to lock DSRs to protect the data access +//=========================================================================== +static cyg_can_state lpc2xxx_get_state(lpc2xxx_can_info_t *info) +{ + cyg_can_state result; + + cyg_drv_dsr_lock(); + result = info->state; + cyg_drv_dsr_unlock(); + + return result; +} + + +//=========================================================================== +// Set state of CAN controller +// The CAN state variable for each channel is modiefied by DSR so if we +// write the state we need to lock DSRs to protect the data access +//=========================================================================== +static void lpc2xxx_set_state(lpc2xxx_can_info_t *info, cyg_can_state state) +{ + cyg_drv_dsr_lock(); + info->state = state; + cyg_drv_dsr_unlock(); +} + + +//=========================================================================== +// Enter low power mode +//=========================================================================== +static Cyg_ErrNo lpc2xxx_enter_lowpower_mode(can_channel *chan) +{ + cyg_uint32 regval; + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; + + // + // Before we enter low power mode, we have to enable wake up interrupt + // Normally this interrupt is always enabled so we do not need to do + // anything here + // + HAL_READ_UINT32(CAN_CTRL_MOD(info), regval); + + // + // Software can only set SM when RM in the CAN Mode register is 0 + // + if (regval & CANMOD_RESET) + { + return -EPERM; + } + + //regval &= CANMOD_SLEEP; + lpc2xxx_set_state(info, CYGNUM_CAN_STATE_STANDBY); + HAL_WRITE_UINT32(CAN_CTRL_MOD(info), CANMOD_SLEEP); + return ENOERR; +} + + +//=========================================================================== +// Start CAN module - set CANMOD operational and enable all interrupts +//=========================================================================== +static void lpc2xxx_start_module(can_channel *chan) +{ + cyg_uint32 regval; + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; + + HAL_WRITE_UINT32(CAN_CTRL_MOD(info), CANMOD_OPERATIONAL); + // + // The interrupt enable register is also modified by ISR and DSR so + // we need to protect acces here + // + cyg_drv_isr_lock(); + HAL_READ_UINT32(CAN_CTRL_IER(info), regval); + regval = regval | IER_RX | CAN_MISC_INT; // enable all interrupts + HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); + info->state = CYGNUM_CAN_STATE_ACTIVE; + cyg_drv_isr_unlock(); +} + + +//=========================================================================== +// Enter reset mode +//=========================================================================== +static void lpc2xx_enter_reset_mode(can_channel *chan) +{ + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; + + info->state = CYGNUM_CAN_STATE_STOPPED; + HAL_WRITE_UINT32(CAN_CTRL_MOD(info), CANMOD_RESET); +} + + +#ifdef CYGOPT_DEVS_CAN_LPC2XXX_EXTENDED_CFG_KEYS +//=========================================================================== +// Add message filter group +//=========================================================================== +static Cyg_ErrNo lpc2xxx_can_config_accfilt_group(can_channel *chan, const void* buf, cyg_uint32* len) +{ + bool res; + cyg_can_filtergroup_cfg *filter_grp = (cyg_can_filtergroup_cfg *)buf; + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; + + + if (*len != sizeof(cyg_can_filtergroup_cfg)) + { + return -EINVAL; + } + + if (filter_grp->lower_id_bound >= filter_grp->upper_id_bound) + { + return -EINVAL; + } + + // + // if the acceptance filter is configured to receive all messages then + // it is not allowed to add single message filter groups because then more + // than one acceptance filter would receive the same CAN id + // + if (info->flags & INFO_FLAG_RX_ALL) + { + return -EPERM; + } + + res = lpc2xxx_can_accfilt_add(info, + filter_grp->lower_id_bound, + filter_grp->upper_id_bound, + filter_grp->ext); + + + return res ? ENOERR : -EPERM; +} +#endif // CYGOPT_DEVS_CAN_LPC2XXX_EXTENDED_CFG_KEYS + + +//=========================================================================== +// Change device configuration +//=========================================================================== +static Cyg_ErrNo lpc2xxx_can_set_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len) +{ + Cyg_ErrNo res = ENOERR; + + switch (key) + { + // + // Setup a new CAN configuration. This will i.e. setup a new baud rate + // + case CYG_IO_SET_CONFIG_CAN_INFO: + { + cyg_can_info_t* config = (cyg_can_info_t*) buf; + if (*len < sizeof(cyg_can_info_t)) + { + return -EINVAL; + } + *len = sizeof(cyg_can_info_t); + if (!lpc2xxx_can_config_channel(chan, config, false)) + { + return -EINVAL; + } + } + break; + +#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + // + // configure message buffers + // + case CYG_IO_SET_CONFIG_CAN_MSGBUF : + { + res = lpc2xxx_can_config_msgbuf(chan, buf, len); + } + break; +#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + +#ifdef CYGOPT_DEVS_CAN_LPC2XXX_EXTENDED_CFG_KEYS + // + // Add message filter group to acceptance filter + // + case CYG_IO_SET_CONFIG_LPC2XXX_ACCFILT_GROUP : + { + return lpc2xxx_can_config_accfilt_group(chan, buf, len); + } + break; +#endif // CYGOPT_DEVS_CAN_LPC2XXX_EXTENDED_CFG_KEYS + + // + // Change CAN state of CAN module + // + case CYG_IO_SET_CONFIG_CAN_MODE : + { + cyg_can_mode *can_mode = (cyg_can_mode*) buf; + + if (*len != sizeof(cyg_can_mode)) + { + return -EINVAL; + } + *len = sizeof(cyg_can_mode); + + // + // decide what to do acording to mode + // + switch (*can_mode) + { + // + // The controller does not support a stopped and standby state so we + // simply enter the low power state here. This state is also safe for + // message buffer configuration + // + case CYGNUM_CAN_MODE_STOP : lpc2xx_enter_reset_mode(chan); break; + case CYGNUM_CAN_MODE_START : lpc2xxx_start_module(chan); break; + case CYGNUM_CAN_MODE_STANDBY : lpc2xxx_enter_lowpower_mode(chan); break; + case CYGNUM_CAN_MODE_CONFIG : lpc2xx_enter_reset_mode(chan); break; + } + } + break; // case CYG_IO_SET_CONFIG_CAN_MODE : + // + // Unknown config key - indicate this by returning -EINVAL + // + default: + return -EINVAL; + } // switch (key) + + return res; +} + + +//=========================================================================== +// Query device configuration +//=========================================================================== +static Cyg_ErrNo lpc2xxx_can_get_config(can_channel *chan, cyg_uint32 key, const void* buf, cyg_uint32* len) +{ + Cyg_ErrNo res = ENOERR; + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; + + switch(key) + { + // + // query state of CAN controller + // + case CYG_IO_GET_CONFIG_CAN_STATE : + { + cyg_can_state *can_state = (cyg_can_state*) buf; + + if (*len != sizeof(cyg_can_state)) + { + return -EINVAL; + } + *len = sizeof(cyg_can_state); + *can_state = lpc2xxx_get_state(info); + } + break; + +#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + // + // Query message box information - returns available and free message + // boxes + // + case CYG_IO_GET_CONFIG_CAN_MSGBUF_INFO : + { + cyg_can_msgbuf_info *mbox_info = (cyg_can_msgbuf_info*) buf; + + if (*len != sizeof(cyg_can_msgbuf_info)) + { + return -EINVAL; + } + cyg_uint32 end_of_table; + *len = sizeof(cyg_can_msgbuf_info); + + HAL_READ_UINT32(CAN_ACCFILT_ENDOFTABLE, end_of_table); + mbox_info->count = LPC2XXX_CAN_MSG_FILTERS_MAX; + mbox_info->free = (ACCFILT_RAM_SIZE - end_of_table) / ACCFILT_COMMON_ENTRY_SIZE; + } + break; +#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + + + // + // Query hardware description of FlexCAN device driver + // + case CYG_IO_GET_CONFIG_CAN_HDI : + { + cyg_can_hdi *hdi = (cyg_can_hdi *)buf; + // + // comes from high level driver so we do not need to + // check buffer size here + // + hdi->support_flags = CYGNUM_CAN_HDI_FRAMETYPE_EXT_ACTIVE + | CYGNUM_CAN_HDI_FULLCAN; + } + break; + + default : + res = -EINVAL; + }// switch(key) + + return res; +} + + +//=========================================================================== +// Send single message +//=========================================================================== +static bool lpc2xxx_can_putmsg(can_channel *chan, CYG_CAN_MSG_T *pmsg, void *pdata) +{ + cyg_uint32 regval; +#ifdef CYGOPT_DEVS_CAN_LPC2XXX_USE_SELF_RECEPTION + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *) chan->dev_priv; +#else + CAN_DECLARE_INFO(info); +#endif + + // + // We use only one single transmit buffer of the three available buffers + // We use buffer 1 (buffer 2 and 3 are unused) + // + // The errata sheet tells the following about the transmit buffers: + // Problem: The Triple Transmit Buffer function cannot be used. + // Work-around: Use any one Transmit buffer only (Use either Transmit Buffer 1, + // Transmit Buffer 2 or Transmit Buffer 3 exclusively). The buffer you decided + // to use should be loaded only when there is no pending transmission. + // + HAL_READ_UINT32(CAN_CTRL_SR(info), regval); + if (!(regval & SR_TX_BUF_WRITE_OK)) + { + return false; + } + + regval = pmsg->dlc << 16; + if (pmsg->rtr) + { + regval |= TFI_DLC_RTR; + } + +#ifdef CYGOPT_IO_CAN_EXT_CAN_ID + if (pmsg->ext) + { + regval |= TFI_DLC_EXT; + } +#endif // #define CYGOPT_IO_CAN_EXT_CAN_ID + HAL_WRITE_UINT32(CAN_CTRL_TFI1(info), regval); // write DLC + HAL_WRITE_UINT32(CAN_CTRL_TID1(info), pmsg->id); // write ID + HAL_WRITE_UINT32(CAN_CTRL_TDA1(info), pmsg->data.dwords[0]); // write first 4 data bytes + HAL_WRITE_UINT32(CAN_CTRL_TDB1(info), pmsg->data.dwords[1]); // write second 4 data bytes + + // + // Request transmission of message + // The errata sheet tells the following about tx request: + // Introduction: The CAN module can lose arbitration to another CAN node during an + // attempt to transmit a CAN message. The message of the CAN node the arbitration was + // lost to is supposed to be received correctly by the CAN module. + // Problem: Messages might not be received correctly if during a CAN Transmission the + // CAN bus arbitration is lost to another CAN node. + // Work-around: Use the Self Reception Request command instead of the Transmission + // Request command. However, it has to be taken into account that now all transmitted + // messages may be received if not prevented by appropriate Acceptance Filter settings. + // (Don't set up Acceptance Filter Message Identifiers for the messages you are + // transmitting yourself.) + // +#ifdef CYGOPT_DEVS_CAN_LPC2XXX_USE_SELF_RECEPTION + // Calc last_tx_id + regval = pmsg->id | (regval & LPC2XXX_CAN_INFO_LAST_TX_ID_FLMASK); + + // Save last message id to next last_tx_id + info->last_tx_index = info->last_tx_index == 0 ? 1 : 0; + info->last_tx_id[info->last_tx_index] = regval; + + // Write self transmission request + HAL_WRITE_UINT32(CAN_CTRL_CMR(info), CMR_SELF_RX_REQ | CMR_SEND_TX_BUF1); +#else + // Write transmission request + HAL_WRITE_UINT32(CAN_CTRL_CMR(info), CMR_TX_REQ | CMR_SEND_TX_BUF1); +#endif + + return true; +} + + +//=========================================================================== +// Read event from device driver +//=========================================================================== +static bool lpc2xxx_can_getevent(can_channel *chan, CYG_CAN_EVENT_T *pevent, void *pdata) +{ + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; + bool res = true; + cyg_uint32 regval; + cyg_uint32 event = *((cyg_uint32*)pdata); + lsc_buf_t data; + + // + // Handle RX event + // + if (event & ICR_RX) + { + cyg_uint32 id; + + pevent->flags |= CYGNUM_CAN_EVENT_RX; + HAL_READ_UINT32(CAN_CTRL_RFS(info), regval); + HAL_READ_UINT32(CAN_CTRL_RID(info), id); + +#ifdef CYGOPT_IO_CAN_EXT_CAN_ID + if (regval & RFS_EXT) + { + pevent->msg.ext = CYGNUM_CAN_ID_EXT; + pevent->msg.id = id & 0x1FFFFFFF; + } + else +#endif // #define CYGOPT_IO_CAN_EXT_CAN_ID + { +#ifdef CYGOPT_IO_CAN_STD_CAN_ID + pevent->msg.ext = CYGNUM_CAN_ID_STD; + pevent->msg.id = id & 0x7FF; +#endif // #ifdef CYGOPT_IO_CAN_STD_CAN_ID + } // if (regval & RFS_EXT) + + if (regval & RFS_RTR) + { + pevent->msg.rtr = CYGNUM_CAN_FRAME_RTR; + } + else + { + pevent->msg.rtr = CYGNUM_CAN_FRAME_DATA; + HAL_READ_UINT32(CAN_CTRL_RDA(info), pevent->msg.data.dwords[0]); + HAL_READ_UINT32(CAN_CTRL_RDB(info), pevent->msg.data.dwords[1]); + } //if (regval & RFS_RTR) + pevent->msg.dlc = RFS_GET_DLC(regval); + + // + // Now check if an data overrun occured - a message was lost because the + // preceeding message to this CAN controller was not read and released + // quickly enough. After reading the status we clear the overrun bit + // + HAL_READ_UINT32(CAN_CTRL_GSR(info), regval); + if (regval & GSR_DATA_OVR) + { + pevent->flags |= CYGNUM_CAN_EVENT_OVERRUN_RX; + HAL_WRITE_UINT32(CAN_CTRL_CMR(info), CMR_CLEAR_DATA_OVR); + } + } + + // + // Handle TX events + // + if (event & ICR_TX1) + { + } + + // + // Handle all other events + // + if (event & (CAN_MISC_INT | ICR_LUT_ERR)) + { + HAL_READ_UINT32(CAN_CTRL_GSR(info), data.dword); + + // + // 1: Error Warning Interrupt -- this bit is set on every change (set or clear) of the Error + // Status or Bus Status bit in CANSR, if the EIE bit in CAN is 1 at the time of the + // change. + // + if (event & ICR_ERR_WARN) + { + // + // If one of the warning counters is above 96 then the controller is in bus warning + // state. If both counters are below 96 the this interrupt indicates that the + // controller has left the bus warning state and is error active again + // + if (data.bytes[2] >= 96) + { + pevent->flags |= CYGNUM_CAN_EVENT_WARNING_RX; + info->state = CYGNUM_CAN_STATE_BUS_WARN; + } + else if (data.bytes[3] >= 96) + { + pevent->flags |= CYGNUM_CAN_EVENT_WARNING_TX; + info->state = CYGNUM_CAN_STATE_BUS_WARN; + } + else + { + info->state = CYGNUM_CAN_STATE_ACTIVE; + } + LPC2XXX_DBG_PRINT("ICR_ERR_WARN (%p)\n", (void*) chan); + } + + // + // 1: Wake-Up Interrupt: this bit is set if the CAN controller is sleeping and bus activity + // is detected, if the WUIE bit in CANIE is 1. + // + if (event & ICR_WAKE_UP) + { + pevent->flags |= CYGNUM_CAN_EVENT_LEAVING_STANDBY; + info->state = CYGNUM_CAN_STATE_ACTIVE; + LPC2XXX_DBG_PRINT("ICR_WAKE_UP (%p)\n", (void*) chan); + } + + // + // Error Passive Interrupt -- this bit is set if the EPIE bit in CANIE is 1, and the CAN + // controller switches between Error Passive and Error Active mode in either + // direction. We have to check if the ERR bit is set in global status register. + // If it is set, then it is a switch to error passive else it is a switch to + // error active state + // + if (event & ICR_ERR_PASSIVE) + { + if (data.dword & GSR_ERR) + { + pevent->flags |= CYGNUM_CAN_EVENT_ERR_PASSIVE; + info->state = CYGNUM_CAN_STATE_ERR_PASSIVE; + } + else + { + info->state = CYGNUM_CAN_STATE_ACTIVE; + } + LPC2XXX_DBG_PRINT("ICR_ERR_PASSIVE (%p)\n", (void*) chan); + } + + // + // Arbitration Lost Interrupt -- this bit is set if the ALIE bit in CANIE is 1, and the + // CAN controller loses arbitration while attempting to transmit. + // + if (event & ICR_ARBITR_LOST) + { + pevent->flags |= CYGNUM_CAN_EVENT_ARBITRATION_LOST; + LPC2XXX_DBG_PRINT("ICR_ARBITR_LOST (%p)\n", (void*) chan); + } + + // + // 1: Bus Error Interrupt -- this bit is set if the BEIE bit in CANIE is 1, and the CAN + // controller detects an error on the bus. + // + if (event & ICR_BUS_ERR) + { + pevent->flags |= CYGNUM_CAN_EVENT_BUS_OFF; + LPC2XXX_DBG_PRINT("ICR_BUS_ERR (%p)\n", (void*) chan); + } + +#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + // + // LUT error interrupt -- this bit is set if bit 0 in LUTerr is 1 and LUTerrAd + // points to entry in filter table for this CAN controller + // + if(event & ICR_LUT_ERR) + { + pevent->flags |= CYGNUM_CAN_EVENT_FILTER_ERR; + LPC2XXX_DBG_PRINT("ICR_LUT_ERR (%p)\n", (void*) chan); + } +#endif + + } // if (event & (CAN_MISC_INT | ICR_LUT_ERR)) + + return res; +} + + +//=========================================================================== +// Kick transmitter +//=========================================================================== +static void lpc2xxx_can_start_xmit(can_channel* chan) +{ + cyg_uint32 regval; + CAN_DECLARE_INFO(chan); + + LPC2XXX_DBG_PRINT("start_xmit (%p)\n", (void*) chan); + + cyg_drv_dsr_lock(); + HAL_READ_UINT32(CAN_CTRL_IER(info), regval); + regval |= IER_TX1; // enable tx interrupt for tx buf 1 + HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); + cyg_drv_dsr_unlock(); + + // + // kick transmitter + // + chan->callbacks->xmt_msg(chan, 0); // Kick transmitter (if necessary) +} + + +//=========================================================================== +// Stop transmitter +//=========================================================================== +static void lpc2xxx_can_stop_xmit(can_channel* chan) +{ + cyg_uint32 regval; + CAN_DECLARE_INFO(chan); + + LPC2XXX_DBG_PRINT("stop_xmit (%p)\n", (void*) chan); + + cyg_drv_dsr_lock(); + HAL_READ_UINT32(CAN_CTRL_IER(info), regval); + regval &= ~IER_TX1; // disable tx interrupt for tx buf 1 + HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); + cyg_drv_dsr_unlock(); +} + + +//=========================================================================== +// Low level transmit interrupt handler +//=========================================================================== +static cyg_uint32 lpc2xxx_can_tx_ISR(cyg_vector_t vector, cyg_addrword_t data) +{ + can_channel *chan = (can_channel *)data; + cyg_uint32 regval; + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; + + // + // The ISR only disables and acknowledges the TX interrupt + // any further processing is done by DSR + // + HAL_READ_UINT32(CAN_CTRL_IER(info), regval); + regval &= ~IER_TX1; // disable tx interrupt for tx buf 1 + HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); + + // + // Now read iput capture register - this clears all interrupt bits in this + // register and also acknowledges the interrupt. We then store the ICR value into + // the icr buffer in the channel info data + // + HAL_READ_UINT32(CAN_CTRL_ICR(info), regval); + info->icr |= (regval &~ ICR_RX); // do not handle RX events - this is done by RX ISR + cyg_drv_interrupt_acknowledge(vector); + LPC2XXX_DBG_PRINT("tx_ISR (%p)\n", (void*) data); + return CYG_ISR_CALL_DSR; +} + + +//=========================================================================== +// High level transmit interrupt handler +//=========================================================================== +static void lpc2xxx_can_tx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + can_channel *chan = (can_channel *)data; + cyg_uint32 regval; + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; + + // + // now receive the event - the events are stored in ICR field of CAN info + // we need to disable ISRs here because the ICR field will be accessed from + // several ISRs (TX ISR and global error ISR) + // + cyg_drv_isr_lock(); // disable ISR s + regval = info->icr; // read the event field + info->icr = 0; // clear the event fields - all events processed in getevent() + cyg_drv_isr_unlock(); // renable ISRs + +#ifdef CYGOPT_IO_CAN_TX_EVENT_SUPPORT + if (regval & (ICR_TX1 & CAN_MISC_INT)) +#else + if (regval & CAN_MISC_INT) +#endif + { + // + // Now receive the events - pass the event field to the getevent function + // + chan->callbacks->rcv_event(chan, ®val); + } + + // + // Now transmit next message and reenable interrupts + // + chan->callbacks->xmt_msg(chan, 0); // send next message + HAL_READ_UINT32(CAN_CTRL_IER(info), regval); + regval |= IER_TX1; // reenable interrupts for the message box that caused the DSR to run + HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); + + LPC2XXX_DBG_PRINT("tx_DSR (%p)\n", (void*) data); +} + + +//=========================================================================== +// Low level receive interrupt handler +//=========================================================================== +static cyg_uint32 lpc2xxx_can_rx_ISR(cyg_vector_t vector, cyg_addrword_t data) +{ + cyg_uint32 regval; + CAN_DECLARE_CHAN(data); // declares chan pointer if required + +#ifdef CYGOPT_DEVS_CAN_LPC2XXX_USE_SELF_RECEPTION + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *) chan->dev_priv; + cyg_uint32 id; + cyg_uint32 index; + + // We have to reject self tx message, so read message id + HAL_READ_UINT32(CAN_CTRL_RID(info), id); + HAL_READ_UINT32(CAN_CTRL_RFS(info), regval); + id |= (regval & LPC2XXX_CAN_INFO_LAST_TX_ID_FLMASK); + + // Test message id + for(index = 0; index < 2; index++) + { + if(id == info->last_tx_id[index]) + { + // Clear last_tx_id + info->last_tx_id[index] = LPC2XXX_CAN_INFO_LAST_TX_ID_NOVALID; + + // Clear receive buffer + HAL_WRITE_UINT32(CAN_CTRL_CMR(info), CMR_RX_RELEASE_BUF); + + // Exit without calling DSR + LPC2XXX_DBG_PRINT("self_rx_ISR (%p)\n", (void*) data); + return CYG_ISR_HANDLED; + } + } +#else + CAN_DECLARE_INFO(info); // declares info pointer if reuired +#endif + + // + // The ISR only disables and acknowledges the RX interrupt + // any further processing is done by DSR + // + HAL_READ_UINT32(CAN_CTRL_IER(info), regval); + regval &= ~IER_RX; // disable rx interrupt for rx buf 1 + HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); + cyg_drv_interrupt_acknowledge(vector); + LPC2XXX_DBG_PRINT("rx_ISR (%p)\n", (void*) data); + + return CYG_ISR_CALL_DSR; +} + + +//=========================================================================== +// High level receive interrupt handler +//=========================================================================== +static void lpc2xxx_can_rx_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + can_channel *chan = (can_channel *)data; + cyg_uint32 regval; + CAN_DECLARE_INFO(chan); + + // + // Read the event, release the receive buffer and then reenable the + // receive interrupt for next message + // + regval = ICR_RX; // indicate RX event to getevent() function + chan->callbacks->rcv_event(chan, ®val); + HAL_WRITE_UINT32(CAN_CTRL_CMR(info), CMR_RX_RELEASE_BUF); + HAL_READ_UINT32(CAN_CTRL_IER(info), regval); + regval |= IER_RX; + HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); + + LPC2XXX_DBG_PRINT("rx_DSR (%p)\n", (void*) data); +} + + +//=========================================================================== +// Err ISR handler +//=========================================================================== +static cyg_uint32 lpc2xxx_can_err_ISR(cyg_vector_t vector, cyg_addrword_t data) +{ + cyg_uint8 i = 0; +#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + // If we use acceptance filter we can get LUT error + cyg_uint32 luterr; + cyg_uint8 luterr_chan0 = 0; // Init to avoid warnings + cyg_uint8 luterr_chan1 = 0; // Init to avoid warnings + + // Read LUT error flag + HAL_READ_UINT32(CAN_ACCFILT_LUT_ERR, luterr); + + if (luterr & 1) + { + cyg_uint32 lutaddr; + cyg_uint32 eff_sa; + lsc_buf_t errentry; + + // Read address of failed entry (it clears interrupt flag) + HAL_READ_UINT32(CAN_ACCFILT_LUT_ERR_ADDR, lutaddr); + + // Read address of extended id individual table + HAL_READ_UINT32(CAN_ACCFILT_EFF_SA, eff_sa); + + // Read error entry + HAL_READ_UINT32(CAN_ACCFILT_RAM_BASE + lutaddr, errentry.dword); + + // If errentry from standard id tables then read two controllers numbers + if(lutaddr < eff_sa) + { + // Calc CAN controllers numbers + luterr_chan0 = (cyg_uint8) ACCFILT_STD_GET_CTRL_UPPER(errentry.dword); + + if(errentry.column.lower & ACCFILT_STD_DIS) + { + luterr_chan1 = luterr_chan0; + } + else + { + luterr_chan1 = (cyg_uint8) ACCFILT_STD_GET_CTRL_LOWER(errentry.dword); + } + } + else + { + // Calc CAN controller number + luterr_chan0 = luterr_chan1 = (cyg_uint8) ACCFILT_EXT_GET_CTRL(errentry.dword); + } + } +#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + + while (lpc2xxx_global_can_info.active_channels[i]) + { + cyg_uint32 regval; + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)lpc2xxx_global_can_info.active_channels[i++]->dev_priv; + + HAL_READ_UINT32(CAN_CTRL_IER(info), regval); + regval &= ~CAN_MISC_INT; // disable all interrupt sources that may cause this int + HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); + HAL_READ_UINT32(CAN_CTRL_ICR(info), regval); + info->icr |= (regval &~ ICR_RX); // do not handle RX intrupts - this is done by RX isr + +#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + // Set ICR_LUT_ERR flag only for controller which cause LUT error + if ((luterr & 1) && ((luterr_chan0 == i) || (luterr_chan1 == i))) + { + info->icr |= ICR_LUT_ERR; + } +#endif + } // while (lpc2xxx_global_can_info.active_channels[i]) + + cyg_drv_interrupt_acknowledge(vector); + LPC2XXX_DBG_PRINT("err_ISR\n"); + return CYG_ISR_CALL_DSR; +} + +//=========================================================================== +// Err ISR handler +//=========================================================================== +static void lpc2xxx_can_err_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data) +{ + cyg_uint8 i = 0; + + while (lpc2xxx_global_can_info.active_channels[i]) + { + cyg_uint32 regval; + can_channel *chan = (can_channel *)lpc2xxx_global_can_info.active_channels[i++]; + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; + + // + // now receive the event - the events are stored in ICR field of CAN info + // + cyg_drv_isr_lock(); // disable ISR s + regval = info->icr; // read the event field + info->icr = 0; // clear the event fields - all events processed in getevent() + cyg_drv_isr_unlock(); // renable ISRs + +#ifdef CYGOPT_IO_CAN_TX_EVENT_SUPPORT + if (regval & (ICR_TX1 | CAN_MISC_INT | ICR_LUT_ERR)) +#else + if (regval & (CAN_MISC_INT | ICR_LUT_ERR)) +#endif + { + chan->callbacks->rcv_event(chan, ®val); + } + // + // Now reenable interrupts + // + HAL_READ_UINT32(CAN_CTRL_IER(info), regval); + regval |= CAN_MISC_INT; // reenable interrupts + HAL_WRITE_UINT32(CAN_CTRL_IER(info), regval); + } // while (lpc2xxx_global_can_info.active_channels[i]) + + LPC2XXX_DBG_PRINT("err_DSR\n"); +} + + +#ifdef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG +//=========================================================================== +// Configure message boxes for reception of any CAN message +//=========================================================================== +static void lpc2xxx_can_config_rx_all(can_channel *chan) +{ + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; + // + // First clear all acceptance filter entries and then insert the + // two RX all groups + // + lpc2xxx_can_config_rx_none(chan); +#ifdef CYGOPT_IO_CAN_STD_CAN_ID + lpc2xxx_can_accfilt_add(info, 0x000, 0x7FF, CYGNUM_CAN_ID_STD); +#endif // CYGOPT_IO_CAN_STD_CAN_ID +#ifdef CYGOPT_IO_CAN_EXT_CAN_ID + lpc2xxx_can_accfilt_add(info, 0x000, 0x1FFFFFFF, CYGNUM_CAN_ID_EXT); +#endif // CYGOPT_IO_CAN_EXT_CAN_ID + + info->flags |= INFO_FLAG_RX_ALL; +#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG + lpc2xxx_can_accfilt_dbg_dump(); +#endif // CYGDBG_DEVS_CAN_LPC2XXX_DEBUG +} +#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + + +#ifndef CYGOPT_IO_CAN_RUNTIME_MBOX_CFG +//=========================================================================== +// Configure message boxes for reception of any CAN message +//=========================================================================== +static void lpc2xxx_can_config_rx_all(can_channel *chan) +{ + lpc2xxx_can_info_t *info = (lpc2xxx_can_info_t *)chan->dev_priv; + + lpc2xxx_can_accfilt_simple_rx_all(); + info->flags |= INFO_FLAG_RX_ALL; + +#ifdef CYGDBG_DEVS_CAN_LPC2XXX_DEBUG + lpc2xxx_can_accfilt_dbg_dump(); +#endif // CYGDBG_DEVS_CAN_LPC2XXX_DEBUG +} +#endif // CYGOPT_IO_CAN_RUNTIME_MBOX_CFG + + +//--------------------------------------------------------------------------- +// EOF can_lpc2xxx.c
--- a/packages/devs/can/arm/lpc2xxx/current/tests/can_test_aux.inl +++ b/packages/devs/can/arm/lpc2xxx/current/tests/can_test_aux.inl @@ -1,148 +1,148 @@ -//========================================================================== -// -// can_test_aux.inl -// -// CAN test auxiliary functions -// -//========================================================================== -//####ECOSGPLCOPYRIGHTBEGIN#### -// ------------------------------------------- -// This file is part of eCos, the Embedded Configurable Operating System. -// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. -// -// eCos is free software; you can redistribute it and/or modify it under -// the terms of the GNU General Public License as published by the Free -// Software Foundation; either version 2 or (at your option) any later version. -// -// eCos is distributed in the hope that it will be useful, but WITHOUT ANY -// WARRANTY; without even the implied warranty of MERCHANTABILITY or -// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -// for more details. -// -// You should have received a copy of the GNU General Public License along -// with eCos; if not, write to the Free Software Foundation, Inc., -// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. -// -// As a special exception, if other files instantiate templates or use macros -// or inline functions from this file, or you compile this file and link it -// with other works to produce a work based on this file, this file does not -// by itself cause the resulting work to be covered by the GNU General Public -// License. However the source code for this file must still be made available -// in accordance with section (3) of the GNU General Public License. -// -// This exception does not invalidate any other reasons why a work based on -// this file might be covered by the GNU General Public License. -// -// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. -// at http://sources.redhat.com/ecos/ecos-license/ -// ------------------------------------------- -//####ECOSGPLCOPYRIGHTEND#### -//========================================================================== -//#####DESCRIPTIONBEGIN#### -// -// Author(s): Uwe Kindler -// Contributors: Uwe Kindler -// Date: 2005-08-07 -// Description: Auxiliary functions for CAN driver tests -//####DESCRIPTIONEND#### - - -//=========================================================================== -// PRINT CAN EVENT -//=========================================================================== -void print_can_msg(cyg_can_message *pmsg, char *pMsg) -{ - char *pmsg_str; - static char* msg_tbl[] = - { - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:]\n", - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X]\n", - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X]\n", - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X]\n", - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X]\n", - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X %02X]\n", - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X %02X %02X]\n", - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X %02X %02X %02X]\n", - "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X %02X %02X %02X %02X]\n" - }; - - if (pmsg->rtr) - { - diag_printf("%s [ID:%03X] [RTR:%d] [EXT:%d] [DLC:%d]\n", - pMsg, - pmsg->id, - pmsg->rtr, - pmsg->ext, - pmsg->dlc); - - return; - } - - if (pmsg->dlc > 8) - { - pmsg_str = msg_tbl[8]; - } - else - { - pmsg_str = msg_tbl[pmsg->dlc]; - } - - diag_printf(pmsg_str, - pMsg, - pmsg->id, - pmsg->rtr, - pmsg->ext, - pmsg->data.bytes[0], - pmsg->data.bytes[1], - pmsg->data.bytes[2], - pmsg->data.bytes[3], - pmsg->data.bytes[4], - pmsg->data.bytes[5], - pmsg->data.bytes[6], - pmsg->data.bytes[7]); -} - - -//=========================================================================== -// PRINT CAN EVENT FLAGS -//=========================================================================== -void print_can_flags(cyg_uint16 flags, char *pMsg) -{ - char *pmsg_str; - cyg_uint8 i ; - static char* msg_tbl[] = - { - "RX ", - "TX ", - "WRX ", - "WTX ", - "ERRP ", - "BOFF ", - "OVRX ", - "OVTX ", - "CERR ", - "LSTY ", - "ESTY ", - "ALOS ", - "DEVC ", - "PHYF ", - "PHYH ", - "PHYL " - }; - i = 0; - while (flags && (i < 16)) - { - if (flags & 0x0001) - { - pmsg_str = msg_tbl[i]; - diag_printf(pmsg_str); - } - flags >>=1; - i++; - } - - diag_printf("\n"); -} - -//--------------------------------------------------------------------------- -// end of can_test_aux.inl +//========================================================================== +// +// can_test_aux.inl +// +// CAN test auxiliary functions +// +//========================================================================== +//####ECOSGPLCOPYRIGHTBEGIN#### +// ------------------------------------------- +// This file is part of eCos, the Embedded Configurable Operating System. +// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. +// +// eCos is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 2 or (at your option) any later version. +// +// eCos is distributed in the hope that it will be useful, but WITHOUT ANY +// WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +// for more details. +// +// You should have received a copy of the GNU General Public License along +// with eCos; if not, write to the Free Software Foundation, Inc., +// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. +// +// As a special exception, if other files instantiate templates or use macros +// or inline functions from this file, or you compile this file and link it +// with other works to produce a work based on this file, this file does not +// by itself cause the resulting work to be covered by the GNU General Public +// License. However the source code for this file must still be made available +// in accordance with section (3) of the GNU General Public License. +// +// This exception does not invalidate any other reasons why a work based on +// this file might be covered by the GNU General Public License. +// +// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc. +// at http://sources.redhat.com/ecos/ecos-license/ +// ------------------------------------------- +//####ECOSGPLCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): Uwe Kindler +// Contributors: Uwe Kindler +// Date: 2005-08-07 +// Description: Auxiliary functions for CAN driver tests +//####DESCRIPTIONEND#### + + +//=========================================================================== +// PRINT CAN EVENT +//=========================================================================== +void print_can_msg(cyg_can_message *pmsg, char *pMsg) +{ + char *pmsg_str; + static char* msg_tbl[] = + { + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:]\n", + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X]\n", + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X]\n", + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X]\n", + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X]\n", + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X %02X]\n", + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X %02X %02X]\n", + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X %02X %02X %02X]\n", + "%s [ID:%03X] [RTR:%d] [EXT:%d] [DATA:%02X %02X %02X %02X %02X %02X %02X %02X]\n" + }; + + if (pmsg->rtr) + { + diag_printf("%s [ID:%03X] [RTR:%d] [EXT:%d] [DLC:%d]\n", + pMsg, + pmsg->id, + pmsg->rtr, + pmsg->ext, + pmsg->dlc); + + return; + } + + if (pmsg->dlc > 8) + { + pmsg_str = msg_tbl[8]; + } + else + { + pmsg_str = msg_tbl[pmsg->dlc]; + } + + diag_printf(pmsg_str, + pMsg, + pmsg->id, + pmsg->rtr, + pmsg->ext, + pmsg->data.bytes[0], + pmsg->data.bytes[1], + pmsg->data.bytes[2], + pmsg->data.bytes[3], + pmsg->data.bytes[4], + pmsg->data.bytes[5], + pmsg->data.bytes[6], + pmsg->data.bytes[7]); +} + + +//=========================================================================== +// PRINT CAN EVENT FLAGS +//=========================================================================== +void print_can_flags(cyg_uint16 flags, char *pMsg) +{ + char *pmsg_str; + cyg_uint8 i ; + static char* msg_tbl[] = + { + "RX ", + "TX ", + "WRX ", + "WTX ", + "ERRP ", + "BOFF ", + "OVRX ", + "OVTX ", + "CERR ", + "LSTY ", + "ESTY ", + "ALOS ", + "DEVC ", + "PHYF ", + "PHYH ", + "PHYL " + }; + i = 0; + while (flags && (i < 16)) + { + if (flags & 0x0001) + { + pmsg_str = msg_tbl[i]; + diag_printf(pmsg_str); + } + flags >>=1; + i++; + } + + diag_printf("\n"); +} + +//--------------------------------------------------------------------------- +// end of can_test_aux.inl
