nuttx/drivers/can/sja1000.c
Radek Pesina 8f9c337c66 drivers/can/sja1000: Add SJA1000 CAN driver support
This driver is based on ESP32 TWAI CAN drivers currently available
in Nuttx, and captures the differences currently present across the
TWAI drivers for easy future adaption to remaining ESP32 platforms
with no loss of support/function. Also provides a generic SJA1000 CAN
driver solution that is CPU-architecture independent.

Changes:
- Low-level driver re-written to allow usage independent of CPU
architecture, and support both SJA1000 and TWAI CAN controllers.
- Platform-specific settings abstracted away to be provided by board
layer.
- Support for multiple instances of SJA1000 driver.
2024-03-19 15:45:53 -03:00

1175 lines
34 KiB
C

/****************************************************************************
* drivers/can/sja1000.c
*
* SJA1000 CAN driver based on esp32c3_twai.c
*
* License header retained from original source.
*
* 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 <assert.h>
#include <debug.h>
#include <endian.h>
#include <errno.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <nuttx/arch.h>
#include <nuttx/can/can.h>
#include <nuttx/mutex.h>
#include <nuttx/signal.h>
#include <nuttx/spinlock.h>
#include <nuttx/can/sja1000.h>
#include "sja1000.h"
#include <nuttx/can.h>
#ifdef CONFIG_CAN_SJA1000
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration
* ************************************************************/
#if defined(CONFIG_CAN_SJA1000_DEBUG)
#define cantrace _info
#else
#define cantrace _none
#endif /* CONFIG_CAN_SJA1000_DEBUG */
/* Default values written to various registers on initialization */
#define SJA1000_INIT_TEC 0
#define SJA1000_INIT_REC 0
#define SJA1000_INIT_EWL 96
#define SJA1000_ACCEPTANCE_CODE 0x0 /* 32-bit address to match */
#define SJA1000_ACCEPTANCE_MASK 0xffffffff /* 32-bit address mask */
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
/* SJA1000 Register access */
#ifdef CONFIG_CANBUS_REGDEBUG
static void sja1000_printreg(uint32_t addr, uint32_t value);
#endif
/* SJA1000 methods */
static void sja1000_reset(struct can_dev_s *dev);
static int sja1000_setup(struct can_dev_s *dev);
static void sja1000_shutdown(struct can_dev_s *dev);
static void sja1000_rxint(struct can_dev_s *dev, bool enable);
static void sja1000_txint(struct can_dev_s *dev, bool enable);
static int sja1000_ioctl(struct can_dev_s *dev, int cmd, unsigned long arg);
static int sja1000_remoterequest(struct can_dev_s *dev, uint16_t id);
static int sja1000_send(struct can_dev_s *dev, struct can_msg_s *msg);
static bool sja1000_txready(struct can_dev_s *dev);
static bool sja1000_txempty(struct can_dev_s *dev);
/* SJA1000 interrupts */
static int sja1000_interrupt(FAR struct sja1000_config_s *config,
void *arg);
/* SJA1000 acceptance filter */
static void sja1000_set_acc_filter(struct sja1000_dev_s *priv,
uint32_t code, uint32_t mask,
bool single_filter);
/* SJA1000 bit-timing initialization */
static int sja1000_baud_rate(struct sja1000_dev_s *priv, int rate,
int clock, int sjw, int sampl_pt, int flags);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct can_ops_s g_sja1000ops =
{
.co_reset = sja1000_reset,
.co_setup = sja1000_setup,
.co_shutdown = sja1000_shutdown,
.co_rxint = sja1000_rxint,
.co_txint = sja1000_txint,
.co_ioctl = sja1000_ioctl,
.co_remoterequest = sja1000_remoterequest,
.co_send = sja1000_send,
.co_txready = sja1000_txready,
.co_txempty = sja1000_txempty,
};
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: sja1000_printreg
*
* Description:
* Print the value read from a register.
*
* Input Parameters:
* addr - The register address
* value - The register value
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_CANBUS_REGDEBUG
static void sja1000_printreg(uint32_t addr, uint32_t value)
{
static uint32_t prevaddr;
static uint32_t preval;
static uint32_t count;
/* 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 %" PRId32 " more times]\n", count - 3);
}
/* Save the new address, value, and count */
prevaddr = addr;
preval = value;
count = 1;
}
/* Show the register value read */
caninfo("%08" PRIx32 "->%08" PRIx32 "\n", addr, value);
}
#endif /* CONFIG_CANBUS_REGDEBUG */
/****************************************************************************
* Name: sja1000_reset
*
* Description:
* Reset the SJA1000 device. Called early to initialize the hardware.
*This function is called, before litex_sja1000_setup() and on error
*conditions.
*
* Input Parameters:
* dev - An instance of the "upper half" CAN driver state structure.
*
* Returned Value:
* None
*
****************************************************************************/
static void sja1000_reset(struct can_dev_s *dev)
{
struct sja1000_dev_s *priv = (struct sja1000_dev_s *)dev->cd_priv;
struct sja1000_config_s *config = priv->config;
uint8_t port = config->port;
irqstate_t flags;
int ret;
caninfo("SJA1000 Device %" PRIu8 "\n", port);
#ifdef CONFIG_ARCH_HAVE_MULTICPU
flags = spin_lock_irqsave(&priv->lock);
#else
flags = enter_critical_section();
#endif /* CONFIG_ARCH_HAVE_MULTICPU */
/* Disable the SJA1000 and stop ongoing transmissions */
uint32_t mode_value = SJA1000_RESET_MODE_M | SJA1000_LISTEN_ONLY_MODE_M;
sja1000_putreg(priv,
SJA1000_MODE_REG, mode_value); /* Enter Reset Mode */
sja1000_modifyreg32(priv,
SJA1000_CLOCK_DIVIDER_REG, 0, SJA1000_EXT_MODE_M);
sja1000_putreg(priv, SJA1000_INT_ENA_REG, 0); /* Disable interrupts */
sja1000_getreg(priv, SJA1000_STATUS_REG); /* Clear status bits */
sja1000_putreg(priv,
SJA1000_TX_ERR_CNT_REG, SJA1000_INIT_TEC); /* TEC */
sja1000_putreg(priv,
SJA1000_RX_ERR_CNT_REG, SJA1000_INIT_REC); /* REC */
sja1000_putreg(priv,
SJA1000_ERR_WARNING_LIMIT_REG, SJA1000_INIT_EWL); /* EWL */
sja1000_set_acc_filter(
priv, SJA1000_ACCEPTANCE_CODE, SJA1000_ACCEPTANCE_MASK, true);
/* Set bit timing */
ret = sja1000_baud_rate(priv, config->bitrate, config->clk_freq,
config->sjw, config->samplep, 0);
if (ret != OK)
{
canerr("ERROR: Failed to set bit timing: %d\n", ret);
}
/* Restart the SJA1000 */
if (config->loopback)
{
/* Leave Reset Mode, enter Test Mode */
sja1000_putreg(priv, SJA1000_MODE_REG, SJA1000_SELF_TEST_MODE_M);
}
else
{
/* Leave Reset Mode */
sja1000_putreg(priv, SJA1000_MODE_REG, 0);
}
/* Abort transmission, release RX buffer and clear overrun.
* Command register can only be modified when in Operation Mode.
*/
sja1000_putreg(priv, SJA1000_CMD_REG, SJA1000_ABORT_TX_M
| SJA1000_RELEASE_BUF_M
| SJA1000_CLR_OVERRUN_M);
#ifdef CONFIG_ARCH_HAVE_MULTICPU
spin_unlock_irqrestore(&priv->lock, flags);
#else
leave_critical_section(flags);
#endif /* CONFIG_ARCH_HAVE_MULTICPU */
}
/****************************************************************************
* Name: sja1000_setup
*
* Description:
* Configure the SJA1000. This method is called the first time that the
*SJA1000 device is opened. This will occur when the port is first opened.
* This setup includes configuring and attaching SJA1000 interrupts.
*
* 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 sja1000_setup(struct can_dev_s *dev)
{
struct sja1000_dev_s *priv = (struct sja1000_dev_s *)dev->cd_priv;
struct sja1000_config_s *config = priv->config;
uint8_t port = config->port;
irqstate_t flags;
int ret = OK;
caninfo("SJA1000 (%" PRIu8 ")\n", port);
#ifdef CONFIG_ARCH_HAVE_MULTICPU
flags = spin_lock_irqsave(&priv->lock);
#else
flags = enter_critical_section();
#endif /* CONFIG_ARCH_HAVE_MULTICPU */
sja1000_putreg(priv, SJA1000_INT_ENA_REG, SJA1000_DEFAULT_INTERRUPTS);
/* clear latched interrupts */
sja1000_getreg(priv, SJA1000_INT_RAW_REG);
/* Attach the SJA1000 interrupts and handler. */
ret = config->attach(
config, (sja1000_handler_t)sja1000_interrupt, (FAR void *)dev);
if (ret < 0)
{
canerr("ERROR: Failed to attach to IRQ Handler!\n");
return ret;
}
#ifdef CONFIG_ARCH_HAVE_MULTICPU
spin_unlock_irqrestore(&priv->lock, flags);
#else
leave_critical_section(flags);
#endif /* CONFIG_ARCH_HAVE_MULTICPU */
return ret;
}
/****************************************************************************
* Name: sja1000_shutdown
*
* Description:
* Disable the SJA1000. This method is called when the SJA1000 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 sja1000_shutdown(struct can_dev_s *dev)
{
int ret;
struct sja1000_dev_s *priv = (struct sja1000_dev_s *)dev->cd_priv;
struct sja1000_config_s *config = priv->config;
uint8_t port = config->port;
cantrace("shutdown SJA1000 (%" PRIu8 ")\n", port);
/* Detach the SJA1000 interrupts and handler. */
ret = config->detach(config);
if (ret < 0)
{
canerr("ERROR: Failed to detach from IRQ Handler!\n");
}
}
/****************************************************************************
* Name: sja1000_rxint
*
* Description:
* Call to enable or disable RX interrupts.
*
* Input Parameters:
* dev - An instance of the "upper half" CAN driver state structure.
* enable - Enable or disable receive interrupt.
*
* Returned Value:
* None
*
****************************************************************************/
static void sja1000_rxint(struct can_dev_s *dev, bool enable)
{
struct sja1000_dev_s *priv = (struct sja1000_dev_s *)dev->cd_priv;
struct sja1000_config_s *config = priv->config;
uint8_t port = config->port;
uint32_t regval;
irqstate_t flags;
cantrace("SJA1000 (%" PRIu8 ") enable: %d\n", port, enable);
/* The INT_ENA register is also modified from the interrupt handler,
* so we have to protect this code section.
*/
#ifdef CONFIG_ARCH_HAVE_MULTICPU
flags = spin_lock_irqsave(&priv->lock);
#else
flags = enter_critical_section();
#endif /* CONFIG_ARCH_HAVE_MULTICPU */
regval = sja1000_getreg(priv, SJA1000_INT_ENA_REG);
if (enable)
{
regval |= SJA1000_RX_INT_ENA_M;
}
else
{
regval &= ~SJA1000_RX_INT_ENA_M;
}
sja1000_putreg(priv, SJA1000_INT_ENA_REG, regval);
#ifdef CONFIG_ARCH_HAVE_MULTICPU
spin_unlock_irqrestore(&priv->lock, flags);
#else
leave_critical_section(flags);
#endif /* CONFIG_ARCH_HAVE_MULTICPU */
}
/****************************************************************************
* Name: sja1000_txint
*
* Description:
* Call to enable or disable TX interrupts.
*
* Input Parameters:
* dev - An instance of the "upper half" CAN driver state structure.
* enable - Enable or disable transmit interrupt.
*
* Returned Value:
* None
*
****************************************************************************/
static void sja1000_txint(struct can_dev_s *dev, bool enable)
{
struct sja1000_dev_s *priv = (struct sja1000_dev_s *)dev->cd_priv;
struct sja1000_config_s *config = priv->config;
uint8_t port = config->port;
uint32_t regval;
irqstate_t flags;
cantrace("SJA1000 (%" PRIu8 ") enable: %d\n", port, enable);
/* Only disabling of the TX interrupt is supported here. The TX interrupt
* is automatically enabled just before a message is sent in order to
* avoid lost TX interrupts.
*/
if (!enable)
{
/* TX interrupts are also disabled from the interrupt handler, so we
* have to protect this code section.
*/
#ifdef CONFIG_ARCH_HAVE_MULTICPU
flags = spin_lock_irqsave(&priv->lock);
#else
flags = enter_critical_section();
#endif /* CONFIG_ARCH_HAVE_MULTICPU */
/* Disable all TX interrupts */
regval = sja1000_getreg(priv, SJA1000_INT_ENA_REG);
regval &= ~(SJA1000_TX_INT_ENA_M);
sja1000_putreg(priv, SJA1000_INT_ENA_REG, regval);
#ifdef CONFIG_ARCH_HAVE_MULTICPU
spin_unlock_irqrestore(&priv->lock, flags);
#else
leave_critical_section(flags);
#endif /* CONFIG_ARCH_HAVE_MULTICPU */
}
cantrace("Exiting.\n");
}
/****************************************************************************
* Name: sja1000_ioctl
*
* Description:
* All ioctl calls will be routed through this method
*
* Input Parameters:
* dev - An instance of the "upper half" CAN driver state structure.
* cmd - A ioctl command.
* arg - A ioctl argument.
*
* Returned Value:
* Zero on success; a negated errno on failure
*
****************************************************************************/
static int sja1000_ioctl(struct can_dev_s *dev, int cmd, unsigned long arg)
{
struct sja1000_dev_s *priv = (struct sja1000_dev_s *)dev->cd_priv;
struct sja1000_config_s *config = priv->config;
int ret = -ENOTTY;
uint8_t port = config->port;
cantrace("SJA1000 (%" PRIu8 ") cmd=%04x arg=%lu\n", port, cmd, arg);
/* Handle the command */
switch (cmd)
{
/* CANIOC_GET_BITTIMING:
* Description: Return the current bit timing settings
* Argument: A pointer to a write-able instance of struct
* canioc_bittiming_s in which current bit timing
* values will be returned.
* Returned Value: Zero (OK) is returned on success. Otherwise -1
* (ERROR) is returned with the errno variable set
* to indicate the nature of the error.
* Dependencies: None
*/
case CANIOC_GET_BITTIMING:
{
struct canioc_bittiming_s *bt = (struct canioc_bittiming_s *)arg;
uint32_t timing0;
uint32_t timing1;
uint32_t brp;
DEBUGASSERT(bt != NULL);
timing0 = sja1000_getreg(priv, SJA1000_BUS_TIMING_0_REG);
timing1 = sja1000_getreg(priv, SJA1000_BUS_TIMING_1_REG);
brp = ((timing0 & SJA1000_BAUD_PRESC_M) + 1) * 2;
bt->bt_sjw = ((timing0 & SJA1000_SYNC_JUMP_WIDTH_M)
>> SJA1000_SYNC_JUMP_WIDTH_S)
+ 1;
bt->bt_tseg1
= ((timing1 & SJA1000_TIME_SEG1_M) >> SJA1000_TIME_SEG1_S)
+ 1;
bt->bt_tseg2
= ((timing1 & SJA1000_TIME_SEG2_M) >> SJA1000_TIME_SEG2_S)
+ 1;
bt->bt_baud = config->clk_freq
/ (brp * (bt->bt_tseg1 + bt->bt_tseg2 + 1));
cantrace("Retrieved baud rate. TS1: %" PRId8 " TS2: %" PRId8
" BRP: %" PRId32 "\n",
bt->bt_tseg1, bt->bt_tseg2, brp);
cantrace("timing0: 0x%" PRIx32 ", timing1: 0x%" PRIx32 " Baud: "
"%" PRId32
"\n",
timing0, timing1, bt->bt_baud);
ret = OK;
}
break;
/* Unsupported/unrecognized command */
default:
canerr("ERROR: Unrecognized command: %04x\n", cmd);
break;
}
return ret;
}
static int sja1000_remoterequest(struct can_dev_s *dev, uint16_t id)
{
canwarn("Remote request not implemented\n");
return -ENOSYS;
}
/****************************************************************************
* Name: sja1000_send
*
* Description:
* Send one SJA1000 message.
*
* One SJA1000-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 SJA1000 identifier
* Byte 1: Bits 5-7: Bits 0-2 of the 11-bit SJA1000 identifier
* Bit 4: Remote Transmission Request (RTR)
* Bits 0-3: Data Length Code (DLC)
* Bytes 2-10: SJA1000 data
*
* Input Parameters:
* dev - An instance of the "upper half" CAN driver state structure.
* msg - A message to send.
*
* Returned Value:
* Zero on success; a negated errno on failure
*
****************************************************************************/
static int sja1000_send(struct can_dev_s *dev, struct can_msg_s *msg)
{
struct sja1000_dev_s *priv = (struct sja1000_dev_s *)dev->cd_priv;
struct sja1000_config_s *config = priv->config;
uint32_t regval;
uint32_t i;
uint32_t len;
uint32_t id;
uint32_t frame_info;
irqstate_t flags;
uint8_t port = config->port;
int ret = OK;
cantrace("SJA1000 (%" PRIu8 ") ID: %" PRIu32 " DLC: %" PRIu8 "\n", port,
(uint32_t)msg->cm_hdr.ch_id, msg->cm_hdr.ch_dlc);
len = (uint32_t)msg->cm_hdr.ch_dlc;
if (len > CAN_MAXDATALEN)
len = CAN_MAXDATALEN;
frame_info = len;
if (msg->cm_hdr.ch_rtr)
{
frame_info |= (1 << 6);
}
#ifdef CONFIG_ARCH_HAVE_MULTICPU
flags = spin_lock_irqsave(&priv->lock);
#else
flags = enter_critical_section();
#endif /* CONFIG_ARCH_HAVE_MULTICPU */
/* Make sure that TX interrupts are enabled BEFORE sending the
* message.
*
* NOTE: The INT_ENA is also modified from the interrupt handler, but the
* following is safe because interrupts are disabled here.
*/
regval = sja1000_getreg(priv, SJA1000_INT_ENA_REG);
regval |= SJA1000_TX_INT_ENA_M;
sja1000_putreg(priv, SJA1000_INT_ENA_REG, regval);
/* Set up the transfer */
#ifdef CONFIG_CAN_EXTID
if (msg->cm_hdr.ch_extid)
{
/* The provided ID should be 29 bits */
id = (uint32_t)msg->cm_hdr.ch_id;
DEBUGASSERT((id & ~CAN_MAX_EXTMSGID) == 0);
frame_info |= (1 << 7);
sja1000_putreg(priv, SJA1000_DATA_0_REG, frame_info);
id <<= 3;
sja1000_putreg(priv, SJA1000_DATA_4_REG, id & 0xff);
id >>= 8;
sja1000_putreg(priv, SJA1000_DATA_3_REG, id & 0xff);
id >>= 8;
sja1000_putreg(priv, SJA1000_DATA_2_REG, id & 0xff);
id >>= 8;
sja1000_putreg(priv, SJA1000_DATA_1_REG, id & 0xff);
for (i = 0; i < len; i++)
{
sja1000_putreg(priv,
(SJA1000_DATA_5_REG + i), msg->cm_data[i]);
}
}
else
#endif
{
/* The provided ID should be 11 bits */
id = (uint32_t)msg->cm_hdr.ch_id;
DEBUGASSERT((id & ~CAN_MAX_STDMSGID) == 0);
sja1000_putreg(priv, SJA1000_DATA_0_REG, frame_info);
id <<= 5;
sja1000_putreg(priv, SJA1000_DATA_1_REG, (id >> 8) & 0xff);
sja1000_putreg(priv, SJA1000_DATA_2_REG, id & 0xff);
for (i = 0; i < len; i++)
{
sja1000_putreg(priv,
(SJA1000_DATA_3_REG + i), msg->cm_data[i]);
}
}
/* Send the message */
if (config->loopback)
{
sja1000_putreg(priv, SJA1000_CMD_REG,
SJA1000_SELF_RX_REQ_M | SJA1000_ABORT_TX_M);
}
else
{
sja1000_putreg(priv, SJA1000_CMD_REG, SJA1000_TX_REQ_M);
}
#ifdef CONFIG_ARCH_HAVE_MULTICPU
spin_unlock_irqrestore(&priv->lock, flags);
#else
leave_critical_section(flags);
#endif /* CONFIG_ARCH_HAVE_MULTICPU */
return ret;
}
/****************************************************************************
* Name: sja1000_txready
*
* Description:
* Return true if the SJA1000 hardware can accept another TX message.
*
* Input Parameters:
* dev - An instance of the "upper half" CAN driver state structure.
*
* Returned Value:
* True if the SJA1000 hardware is ready to accept another TX message.
*
****************************************************************************/
static bool sja1000_txready(struct can_dev_s *dev)
{
struct sja1000_dev_s *priv = dev->cd_priv;
struct sja1000_config_s *config = priv->config;
uint8_t port = config->port;
uint32_t regval = sja1000_getreg(priv, SJA1000_STATUS_REG);
caninfo("SJA1000 (%" PRIu8 ") txready: %d\n", port,
((regval & SJA1000_TX_BUF_ST_M) != 0));
return ((regval & SJA1000_TX_BUF_ST_M) != 0);
}
/****************************************************************************
* Name: sja1000_txempty
*
* Description:
* Return true if all message have been sent. If for example, the SJA1000
* 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 SJA1000 hardware.
*
****************************************************************************/
static bool sja1000_txempty(struct can_dev_s *dev)
{
struct sja1000_dev_s *priv = dev->cd_priv;
struct sja1000_config_s *config = priv->config;
uint8_t port = config->port;
uint32_t regval = sja1000_getreg(priv, SJA1000_STATUS_REG);
caninfo("SJA1000 (%" PRIu8 ") txempty: %d\n", port,
((regval & SJA1000_TX_BUF_ST_M) != 0));
return ((regval & SJA1000_TX_BUF_ST_M) != 0);
}
/****************************************************************************
* Name: sja1000_interrupt
*
* Description:
* SJA1000 RX/TX interrupt handler
*
* Input Parameters:
* irq - The IRQ number of the interrupt.
* context - The register state save array at the time of the interrupt.
* arg - The pointer to driver structure.
*
* Returned Value:
* Zero on success; a negated errno on failure
*
****************************************************************************/
static int sja1000_interrupt(FAR struct sja1000_config_s *config, void *arg)
{
#ifdef CONFIG_CAN_SJA1000
struct can_dev_s *dev = (struct can_dev_s *)arg;
struct sja1000_dev_s *priv = dev->cd_priv;
struct can_hdr_s hdr;
uint8_t data[8];
uint32_t frame_info;
uint32_t len;
uint32_t datastart;
uint32_t regval;
uint32_t i;
/* Read the interrupt register results in clearing bits */
regval = sja1000_getreg(priv, SJA1000_INT_RAW_REG);
cantrace("Entered. Regval = 0x%" PRIx32 "\n", regval);
/* Check for a receive interrupt */
if ((regval & SJA1000_RX_INT_ST_M) != 0)
{
memset(&hdr, 0, sizeof(hdr));
memset(data, 0, sizeof(data));
frame_info = sja1000_getreg(priv, SJA1000_DATA_0_REG);
/* Construct the SJA1000 header */
if (frame_info & (1 << 6))
{
hdr.ch_rtr = 1;
}
#ifdef CONFIG_CAN_EXTID
if (frame_info & (1 << 7))
{
/* The provided ID should be 29 bits */
hdr.ch_extid = 1;
hdr.ch_id = (sja1000_getreg(priv, SJA1000_DATA_1_REG) << 21)
+ (sja1000_getreg(priv, SJA1000_DATA_2_REG) << 13)
+ (sja1000_getreg(priv, SJA1000_DATA_3_REG) << 5)
+ (sja1000_getreg(priv, SJA1000_DATA_4_REG) >> 3);
datastart = SJA1000_DATA_5_REG;
}
else
#endif /* CONFIG_CAN_EXTID */
{
/* The provided ID should be 11 bits */
hdr.ch_id = (sja1000_getreg(priv, SJA1000_DATA_1_REG) << 3)
+ (sja1000_getreg(priv, SJA1000_DATA_2_REG) >> 5);
datastart = SJA1000_DATA_3_REG;
}
len = frame_info & 0xf;
if (len > CAN_MAXDATALEN)
{
len = CAN_MAXDATALEN;
}
hdr.ch_dlc = len;
for (i = 0; i < len; i++)
{
data[i] = sja1000_getreg(priv, (datastart + i));
}
/* Release the receive buffer */
sja1000_putreg(priv, SJA1000_CMD_REG, SJA1000_RELEASE_BUF_M);
#ifdef CONFIG_CAN_ERRORS
hdr.ch_error = 0; /* Error reporting not supported */
#endif /* CONFIG_CAN_ERRORS */
can_receive(dev, &hdr, data);
}
/* Check for TX buffer complete */
if ((regval & SJA1000_TX_INT_ST_M) != 0)
{
/* Disable all further TX buffer interrupts */
regval = sja1000_getreg(priv, SJA1000_INT_ENA_REG);
regval &= ~SJA1000_TX_INT_ENA_M;
sja1000_putreg(priv, SJA1000_INT_ENA_REG, regval);
/* Indicate that the TX is done and a new TX buffer is available */
can_txdone(dev);
}
#endif /* CONFIG_CAN_SJA1000 */
return OK;
}
/****************************************************************************
* Name: sja1000_set_acc_filter
*
* Description:
* Call to set acceptance filter.
* Must be called in reset mode.
*
* Input Parameters:
* priv - Private SJA1000 context
* code - Acceptance Code.
* mask - Acceptance Mask.
* single_filter - Whether to enable single filter mode.
*
* Returned Value:
* None
*
****************************************************************************/
static void sja1000_set_acc_filter(struct sja1000_dev_s *priv,
uint32_t code, uint32_t mask,
bool single_filter)
{
uint32_t regval;
uint32_t code_swapped = __builtin_bswap32(code);
uint32_t mask_swapped = __builtin_bswap32(mask);
regval = sja1000_getreg(priv, SJA1000_MODE_REG);
if (single_filter)
{
regval |= SJA1000_RX_FILTER_MODE_M;
}
else
{
regval &= ~(SJA1000_RX_FILTER_MODE_M);
}
sja1000_putreg(priv, SJA1000_MODE_REG, regval);
for (int i = 0; i < 4; i++)
{
sja1000_putreg(priv, (SJA1000_DATA_0_REG + i),
((code_swapped >> (i * 8)) & 0xff));
sja1000_putreg(priv, (SJA1000_DATA_4_REG + i),
((mask_swapped >> (i * 8)) & 0xff));
}
}
/****************************************************************************
* Name: sja1000_baud_rate
*
* Description:
* Set the CAN bus timing registers based on the configured bit-rate and
* sample point position.
*
* 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
*
* Input Parameters:
* priv - A reference to the CAN block status
*
* Returned Value:
* Zero on success; a negated errno on failure
*
****************************************************************************/
static int sja1000_baud_rate(struct sja1000_dev_s *priv, int rate,
int clock, int sjw, int sampl_pt, int flags)
{
struct sja1000_config_s *config = priv->config;
const struct can_bittiming_const_s *timing = config->bittiming_const;
int best_error = 1000000000;
int error;
int best_tseg = 0;
int best_brp = 0;
int best_rate = 0;
int brp = 0;
int tseg = 0;
int tseg1 = 0;
int tseg2 = 0;
uint32_t timing0;
uint32_t timing1;
/* tseg even = round down, odd = round up */
for (tseg = (0 + 0 + 2) * 2;
tseg <= (timing->tseg2_max + timing->tseg1_max + 2) * 2 + 1; tseg++)
{
brp = clock / ((1 + tseg / 2) * rate) + tseg % 2;
if (brp == 0 || brp > 64)
{
continue;
}
error = rate - clock / (brp * (1 + tseg / 2));
if (error < 0)
{
error = -error;
}
if (error <= best_error)
{
best_error = error;
best_tseg = tseg / 2;
best_brp = brp;
best_rate = clock / (brp * (1 + tseg / 2));
}
}
if (best_error && (rate / best_error < 10))
{
canerr(
"baud rate %d is not possible with %d Hz clock\n", rate, clock);
canerr("%d bps. brp=%d, best_tseg=%d, tseg1=%d, tseg2=%d\n",
best_rate, best_brp, best_tseg, tseg1, tseg2);
return -EINVAL;
}
tseg2 = best_tseg - (sampl_pt * (best_tseg + 1)) / 100 + 1;
if (tseg2 < 0)
{
tseg2 = 0;
}
if (tseg2 > timing->tseg2_max)
{
tseg2 = timing->tseg2_max;
}
tseg1 = best_tseg - tseg2;
if (tseg1 > timing->tseg1_max)
{
tseg1 = timing->tseg1_max;
tseg2 = best_tseg - tseg1;
}
caninfo("Setting baud rate. TS1: %d TS2: %d BRP: %d\n", tseg1, tseg2,
best_brp);
/* Configure bit timing */
timing0 = ((best_brp - 1) / 2) & SJA1000_BAUD_PRESC_M;
timing0 |= ((sjw - 1) << SJA1000_SYNC_JUMP_WIDTH_S)
& SJA1000_SYNC_JUMP_WIDTH_M;
timing1 = (tseg1 - 1) & SJA1000_TIME_SEG1_M;
timing1 |= ((tseg2 - 1) << SJA1000_TIME_SEG2_S) & SJA1000_TIME_SEG2_M;
if (config->triple_sample)
{
/* The bus is sampled 3 times (recommended for low to medium speed
* buses to spikes on the bus-line).
*/
timing1 |= (config->triple_sample << SJA1000_TIME_SAMP_S)
& SJA1000_TIME_SAMP_M;
}
cantrace("Writing to BTR0, BTR1: timing0: 0x%" PRIx32 " timing1: "
"0x%" PRIx32 "\n",
timing0, timing1);
sja1000_putreg(priv, SJA1000_BUS_TIMING_1_REG, timing1);
sja1000_putreg(priv, SJA1000_BUS_TIMING_0_REG, timing0);
#ifdef CONFIG_CANBUS_REGDEBUG
timing1 = sja1000_getreg(priv, SJA1000_BUS_TIMING_1_REG);
timing0 = sja1000_getreg(priv, SJA1000_BUS_TIMING_0_REG);
caninfo("Read-verify: timing0: 0x%" PRIx32 " timing1: 0x%" PRIx32 "\n",
timing0, timing1);
#endif /* CONFIG_CANBUS_REGDEBUG */
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: sja1000_instantiate
*
* Description:
* Initialize the selected SJA1000 CAN Bus Controller
*
* Input Parameters:
* priv - An instance of the "lower half" CAN driver state structure.
*
* Returned Value:
* Valid CAN device structure reference on success; a NULL on failure
*
****************************************************************************/
FAR struct can_dev_s *sja1000_instantiate(FAR struct sja1000_dev_s *priv)
{
struct sja1000_config_s *config = priv->config;
FAR struct can_dev_s *dev;
irqstate_t flags;
DEBUGASSERT(dev);
DEBUGASSERT(priv);
DEBUGASSERT(config);
cantrace("Starting sja1000_instantiate()!\n");
/* Allocate a CAN Device structure */
dev = kmm_zalloc(sizeof(struct can_dev_s));
if (dev == NULL)
{
canerr("ERROR: Failed to allocate instance of can_dev_s!\n");
return NULL;
}
#ifdef CONFIG_ARCH_HAVE_MULTICPU
flags = spin_lock_irqsave(&priv->lock);
#else
flags = enter_critical_section();
#endif /* CONFIG_ARCH_HAVE_MULTICPU */
#ifdef CONFIG_ARCH_HAVE_MULTICPU
priv->lock = SP_UNLOCKED;
#endif /* CONFIG_ARCH_HAVE_MULTICPU */
dev->cd_ops = &g_sja1000ops;
dev->cd_priv = (FAR void *)priv;
#ifdef CONFIG_ARCH_HAVE_MULTICPU
spin_unlock_irqrestore(&priv->lock, flags);
#else
leave_critical_section(flags);
#endif /* CONFIG_ARCH_HAVE_MULTICPU */
/* Reset chip */
sja1000_reset(dev);
return dev;
}
#endif /* CONFIG_CAN_SJA1000 */