diff --git a/arch/arm/src/samv7/sam_mcan.c b/arch/arm/src/samv7/sam_mcan.c index 5be48501d1..a4c660e343 100644 --- a/arch/arm/src/samv7/sam_mcan.c +++ b/arch/arm/src/samv7/sam_mcan.c @@ -2225,6 +2225,63 @@ static int mcan_del_stdfilter(FAR struct sam_mcan_s *priv, int ndx) return OK; } +/**************************************************************************** + * Name: mcan_start_busoff_recovery_sequence + * + * Description: + * This function initiates the BUS-OFF recovery sequence. + * CAN Specification Rev. 2.0 or ISO11898-1:2015 + * According the SAMV71 datasheet: + * If the device goes Bus_Off, it will set MCAN_CCCR.INIT of its own accord, + * stopping all bus activities. Once MCAN_CCCR.INIT has been cleared by the + * processor (application), the device will then wait for 129 occurrences of + * Bus Idle (129 * 11 consecutive recessive bits) before resuming normal + * operation. At the end of the Bus_Off recovery sequence, the Error + * Management Counters will be reset. During the waiting time after the + * resetting of MCAN_CCCR.INIT, each time a sequence of 11 recessive bits + * has been monitored, a Bit0 Error code is written to MCAN_PSR.LEC, enablin + * the processor to readily check up whether the CAN bus is stuck at dominant + * or continuously disturbed and to monitor the Bus_Off recovery sequence. + * MCAN_ECR.REC is used to count these sequences. + * + * Input Parameters: + * priv - An instance of the MCAN driver state structure. + * + * Returned Value: + * Zero (OK) is returned on success. Otherwise a negated errno value is + * returned to indicate the nature of the error. + * + ****************************************************************************/ + +static int mcan_start_busoff_recovery_sequence(FAR struct sam_mcan_s *priv) +{ + uint32_t regval; + + DEBUGASSERT(priv); + + /* Get exclusive access to the MCAN peripheral */ + + mcan_dev_lock(priv); + + /* only start BUS-OFF recovery if we are in BUS-OFF state */ + + regval = mcan_getreg(priv, SAM_MCAN_PSR_OFFSET); + if (!(regval & MCAN_PSR_BO)) + { + mcan_dev_unlock(priv); + return -EPERM; + } + + /* Disable initialization mode to issue the recovery sequence */ + + regval = mcan_getreg(priv, SAM_MCAN_CCCR_OFFSET); + regval &= ~MCAN_CCCR_INIT; + mcan_putreg(priv, SAM_MCAN_CCCR_OFFSET, regval); + + mcan_dev_unlock(priv); + return OK; +} + /**************************************************************************** * Name: mcan_reset * @@ -2709,6 +2766,21 @@ static int mcan_ioctl(FAR struct can_dev_s *dev, int cmd, unsigned long arg) } break; + /* CANIOC_BUSOFF_RECOVERY: + * Description : Initiates the BUS - OFF recovery sequence + * Argument : None + * 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_BUSOFF_RECOVERY: + { + ret = mcan_start_busoff_recovery_sequence(priv); + } + break; + /* Unsupported/unrecognized command */ default: diff --git a/include/nuttx/can/can.h b/include/nuttx/can/can.h index e85a9fa54d..e66e0e7698 100644 --- a/include/nuttx/can/can.h +++ b/include/nuttx/can/can.h @@ -185,6 +185,14 @@ * is returned with the errno variable set to indicate the * nature of the error. * Dependencies: None + * + * CANIOC_BUSOFF_RECOVERY: + * Description: Initiates the BUS-OFF recovery sequence + * Argument: None + * 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 */ #define CANIOC_RTR _CANIOC(1) @@ -196,9 +204,10 @@ #define CANIOC_DEL_EXTFILTER _CANIOC(7) #define CANIOC_GET_CONNMODES _CANIOC(8) #define CANIOC_SET_CONNMODES _CANIOC(9) +#define CANIOC_BUSOFF_RECOVERY _CANIOC(10) #define CAN_FIRST 0x0001 /* First common command */ -#define CAN_NCMDS 9 /* Nine common commands */ +#define CAN_NCMDS 10 /* Ten common commands */ /* User defined ioctl commands are also supported. These will be forwarded * by the upper-half CAN driver to the lower-half CAN driver via the co_ioctl()