From 9f331c4e5b05657516a1d634da9e38758d82c601 Mon Sep 17 00:00:00 2001 From: patacongo Date: Wed, 21 Dec 2011 15:50:06 +0000 Subject: Add the beginning of an STM32 CAN driver git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@4209 42af7a65-404d-4744-a932-0658087f49c3 --- nuttx/arch/arm/src/stm32/Make.defs | 6 +- nuttx/arch/arm/src/stm32/stm32_can.c | 761 +++++++++++++++++++++++++++++++++++ nuttx/arch/arm/src/stm32/stm32_pwm.c | 2 +- 3 files changed, 767 insertions(+), 2 deletions(-) create mode 100755 nuttx/arch/arm/src/stm32/stm32_can.c (limited to 'nuttx/arch/arm/src/stm32') diff --git a/nuttx/arch/arm/src/stm32/Make.defs b/nuttx/arch/arm/src/stm32/Make.defs index d877516ab..0d046ebc3 100644 --- a/nuttx/arch/arm/src/stm32/Make.defs +++ b/nuttx/arch/arm/src/stm32/Make.defs @@ -2,7 +2,7 @@ # arch/arm/src/stm32/Make.defs # # Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved. -# Author: Gregory Nutt +# Author: Gregory Nutt # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions @@ -87,6 +87,10 @@ ifeq ($(CONFIG_PWM),y) CHIP_CSRCS += stm32_pwm.c endif +ifeq ($(CONFIG_CAN),y) +CHIP_CSRCS += stm32_can.c +endif + ifeq ($(CONFIG_DEBUG),y) CHIP_CSRCS += stm32_dumpgpio.c endif diff --git a/nuttx/arch/arm/src/stm32/stm32_can.c b/nuttx/arch/arm/src/stm32/stm32_can.c new file mode 100755 index 000000000..404bf4a1a --- /dev/null +++ b/nuttx/arch/arm/src/stm32/stm32_can.c @@ -0,0 +1,761 @@ +/************************************************************************************ + * arch/arm/src/stm32/stm32_can.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * 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. + * + ************************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "up_internal.h" +#include "up_arch.h" + +#include "os_internal.h" + +#include "chip.h" +#include "stm32_internal.h" +#include "stm32_can.h" + +#ifdef CONFIG_CAN + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +/* Configuration ************************************************************/ +/* Up to 2 CAN interfaces are supported */ + +#if STM32_NCAN < 2 +# undef CONFIG_STM32_CAN2 +#endif + +#if STM32_NCAN < 1 +# undef CONFIG_STM32_CAN1 +#endif + +#if defined(CONFIG_STM32_CAN1) || defined(CONFIG_STM32_CAN2) + +/* CAN BAUD */ + +#if defined(CONFIG_STM32_CAN1) && !defined(CONFIG_CAN1_BAUD) +# error "CONFIG_CAN1_BAUD is not defined" +#endif + +#if defined(CONFIG_STM32_CAN2) && !defined(CONFIG_CAN2_BAUD) +# error "CONFIG_CAN2_BAUD is not defined" +#endif + +/* Debug ********************************************************************/ +/* Non-standard debug that may be enabled just for testing CAN */ + +#ifdef CONFIG_DEBUG_CAN +# define candbg dbg +# define canvdbg vdbg +# define canlldbg lldbg +# define canllvdbg llvdbg +#else +# define candbg(x...) +# define canvdbg(x...) +# define canlldbg(x...) +# define canllvdbg(x...) +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct stm32_can_s +{ + uint8_t port; /* CAN port number (1 or 2) */ + uint8_t cantx; /* CAN TX IRQ number */ + uint8_t canrx0; /* CAN RX FIFO 0 IRQ number */ + uint8_t canrx1; /* CAN RX FIFO 1 IRQ number */ + uint8_t cansce; /* CAN RX0 Status change error (SCE) IRQ number */ + uint32_t baud; /* Configured baud */ +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/* CAN driver 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 can_txempty(FAR struct can_dev_s *dev); + +/* CAN interrupt handling */ + +static int can_txinterrupt(int irq, void *context); +static int can_rx0interrupt(int irq, void *context); +static int can_rx1interrupt(int irq, void *context); +static int can_sceinterrupt(int irq, void *context); + +/**************************************************************************** + * 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_txempty = can_txempty, +}; + +#ifdef CONFIG_STM32_CAN1 +static struct stm32_can_s g_can1priv = +{ + .port = 1, +#if defined(CONFIG_STM32_STM32F10XX) && !defined(CONFIG_STM32_CONNECTIVITY_LINE) + .cantx = STM32_IRQ_USBHPCANTX, + .canrx0 = STM32_IRQ_USBLPCANRX0, +#else + .cantx = STM32_IRQ_CAN1TX, + .canrx0 = STM32_IRQ_CAN1RX0, +#endif + .canrx1 = STM32_IRQ_CAN1RX1, + .cansce = STM32_IRQ_CAN1SCE, + .baud = CONFIG_CAN1_BAUD, +}; + +static struct can_dev_s g_can1dev = +{ + .cd_ops = &g_canops, + .cd_priv = &g_can1priv, +}; +#endif + +#ifdef CONFIG_STM32_CAN2 +static struct stm32_can_s g_can2priv = +{ + .port = 2, + .cantx = STM32_IRQ_CAN2TX, + .canrx0 = STM32_IRQ_CAN2RX0, + .canrx1 = STM32_IRQ_CAN2RX1, + .cansce = STM32_IRQ_CAN2SCE, + .baud = CONFIG_CAN2_BAUD, +}; + +static struct can_dev_s g_can2dev = +{ + .cd_ops = &g_canops, + .cd_priv = &g_can2priv, +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * 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 stm32_can_s *priv = dev->cd_priv; + irqstate_t flags; + + /* Disable interrupts momentary to stop any ongoing CAN event processing */ + + flags = irqsave(); + +#ifdef CONFIG_STM32_CAN1 + if (priv->port == 1) + { +#warning "Missing logic" + } + else +#endif +#ifdef CONFIG_STM32_CAN2 + if (priv->port == 2) + { +#warning "Missing logic" + } + else +#endif + { + candbg("Unsupport port %d\n", priv->port); + } + irqrestore(flags); +} + +/**************************************************************************** + * 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 stm32_can_s *priv = dev->cd_priv; + int ret; + + /* Attach all CAN interrupts */ + + ret = irq_attach(priv->cantx, can_txinterrupt); + if (ret < 0) + { + candbg("Failed to attach CAN%d TX IRQ (%d)", priv->port, priv->cantx); + return ret; + } + + ret = irq_attach(priv->canrx0, can_rx0interrupt); + if (ret < 0) + { + candbg("Failed to attach CAN%d RX0 IRQ (%d)", priv->port, priv->canrx0); + return ret; + } + + ret = irq_attach(priv->canrx1, can_rx1interrupt); + if (ret < 0) + { + candbg("Failed to attach CAN%d RX1 IRQ (%d)", priv->port, priv->canrx1); + return ret; + } + + ret = irq_attach(priv->cansce, can_sceinterrupt); + if (ret < 0) + { + candbg("Failed to attach CAN%d SCE IRQ (%d)", priv->port, priv->cansce); + return ret; + } + + /* Enable all interrupts at the NVIC. Interrupts are still disabled in + * the CAN module. Since we coming out of reset here, there should be + */ + + up_enable_irq(priv->cantx); + up_enable_irq(priv->canrx0); + up_enable_irq(priv->canrx1); + up_enable_irq(priv->cansce); + return OK; +} + +/**************************************************************************** + * 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 stm32_can_s *priv = dev->cd_priv; + + /* Disable all interrupts */ + + up_disable_irq(priv->cantx); + up_disable_irq(priv->canrx0); + up_disable_irq(priv->canrx1); + up_disable_irq(priv->cansce); + + /* Detach all interrupts */ + + irq_detach(priv->cantx); + irq_detach(priv->canrx0); + irq_detach(priv->canrx1); + irq_detach(priv->cansce); + + /* And reset the hardware */ + + can_reset(dev); +} + +/**************************************************************************** + * Name: can_rxint + * + * Description: + * Call to enable or disable RX interrupts. + * + * 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 stm32_can_s *priv = dev->cd_priv; + +#ifdef CONFIG_STM32_CAN1 + if (priv->port == 1) + { +#warning "Missing logic" + } + else +#endif +#ifdef CONFIG_STM32_CAN2 + if (priv->port == 2) + { +#warning "Missing logic" + } + else +#endif + { + candbg("Unsupport port %d\n", priv->port); + } +} + +/**************************************************************************** + * 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) +{ + FAR struct stm32_can_s *priv = dev->cd_priv; + +#ifdef CONFIG_STM32_CAN1 + if (priv->port == 1) + { +#warning "Missing logic" + } + else +#endif +#ifdef CONFIG_STM32_CAN2 + if (priv->port == 2) + { +#warning "Missing logic" + } + else +#endif + { + candbg("Unsupport port %d\n", priv->port); + } +} + +/**************************************************************************** + * 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) +{ + /* No CAN ioctls are supported */ + + return -ENOTTY; +} + +/**************************************************************************** + * 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) +{ +#warning "Missing logic" + return -ENOSYS; +} + +/**************************************************************************** + * Name: can_send + * + * Description: + * + * 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 stm32_can_s *priv = dev->cd_priv; + +#ifdef CONFIG_STM32_CAN1 + if (priv->port == 1) + { +#warning "Missing logic" + } + else +#endif +#ifdef CONFIG_STM32_CAN2 + if (priv->port == 2) + { +#warning "Missing logic" + } + else +#endif + { + candbg("Unsupport port %d\n", priv->port); + return -EINVAL; + } + +#warning "Missing logic" + return OK; +} + +/**************************************************************************** + * Name: can_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: + * Zero on success; a negated errno on failure + * + ****************************************************************************/ + +static bool can_txempty(FAR struct can_dev_s *dev) +{ + FAR struct stm32_can_s *priv = dev->cd_priv; + +#ifdef CONFIG_STM32_CAN1 + if (priv->port == 1) + { +#warning "Missing logic" + } + else +#endif +#ifdef CONFIG_STM32_CAN2 + if (priv->port == 2) + { +#warning "Missing logic" + } + else +#endif + { + candbg("Unsupport port %d\n", priv->port); + return true; + } + +#warning "Missing logic" + return true; +} + +/**************************************************************************** + * Name: can_txinterrupt + * + * Description: + * CAN TX interrupt handler + * + * 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_txinterrupt(int irq, void *context) +{ + FAR struct stm32_can_s *priv; + +#if defined(CONFIG_STM32_CAN1) && defined(CONFIG_STM32_CAN2) + if (g_can1priv.cantx == irq) + { + priv = &g_can1priv; + } + else if (g_can2priv.cantx == irq) + { + priv = &g_can2priv; + } + else + { + PANIC(OSERR_UNEXPECTEDISR); + } +#elif defined(CONFIG_STM32_CAN1) + priv = &g_can1priv; +#else /* defined(CONFIG_STM32_CAN2) */ + priv = &g_can2priv; +#endif + +#warning "Missing logic" + return OK; +} + +/**************************************************************************** + * Name: can_rx0interrupt + * + * Description: + * CAN RX FIFO 0 interrupt handler + * + * 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_rx0interrupt(int irq, void *context) +{ + FAR struct stm32_can_s *priv; + +#if defined(CONFIG_STM32_CAN1) && defined(CONFIG_STM32_CAN2) + if (g_can1priv.canrx0 == irq) + { + priv = &g_can1priv; + } + else if (g_can2priv.canrx0 == irq) + { + priv = &g_can2priv; + } + else + { + PANIC(OSERR_UNEXPECTEDISR); + } +#elif defined(CONFIG_STM32_CAN1) + priv = &g_can1priv; +#else /* defined(CONFIG_STM32_CAN2) */ + priv = &g_can2priv; +#endif + +#warning "Missing logic" + return OK; +} + +/**************************************************************************** + * Name: can_rx1interrupt + * + * Description: + * CAN FIFO 1 interrupt handler + * + * 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_rx1interrupt(int irq, void *context) +{ + FAR struct stm32_can_s *priv; + +#if defined(CONFIG_STM32_CAN1) && defined(CONFIG_STM32_CAN2) + if (g_can1priv.canrx1 == irq) + { + priv = &g_can1priv; + } + else if (g_can2priv.canrx1 == irq) + { + priv = &g_can2priv; + } + else + { + PANIC(OSERR_UNEXPECTEDISR); + } +#elif defined(CONFIG_STM32_CAN1) + priv = &g_can1priv; +#else /* defined(CONFIG_STM32_CAN2) */ + priv = &g_can2priv; +#endif + +#warning "Missing logic" + return OK; +} + +/**************************************************************************** + * Name: can_sceinterrupt + * + * Description: + * CAN Status Change Error (SCE) interrupt handler + * + * 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_sceinterrupt(int irq, void *context) +{ + FAR struct stm32_can_s *priv; + +#if defined(CONFIG_STM32_CAN1) && defined(CONFIG_STM32_CAN2) + if (g_can1priv.cansce == irq) + { + priv = &g_can1priv; + } + else if (g_can2priv.cansce == irq) + { + priv = &g_can2priv; + } + else + { + PANIC(OSERR_UNEXPECTEDISR); + } +#elif defined(CONFIG_STM32_CAN1) + priv = &g_can1priv; +#else /* defined(CONFIG_STM32_CAN2) */ + priv = &g_can2priv; +#endif + +#warning "Missing logic" + return OK; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: up_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 *up_caninitialize(int port) +{ + struct can_dev_s *dev = NULL; + +#ifdef CONFIG_STM32_CAN1 + if( port == 1 ) + { + dev = &g_can1dev; + } + else +#endif +#ifdef CONFIG_STM32_CAN2 + if ( port ==2 ) + { + dev = &g_can2dev; + } + else +#endif + { + candbg("Unsupport port %d\n", priv->port); + return NULL; + } + +#warning "Missing logic" + return dev; +} + +#endif /* CONFIG_STM32_CAN1 || CONFIG_STM32_CAN2 */ +#endif /* CONFIG_CAN */ + diff --git a/nuttx/arch/arm/src/stm32/stm32_pwm.c b/nuttx/arch/arm/src/stm32/stm32_pwm.c index 99d2e310c..fb3323d7e 100644 --- a/nuttx/arch/arm/src/stm32/stm32_pwm.c +++ b/nuttx/arch/arm/src/stm32/stm32_pwm.c @@ -2,7 +2,7 @@ * arch/arm/src/stm32/stm32_pwm.c * * Copyright (C) 2011 Gregory Nutt. All rights reserved. - * Author: Gregory Nutt + * Author: Gregory Nutt * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions -- cgit v1.2.3