forked from Archive/PX4-Autopilot
Add logic to control CAN bit rate via the .config file
git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4266 7fd9a85b-ad96-42d3-883c-3090e2eb8679
This commit is contained in:
parent
f16e231491
commit
7de5004f47
|
@ -2346,3 +2346,5 @@
|
|||
(Contributed by Mike Smith)
|
||||
* configs/stm3240g-eval/src: Add APIs support to support user access to the
|
||||
LEDs
|
||||
* arch/arm/src/lpc17xx/lpc17_can.c: Add logic to change the CAN bit rate based
|
||||
on the NuttX configuration.
|
||||
|
|
|
@ -96,6 +96,12 @@
|
|||
# define canllvdbg(x...)
|
||||
#endif
|
||||
|
||||
/* Timing *******************************************************************/
|
||||
/* CAN clocking is provided at CCLK/4 (hardcoded in lpc17_caninitialize()) */
|
||||
|
||||
#define CAN_CCLK_DIVISOR 4
|
||||
#define CAN_CLOCK_FREQUENCY (LPC17_CCLK / CAN_CCLK_DIVISOR)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
|
@ -139,9 +145,15 @@ 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 interrupts */
|
||||
|
||||
static void can_interrupt(FAR struct can_dev_s *dev);
|
||||
static int can12_interrupt(int irq, void *context);
|
||||
|
||||
/* Initialization */
|
||||
|
||||
static int can_bittiming(struct up_dev_s *priv);
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
|
@ -400,19 +412,30 @@ 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 baud;
|
||||
int ret;
|
||||
irqstate_t flags;
|
||||
|
||||
canvdbg("CAN%d\n", priv->port);
|
||||
|
||||
#warning "BTR setting must be calculated from priv->baud"
|
||||
baud = 0x25c003;
|
||||
flags = irqsave();
|
||||
|
||||
/* Disable the CAN and stop ongong transmissions */
|
||||
|
||||
can_putreg(priv, LPC17_CAN_MOD_OFFSET, CAN_MOD_RM); /* Enter Reset Mode */
|
||||
can_putreg(priv, LPC17_CAN_IER_OFFSET, 0); /* Disable interrupts */
|
||||
can_putreg(priv, LPC17_CAN_GSR_OFFSET, 0); /* Clear status bits */
|
||||
can_putreg(priv, LPC17_CAN_CMR_OFFSET, CAN_CMR_AT); /* Abort transmission */
|
||||
can_putreg(priv, LPC17_CAN_BTR_OFFSET, baud); /* Set bit timing */
|
||||
|
||||
/* Set bit timing */
|
||||
|
||||
ret = can_bittiming(priv);
|
||||
if (ret != OK)
|
||||
{
|
||||
candbg("ERROR: Failed to set bit timing: %d\n", ret);
|
||||
}
|
||||
|
||||
/* Restart the CAN */
|
||||
|
||||
#ifdef CONFIG_CAN_LOOPBACK
|
||||
can_putreg(priv, LPC17_CAN_MOD_OFFSET, CAN_MOD_STM); /* Leave Reset Mode, enter Test Mode */
|
||||
#else
|
||||
|
@ -873,6 +896,146 @@ static int can12_interrupt(int irq, void *context)
|
|||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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 * Tpclk1
|
||||
*
|
||||
* Where:
|
||||
* Tpclk1 is the period of the APB clock (PCLK = CCLK / 4).
|
||||
*
|
||||
* 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 canbtr;
|
||||
uint32_t brp;
|
||||
uint32_t ts1;
|
||||
uint32_t ts2;
|
||||
uint32_t sjw;
|
||||
|
||||
canllvdbg("CAN%d PCLK1: %d baud: %d\n", priv->port, CAN_CLOCK_FREQUENCY, priv->baud);
|
||||
|
||||
/* Try to get 14 quanta in one bit_time. That is based on the idea that the ideal
|
||||
* would be ts1=6 nd ts2=7 and (1 + ts1 + ts2) = 14.
|
||||
*
|
||||
* bit_time = Tq*(1 +ts1 + ts2)
|
||||
* nquanta = bit_time/Tq
|
||||
* nquanta = (1 +ts1 + ts2)
|
||||
*
|
||||
* bit_time = brp * Tpclk1 * (1 + ts1 + ts2)
|
||||
* nquanta = bit_time / brp / Tpclk1
|
||||
* = PCLK1 / baud / brp
|
||||
* brp = PCLK1 / baud / nquanta;
|
||||
*
|
||||
* Example:
|
||||
* PCLK1 = 42,000,000 baud = 1,000,000 nquanta = 14 : brp = 3
|
||||
* PCLK1 = 42,000,000 baud = 700,000 nquanta = 14 : brp = 4
|
||||
*/
|
||||
|
||||
canbtr = CAN_CLOCK_FREQUENCY / priv->baud;
|
||||
if (canbtr < 14)
|
||||
{
|
||||
/* At the smallest brp value (1), there are already fewer bit times
|
||||
* (CAN_CLOCK / baud) is already smaller than our goal. brp must be one
|
||||
* and we need make some reasonalble guesses about ts1 and ts2.
|
||||
*/
|
||||
|
||||
brp = 1;
|
||||
|
||||
/* In this case, we have to guess a good value for ts1 and ts2 */
|
||||
|
||||
ts1 = (canbtr - 1) >> 1;
|
||||
ts2 = canbtr - ts1 - 1;
|
||||
if (ts1 == ts2 && ts1 > 1 && ts2 < 16)
|
||||
{
|
||||
ts1--;
|
||||
ts2++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, nquanta is 14, ts1 is 6, ts2 is 7 and we calculate brp to
|
||||
* achieve 14 quanta in the bit time
|
||||
*/
|
||||
|
||||
else
|
||||
{
|
||||
ts1 = 6;
|
||||
ts2 = 7;
|
||||
brp = (canbtr + 7) / 14;
|
||||
DEBUGASSERT(brp >=1 && brp < 1024);
|
||||
}
|
||||
|
||||
sjw = 1;
|
||||
|
||||
canllvdbg("TS1: %d TS2: %d BRP: %d SJW= %d\n", ts1, ts2, brp, sjw);
|
||||
|
||||
/* Configure bit timing */
|
||||
|
||||
canbtr = ((brp - 1) << CAN_BTR_BRP_SHIFT) |
|
||||
((ts1 - 1) << CAN_BTR_TESG1_SHIFT) |
|
||||
((ts2 - 1) << CAN_BTR_TESG2_SHIFT) |
|
||||
((sjw - 1) << CAN_BTR_SJW_SHIFT);
|
||||
|
||||
#ifdef CONFIG_CAN_SAM
|
||||
/* The bus is sampled 3 times (recommended for low to medium speed buses
|
||||
* to spikes on the bus-line).
|
||||
*/
|
||||
|
||||
canbtr |= CAN_BTR_SAM;
|
||||
#endif
|
||||
|
||||
canllvdbg("Setting CANxBTR= 0x%08x\n", canbtr);
|
||||
can_putreg(priv, LPC17_CAN_BTR_OFFSET, canbtr); /* Set bit timing */
|
||||
return OK;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
@ -910,7 +1073,7 @@ FAR struct can_dev_s *lpc17_caninitialize(int port)
|
|||
can_putcommon(LPC17_SYSCON_PCONP, regval);
|
||||
|
||||
/* Enable clocking to the CAN module (not necessary... already done
|
||||
* in low level clock configuration logic.
|
||||
* in low level clock configuration logic).
|
||||
*/
|
||||
|
||||
regval = can_getcommon(LPC17_SYSCON_PCLKSEL0);
|
||||
|
@ -937,7 +1100,7 @@ FAR struct can_dev_s *lpc17_caninitialize(int port)
|
|||
can_putcommon(LPC17_SYSCON_PCONP, regval);
|
||||
|
||||
/* Enable clocking to the CAN module (not necessary... already done
|
||||
* in low level clock configuration logic.
|
||||
* in low level clock configuration logic).
|
||||
*/
|
||||
|
||||
regval = can_getcommon(LPC17_SYSCON_PCLKSEL0);
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
/**************************************************************************
|
||||
* arch/arm/src/lpc17xx/lpc17_lowputc.c
|
||||
*
|
||||
* Copyright (C) 2010-2011 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||
* Copyright (C) 2010-2012 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
|
@ -130,7 +130,7 @@
|
|||
#define CONSOLE_FCR_VALUE (UART_FCR_RXTRIGGER_8 | UART_FCR_TXRST |\
|
||||
UART_FCR_RXRST | UART_FCR_FIFOEN)
|
||||
|
||||
/* Select a CCLK divider to produce the UART PCLK. The stratey is to select the
|
||||
/* Select a CCLK divider to produce the UART PCLK. The strategy is to select the
|
||||
* smallest divisor that results in an solution within range of the 16-bit
|
||||
* DLM and DLL divisor:
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue