You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by GitBox <gi...@apache.org> on 2022/01/07 20:21:46 UTC

[GitHub] [incubator-nuttx] hartmannathan commented on a change in pull request #5151: WIP: Tiva CAN driver

hartmannathan commented on a change in pull request #5151:
URL: https://github.com/apache/incubator-nuttx/pull/5151#discussion_r780506415



##########
File path: arch/arm/src/tiva/hardware/tiva_can.h
##########
@@ -0,0 +1,459 @@
+/****************************************************************************
+ * arch/arm/src/tiva/hardware/tiva_can.h
+ *
+ *   Copyright (C) 2006-2020 Texas Instruments Incorporated.
+ *                           All rights reserved.
+ *   Author: Matthew Trescott <ma...@gmail.com>
+ *
+ * From the TivaWare Peripheral Driver Library, with minor changes for
+ * clarity and style.
+ *
+ * The TivaWare sample code has a BSD compatible license that requires this
+ * copyright notice:
+ *
+ * Copyright (c) 2005-2020 Texas Instruments Incorporated.
+ * All rights reserved.
+ * Software License Agreement
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *   Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ *   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.
+ *
+ *   Neither the name of Texas Instruments Incorporated 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.
+ *
+ * This is part of revision 2.2.0295 of the Tiva Peripheral Driver Library.
+ *
+ ****************************************************************************/
+

Review comment:
       Need to add this to LICENSE?
   
   I think it's enough to add this filename, `arch/arm/src/tiva/hardware/tiva_can.h`, to the list that currently starts at line 1680 of LICENSE in the project root.

