diff --git a/arch/arm/src/stm32l4/stm32l4_can.c b/arch/arm/src/stm32l4/stm32l4_can.c index c7808c88953..38210557608 100644 --- a/arch/arm/src/stm32l4/stm32l4_can.c +++ b/arch/arm/src/stm32l4/stm32l4_can.c @@ -809,7 +809,7 @@ static int stm32l4_canioctl(FAR struct can_dev_s *dev, int cmd, * Description: Set new current bit timing values * Argument: A pointer to a read-able instance of struct * canioc_bittiming_s in which the new bit timing - * valuesare provided. + * values are provided. * Returned Value: Zero (OK) is returned on success. Otherwise -1 * (ERROR)is returned with the errno variable set * to indicate thenature of the error. @@ -827,8 +827,9 @@ static int stm32l4_canioctl(FAR struct can_dev_s *dev, int cmd, FAR const struct canioc_bittiming_s *bt = (FAR const struct canioc_bittiming_s *)arg; uint32_t brp; - uint32_t stm32l4_canbit_quanta; + uint32_t can_bit_quanta; uint32_t tmp; + uint32_t regval; DEBUGASSERT(bt != NULL); DEBUGASSERT(bt->bt_baud < STM32L4_PCLK1_FREQUENCY); @@ -836,6 +837,8 @@ static int stm32l4_canioctl(FAR struct can_dev_s *dev, int cmd, DEBUGASSERT(bt->bt_tseg1 > 0 && bt->bt_tseg1 <= 16); DEBUGASSERT(bt->bt_tseg2 > 0 && bt->bt_tseg2 <= 8); + regval = stm32l4_cangetreg(priv, STM32L4_CAN_BTR_OFFSET); + /* Extract bit timing data */ /* tmp is in clocks per bit time */ @@ -843,35 +846,13 @@ static int stm32l4_canioctl(FAR struct can_dev_s *dev, int cmd, /* This value is dynamic as requested by user */ - stm32l4_canbit_quanta = bt->bt_tseg1 + bt->bt_tseg2 + 1; + can_bit_quanta = bt->bt_tseg1 + bt->bt_tseg2 + 1; - if (tmp < stm32l4_canbit_quanta) + if (tmp < can_bit_quanta) { -#if 0 - /* At the smallest brp value (1), there are already too few - * bit times (PCLK1 / baud) to meet our goal. brp must be one - * and we need make some reasonable guesses about ts1 and ts2. - */ + /* This timing is not possible */ - brp = 1; - - /* In this case, we have to guess a good value for ts1 and ts2 */ - - tseg1 = (tmp - 1) >> 1; /* cut available time in half */ - tseg2 = tmp - tseg1 - 1; /* ts2 uses the rest minus one */ - - /* if we can, try to approximate the CAN requirements, - * which are not exactly "cut baud time in half" - */ - - if (tseg1 == tseg2 && tseg1 > 1 && tseg2 < CAN_BTR_TSEG2_MAX) - { - tseg1--; - tseg2++; - } -#else ret = -EINVAL; -#endif } /* Otherwise, nquanta is stm32l4_canbit_quanta, ts1 and ts2 are @@ -881,31 +862,21 @@ static int stm32l4_canioctl(FAR struct can_dev_s *dev, int cmd, else { - brp = (tmp + (stm32l4_canbit_quanta/2)) / stm32l4_canbit_quanta; + brp = (tmp + (can_bit_quanta/2)) / can_bit_quanta; DEBUGASSERT(brp >= 1 && brp <= CAN_BTR_BRP_MAX); } caninfo("TS1: %d TS2: %d BRP: %d\n", bt->bt_tseg1, bt->bt_tseg2, brp); - /* Configure bit timing. This also does the following, less obvious - * things. Unless loopback mode is enabled, it: - * - * - Disables silent mode. - * - Disables loopback mode. - * - */ + /* Configure bit timing. */ - tmp = ((brp - 1) << CAN_BTR_BRP_SHIFT) | - ((bt->bt_tseg1 - 1) << CAN_BTR_TS1_SHIFT) | - ((bt->bt_tseg2 - 1) << CAN_BTR_TS2_SHIFT) | - ((bt->bt_sjw - 1) << CAN_BTR_SJW_SHIFT); -#ifdef CONFIG_CAN_LOOPBACK - tmp |= CAN_BTR_LBKM; -#endif - - /* Bit timing can only be configured in init mode. - * No registers are changed. - */ + regval &= ~(CAN_BTR_BRP_MASK | CAN_BTR_TS1_MASK | CAN_BTR_TS2_MASK | CAN_BTR_SJW_MASK); + regval |= ((brp - 1) << CAN_BTR_BRP_SHIFT) | + ((bt->bt_tseg1 - 1) << CAN_BTR_TS1_SHIFT) | + ((bt->bt_tseg2 - 1) << CAN_BTR_TS2_SHIFT) | + ((bt->bt_sjw - 1) << CAN_BTR_SJW_SHIFT); + + /* Bit timing can only be configured in init mode. */ ret = stm32l4_canenterinitmode(priv); if (ret != 0) @@ -913,7 +884,8 @@ static int stm32l4_canioctl(FAR struct can_dev_s *dev, int cmd, break; } - stm32l4_canputreg(priv, STM32L4_CAN_BTR_OFFSET, tmp); + stm32l4_canputreg(priv, STM32L4_CAN_BTR_OFFSET, regval); + ret = stm32l4_canexitinitmode(priv); if (ret == 0) @@ -923,6 +895,86 @@ static int stm32l4_canioctl(FAR struct can_dev_s *dev, int cmd, } break; + /* CANIOC_GET_CONNMODES: + * Description: Get the current bus connection modes + * Argument: A pointer to a write-able instance of struct + * canioc_connmodes_s in which the new bus modes will + * be returned. + * 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_GET_CONNMODES: + { + FAR struct canioc_connmodes_s *bm = + (FAR struct canioc_connmodes_s *)arg; + uint32_t regval; + + DEBUGASSERT(bm != NULL); + + regval = stm32l4_cangetreg(priv, STM32L4_CAN_BTR_OFFSET); + + bm->bm_loopback = ((regval & CAN_BTR_LBKM) == CAN_BTR_LBKM); + bm->bm_silent = ((regval & CAN_BTR_SILM) == CAN_BTR_SILM); + ret = OK; + break; + } + + /* CANIOC_SET_CONNMODES: + * Description: Set new bus connection modes values + * Argument: A pointer to a read-able instance of struct + * canioc_connmodes_s in which the new bus modes + * are provided. + * 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_SET_CONNMODES: + { + FAR struct canioc_connmodes_s *bm = + (FAR struct canioc_connmodes_s *)arg; + uint32_t regval; + + DEBUGASSERT(bm != NULL); + + regval = stm32l4_cangetreg(priv, STM32L4_CAN_BTR_OFFSET); + + if (bm->bm_loopback) + { + regval |= CAN_BTR_LBKM; + } + else + { + regval &= ~CAN_BTR_LBKM; + } + + if (bm->bm_silent) + { + regval |= CAN_BTR_SILM; + } + else + { + regval &= ~CAN_BTR_SILM; + } + + /* This register can only be configured in init mode. */ + + ret = stm32l4_canenterinitmode(priv); + if (ret != 0) + { + break; + } + + stm32l4_canputreg(priv, STM32L4_CAN_BTR_OFFSET, regval); + + ret = stm32l4_canexitinitmode(priv); + } + break; + #ifdef CONFIG_CAN_EXTID /* CANIOC_ADD_EXTFILTER: * Description: Add an address filter for a extended 29 bit diff --git a/include/nuttx/can.h b/include/nuttx/can.h index 68f65b9703f..27ef01d77c4 100644 --- a/include/nuttx/can.h +++ b/include/nuttx/can.h @@ -192,8 +192,8 @@ #define CANIOC_ADD_EXTFILTER _CANIOC(5) #define CANIOC_DEL_STDFILTER _CANIOC(6) #define CANIOC_DEL_EXTFILTER _CANIOC(7) -#define CANIOC_GET_CONNMODE _CANIOC(8) -#define CANIOC_SET_CONNMODE _CANIOC(9) +#define CANIOC_GET_CONNMODES _CANIOC(8) +#define CANIOC_SET_CONNMODES _CANIOC(9) /* CANIOC_USER: Device specific ioctl calls can be supported with cmds greater * than this value