Hi,
Possibly a new issue with DCAN module on AM335x. The problem is with usage of the auto Bus-Off recovery feature of the DCAN module. In tests related to error recovery I have found out that if Bus-Off will happen with the next code the DCAN module will be not able to receive and send messages anymore. Proposed workaround below, but feedback wanted from the StarterWare team if this is an accurate solution?
Thanks.
/Magnus
Code and following workaround:
/**< Base address of DCAN module memory mapped registers */
#define DCAN_1_REG_BASE (0x481D0000)
/* CAN interrupts related defines */
#define SYS_INT_DCAN1_INT0 (55)
#define SYS_INT_DCAN1_INT1 (56)
#define SYS_INT_DCAN1_PARITY (57)
/**< Clock frequency of CAN controller */
#define DCAN_IN_CLK (25000000u)
/**< Bit rate used for CAN communication */
#define DCAN_BIT_RATE (1000000u)
/**< Auto Bus-Off Recovery time */
#define DCAN_ABO_TIME (DCAN_IN_CLK / 100)
/**< Number of CAN message objects in DCAN RAM */
#define CAN_NUM_OF_MSG_OBJS (64)
/**< CAN Identifier used for object masking during acceptance filtering */
#define DCAN_ID_MASK (0x0u)
/**< CAN objects mapping inside the driver */
#define DCAN_RX_MSG_OBJS_START (1)
#define DCAN_NUM_OF_RX_MSG_OBJS (16)
#define DCAN_RX_MSG_OBJS_END (DCAN_RX_MSG_OBJS_START + DCAN_NUM_OF_RX_MSG_OBJS)
#define DCAN_TX_MSG_OBJS_START (DCAN_RX_MSG_OBJS_END)
#define DCAN_NUM_OF_TX_MSG_OBJS (16)
#define DCAN_TX_MSG_OBJS_END (DCAN_TX_MSG_OBJS_START + DCAN_NUM_OF_TX_MSG_OBJS)
static void CAN_ISR(void)
{
do
{
unsigned int errVal;
/* Check the status of DCAN Status and error register */
errVal = DCANErrAndStatusRegInfoGet(DCAN_1_REG_BASE);
/* CAN Bus-Off event occurred */
if(0 != (errVal & DCAN_MOD_IN_BUS_OFF_STATE))
{
BusOffCount++;
}
/* CAN in error passive state */
if(0 != (errVal & DCAN_CORE_IN_ERR_PASSIVE))
{
ErrorPassiveCount++;
}
/* Error warning limit reached */
if(0 != (errVal & DCAN_ERR_WARN_STATE_RCHD))
{
ErrorWarningCount++;
}
/* Error during RX or TX */
if((DCAN_LST_ERRCODE_NO_ERR != (errVal & DCAN_ES_LEC)) &&
(DCAN_NO_EVENT_ON_CAN_BUS != (errVal & DCAN_ES_LEC)))
{
BusErrorCount++;
}
/* Receive service */
if(0 != (errVal & DCAN_RXD_MSG_SUCCESSFULLY))
{
ReadRxObjects();
}
/* Transmit service */
if(0 != (errVal & DCAN_TXD_MSG_SUCCESSFULLY))
{
SendNextTxObject();
}
} while(DCAN_NO_INT_PENDING != DCANIntRegStatusGet(DCAN_1_REG_BASE,
DCAN_INT_LINE0_STAT));
}
static int DCAN_INIT_HW(void)
{
unsigned int index = CAN_NUM_OF_MSG_OBJS;
/* Reset the DCAN module */
DCANReset(DCAN_1_REG_BASE);
/* Enter the Initialization mode of CAN controller */
DCANInitModeSet(DCAN_1_REG_BASE);
/* Enable the write access to the DCAN configuration registers */
DCANConfigRegWriteAccessControl(DCAN_1_REG_BASE, DCAN_CONF_REG_WR_ACCESS_ENABLE);
/* Configure the bit timing values for CAN communication */
CANSetBitTiming(DCAN_1_REG_BASE, DCAN_IN_CLK, DCAN_BIT_RATE);
/*
** This feature will automatically get the CAN bus to bus-on
** state once the error counters are below the error warning
** limit.
*/
DCANAutoBusOnTimeValSet(DCAN_1_REG_BASE, DCAN_ABO_TIME);
DCANAutoBusOnControl(DCAN_1_REG_BASE, DCAN_AUTO_BUS_ON_ENABLE);
/* Disable the write access to the DCAN configuration registers */
DCANConfigRegWriteAccessControl(DCAN_1_REG_BASE, DCAN_CONF_REG_WR_ACCESS_DISABLE);
while(index--)
{
/* Clear the MsgVal bit of DCAN_IFARB register */
DCANMsgObjInvalidate(DCAN_1_REG_BASE, DCAN_IF2_REG);
/* Set the Arb bit of DCAN_IFCMD register */
DCANCommandRegSet(DCAN_1_REG_BASE, (DCAN_ACCESS_ARB_BITS | DCAN_MSG_WRITE),
index, DCAN_IF2_REG);
}
/* Configure receive objects */
CAN_ConfigRxObj();
/* Configure transmit objects */
CAN_ConfigTxObj();
/* Register the DCAN Interrupt handler for interrupt line 0 */
IntRegister(SYS_INT_DCAN1_INT0, &CAN_ISR);
/* Assign priority to the interrupt */
IntPrioritySet(SYS_INT_DCAN1_INT0, 0, AINTC_HOSTINT_ROUTE_IRQ);
/* Enable the system interrupts in AINTC */
IntSystemEnable(SYS_INT_DCAN1_INT0);
/* Enable error and status change interrupts */
DCANIntEnable(DCAN_1_REG_BASE, DCAN_ERROR_INT | DCAN_STATUS_CHANGE_INT);
/* Enable the interrupt line 0 of DCAN module */
DCANIntLineEnable(DCAN_1_REG_BASE, DCAN_INT_LINE0);
/* Start the CAN controller */
DCANNormalModeSet(DCAN_1_REG_BASE);
return 0;
}
|
Proposed workaround:
static void CAN_ISR(void)
{
...
...
/* CAN Bus-Off event occurred */
if(0 != (errVal & DCAN_MOD_IN_BUS_OFF_STATE))
{
BusOffCount++;
/* Restart the CAN controller */
DCANNormalModeSet(DCAN_1_REG_BASE);
}
...
...
}
static int DCAN_INIT_HW(void)
{
...
...
/*
** This feature will automatically get the CAN bus to bus-on
** state once the error counters are below the error warning
** limit.
*/
/* DCANAutoBusOnTimeValSet(DCAN_1_REG_BASE, DCAN_ABO_TIME);
DCANAutoBusOnControl(DCAN_1_REG_BASE, DCAN_AUTO_BUS_ON_ENABLE); */
...
...
}
|