9
0
Fork 0

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:
patacongo 2012-01-05 20:39:56 +00:00
parent 431ebd4eb6
commit 07f2a821dd
3 changed files with 173 additions and 8 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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:
*