From 485f0ebd402c1e354a80d0aad0abccb3671a8a2b Mon Sep 17 00:00:00 2001 From: Alexander Vasiljev Date: Wed, 15 Nov 2017 07:48:39 -0600 Subject: [PATCH] arch/arm/src/lpc43: Add LPC43xx CAN driver --- arch/arm/src/lpc43xx/Kconfig | 6 +- arch/arm/src/lpc43xx/Make.defs | 8 + .../lpc43xx/chip/lpc4337jet100_pinconfig.h | 11 +- arch/arm/src/lpc43xx/chip/lpc43_can.h | 90 +- arch/arm/src/lpc43xx/lpc43_can.c | 1279 +++++++++++++++++ arch/arm/src/lpc43xx/lpc43_can.h | 85 ++ 6 files changed, 1426 insertions(+), 53 deletions(-) create mode 100644 arch/arm/src/lpc43xx/lpc43_can.c create mode 100644 arch/arm/src/lpc43xx/lpc43_can.h diff --git a/arch/arm/src/lpc43xx/Kconfig b/arch/arm/src/lpc43xx/Kconfig index db16b30626..eb96dbf8f0 100644 --- a/arch/arm/src/lpc43xx/Kconfig +++ b/arch/arm/src/lpc43xx/Kconfig @@ -172,11 +172,11 @@ config LPC43_ATIMER bool "Alarm timer" default n -config LPC43_CAN1 - bool "C_CAN1" +config LPC43_CAN0 + bool "C_CAN0" default n -config LPC43_CAN2 +config LPC43_CAN1 bool "C_CAN1" default n diff --git a/arch/arm/src/lpc43xx/Make.defs b/arch/arm/src/lpc43xx/Make.defs index d68a19635b..4d3df8d3a0 100644 --- a/arch/arm/src/lpc43xx/Make.defs +++ b/arch/arm/src/lpc43xx/Make.defs @@ -160,6 +160,14 @@ CHIP_CSRCS += lpc43_i2c.c endif endif +ifeq ($(CONFIG_LPC43_CAN0),y) +CHIP_CSRCS += lpc43_can.c +else +ifeq ($(CONFIG_LPC43_CAN1),y) +CHIP_CSRCS += lpc43_can.c +endif +endif + ifeq ($(CONFIG_LPC43_ADC0),y) CHIP_CSRCS += lpc43_adc.c else diff --git a/arch/arm/src/lpc43xx/chip/lpc4337jet100_pinconfig.h b/arch/arm/src/lpc43xx/chip/lpc4337jet100_pinconfig.h index 38a951e5e6..2f1312fc07 100644 --- a/arch/arm/src/lpc43xx/chip/lpc4337jet100_pinconfig.h +++ b/arch/arm/src/lpc43xx/chip/lpc4337jet100_pinconfig.h @@ -41,6 +41,7 @@ ****************************************************************************************************/ #include +#include "lpc43_pinconfig.h" /**************************************************************************************************** * Pre-processor Definitions @@ -89,14 +90,14 @@ #define PINCONF_ADCTRIG1_1 (PINCONF_FUNC2|PINCONF_PINSE|PINCONF_PIN_3) #define PINCONF_ADCTRIG1_2 (PINCONF_FUNC3|PINCONF_PINS2|PINCONF_PIN_5) -#define PINCONF_CAN0_RD_1 (PINCONF_FUNC1|PINCONF_PINSE|PINCONF_PIN_2) -#define PINCONF_CAN0_RD_2 (PINCONF_FUNC2|PINCONF_PINS3|PINCONF_PIN_1) +#define PINCONF_CAN0_RD_1 (PINCONF_FUNC1|PINCONF_INBUFFER|PINCONF_PINSE|PINCONF_PIN_2) +#define PINCONF_CAN0_RD_2 (PINCONF_FUNC2|PINCONF_INBUFFER|PINCONF_PINS3|PINCONF_PIN_1) #define PINCONF_CAN0_TD_1 (PINCONF_FUNC1|PINCONF_PINSE|PINCONF_PIN_3) #define PINCONF_CAN0_TD_2 (PINCONF_FUNC2|PINCONF_PINS3|PINCONF_PIN_2) -#define PINCONF_CAN1_RD_1 (PINCONF_FUNC5|PINCONF_PINS1|PINCONF_PIN_18) -#define PINCONF_CAN1_RD_2 (PINCONF_FUNC5|PINCONF_PINSE|PINCONF_PIN_1) -#define PINCONF_CAN1_RD_3 (PINCONF_FUNC6|PINCONF_PINS4|PINCONF_PIN_9) +#define PINCONF_CAN1_RD_1 (PINCONF_FUNC5|PINCONF_INBUFFER|PINCONF_PINS1|PINCONF_PIN_18) +#define PINCONF_CAN1_RD_2 (PINCONF_FUNC5|PINCONF_INBUFFER|PINCONF_PINSE|PINCONF_PIN_1) +#define PINCONF_CAN1_RD_3 (PINCONF_FUNC6|PINCONF_INBUFFER|PINCONF_PINS4|PINCONF_PIN_9) #define PINCONF_CAN1_TD_1 (PINCONF_FUNC5|PINCONF_PINS1|PINCONF_PIN_17) #define PINCONF_CAN1_TD_2 (PINCONF_FUNC5|PINCONF_PINSE|PINCONF_PIN_0) #define PINCONF_CAN1_TD_3 (PINCONF_FUNC6|PINCONF_PINS4|PINCONF_PIN_8) diff --git a/arch/arm/src/lpc43xx/chip/lpc43_can.h b/arch/arm/src/lpc43xx/chip/lpc43_can.h index cebeaccd8c..c03ceab04b 100644 --- a/arch/arm/src/lpc43xx/chip/lpc43_can.h +++ b/arch/arm/src/lpc43xx/chip/lpc43_can.h @@ -93,6 +93,50 @@ /* Register Addresses ***************************************************************/ +#define LPC43_CAN0_CNTL (LPC43_CAN0_BASE+LPC43_CAN_CNTL_OFFSET) +#define LPC43_CAN0_STAT (LPC43_CAN0_BASE+LPC43_CAN_STAT_OFFSET) +#define LPC43_CAN0_EC (LPC43_CAN0_BASE+LPC43_CAN_EC_OFFSET) +#define LPC43_CAN0_BT (LPC43_CAN0_BASE+LPC43_CAN_BT_OFFSET) +#define LPC43_CAN0_INT (LPC43_CAN0_BASE+LPC43_CAN_INT_OFFSET) +#define LPC43_CAN0_TEST (LPC43_CAN0_BASE+LPC43_CAN_TEST_OFFSET) +#define LPC43_CAN0_BRPE (LPC43_CAN0_BASE+LPC43_CAN_BRPE_OFFSET) + +#define LPC43_CAN0_IF1_CMDREQ (LPC43_CAN0_BASE+LPC43_CAN_IF1_CMDREQ_OFFSET) +#define LPC43_CAN0_IF1_CMDMSKW (LPC43_CAN0_BASE+LPC43_CAN_IF1_CMDMSKW_OFFSET) +#define LPC43_CAN0_IF1_CMDMSKR (LPC43_CAN0_BASE+LPC43_CAN_IF1_CMDMSKR_OFFSET) +#define LPC43_CAN0_IF1_MSK1 (LPC43_CAN0_BASE+LPC43_CAN_IF1_MSK1_OFFSET) +#define LPC43_CAN0_IF1_MSK2 (LPC43_CAN0_BASE+LPC43_CAN_IF1_MSK2_OFFSET) +#define LPC43_CAN0_IF1_ARB1 (LPC43_CAN0_BASE+LPC43_CAN_IF1_ARB1_OFFSET) +#define LPC43_CAN0_IF1_ARB2 (LPC43_CAN0_BASE+LPC43_CAN_IF1_ARB2_OFFSET) +#define LPC43_CAN0_IF1_MCTRL (LPC43_CAN0_BASE+LPC43_CAN_IF1_MCTRL_OFFSET) +#define LPC43_CAN0_IF1_DA1 (LPC43_CAN0_BASE+LPC43_CAN_IF1_DA1_OFFSET) +#define LPC43_CAN0_IF1_DA2 (LPC43_CAN0_BASE+LPC43_CAN_IF1_DA2_OFFSET) +#define LPC43_CAN0_IF1_DB1 (LPC43_CAN0_BASE+LPC43_CAN_IF1_DB1_OFFSET) +#define LPC43_CAN0_IF1_DB2 (LPC43_CAN0_BASE+LPC43_CAN_IF1_DB2_OFFSET) + +#define LPC43_CAN0_IF2_CMDREQ (LPC43_CAN0_BASE+LPC43_CAN_IF2_CMDREQ_OFFSET) +#define LPC43_CAN0_IF2_CMDMSKW (LPC43_CAN0_BASE+LPC43_CAN_IF2_CMDMSKW_OFFSET) +#define LPC43_CAN0_IF2_CMDMSKR (LPC43_CAN0_BASE+LPC43_CAN_IF2_CMDMSKR_OFFSET) +#define LPC43_CAN0_IF2_MSK1 (LPC43_CAN0_BASE+LPC43_CAN_IF2_MSK1_OFFSET) +#define LPC43_CAN0_IF2_MSK2 (LPC43_CAN0_BASE+LPC43_CAN_IF2_MSK2_OFFSET) +#define LPC43_CAN0_IF2_ARB1 (LPC43_CAN0_BASE+LPC43_CAN_IF2_ARB1_OFFSET) +#define LPC43_CAN0_IF2_ARB2 (LPC43_CAN0_BASE+LPC43_CAN_IF2_ARB2_OFFSET) +#define LPC43_CAN0_IF2_MCTRL (LPC43_CAN0_BASE+LPC43_CAN_IF2_MCTRL_OFFSET) +#define LPC43_CAN0_IF2_DA1 (LPC43_CAN0_BASE+LPC43_CAN_IF2_DA1_OFFSET) +#define LPC43_CAN0_IF2_DA2 (LPC43_CAN0_BASE+LPC43_CAN_IF2_DA2_OFFSET) +#define LPC43_CAN0_IF2_DB1 (LPC43_CAN0_BASE+LPC43_CAN_IF2_DB1_OFFSET) +#define LPC43_CAN0_IF2_DB2 (LPC43_CAN0_BASE+LPC43_CAN_IF2_DB2_OFFSET) + +#define LPC43_CAN0_TXREQ1 (LPC43_CAN0_BASE+LPC43_CAN_TXREQ1_OFFSET) +#define LPC43_CAN0_TXREQ2 (LPC43_CAN0_BASE+LPC43_CAN_TXREQ2_OFFSET) +#define LPC43_CAN0_ND1 (LPC43_CAN0_BASE+LPC43_CAN_ND1_OFFSET) +#define LPC43_CAN0_ND2 (LPC43_CAN0_BASE+LPC43_CAN_ND2_OFFSET) +#define LPC43_CAN0_IR1 (LPC43_CAN0_BASE+LPC43_CAN_IR1_OFFSET) +#define LPC43_CAN0_IR2 (LPC43_CAN0_BASE+LPC43_CAN_IR2_OFFSET) +#define LPC43_CAN0_MSGV1 (LPC43_CAN0_BASE+LPC43_CAN_MSGV1_OFFSET) +#define LPC43_CAN0_MSGV2 (LPC43_CAN0_BASE+LPC43_CAN_MSGV2_OFFSET) +#define LPC43_CAN0_CLKDIV (LPC43_CAN0_BASE+LPC43_CAN_CLKDIV_OFFSET) + #define LPC43_CAN1_CNTL (LPC43_CAN1_BASE+LPC43_CAN_CNTL_OFFSET) #define LPC43_CAN1_STAT (LPC43_CAN1_BASE+LPC43_CAN_STAT_OFFSET) #define LPC43_CAN1_EC (LPC43_CAN1_BASE+LPC43_CAN_EC_OFFSET) @@ -137,50 +181,6 @@ #define LPC43_CAN1_MSGV2 (LPC43_CAN1_BASE+LPC43_CAN_MSGV2_OFFSET) #define LPC43_CAN1_CLKDIV (LPC43_CAN1_BASE+LPC43_CAN_CLKDIV_OFFSET) -#define LPC43_CAN2_CNTL (LPC43_CAN2_BASE+LPC43_CAN_CNTL_OFFSET) -#define LPC43_CAN2_STAT (LPC43_CAN2_BASE+LPC43_CAN_STAT_OFFSET) -#define LPC43_CAN2_EC (LPC43_CAN2_BASE+LPC43_CAN_EC_OFFSET) -#define LPC43_CAN2_BT (LPC43_CAN2_BASE+LPC43_CAN_BT_OFFSET) -#define LPC43_CAN2_INT (LPC43_CAN2_BASE+LPC43_CAN_INT_OFFSET) -#define LPC43_CAN2_TEST (LPC43_CAN2_BASE+LPC43_CAN_TEST_OFFSET) -#define LPC43_CAN2_BRPE (LPC43_CAN2_BASE+LPC43_CAN_BRPE_OFFSET) - -#define LPC43_CAN2_IF1_CMDREQ (LPC43_CAN2_BASE+LPC43_CAN_IF1_CMDREQ_OFFSET) -#define LPC43_CAN2_IF1_CMDMSKW (LPC43_CAN2_BASE+LPC43_CAN_IF1_CMDMSKW_OFFSET) -#define LPC43_CAN2_IF1_CMDMSKR (LPC43_CAN2_BASE+LPC43_CAN_IF1_CMDMSKR_OFFSET) -#define LPC43_CAN2_IF1_MSK1 (LPC43_CAN2_BASE+LPC43_CAN_IF1_MSK1_OFFSET) -#define LPC43_CAN2_IF1_MSK2 (LPC43_CAN2_BASE+LPC43_CAN_IF1_MSK2_OFFSET) -#define LPC43_CAN2_IF1_ARB1 (LPC43_CAN2_BASE+LPC43_CAN_IF1_ARB1_OFFSET) -#define LPC43_CAN2_IF1_ARB2 (LPC43_CAN2_BASE+LPC43_CAN_IF1_ARB2_OFFSET) -#define LPC43_CAN2_IF1_MCTRL (LPC43_CAN2_BASE+LPC43_CAN_IF1_MCTRL_OFFSET) -#define LPC43_CAN2_IF1_DA1 (LPC43_CAN2_BASE+LPC43_CAN_IF1_DA1_OFFSET) -#define LPC43_CAN2_IF1_DA2 (LPC43_CAN2_BASE+LPC43_CAN_IF1_DA2_OFFSET) -#define LPC43_CAN2_IF1_DB1 (LPC43_CAN2_BASE+LPC43_CAN_IF1_DB1_OFFSET) -#define LPC43_CAN2_IF1_DB2 (LPC43_CAN2_BASE+LPC43_CAN_IF1_DB2_OFFSET) - -#define LPC43_CAN2_IF2_CMDREQ (LPC43_CAN2_BASE+LPC43_CAN_IF2_CMDREQ_OFFSET) -#define LPC43_CAN2_IF2_CMDMSKW (LPC43_CAN2_BASE+LPC43_CAN_IF2_CMDMSKW_OFFSET) -#define LPC43_CAN2_IF2_CMDMSKR (LPC43_CAN2_BASE+LPC43_CAN_IF2_CMDMSKR_OFFSET) -#define LPC43_CAN2_IF2_MSK1 (LPC43_CAN2_BASE+LPC43_CAN_IF2_MSK1_OFFSET) -#define LPC43_CAN2_IF2_MSK2 (LPC43_CAN2_BASE+LPC43_CAN_IF2_MSK2_OFFSET) -#define LPC43_CAN2_IF2_ARB1 (LPC43_CAN2_BASE+LPC43_CAN_IF2_ARB1_OFFSET) -#define LPC43_CAN2_IF2_ARB2 (LPC43_CAN2_BASE+LPC43_CAN_IF2_ARB2_OFFSET) -#define LPC43_CAN2_IF2_MCTRL (LPC43_CAN2_BASE+LPC43_CAN_IF2_MCTRL_OFFSET) -#define LPC43_CAN2_IF2_DA1 (LPC43_CAN2_BASE+LPC43_CAN_IF2_DA1_OFFSET) -#define LPC43_CAN2_IF2_DA2 (LPC43_CAN2_BASE+LPC43_CAN_IF2_DA2_OFFSET) -#define LPC43_CAN2_IF2_DB1 (LPC43_CAN2_BASE+LPC43_CAN_IF2_DB1_OFFSET) -#define LPC43_CAN2_IF2_DB2 (LPC43_CAN2_BASE+LPC43_CAN_IF2_DB2_OFFSET) - -#define LPC43_CAN2_TXREQ1 (LPC43_CAN2_BASE+LPC43_CAN_TXREQ1_OFFSET) -#define LPC43_CAN2_TXREQ2 (LPC43_CAN2_BASE+LPC43_CAN_TXREQ2_OFFSET) -#define LPC43_CAN2_ND1 (LPC43_CAN2_BASE+LPC43_CAN_ND1_OFFSET) -#define LPC43_CAN2_ND2 (LPC43_CAN2_BASE+LPC43_CAN_ND2_OFFSET) -#define LPC43_CAN2_IR1 (LPC43_CAN2_BASE+LPC43_CAN_IR1_OFFSET) -#define LPC43_CAN2_IR2 (LPC43_CAN2_BASE+LPC43_CAN_IR2_OFFSET) -#define LPC43_CAN2_MSGV1 (LPC43_CAN2_BASE+LPC43_CAN_MSGV1_OFFSET) -#define LPC43_CAN2_MSGV2 (LPC43_CAN2_BASE+LPC43_CAN_MSGV2_OFFSET) -#define LPC43_CAN2_CLKDIV (LPC43_CAN2_BASE+LPC43_CAN_CLKDIV_OFFSET) - /* Register Bit Definitions *********************************************************/ /* CAN control register */ @@ -267,7 +267,7 @@ # define CAN_INT_MSG30 (30 << CAN_INT_SHIFT) /* Message 30 */ # define CAN_INT_MSG31 (31 << CAN_INT_SHIFT) /* Message 31 */ # define CAN_INT_MSG32 (32 << CAN_INT_SHIFT) /* Message 32 */ -# define CAN_INT_MSG32 (0x8000 << CAN_INT_SHIFT) /* Status interrupt */ +# define CAN_INT_STAT (0x8000 << CAN_INT_SHIFT) /* Status interrupt */ /* Bits 16-31: Reserved */ /* Test register */ /* Bits 0-1: Reserved */ diff --git a/arch/arm/src/lpc43xx/lpc43_can.c b/arch/arm/src/lpc43xx/lpc43_can.c new file mode 100644 index 0000000000..415a7b28ef --- /dev/null +++ b/arch/arm/src/lpc43xx/lpc43_can.c @@ -0,0 +1,1279 @@ +/**************************************************************************** + * arch/arm/src/lpc43xx/lpc43_can.c + * + * Copyright(C) 2017 Gregory Nutt. All rights reserved. + * + * Created on: 2 May 2017 + * Author: katherine + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "up_internal.h" +#include "up_arch.h" +#include "cache.h" + +#include "chip.h" +#include "lpc43_gpio.h" +#include "chip/lpc43_can.h" +#include "chip/lpc43_rgu.h" +#include "lpc43_ccu.h" +#include "lpc43_cgu.h" + +#if defined(CONFIG_LPC43_CAN0) || defined(CONFIG_LPC43_CAN1) + +#define CAN_MSG_OBJECTS_NUM 0x20 +#define CAN_RX_OBJ_NUM 0x10 +#define CAN_TX_OBJ_NUM 0x10 + +#define CAN_RX_OBJ_FIRST 0x01 +#define CAN_RX_OBJ_LAST (CAN_RX_OBJ_FIRST + CAN_RX_OBJ_NUM - 0x01) + +#define CAN_TX_OBJ_FIRST (CAN_RX_OBJ_LAST + 0x01) +#define CAN_TX_OBJ_LAST (CAN_TX_OBJ_FIRST + CAN_TX_OBJ_NUM - 0x01) + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +#ifdef CONFIG_LPC43_CAN0 + +/* A CAN bit rate must be provided */ + +# ifndef CONFIG_CAN0_BAUD +# define CONFIG_CAN0_BAUD 1000000 +# endif +#endif + +#ifdef CONFIG_LPC43_CAN1 + +/* A CAN bit rate must be provided */ + +# ifndef CONFIG_CAN1_BAUD +# define CONFIG_CAN1_BAUD 1000000 +# endif +#endif + +/* User-defined TSEG1 and TSEG2 settings may be used. + * + * CONFIG_CAN_TSEG1 = the number of CAN time quanta in segment 1 + * CONFIG_CAN_TSEG2 = the number of CAN time quanta in segment 2 + * CAN_BIT_QUANTA = The number of CAN time quanta in on bit time + */ + +#ifndef CONFIG_CAN_TSEG1 +# define CONFIG_CAN_TSEG1 12 +#endif + +#ifndef CONFIG_CAN_TSEG2 +# define CONFIG_CAN_TSEG2 4 +#endif + +#define CAN_BIT_QUANTA (CONFIG_CAN_TSEG1 + CONFIG_CAN_TSEG2 + 1) + +/* Timing *******************************************************************/ + +/* CAN clock source is defined in board.h */ + +#define CAN_CLOCK_FREQUENCY(c) ((uint32_t)LPC43_CCLK / ((uint32_t)(c))) + +/* CAN module clock must be less then 50 MHz */ + +#define CAN_CLKDIVVAL 0x05 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct up_dev_s +{ + uint8_t port; /* CAN port number */ + uint8_t clkdiv; /* CLKDIV register */ + uint32_t baud; /* Configured baud */ + uint32_t base; /* CAN register base address */ + uint8_t irq; /* IRQ associated with this CAN */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ +/* CAN Register access */ + +#ifdef CONFIG_CAN_REGDEBUG +static void can_printreg(uint32_t addr, uint32_t value); +#endif + +static uint32_t can_getreg(struct up_dev_s *priv, int offset); +static void can_putreg(struct up_dev_s *priv, int offset, uint32_t value); + +#ifdef CONFIG_CAN_REGDEBUG +static uint32_t can_getcommon(uint32_t addr); +static void can_putcommon(uint32_t addr, uint32_t value); +#else +# define can_getcommon(addr) getreg32(addr) +# define can_putcommon(addr, value) putreg32(value, addr) +#endif + +/* CAN methods */ + +static void can_reset(FAR struct can_dev_s *dev); +static int can_setup(FAR struct can_dev_s *dev); +static void can_shutdown(FAR struct can_dev_s *dev); +static void can_rxint(FAR struct can_dev_s *dev, bool enable); +static void can_txint(FAR struct can_dev_s *dev, bool enable); +static int can_ioctl(FAR struct can_dev_s *dev, int cmd, unsigned long arg); +static int can_remoterequest(FAR struct can_dev_s *dev, uint16_t id); +static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg); +static bool candev_txready(FAR struct can_dev_s *dev); +static bool candev_txempty(FAR struct can_dev_s *dev); + +/* CAN interrupts */ + +#ifdef CONFIG_LPC43_CAN0 +static int can0_interrupt(int irq, void *context, FAR void *arg); +#endif +#ifdef CONFIG_LPC43_CAN1 +static int can1_interrupt(int irq, void *context, FAR void *arg); +#endif +static void can_interrupt(FAR struct can_dev_s *dev); + +/* Message Processing */ + +static void can_savemsg(struct up_dev_s *priv, struct can_hdr_s *hdr, + uint32_t *data); +static void can_readobj(struct up_dev_s *priv, uint32_t index); +static void can_invalobj(struct up_dev_s *priv, uint32_t index); +static void can_setuprxobj(struct up_dev_s *priv); + +/* Initialization */ + +static int can_bittiming(struct up_dev_s *priv); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct can_ops_s g_canops = +{ + .co_reset = can_reset, + .co_setup = can_setup, + .co_shutdown = can_shutdown, + .co_rxint = can_rxint, + .co_txint = can_txint, + .co_ioctl = can_ioctl, + .co_remoterequest = can_remoterequest, + .co_send = can_send, + .co_txready = candev_txready, + .co_txempty = candev_txempty, +}; + +#ifdef CONFIG_LPC43_CAN0 +static struct up_dev_s g_can0priv = +{ + .port = 0, + .clkdiv = CAN_CLKDIVVAL + 1, + .baud = CONFIG_CAN0_BAUD, + .base = LPC43_CAN0_BASE, + .irq = LPC43M4_IRQ_CAN0, +}; + +static struct can_dev_s g_can0dev = +{ + .cd_ops = &g_canops, + .cd_priv = &g_can0priv, +}; +#endif + +#ifdef CONFIG_LPC43_CAN1 +static struct up_dev_s g_can1priv = +{ + .port = 1, + .clkdiv = CAN_CLKDIVVAL + 1, + .baud = CONFIG_CAN1_BAUD, + .base = LPC43_CAN1_BASE, + .irq = LPC43M4_IRQ_CAN1, +}; + +static struct can_dev_s g_can1dev = +{ + .cd_ops = &g_canops, + .cd_priv = &g_can1priv, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: can_printreg + * + * Description: + * Print the value read from a register. + * + * Input Parameters: + * addr - The register address + * value - The register value + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_CAN_REGDEBUG +static void can_printreg(uint32_t addr, uint32_t value) +{ + static uint32_t prevaddr = 0; + static uint32_t preval = 0; + static uint32_t count = 0; + + /* Is this the same value that we read from the same register last time? + * Are we polling the register? If so, suppress some of the output. + */ + + if (addr == prevaddr && value == preval) + { + if (count == 0xffffffff || ++count > 3) + { + if (count == 4) + { + caninfo("...\n"); + } + + return; + } + } + + /* No this is a new address or value */ + + else + { + /* Did we print "..." for the previous value? */ + + if (count > 3) + { + /* Yes.. then show how many times the value repeated */ + + caninfo("[repeats %d more times]\n", count-3); + } + + /* Save the new address, value, and count */ + + prevaddr = addr; + preval = value; + count = 1; + } + + /* Show the register value read */ + + caninfo("%08x->%08x\n", addr, value); +} +#endif /* CONFIG_CAN_REGDEBUG */ + +/**************************************************************************** + * Name: can_getreg + * + * Description: + * Read the value of an CAN1/2 register. + * + * Input Parameters: + * priv - A reference to the CAN block status + * offset - The offset to the register to read + * + * Returned Value: + * + ****************************************************************************/ + +#ifdef CONFIG_CAN_REGDEBUG +static uint32_t can_getreg(struct up_dev_s *priv, int offset) +{ + uint32_t addr; + uint32_t value; + + /* Read the value from the register */ + + addr = priv->base + offset; + value = getreg32(addr); + can_printreg(addr, value); + return value; +} +#else +static uint32_t can_getreg(struct up_dev_s *priv, int offset) +{ + return getreg32(priv->base + offset); +} +#endif /* CONFIG_CAN_REGDEBUG */ + +/**************************************************************************** + * Name: can_putreg + * + * Description: + * Set the value of an CAN1/2 register. + * + * Input Parameters: + * priv - A reference to the CAN block status + * offset - The offset to the register to write + * value - The value to write to the register + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_CAN_REGDEBUG +static void can_putreg(struct up_dev_s *priv, int offset, uint32_t value) +{ + uint32_t addr = priv->base + offset; + + /* Show the register value being written */ + + caninfo("%08x<-%08x\n", addr, value); + + /* Write the value */ + + putreg32(value, addr); +} +#else +static void can_putreg(struct up_dev_s *priv, int offset, uint32_t value) +{ + putreg32(value, priv->base + offset); +} +#endif /* CONFIG_CAN_REGDEBUG */ + +/**************************************************************************** + * Name: can_getcommon + * + * Description: + * Get the value of common register. + * + * Input Parameters: + * addr - The address of the register to read + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_CAN_REGDEBUG +static uint32_t can_getcommon(uint32_t addr) +{ + uint32_t value; + + /* Read the value from the register */ + + value = getreg32(addr); + can_printreg(addr, value); + return value; +} +#endif /* CONFIG_CAN_REGDEBUG */ + +/**************************************************************************** + * Name: can_putcommon + * + * Description: + * Set the value of common register. + * + * Input Parameters: + * addr - The address of the register to write + * value - The value to write to the register + * + * Returned Value: + * None + * + ****************************************************************************/ + +#ifdef CONFIG_CAN_REGDEBUG +static void can_putcommon(uint32_t addr, uint32_t value) +{ + /* Show the register value being written */ + + caninfo("%08x<-%08x\n", addr, value); + + /* Write the value */ + + putreg32(value, addr); +} +#endif /* CONFIG_CAN_REGDEBUG */ + +/**************************************************************************** + * Name: can_reset + * + * Description: + * Reset the CAN device. Called early to initialize the hardware. This + * function is called, before can_setup() and on error conditions. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void can_reset(FAR struct can_dev_s *dev) +{ + FAR struct up_dev_s *priv = (FAR struct up_dev_s *)dev->cd_priv; + uint32_t regval; + + caninfo("CAN%d reset\n", priv->port); + +#ifdef CONFIG_LPC43_CAN0 + if (priv->port == 0) + { + regval = ~(getreg32(LPC43_RGU_ACTIVE1)); + regval |= RGU_CTRL1_CAN0_RST; + putreg32(regval, LPC43_RGU_CTRL1); + } +#endif /* CONFIG_LPC43_CAN0 */ + +#ifdef CONFIG_LPC43_CAN1 + if (priv->port == 1) + { + regval = ~(getreg32(LPC43_RGU_ACTIVE1)); + regval |= RGU_CTRL1_CAN1_RST; + putreg32(regval, LPC43_RGU_CTRL1); + } +#endif /* CONFIG_LPC43_CAN1 */ +} + +/**************************************************************************** + * Name: can_setup + * + * Description: + * Configure the CAN. This method is called the first time that the CAN + * device is opened. This will occur when the port is first opened. + * This setup includes configuring and attaching CAN interrupts. + * All CAN interrupts are disabled upon return. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int can_setup(FAR struct can_dev_s *dev) +{ + FAR struct up_dev_s *priv = (FAR struct up_dev_s *) dev->cd_priv; + uint32_t regval; + uint8_t i; + int ret = ERROR; + + caninfo("CAN%d setup\n", priv->port); + + can_bittiming(priv); + + /* Clock must be divided by the CAN clock divider CLKDIV to be less than + * 50 MHz. + */ + + can_putreg(priv, LPC43_CAN_CLKDIV_OFFSET, CAN_CLKDIVVAL); + + /* Invalidate all message objects */ + + for (i = 1; i <= CAN_MSG_OBJECTS_NUM; ++i) + { + can_invalobj(priv, i); + } + + /* Initialization finished, normal operation now. */ + + regval = can_getreg(priv, LPC43_CAN_CNTL_OFFSET); + regval &= ~CAN_CNTL_INIT; + can_putreg(priv, LPC43_CAN_CNTL_OFFSET, regval); + + while (can_getreg(priv, LPC43_CAN_CNTL_OFFSET) & CAN_CNTL_INIT); + +#ifdef CONFIG_LPC43_CAN0 + if (priv->irq == LPC43M4_IRQ_CAN0) + { + ret = irq_attach(priv->irq, can0_interrupt, 0); + } +#endif + +#ifdef CONFIG_LPC43_CAN1 + if (priv->irq == LPC43M4_IRQ_CAN1) + { + ret = irq_attach(priv->irq, can1_interrupt, 0); + } +#endif + + if (ret == OK) + { + up_enable_irq(priv->irq); + + /* Enable CAN interrupts within CAN module */ + + regval = can_getreg(priv, LPC43_CAN_CNTL_OFFSET); + regval |= (CAN_CNTL_IE | CAN_CNTL_SIE | CAN_CNTL_EIE); + can_putreg(priv, LPC43_CAN_CNTL_OFFSET, regval); + } + + return ret; +} + +/**************************************************************************** + * Name: can_shutdown + * + * Description: + * Disable the CAN. This method is called when the CAN device is closed. + * This method reverses the operation the setup method. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void can_shutdown(FAR struct can_dev_s *dev) +{ + FAR struct up_dev_s *priv = (FAR struct up_dev_s *) dev->cd_priv; + uint32_t regval; + + caninfo("CAN%d\n", priv->port); + + /* Stop operation mode */ + + regval = can_getreg(priv, LPC43_CAN_CNTL_OFFSET); + regval |= CAN_CNTL_INIT; + can_putreg(priv, LPC43_CAN_CNTL_OFFSET, regval); + + /* Disable CAN interrupts */ + + regval = can_getreg(priv, LPC43_CAN_CNTL_OFFSET); + regval &= ~(CAN_CNTL_IE | CAN_CNTL_SIE | CAN_CNTL_EIE); + can_putreg(priv, LPC43_CAN_CNTL_OFFSET, regval); + + up_disable_irq(priv->irq); + + /* Then detach the CAN interrupt handler. */ + + irq_detach(priv->irq); +} + +/**************************************************************************** + * Name: can_rxint + * + * Description: + * Call to enable or disable RX interrupts. + * This function is called two times: from can_open and can_close. Therefore + * this function enables and disables not only RX interrupts but all message + * objects. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void can_rxint(FAR struct can_dev_s *dev, bool enable) +{ + FAR struct up_dev_s *priv = (FAR struct up_dev_s *) dev->cd_priv; + + if (enable == true) + { + can_setuprxobj(priv); + } + else + { + uint8_t i = 0; + for (i = CAN_RX_OBJ_FIRST; i <= CAN_RX_OBJ_LAST; ++i) + { + can_invalobj(priv, i); + } + } +} + +/**************************************************************************** + * Name: can_txint + * + * Description: + * Call to enable or disable TX interrupts. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void can_txint(FAR struct can_dev_s *dev, bool enable) +{ + /* The TX interrupt is automatically enabled in can_send within a + * message object. + */ +} + +/**************************************************************************** + * Name: can_ioctl + * + * Description: + * All ioctl calls will be routed through this method + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int can_ioctl(FAR struct can_dev_s *dev, int cmd, unsigned long arg) +{ + caninfo("Fix me:Not Implemented\n"); + return 0; +} + +/**************************************************************************** + * Name: can_remoterequest + * + * Description: + * Send a remote request + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int can_remoterequest(FAR struct can_dev_s *dev, uint16_t id) +{ + caninfo("Fix me:Not Implemented\n"); + return 0; +} + +/**************************************************************************** + * Name: can_send + * + * Description: + * Send one can message. + * + * One CAN-message consists of a maximum of 10 bytes. A message is + * composed of at least the first 2 bytes (when there are no data bytes). + * + * Byte 0: Bits 0-7: Bits 3-10 of the 11-bit CAN identifier + * Byte 1: Bits 5-7: Bits 0-2 of the 11-bit CAN identifier + * Bit 4: Remote Tranmission Request (RTR) + * Bits 0-3: Data Length Code (DLC) + * Bytes 2-10: CAN data + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg) +{ + FAR struct up_dev_s *priv = (FAR struct up_dev_s *) dev->cd_priv; + uint32_t regval; + uint32_t clz; + uint32_t id; + uint32_t dlc; + uint8_t txobj; + + if(msg == NULL) + { + return ERROR; + } + + regval = (can_getreg(priv, LPC43_CAN_MSGV2_OFFSET) & 0xFFFF); + clz = arm_clz(regval); + + if (clz == 0x10) + { + return ERROR; + } + + txobj = CAN_TX_OBJ_LAST - clz + CAN_TX_OBJ_FIRST; + DEBUGASSERT((txobj >= CAN_TX_OBJ_FIRST) && (txobj <= CAN_TX_OBJ_LAST)); + + id = (uint32_t) msg->cm_hdr.ch_id; + dlc = (uint32_t) msg->cm_hdr.ch_dlc; + + caninfo("CAN%d ID: %d DLC: %d\n", + priv->port, msg->cm_hdr.ch_id, msg->cm_hdr.ch_dlc); + + can_putreg(priv, LPC43_CAN_IF1_MSK1_OFFSET, 0xFFFF); + can_putreg(priv, LPC43_CAN_IF1_MSK2_OFFSET, 0xFFFF); + + regval = ((dlc & CAN_MCTRL_DLC_MASK) | CAN_MCTRL_EOB | CAN_MCTRL_TXRQST + | CAN_MCTRL_TXIE ); + can_putreg(priv, LPC43_CAN_IF1_MCTRL_OFFSET, regval); + + /* Write data to IF1 data registers */ + + regval = msg->cm_data[0] + (msg->cm_data[1] << 8); + can_putreg(priv, LPC43_CAN_IF1_DA1_OFFSET, regval); + + regval = msg->cm_data[2] + (msg->cm_data[3] << 8); + can_putreg(priv, LPC43_CAN_IF1_DA2_OFFSET, regval); + + regval = msg->cm_data[4] + (msg->cm_data[5] << 8); + can_putreg(priv, LPC43_CAN_IF1_DB1_OFFSET, regval); + + regval = msg->cm_data[6] + (msg->cm_data[7] << 8); + can_putreg(priv, LPC43_CAN_IF1_DB2_OFFSET, regval); + +#ifdef CONFIG_CAN_EXTID + can_putreg(priv, LPC43_CAN_IF1_ARB1_OFFSET, id & 0x0000FFFF); + can_putreg(priv, LPC43_CAN_IF1_ARB2_OFFSET, CAN_MSK2_DIR | CAN_MSK2_XTD + | CAN_MSK2_MSGVAL | id >> 16); +#else + can_putreg(priv, LPC43_CAN_IF1_ARB1_OFFSET, 0x0000); + can_putreg(priv, LPC43_CAN_IF1_ARB2_OFFSET, CAN_MSK2_DIR | CAN_MSK2_MSGVAL + | id << 2); +#endif + + regval = (CAN_CMDMSKW_WRRD | CAN_CMDMSKW_MASK | CAN_CMDMSKW_ARB + | CAN_CMDMSKW_CTRL | CAN_CMDMSKW_CLRINTPND | CAN_CMDMSKW_TXRQST + | CAN_CMDMSKW_DATAA | CAN_CMDMSKW_DATAB); + can_putreg(priv, LPC43_CAN_IF1_CMDMSKW_OFFSET, regval); + + /* Write to Message RAM */ + + can_putreg(priv, LPC43_CAN_IF1_CMDREQ_OFFSET, txobj); + +#ifdef CONFIG_CAN_TXREADY + can_txdone(dev); +#endif + + return OK; +} + +/**************************************************************************** + * Name: candev_txready + * + * Description: + * Return true if the CAN hardware can accept another TX message. + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * True if the CAN hardware is ready to accept another TX message. + * + ****************************************************************************/ + +static bool candev_txready(FAR struct can_dev_s *dev) +{ + FAR struct up_dev_s *priv = (FAR struct up_dev_s *) dev->cd_priv; + + if (can_getreg(priv, LPC43_CAN_MSGV2_OFFSET) & 0x8000) + { + return false; + } + + if (can_getreg(priv, LPC43_CAN_IF1_CMDREQ_OFFSET) & CAN_CMDREQ_BUSY) + { + return false; + } + + return true; +} + +/**************************************************************************** + * Name: candev_txempty + * + * Description: + * Return true if all message have been sent. If for example, the CAN + * hardware implements FIFOs, then this would mean the transmit FIFO is + * empty. This method is called when the driver needs to make sure that + * all characters are "drained" from the TX hardware before calling + * co_shutdown(). + * + * Input Parameters: + * dev - An instance of the "upper half" can driver state structure. + * + * Returned Value: + * True if there are no pending TX transfers in the CAN hardware. + * + ****************************************************************************/ + +static bool candev_txempty(FAR struct can_dev_s *dev) +{ + FAR struct up_dev_s *priv = (FAR struct up_dev_s *) dev->cd_priv; + return (!((can_getreg(priv, LPC43_CAN_MSGV2_OFFSET)) & 0xFFFF)); +} + +/**************************************************************************** + * Name: can0/1_interrupt + * + * Description: + * CAN interrupt handler for CAN0 and CAN1. + * + * Input Parameters: + * irq - The IRQ number of the interrupt. + * context - The register state save array at the time of the interrupt. + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + + +#ifdef CONFIG_LPC43_CAN0 +static int can0_interrupt(int irq, void *context, FAR void *arg) +{ + can_interrupt(&g_can0dev); + return OK; +} +#endif + +#ifdef CONFIG_LPC43_CAN1 +static int can1_interrupt(int irq, void *context, FAR void *arg) +{ + can_interrupt(&g_can1dev); + return OK; +} +#endif + +/**************************************************************************** + * Name: can_interrupt + * + * Description: + * CAN interrupt handler. There is a single interrupt for both CAN0 and + * CAN1. + * + ****************************************************************************/ + +static void can_interrupt(FAR struct can_dev_s *dev) +{ + FAR struct up_dev_s *priv = (FAR struct up_dev_s *) dev->cd_priv; + uint32_t regval = 0; + + uint32_t msgindex = 0; + + /* Read CAN interrupt register */ + + uint32_t interrupt = can_getreg(priv, LPC43_CAN_INT_OFFSET); + + /* Read CAN status register */ + + uint32_t stat = can_getreg(priv, LPC43_CAN_STAT_OFFSET); + + if ( interrupt & CAN_INT_STAT ) + { + /* Clear all warning/error states except RXOK/TXOK */ + + regval = can_getreg(priv, LPC43_CAN_STAT_OFFSET); + regval &= CAN_STAT_RXOK | CAN_STAT_TXOK; + can_putreg(priv, LPC43_CAN_STAT_OFFSET, regval); + } + else + { + msgindex = interrupt & 0x7FFF; + + /* if no error detected */ + + if (((stat & CAN_STAT_LEC_MASK) == 0) || + ((stat & CAN_STAT_LEC_MASK) == CAN_STAT_LEC_MASK)) + { + if (msgindex <= CAN_RX_OBJ_LAST) + { + struct can_hdr_s hdr; + uint32_t data[2]; + + regval = can_getreg(priv, LPC43_CAN_STAT_OFFSET); + regval &= ~CAN_STAT_RXOK; + can_putreg(priv, LPC43_CAN_STAT_OFFSET, regval); + + can_readobj(priv, msgindex); + can_savemsg(priv, &hdr, data); + can_invalobj(priv, msgindex); + can_receive(dev, &hdr, (uint8_t *)data); + } + else + { + regval = can_getreg(priv, LPC43_CAN_STAT_OFFSET); + regval &= ~CAN_STAT_TXOK; + can_putreg(priv, LPC43_CAN_STAT_OFFSET, regval); + + can_invalobj(priv, msgindex); +#ifdef CONFIG_CAN_TXREADY + can_txready(dev); +#else + can_txdone(dev); +#endif + } + } + else + { + can_invalobj(priv, msgindex); + } + + can_putreg(priv, LPC43_CAN_STAT_OFFSET, 0); + + if (msgindex == CAN_RX_OBJ_LAST) + { + can_setuprxobj(priv); + } + } +} + +/**************************************************************************** + * Name: can_savemsg + * + * Description: + * Save received message. + * + * Input Parameters: + * priv - A reference to the CAN block status + * hdr - A reference to the message header + * data - A reference to the data block + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void can_savemsg(struct up_dev_s *priv, struct can_hdr_s *hdr, + uint32_t *data) +{ +#ifdef CONFIG_CAN_EXTID + hdr->ch_id = (can_getreg(priv, LPC43_CAN_IF2_ARB1_OFFSET) & 0xFFFF) | + (can_getreg(priv, LPC43_CAN_IF2_ARB2_OFFSET) & 0x0FFF) << 16; + hdr->ch_extid = 1; +#else + hdr->ch_id = (can_getreg(priv, LPC43_CAN_IF2_ARB2_OFFSET) & 0x1FFF) >> 2; +#endif + hdr->ch_dlc = can_getreg(priv, LPC43_CAN_IF2_MCTRL_OFFSET) & 0x000F; + hdr->ch_rtr = 0; + + data[0] = can_getreg(priv, LPC43_CAN_IF2_DA2_OFFSET) << 16 | + can_getreg(priv, LPC43_CAN_IF2_DA1_OFFSET); + data[1] = can_getreg(priv, LPC43_CAN_IF2_DB2_OFFSET) << 16 | + can_getreg(priv, LPC43_CAN_IF2_DB1_OFFSET); +} + +/**************************************************************************** + * Name: can_readobj + * + * Description: + * Transfer Message Object into IF registers. + * + * Input Parameters: + * priv - A reference to the CAN block status + * index - Message Object number + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void can_readobj(struct up_dev_s *priv, uint32_t index) +{ + uint32_t regval; + + while (can_getreg(priv, LPC43_CAN_IF2_CMDREQ_OFFSET) & CAN_CMDREQ_BUSY); + + regval = (CAN_CMDMSKR_MASK | CAN_CMDMSKR_ARB | CAN_CMDMSKR_CTRL | + CAN_CMDMSKR_CLRINTPND | CAN_CMDMSKR_DATAA | CAN_CMDMSKR_DATAB); + can_putreg(priv, LPC43_CAN_IF2_CMDMSKR_OFFSET, regval); + can_putreg(priv, LPC43_CAN_IF2_CMDREQ_OFFSET, index); +} + +/**************************************************************************** + * Name: can_invalobj + * + * Description: + * Invalidate Message Object. + * + * Input Parameters: + * priv - A reference to the CAN block status + * index - Message Object number + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void can_invalobj(struct up_dev_s *priv, uint32_t index) +{ + while (can_getreg(priv, LPC43_CAN_IF2_CMDREQ_OFFSET) & CAN_CMDREQ_BUSY); + + can_putreg(priv, LPC43_CAN_IF2_ARB1_OFFSET, 0x0000); + can_putreg(priv, LPC43_CAN_IF2_ARB2_OFFSET, 0x0000); + + /* Disable reception and transmission interrupts, clear transmit request */ + + can_putreg(priv, LPC43_CAN_IF2_MCTRL_OFFSET, CAN_MCTRL_EOB); + can_putreg(priv, LPC43_CAN_IF2_CMDMSKW_OFFSET, CAN_CMDMSKW_WRRD + | CAN_CMDMSKW_CLRINTPND | CAN_CMDMSKW_CTRL | CAN_CMDMSKW_ARB); + can_putreg(priv, LPC43_CAN_IF2_CMDREQ_OFFSET, index); +} + +/**************************************************************************** + * Name: can_setuprxobj + * + * Description: + * Setup Message Object as buffer for received messages. + * + * Input Parameters: + * priv - A reference to the CAN block status + * + * Returned Value: + * None + * + ****************************************************************************/ + +static void can_setuprxobj(struct up_dev_s *priv) +{ + uint32_t regval; + uint8_t i; + + while (can_getreg(priv, LPC43_CAN_IF2_CMDREQ_OFFSET) & CAN_CMDREQ_BUSY); + + can_putreg(priv, LPC43_CAN_IF2_MSK1_OFFSET, 0x0000); + regval = (CAN_MSK2_MXTD | CAN_MSK2_MDIR); + can_putreg(priv, LPC43_CAN_IF2_MSK2_OFFSET, regval); + + regval = (CAN_MCTRL_DLC_MASK | CAN_MCTRL_EOB | CAN_MCTRL_RXIE | + CAN_MCTRL_UMASK); + can_putreg(priv, LPC43_CAN_IF2_MCTRL_OFFSET, regval); + + can_putreg(priv, LPC43_CAN_IF2_ARB1_OFFSET, 0x0000); +#ifdef CONFIG_CAN_EXTID + can_putreg(priv, LPC43_CAN_IF2_ARB2_OFFSET, CAN_MSK2_MSGVAL | CAN_MSK2_XTD); +#else + can_putreg(priv, LPC43_CAN_IF2_ARB2_OFFSET, CAN_MSK2_MSGVAL); +#endif + + regval = (CAN_CMDMSKR_WRRD | CAN_CMDMSKR_MASK | CAN_CMDMSKR_ARB | + CAN_CMDMSKR_CTRL | CAN_CMDMSKR_CLRINTPND | CAN_CMDMSKR_DATAA | + CAN_CMDMSKR_DATAB); + can_putreg(priv, LPC43_CAN_IF2_CMDMSKR_OFFSET, regval); + + for (i = CAN_RX_OBJ_FIRST; i <= CAN_RX_OBJ_LAST; ++i) + { + while (can_getreg(priv, LPC43_CAN_IF2_CMDREQ_OFFSET) & CAN_CMDREQ_BUSY); + can_putreg(priv, LPC43_CAN_IF2_CMDREQ_OFFSET, i); + } +} + +/**************************************************************************** + * Name: can_bittiming + * + * Description: + * Set the CAN bit timing register (BTR) based on the configured BAUD. + * + * The bit timing logic monitors the serial bus-line and performs sampling + * and adjustment of the sample point by synchronizing on the start-bit edge + * and resynchronizing on the following edges. + * + * Its operation may be explained simply by splitting nominal bit time into + * three segments as follows: + * + * 1. Synchronization segment (SYNC_SEG): a bit change is expected to occur + * within this time segment. It has a fixed length of one time quantum + * (1 x tCAN). + * 2. Bit segment 1 (BS1): defines the location of the sample point. It + * includes the PROP_SEG and PHASE_SEG1 of the CAN standard. Its duration + * is programmable between 1 and 16 time quanta but may be automatically + * lengthened to compensate for positive phase drifts due to differences + * in the frequency of the various nodes of the network. + * 3. Bit segment 2 (BS2): defines the location of the transmit point. It + * represents the PHASE_SEG2 of the CAN standard. Its duration is + * programmable between 1 and 8 time quanta but may also be automatically + * shortened to compensate for negative phase drifts. + * + * Pictorially: + * + * |<----------------- NOMINAL BIT TIME ----------------->| + * |<- SYNC_SEG ->|<------ BS1 ------>|<------ BS2 ------>| + * |<---- Tq ---->|<----- Tbs1 ------>|<----- Tbs2 ------>| + * + * Where + * Tbs1 is the duration of the BS1 segment + * Tbs2 is the duration of the BS2 segment + * Tq is the "Time Quantum" + * + * Relationships: + * + * baud = 1 / bit_time + * bit_time = Tq + Tbs1 + Tbs2 + * Tbs1 = Tq * ts1 + * Tbs2 = Tq * ts2 + * Tq = brp * Tcan + * + * Where: + * Tcan is the period of the APB clock (PCLK = CCLK / CONFIG_CAN1_DIVISOR). + * + * Input Parameter: + * priv - A reference to the CAN block status + * + * Returned Value: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static int can_bittiming(struct up_dev_s *priv) +{ + uint32_t ts1 = CONFIG_CAN_TSEG1; + uint32_t ts2 = CONFIG_CAN_TSEG2; + uint32_t sjw = 1; + uint32_t brp = CAN_CLOCK_FREQUENCY(priv->clkdiv) / + (priv->baud * CAN_BIT_QUANTA); + + uint32_t regval; + + canllvdbg("CAN%d PCLK: %d baud: %d\n", + priv->port, CAN_CLOCK_FREQUENCY(priv->clkdiv), priv->baud); + canllvdbg("TS1: %d TS2: %d BRP: %d SJW= %d\n", ts1, ts2, brp, sjw); + + /* Start configuring bit timing */ + + regval = can_getreg(priv, LPC43_CAN_CNTL_OFFSET); + regval |= CAN_CNTL_CCE; + can_putreg(priv, LPC43_CAN_CNTL_OFFSET, regval); + + regval = (((brp - 1) << CAN_BT_BRP_SHIFT) + | ((ts1 - 1) << CAN_BT_TSEG1_SHIFT) + | ((ts2 - 1) << CAN_BT_TSEG2_SHIFT) + | ((sjw - 1) << CAN_BT_SJW_SHIFT)); + + canllvdbg("Setting CANxBTR= 0x%08x\n", regval); + + /* Set bit timing */ + + can_putreg(priv, LPC43_CAN_BT_OFFSET, regval); + + /* Stop configuring bit timing */ + + regval = can_getreg(priv, LPC43_CAN_CNTL_OFFSET); + regval &= ~CAN_CNTL_CCE; + can_putreg(priv, LPC43_CAN_CNTL_OFFSET, regval); + + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: lpc43_caninitialize + * + * Description: + * Initialize the selected can port + * + * Input Parameter: + * Port number (for hardware that has mutiple can interfaces) + * + * Returned Value: + * Valid can device structure reference on succcess; a NULL on failure + * + ****************************************************************************/ + +FAR struct can_dev_s *lpc43_caninitialize(int port) +{ + FAR struct can_dev_s *candev; + irqstate_t flags; + uint32_t regval; + + canllvdbg("CAN%d\n", port); + + flags = enter_critical_section(); + +#ifdef CONFIG_LPC43_CAN0 + if (port == 0) + { + /* Enable clock */ + + regval = getreg32(LPC43_CCU1_APB3_CAN0_CFG); + regval |= CCU_CLK_CFG_RUN; + putreg32(regval, LPC43_CCU1_APB3_CAN0_CFG); + + /* Configure CAN GPIO pins */ + + lpc43_pin_config(PINCONF_CAN0_RD); + lpc43_pin_config(PINCONF_CAN0_TD); + + candev = &g_can0dev; + } + else +#endif /* CONFIG_LPC43_CAN0 */ + +#ifdef CONFIG_LPC43_CAN1 + if (port == 1) + { + /* Enable clock */ + + regval = getreg32(LPC43_CCU1_APB1_CAN1_CFG); + regval |= CCU_CLK_CFG_RUN; + putreg32(regval, LPC43_CCU1_APB1_CAN1_CFG); + + /* Configure CAN GPIO pins */ + + lpc43_pin_config(PINCONF_CAN1_RD); + lpc43_pin_config(PINCONF_CAN1_TD); + + candev = &g_can1dev; + } + else +#endif /* CONFIG_LPC43_CAN1 */ + { + canerr("Unsupported port: %d\n", port); + + leave_critical_section(flags); + return NULL; + } + + leave_critical_section(flags); + + return candev; +} +#endif diff --git a/arch/arm/src/lpc43xx/lpc43_can.h b/arch/arm/src/lpc43xx/lpc43_can.h new file mode 100644 index 0000000000..f321c9b72f --- /dev/null +++ b/arch/arm/src/lpc43xx/lpc43_can.h @@ -0,0 +1,85 @@ +/**************************************************************************** + * arch/arm/src/lpc43xx/lpc43_can.h + * + * Copyright(C) 2017 Gregory Nutt. All rights reserved. + * + * Created on: 2 May 2017 + * Author: katherine + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES(INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +#ifndef __ARCH_ARM_SRC_LPC43XX_LPC43_CAN_H_ +#define __ARCH_ARM_SRC_LPC43XX_LPC43_CAN_H_ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include "chip/lpc43_can.h" + +#ifndef __ASSEMBLY__ + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#ifdef __cplusplus +extern "C" +{ +#endif + +/**************************************************************************** + * Name: lpc43_caninitialize + * + * Description: + * Initialize the selected can port + * + * Input Parameter: + * Port number (for hardware that has mutiple can interfaces) + * + * Returned Value: + * Valid can device structure reference on succcess; a NULL on failure + * + ****************************************************************************/ + +#if defined(CONFIG_CAN) && (defined(CONFIG_LPC43_CAN0) || defined(CONFIG_LPC43_CAN1)) +struct can_dev_s; +FAR struct can_dev_s *lpc43_caninitialize(int port); +#endif + +#ifdef __cplusplus +} +#endif +#endif /* __ASSEMBLY__ */ + +#endif /* __ARCH_ARM_SRC_LPC43XX_LPC43_CAN_H_ */