##########
File path: arch/arm/src/tiva/common/tiva_can.c
##########
@@ -0,0 +1,2401 @@
+/****************************************************************************
+ * arch/arm/src/tiva/common/tiva_can.c
+ * Classic (character-device) lower-half driver for the Tiva CAN modules.
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.  The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <debug.h>
+
+#include <arch/board/board.h>
+
+#include <nuttx/arch.h>
+#include <nuttx/irq.h>
+#include <nuttx/kthread.h>
+#include <nuttx/mutex.h>
+#include <nuttx/semaphore.h>
+
+#include <nuttx/can/can.h>
+
+#ifdef CONFIG_CAN_ERRORS
+/* A self-reenqueuing worker is used to report errors periodically when
+ * status interrupts are disabled due to overload.
+ */
+
+#include <nuttx/wqueue.h>
+#endif
+
+#include "arm_arch.h"
+#include "chip.h"
+#include "tiva_can.h"
+#include "hardware/tiva_can.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if defined(CONFIG_TIVA_CAN) && (defined(CONFIG_TIVA_CAN0) || defined(CONFIG_TIVA_CAN1))
+
+#if defined(CONFIG_CAN_ERRORS) && !defined(CONFIG_SCHED_LPWORK)
+#  error "Error reporting requires the low-priority work queue to be enabled."
+#endif
+
+/* Combines two 16-bit registers into a single 32 bit value */
+#define tivacan_readsplitreg32(base, r1, r2) ((getreg32((base) + (r1)) & 0xffff) | (getreg32((base) + (r2)) << 16))
+
+#define tivacan_get_nwda32(base) tivacan_readsplitreg32((base), TIVA_CAN_OFFSET_NWDA1, TIVA_CAN_OFFSET_NWDA2)
+#define tivacan_get_txrq32(base) tivacan_readsplitreg32((base), TIVA_CAN_OFFSET_TXRQ1, TIVA_CAN_OFFSET_TXRQ2)
+#define tivacan_get_msgval32(base) tivacan_readsplitreg32((base), TIVA_CAN_OFFSET_MSG1VAL, TIVA_CAN_OFFSET_MSG2VAL)
+
+/* Only the last few mailboxes are used for TX to help ensure that responses
+ * to remote request frames we send are always collected by an RX FIFO and
+ * not by the mailbox used to send the remote frame. (The Tiva hardware uses
+ * the mailbox with the lowest number first.)
+ *
+ * This number is zero-indexed, althought the Command Request Register isn't.
+ */
+#define TIVA_CAN_TX_FIFO_START (TIVA_CAN_NUM_MBOXES - CONFIG_TIVA_CAN_TX_FIFO_DEPTH)
+
+/* Frequency of async error message reporting when rate-limited */
+#define TIVA_CAN_ERR_HANDLER_TICKS MSEC2TICK(CONFIG_TIVA_CAN_ERR_HANDLER_PER)
+
+/* For the RX receive kthread */
+#define TIVA_CAN_KTHREAD_STACKSIZE 1024
+
+/* For tivacan_initfilter */
+#define TIVA_CAN_FILTER_TYPE_STD 0
+#define TIVA_CAN_FILTER_TYPE_EXT 1
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* Bitfield representing the mailboxes belonging to this FIFO. The
+ * high bit (mask: 1 << 31) corresponds to mailbox 31, the low bit
+ * (mask: 1 << 0) corresponds to mailbox 0.
+ *
+ * NOTE: If a new chip came along with more mailboxes, this would
+ * need to be reworked.
+ */
+
+typedef uint32_t tiva_can_fifo_t;
+
+/* This structure represents a CAN module on the microcontroller */
+
+struct tiva_canmod_s
+{
+  /* Module number, mostly for syscon register fields */
+
+  int       modnum;
+
+  /* Registers base address */
+
+  uint32_t  base;
+
+  /* Contents of the CANSTS reg the last time errors were processed. */
+
+  uint32_t  status;
+
+  /* Contents of the CANERR reg the last time errors were processed. */
+
+  uint32_t  errors;
+
+  /* kthread message handler waits on this; ISR posts */
+
+  sem_t     rxsem;
+
+  /* Mailbox number (zero-indexed) that the kthread message handler is
+   * currently retrieving from the CAN module SRAM or in the process of
+   * sending to the application. The kthread works through messages in
+   * ascending order, so if the ISR will only post the semaphore for received
+   * messages that the kthread has already "passed by."
+   */
+
+  int       kthd_cur_mbox;
+
+  /* kthread message handler thread ID */
+
+  int       kthd_id;
+
+#ifdef CONFIG_CAN_ERRORS
+  /* Asynchronously report errors when status interrupts are disabled */
+
+  struct work_s error_work;
+#endif
+
+  /* Whether to autorecover from bus-off conditions */
+
+  bool      autorecover;
+
+  /* Mutex for threads accessing the interface registers */
+
+  mutex_t   thd_iface_mtx;
+
+  /* Interface registers base address for threads threads */
+
+  uint32_t  thd_iface_base;
+
+  /* Interface registers base address reserved exclusively for the ISR */
+
+  uint32_t  isr_iface_base;
+
+  /* Mutex for claiming, freeing, and potentially resizing RX FIFOs.
+   * The TX FIFO should never be resized at runtime.
+   */
+
+  mutex_t   fifo_mtx;
+
+  /* All RX FIFOs + 1 TX FIFO */
+
+  tiva_can_fifo_t fifos[CONFIG_TIVA_CAN_FILTERS_MAX + 1];
+
+  /* Pointer to default catch-all RX FIFO initialized by the driver. */
+
+  FAR tiva_can_fifo_t *rxdefault_fifo;
+
+  /* Pointer to the permanent, fixed-size TX FIFO. This is always located at
+   * the end of the series of mailboxes to help ensure that responses to
+   * remote request frames go to an RX (filter) FIFO and don't interfere.
+   */
+
+  FAR tiva_can_fifo_t *tx_fifo;
+
+  /* Index in the TX FIFO where new messages should be added. The Tiva CAN
+   * module doesn't support a ring buffer, so new messages are only added
+   * when the TX FIFO is empty (tx_fifo_tail == 0).
+   */
+
+  int tx_fifo_tail;
+};
+
+/* This structure represents the CAN bit timing settings as seen by the hw. */
+
+struct tiva_can_timing_s
+{
+  int       prescaler;
+  int       tseg1;
+  int       tseg2;
+  int       sjw;
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Callbacks for upper-half CAN driver */
+
+static void tivacan_reset(FAR struct can_dev_s *dev);
+static int  tivacan_setup(FAR struct can_dev_s *dev);
+static void tivacan_shutdown(FAR struct can_dev_s *dev);
+static void tivacan_rxintctl(FAR struct can_dev_s *dev, bool enable);
+static void tivacan_txintctl(FAR struct can_dev_s *dev, bool enable);
+static int  tivacan_ioctl(FAR struct can_dev_s *dev,
+                          int cmd, unsigned long arg);
+static int  tivacan_send(FAR struct can_dev_s *dev,
+                         FAR struct can_msg_s *msg);
+static bool tivacan_txready(FAR struct can_dev_s *dev);
+static bool tivacan_txempty(FAR struct can_dev_s *dev);
+
+/* ISR */
+
+static int  tivacan_isr(int irq, FAR void *context, FAR void *dev);
+
+/* Internal utility functions */
+
+static struct tiva_can_timing_s
+tivacan_bittiming_get(FAR struct can_dev_s *dev);
+
+static void tivacan_bittiming_set(FAR struct can_dev_s *dev,
+                                  FAR struct tiva_can_timing_s *timing);
+
+int tivacan_alloc_fifo(FAR struct can_dev_s *dev, int depth);
+static void tivacan_free_fifo(FAR struct can_dev_s *dev,
+                              FAR tiva_can_fifo_t *fifo);
+static void tivacan_disable_mbox(FAR struct can_dev_s *dev,
+                                 uint32_t iface_base,
+                                 int num);
+static int  tivacan_initfilter(FAR struct can_dev_s       *dev,
+                               FAR tiva_can_fifo_t        *fifo,
+                               FAR void                   *filter,
+                               int                         type);
+static int  tivacan_rxhandler(int argc, char** argv);
+int tivacan_handle_errors(FAR struct can_dev_s *dev);
+
+#ifdef CONFIG_CAN_ERRORS
+void tivacan_handle_errors_wqueue(FAR void * dev);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* List of callbacks provided to can_register via g_tivacanNdev */
+
+static const struct can_ops_s g_tivacanops =
+{
+  .co_reset         = tivacan_reset,
+  .co_setup         = tivacan_setup,
+  .co_shutdown      = tivacan_shutdown,
+  .co_rxint         = tivacan_rxintctl,
+  .co_txint         = tivacan_txintctl,
+  .co_ioctl         = tivacan_ioctl,
+  .co_remoterequest = NULL,               /* Use CONFIG_CAN_USE_RTR instead */
+  .co_send          = tivacan_send,
+  .co_txready       = tivacan_txready,
+  .co_txempty       = tivacan_txempty,
+};
+
+#ifdef CONFIG_TIVA_CAN0
+static struct tiva_canmod_s g_tivacan0priv =
+{
+  .modnum           = 0,
+  .base             = TIVA_CAN_BASE(0),
+  .thd_iface_base   = TIVA_CAN_IFACE_BASE(0, 0),
+  .isr_iface_base   = TIVA_CAN_IFACE_BASE(0, 1),
+  .rxdefault_fifo   = NULL,
+};
+
+static struct can_dev_s g_tivacan0dev =
+{
+  .cd_ops           = &g_tivacanops,
+  .cd_priv          = &g_tivacan0priv,
+};
+#endif /* CONFIG_TIVA_CAN0 */
+
+#ifdef CONFIG_TIVA_CAN1
+static struct tiva_canmod_s g_tivacan1priv =
+{
+  .modnum           = 1,
+  .base             = TIVA_CAN_BASE(1),
+  .thd_iface_base   = TIVA_CAN_IFACE_BASE(1, 0),
+  .isr_iface_base   = TIVA_CAN_IFACE_BASE(1, 1),
+  .rxdefault_fifo   = NULL,
+};
+
+static struct can_dev_s g_tivacan1dev =
+{
+  .cd_ops           = &g_tivacanops,
+  .cd_priv          = &g_tivacan1priv,
+};
+#endif /* CONFIG_TIVA_CAN1 */
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: tivacan_reset
+ *
+ * Description:
+ *   Software-reset the CAN module using the SYSCON registers.
+ *
+ *   A pointer to this function is passed to can_register.
+ *
+ * Input parameters:
+ *   dev - An instance of the "upper half" CAN driver structure
+ *
+ * Returned value: None
+ ****************************************************************************/
+
+static void tivacan_reset(FAR struct can_dev_s *dev)
+{
+  FAR struct tiva_canmod_s *canmod = dev->cd_priv;
+  int modnum = canmod->modnum;
+#ifndef CONFIG_TIVA_CAN0
+  if (modnum == 0)
+    {
+      canerr("ERROR: tried to reset disabled module CAN0\n");
+      return;
+    }
+
+#endif
+#ifndef CONFIG_TIVA_CAN1
+  if (modnum == 1)
+    {
+      canerr("ERROR: tried to reset disabled module CAN1\n");
+    }
+
+#endif
+  if (modnum > 1)
+    {
+      canerr("ERROR: tried to reset nonexistant module CAN%d\n",
+             canmod->modnum);
+    }
+
+  modifyreg32(TIVA_SYSCON_SRCAN, 0, SYSCON_SRCAN(modnum));
+
+  /* Spin for a few clock cycles */
+
+  for (int i = 0; i < 16; ++i);
+
+  modifyreg32(TIVA_SYSCON_SRCAN, SYSCON_SRCAN(modnum), 0);
+
+  /* Wait for peripheral-ready signal */
+
+  while (!(getreg32(TIVA_SYSCON_PRCAN) & (1 << modnum)));
+}
+
+/****************************************************************************
+ * Name: tivacan_setup
+ *
+ * Description:
+ *   Set up the CAN module. Register the ISR and enable the interrupt in the
+ *   NVIC. Set default bit-timing and set filters to a consistent state. On
+ *   return, the INIT bit is cleared in the CANCTL register, and interrupts
+ *   are enabled on the side of the CAN module. (can_ops_s.txint and
+ *   can_ops_s.rxint are unsuitable because the Tiva CAN modules do not allow
+ *   disabling TX and RX interrupts separately).
+ *
+ *   A pointer to this function is passed to can_register.
+ *
+ * Input parameters:
+ *   dev - An instance of the "upper half" CAN driver structure
+ *
+ * Returned value:
+ *   Zero on success, or a negated errno on failure.
+ ****************************************************************************/
+
+static int tivacan_setup(FAR struct can_dev_s *dev)
+{
+  uint32_t  irq;
+  int       ret;
+  uint32_t  reg;
+  FAR struct tiva_canmod_s    *canmod = dev->cd_priv;
+  char     *kthd_argv[2];
+  kthd_argv[1] = NULL;
+
+  ret = nxsem_init(&canmod->rxsem, 0, 0);
+
+  if (ret < 0)
+    {
+      return ret;
+    }
+
+  switch (canmod->modnum)
+    {
+#ifdef CONFIG_TIVA_CAN0
+      case 0:
+        {
+          kthd_argv[0] = "0";
+          ret = kthread_create("Tiva CAN0",
+                               CONFIG_TIVA_CAN0_PRIO,
+                               TIVA_CAN_KTHREAD_STACKSIZE,
+                               tivacan_rxhandler,
+                               kthd_argv);
+        }
+      break;
+#endif
+#ifdef CONFIG_TIVA_CAN1
+      case 1:
+        {
+          kthd_argv[0] = "1";
+          ret = kthread_create("Tiva CAN1",
+                               CONFIG_TIVA_CAN1_PRIO,
+                               TIVA_CAN_KTHREAD_STACKSIZE,
+                               tivacan_rxhandler,
+                               kthd_argv);
+        }
+      break;
+#endif
+      default:
+        return -EINVAL;
+    }
+
+  if (ret < 0)
+    {
+      canerr("tiva_can: failed to create kthread\n");
+      return ret;
+    }
+  else
+    {
+      canmod->kthd_id = ret;
+    }
+
+#ifdef CONFIG_CAN_EXTID
+  struct canioc_extfilter_s default_filter =
+  {
+    .xf_id1   = 0x123,
+    .xf_id2   = 0,
+    .xf_type  = CAN_FILTER_MASK,
+    .xf_prio  = CAN_MSGPRIO_HIGH,
+  };
+#else
+  struct canioc_stdfilter_s default_filter =
+  {
+    .sf_id1   = 0x123,
+    .sf_id2   = 0,
+    .sf_type  = CAN_FILTER_MASK,
+    .sf_prio  = CAN_MSGPRIO_HIGH,
+  };
+#endif
+
+  /* REVISIT: This will not necessarily come out nicely on boards with
+   * different crystals.
+   */
+

Review comment:
       Can this be calculated from SYSCLK_FREQUENCY defined in the board's board.h?




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: commits-unsubscribe@nuttx.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org