forked from Archive/PX4-Autopilot
STM32 CAN debug fixes
git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4214 7fd9a85b-ad96-42d3-883c-3090e2eb8679
This commit is contained in:
parent
bfc578860c
commit
e2ef959d92
|
@ -248,6 +248,8 @@ static void can_reset(FAR struct can_dev_s *dev)
|
|||
uint32_t regbit = 0;
|
||||
irqstate_t flags;
|
||||
|
||||
canllvdbg("CAN%d\n", priv->port);
|
||||
|
||||
/* Get the bits in the AHB1RSTR register needed to reset this CAN device */
|
||||
|
||||
#ifdef CONFIG_STM32_CAN1
|
||||
|
@ -265,7 +267,8 @@ static void can_reset(FAR struct can_dev_s *dev)
|
|||
else
|
||||
#endif
|
||||
{
|
||||
candbg("Unsupported port %d\n", priv->port);
|
||||
canlldbg("Unsupported port %d\n", priv->port);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Disable interrupts momentary to stop any ongoing CAN event processing and
|
||||
|
@ -276,9 +279,12 @@ static void can_reset(FAR struct can_dev_s *dev)
|
|||
|
||||
/* Reset the CAN */
|
||||
|
||||
regval = getreg32(STM32_RCC_AHB1RSTR);
|
||||
regval = getreg32(STM32_RCC_APB1RSTR);
|
||||
regval |= regbit;
|
||||
putreg32(regval, STM32_RCC_AHB1RSTR);
|
||||
putreg32(regval, STM32_RCC_APB1RSTR);
|
||||
|
||||
regval &= ~regbit;
|
||||
putreg32(regval, STM32_RCC_APB1RSTR);
|
||||
irqrestore(flags);
|
||||
}
|
||||
|
||||
|
@ -304,12 +310,14 @@ static int can_setup(FAR struct can_dev_s *dev)
|
|||
FAR struct stm32_can_s *priv = dev->cd_priv;
|
||||
int ret;
|
||||
|
||||
canllvdbg("CAN%d\n", priv->port);
|
||||
|
||||
/* CAN cell initialization */
|
||||
|
||||
ret = can_cellinit(priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
candbg("CAN cell initialization failed: %d\n", ret);
|
||||
canlldbg("CAN%d cell initialization failed: %d\n", priv->port, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -318,7 +326,7 @@ static int can_setup(FAR struct can_dev_s *dev)
|
|||
ret = can_filterinit(priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
candbg("CAN filter initialization failed: %d\n", ret);
|
||||
canlldbg("CAN%d filter initialization failed: %d\n", priv->port, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -327,7 +335,7 @@ static int can_setup(FAR struct can_dev_s *dev)
|
|||
ret = irq_attach(priv->canrx0, can_rx0interrupt);
|
||||
if (ret < 0)
|
||||
{
|
||||
candbg("Failed to attach CAN%d RX0 IRQ (%d)", priv->port, priv->canrx0);
|
||||
canlldbg("Failed to attach CAN%d RX0 IRQ (%d)", priv->port, priv->canrx0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -359,6 +367,8 @@ static void can_shutdown(FAR struct can_dev_s *dev)
|
|||
{
|
||||
FAR struct stm32_can_s *priv = dev->cd_priv;
|
||||
|
||||
canllvdbg("CAN%d\n", priv->port);
|
||||
|
||||
/* Disable the RX FIFO 0 interrupt */
|
||||
|
||||
up_disable_irq(priv->canrx0);
|
||||
|
@ -391,6 +401,8 @@ static void can_rxint(FAR struct can_dev_s *dev, bool enable)
|
|||
FAR struct stm32_can_s *priv = dev->cd_priv;
|
||||
uint32_t regval;
|
||||
|
||||
canllvdbg("CAN%d enable: %d\n", priv->port, enable);
|
||||
|
||||
/* Enable/disable the FIFO 0 message pending interrupt */
|
||||
|
||||
regval = can_getreg(priv, STM32_CAN_IER_OFFSET);
|
||||
|
@ -497,6 +509,9 @@ static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
|
|||
int dlc;
|
||||
int txmb;
|
||||
|
||||
canllvdbg("CAN%d ID: %d DLC: %d\n",
|
||||
priv->port, CAN_ID(msg->cm_hdr), CAN_DLC(msg->cm_hdr));
|
||||
|
||||
/* Select one empty transmit mailbox */
|
||||
|
||||
regval = can_getreg(priv, STM32_CAN_TSR_OFFSET);
|
||||
|
@ -514,7 +529,7 @@ static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
|
|||
}
|
||||
else
|
||||
{
|
||||
candbg("ERROR: No available mailbox\n");
|
||||
canlldbg("ERROR: No available mailbox\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
|
@ -603,6 +618,14 @@ static int can_send(FAR struct can_dev_s *dev, FAR struct can_msg_s *msg)
|
|||
regval = can_getreg(priv, STM32_CAN_TIR_OFFSET(txmb));
|
||||
regval |= CAN_TIR_TXRQ; /* Transmit Mailbox Request */
|
||||
can_putreg(priv, STM32_CAN_TIR_OFFSET(txmb), regval);
|
||||
|
||||
/* Tell the upper half that the tansfer is finished now (we would have to
|
||||
* take the transfer complete interrupt to know it "really" finished. So
|
||||
* although the transfer is not finished, all of the upper half resources
|
||||
* are now available so makes sense to call can_txdone now.
|
||||
*/
|
||||
|
||||
(void)can_txdone(dev);
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -632,6 +655,8 @@ static bool can_txempty(FAR struct can_dev_s *dev)
|
|||
/* Return false if any mailbox is unavailable */
|
||||
|
||||
regval = can_getreg(priv, STM32_CAN_TSR_OFFSET);
|
||||
canllvdbg("CAN%d TSR: %08x\n", priv->port, regval);
|
||||
|
||||
if ((regval & CAN_TSR_TME0) == 0)
|
||||
{
|
||||
return false;
|
||||
|
@ -699,6 +724,7 @@ static int can_rx0interrupt(int irq, void *context)
|
|||
npending = (regval & CAN_RFR_FMP_MASK) >> CAN_RFR_FMP_SHIFT;
|
||||
if (npending < 1)
|
||||
{
|
||||
canlldbg("WARNING: No messages pending\n");
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -812,94 +838,60 @@ static int can_bittiming(struct stm32_can_s *priv)
|
|||
uint32_t brp;
|
||||
uint32_t ts1;
|
||||
uint32_t ts2;
|
||||
int candidate;
|
||||
int diff;
|
||||
|
||||
canvdbg("PCLK1: %d baud: %d\n" ,STM32_PCLK1_FREQUENCY, priv->baud);
|
||||
canllvdbg("CAN%d PCLK1: %d baud: %d\n", priv->port, STM32_PCLK1_FREQUENCY, priv->baud);
|
||||
|
||||
/* Loop trying different values of ts1 until we get a solution with the
|
||||
* ts1 near ts2 and both values within range.
|
||||
/* 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 : tmp = 13
|
||||
* PCLK1 = 42,000,000 baud = 1,000,000 nquanta = 14 : brp = 3
|
||||
* PCLK1 = 42,000,000 baud = 700,000 nquanta = 14 : brp = 4
|
||||
*/
|
||||
|
||||
tmp = STM32_PCLK1_FREQUENCY / 3 / priv->baud - 1;
|
||||
|
||||
for (candidate = 1, ts1 = 17, diff = 16; candidate <= 16; candidate++)
|
||||
tmp = STM32_PCLK1_FREQUENCY / priv->baud;
|
||||
if (tmp < 14)
|
||||
{
|
||||
/* Then calculate the new ts2 value corresponding to this candidate:
|
||||
*
|
||||
* Example:
|
||||
* ...
|
||||
* PCLK1 = 42,000,000 baud = 1,000,000 tmp = 13 candidate = 4 : ts2 = 9
|
||||
* PCLK1 = 42,000,000 baud = 1,000,000 tmp = 13 candidate = 5 : ts2 = 8
|
||||
* PCLK1 = 42,000,000 baud = 1,000,000 tmp = 13 candidate = 6 : ts2 = 7
|
||||
* ...
|
||||
/* At the smallest brp value (1), there are already fewer bit times
|
||||
* (PCLCK1 / baud) is already smaller than our goal. brp must be one
|
||||
* and we need make some reasonalble guesses about ts1 and ts2.
|
||||
*/
|
||||
|
||||
ts2 = tmp - candidate;
|
||||
brp = 1;
|
||||
|
||||
/* Break out if ts2 is too small (it will only get smaller on the following
|
||||
* passes.
|
||||
*/
|
||||
/* In this case, we have to guess a good value for ts1 and ts2 */
|
||||
|
||||
if (ts2 < 1)
|
||||
ts1 = (tmp - 1) >> 1;
|
||||
ts2 = tmp - ts1 - 1;
|
||||
if (ts1 == ts2 && ts1 > 1 && ts2 < 16)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Is ts2 within its upper range. No then keep looping because it
|
||||
* will get smaller.
|
||||
*/
|
||||
|
||||
else if (ts2 <= 8)
|
||||
{
|
||||
/* In range is is the best so far? */
|
||||
|
||||
int tmpdiff = candidate - ts2;
|
||||
if (tmpdiff < 0)
|
||||
{
|
||||
tmpdiff = -tmpdiff;
|
||||
}
|
||||
|
||||
if (tmpdiff < diff)
|
||||
{
|
||||
diff = tmpdiff;
|
||||
ts1 = candidate;
|
||||
}
|
||||
ts1--;
|
||||
ts2++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for errors */
|
||||
|
||||
if (ts1 > 16)
|
||||
{
|
||||
/* If this happens, it means that there is a bug in the algorithm */
|
||||
|
||||
candbg("Could not find a value for TS1/2\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Calculate the BRP value would support the selected values of ts1 value and ts2:
|
||||
*
|
||||
* Example:
|
||||
* PCLK1 = 42,000,000 baud = 1,000,000 ts1 = 6 ts2 = 7 : tmp = 3,000,000 brp = 3
|
||||
/* Otherwise, nquanta is 14, ts1 is 6, ts2 is 7 and we calculate brp to
|
||||
* achieve 14 quanta in the bit time
|
||||
*/
|
||||
|
||||
tmp = STM32_PCLK1_FREQUENCY / (ts1 + ts2 + 1);
|
||||
brp = (tmp + (priv->baud - 1)) / priv->baud;
|
||||
|
||||
/* Check for errors */
|
||||
|
||||
if (brp > 1024)
|
||||
else
|
||||
{
|
||||
/* If this happens, it means that there is a bug in the algorithm */
|
||||
|
||||
candbg("BRP is out of range: TS1: %d TS2: %d BRP: %d\n", ts1, ts2, brp);
|
||||
return -EINVAL;
|
||||
ts1 = 6;
|
||||
ts2 = 7;
|
||||
brp = tmp / 14;
|
||||
DEBUGASSERT(brp >=1 && brp < 1024);
|
||||
}
|
||||
canvdbg("TS1: %d TS2: %d BRP: %d\n", ts1, ts2, brp);
|
||||
|
||||
canllvdbg("TS1: %d TS2: %d BRP: %d\n", ts1, ts2, brp);
|
||||
|
||||
/* Configure bit timing. This also does the the following, less obvious
|
||||
* things. Unless loopback mode is enabled, it:
|
||||
|
@ -941,6 +933,8 @@ static int can_cellinit(struct stm32_can_s *priv)
|
|||
uint32_t regval;
|
||||
int ret;
|
||||
|
||||
canllvdbg("CAN%d\n", priv->port);
|
||||
|
||||
/* Exit from sleep mode */
|
||||
|
||||
regval = can_getreg(priv, STM32_CAN_MCR_OFFSET);
|
||||
|
@ -955,7 +949,7 @@ static int can_cellinit(struct stm32_can_s *priv)
|
|||
|
||||
/* Wait until initialization mode is acknowledged */
|
||||
|
||||
for (timeout = INAK_TIMEOUT; timeout > 0; timeout++)
|
||||
for (timeout = INAK_TIMEOUT; timeout > 0; timeout--)
|
||||
{
|
||||
regval = can_getreg(priv, STM32_CAN_MSR_OFFSET);
|
||||
if ((regval & CAN_MSR_INAK) != 0)
|
||||
|
@ -970,7 +964,7 @@ static int can_cellinit(struct stm32_can_s *priv)
|
|||
|
||||
if (timeout < 1)
|
||||
{
|
||||
candbg("ERROR: Timed out waiting to enter intialization mode\n");
|
||||
canlldbg("ERROR: Timed out waiting to enter initialization mode\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
@ -993,7 +987,7 @@ static int can_cellinit(struct stm32_can_s *priv)
|
|||
ret = can_bittiming(priv);
|
||||
if (ret < 0)
|
||||
{
|
||||
candbg("ERROR: Failed to set bit timing: %d\n", ret);
|
||||
canlldbg("ERROR: Failed to set bit timing: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1005,7 +999,7 @@ static int can_cellinit(struct stm32_can_s *priv)
|
|||
|
||||
/* Wait until initialization mode is acknowledged */
|
||||
|
||||
for (timeout = INAK_TIMEOUT; timeout > 0; timeout++)
|
||||
for (timeout = INAK_TIMEOUT; timeout > 0; timeout--)
|
||||
{
|
||||
regval = can_getreg(priv, STM32_CAN_MSR_OFFSET);
|
||||
if ((regval & CAN_MSR_INAK) == 0)
|
||||
|
@ -1020,7 +1014,7 @@ static int can_cellinit(struct stm32_can_s *priv)
|
|||
|
||||
if (timeout < 1)
|
||||
{
|
||||
candbg("ERROR: Timed out waiting to exit intialization mode\n");
|
||||
canlldbg("ERROR: Timed out waiting to exit initialization mode: %08x\n", regval);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
return OK;
|
||||
|
@ -1045,13 +1039,13 @@ static int can_filterinit(struct stm32_can_s *priv)
|
|||
uint32_t regval;
|
||||
uint32_t bitmask;
|
||||
|
||||
canvdbg("CAN%d filter: %d\n", priv->port, priv->filter);
|
||||
canllvdbg("CAN%d filter: %d\n", priv->port, priv->filter);
|
||||
|
||||
/* Get the bitmask associated with the filter used by this CAN block */
|
||||
|
||||
bitmask = ((uint32_t)1) << priv->filter;
|
||||
|
||||
/* Enter filter intialization mode */
|
||||
/* Enter filter initialization mode */
|
||||
|
||||
regval = can_getreg(priv, STM32_CAN_FMR_OFFSET);
|
||||
regval |= CAN_FMR_FINIT;
|
||||
|
@ -1124,6 +1118,8 @@ FAR struct can_dev_s *stm32_caninitialize(int port)
|
|||
{
|
||||
struct can_dev_s *dev = NULL;
|
||||
|
||||
canvdbg("CAN%d\n", port);
|
||||
|
||||
/* NOTE: Peripherical clocking for CAN1 and/or CAN2 was already provided
|
||||
* by stm32_clockconfig() early in the reset sequence.
|
||||
*/
|
||||
|
@ -1165,7 +1161,7 @@ FAR struct can_dev_s *stm32_caninitialize(int port)
|
|||
else
|
||||
#endif
|
||||
{
|
||||
candbg("Unsupported port %d\n", port);
|
||||
candbg("ERROR: Unsupported port %d\n", port);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -133,6 +133,8 @@ static int can_open(FAR struct file *filep)
|
|||
uint8_t tmp;
|
||||
int ret = OK;
|
||||
|
||||
canvdbg("ocount: %d\n", dev->cd_ocount);
|
||||
|
||||
/* If the port is the middle of closing, wait until the close is finished */
|
||||
|
||||
if (sem_wait(&dev->cd_closesem) != OK)
|
||||
|
@ -204,6 +206,8 @@ static int can_close(FAR struct file *filep)
|
|||
irqstate_t flags;
|
||||
int ret = OK;
|
||||
|
||||
canvdbg("ocount: %d\n", dev->cd_ocount);
|
||||
|
||||
if (sem_wait(&dev->cd_closesem) != OK)
|
||||
{
|
||||
ret = -errno;
|
||||
|
@ -279,6 +283,8 @@ static ssize_t can_read(FAR struct file *filep, FAR char *buffer, size_t buflen)
|
|||
irqstate_t flags;
|
||||
int ret = 0;
|
||||
|
||||
canvdbg("buflen: %d\n", buflen);
|
||||
|
||||
/* The caller must provide enough memory to catch the smallest possible message
|
||||
* This is not a system error condition, but we won't permit it, Hence we return 0.
|
||||
*/
|
||||
|
@ -367,6 +373,8 @@ static int can_xmit(FAR struct can_dev_s *dev)
|
|||
bool enable = false;
|
||||
int ret = OK;
|
||||
|
||||
canllvdbg("xmit head: %d tail: %d\n", dev->cd_xmit.cf_head, dev->cd_xmit.cf_tail);
|
||||
|
||||
/* Check if the xmit FIFO is empty */
|
||||
|
||||
if (dev->cd_xmit.cf_head != dev->cd_xmit.cf_tail)
|
||||
|
@ -400,6 +408,8 @@ static ssize_t can_write(FAR struct file *filep, FAR const char *buffer, size_t
|
|||
int msglen;
|
||||
int ret = 0;
|
||||
|
||||
canvdbg("buflen: %d\n", buflen);
|
||||
|
||||
/* Interrupts must disabled throughout the following */
|
||||
|
||||
flags = irqsave();
|
||||
|
@ -573,6 +583,8 @@ static int can_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
|||
FAR struct can_dev_s *dev = inode->i_private;
|
||||
int ret = OK;
|
||||
|
||||
canvdbg("cmd: %d arg: %ld\n", cmd, arg);
|
||||
|
||||
/* Handle built-in ioctl commands */
|
||||
|
||||
switch (cmd)
|
||||
|
@ -661,6 +673,8 @@ int can_receive(FAR struct can_dev_s *dev, uint16_t hdr, FAR uint8_t *data)
|
|||
int err = -ENOMEM;
|
||||
int i;
|
||||
|
||||
canllvdbg("ID: %d DLC: %d\n", CAN_ID(hdr), CAN_DLC(hdr));
|
||||
|
||||
/* Check if adding this new message would over-run the drivers ability to enqueue
|
||||
* read data.
|
||||
*/
|
||||
|
@ -742,7 +756,7 @@ int can_receive(FAR struct can_dev_s *dev, uint16_t hdr, FAR uint8_t *data)
|
|||
* Called from the CAN interrupt handler at the completion of a send operation.
|
||||
*
|
||||
* Parameters:
|
||||
* dev - The specifi CAN device
|
||||
* dev - The specific CAN device
|
||||
* hdr - The 16-bit CAN header
|
||||
* data - An array contain the CAN data.
|
||||
*
|
||||
|
@ -755,6 +769,8 @@ int can_txdone(FAR struct can_dev_s *dev)
|
|||
{
|
||||
int ret = -ENOENT;
|
||||
|
||||
canllvdbg("xmit head: %d tail: %d\n", dev->cd_xmit.cf_head, dev->cd_xmit.cf_tail);
|
||||
|
||||
/* Verify that the xmit FIFO is not empty */
|
||||
|
||||
if (dev->cd_xmit.cf_head != dev->cd_xmit.cf_tail)
|
||||
|
|
Loading…
Reference in New Issue