diff --git a/drivers/can/can_mcan.c b/drivers/can/can_mcan.c index 0655d3d9e5a35ae..5d2f0a026912f1f 100644 --- a/drivers/can/can_mcan.c +++ b/drivers/can/can_mcan.c @@ -524,13 +524,67 @@ static void can_mcan_tx_event_handler(const struct device *dev) } } +#if CONFIG_CAN_STATS +static void can_mcan_lec_update_stats(const struct device *dev, uint32_t lec) +{ + switch (lec) { + case CAN_MCAN_PSR_LEC_STUFF_ERROR: + CAN_STATS_STUFF_ERROR_INC(dev); + break; + case CAN_MCAN_PSR_LEC_FORM_ERROR: + CAN_STATS_FORM_ERROR_INC(dev); + break; + case CAN_MCAN_PSR_LEC_ACK_ERROR: + CAN_STATS_ACK_ERROR_INC(dev); + break; + case CAN_MCAN_PSR_LEC_BIT1_ERROR: + CAN_STATS_BIT1_ERROR_INC(dev); + break; + case CAN_MCAN_PSR_LEC_BIT0_ERROR: + CAN_STATS_BIT0_ERROR_INC(dev); + break; + case CAN_MCAN_PSR_LEC_CRC_ERROR: + CAN_STATS_CRC_ERROR_INC(dev); + break; + case CAN_MCAN_PSR_LEC_NO_ERROR: + case CAN_MCAN_PSR_LEC_NO_CHANGE: + default: + break; + } +} + +static void can_mcan_psr_update_stats(const struct device *dev, uint32_t psr_reg) +{ + /* Reading the lower byte of the PSR register clears the protocol last + * error codes (LEC). To avoid missing errors, this function should be + * called whenever the PSR register is read. + */ + /* TODO: Protocol Exception Event (PXE) not working... + * if ((psr_reg & CAN_MCAN_PSR_PXE) != 0U) + */ + { + /* A protocol error has occurred since the last read, update stats */ + uint32_t lec; + + lec = FIELD_GET(CAN_MCAN_PSR_LEC, psr_reg); + can_mcan_lec_update_stats(dev, lec); +#ifdef CONFIG_CAN_FD_MODE + lec = FIELD_GET(CAN_MCAN_PSR_DLEC, psr_reg); + can_mcan_lec_update_stats(dev, lec); +#endif + } +} +#else +#define can_mcan_psr_update_stats(dev, psr_reg) +#endif + void can_mcan_line_0_isr(const struct device *dev) { const uint32_t events = CAN_MCAN_IR_BO | CAN_MCAN_IR_EP | CAN_MCAN_IR_EW | CAN_MCAN_IR_TEFN | CAN_MCAN_IR_TEFL | CAN_MCAN_IR_ARA | - CAN_MCAN_IR_MRAF; + CAN_MCAN_IR_MRAF | CAN_MCAN_IR_PEA | CAN_MCAN_IR_PED; struct can_mcan_data *data = dev->data; - uint32_t ir; + uint32_t ir, reg; int err; err = can_mcan_read_reg(dev, CAN_MCAN_IR, &ir); @@ -562,10 +616,19 @@ void can_mcan_line_0_isr(const struct device *dev) LOG_ERR("Access to reserved address"); } - if (ir & CAN_MCAN_IR_MRAF) { + if ((ir & CAN_MCAN_IR_MRAF) != 0U) { LOG_ERR("Message RAM access failure"); } + if ((ir & (CAN_MCAN_IR_PEA | CAN_MCAN_IR_PED)) != 0U) { + LOG_WRN("Protocol Error"); + /* Read and update protocol error stats */ + err = can_mcan_read_reg(dev, CAN_MCAN_PSR, ®); + if (err == 0) { + can_mcan_psr_update_stats(dev, reg); + } + } + err = can_mcan_read_reg(dev, CAN_MCAN_IR, &ir); if (err != 0) { return; @@ -739,10 +802,12 @@ void can_mcan_line_1_isr(const struct device *dev) if ((ir & CAN_MCAN_IR_RF0L) != 0U) { LOG_ERR("Message lost on FIFO0"); + CAN_STATS_RX_OVERRUN_INC(dev); } if ((ir & CAN_MCAN_IR_RF1L) != 0U) { LOG_ERR("Message lost on FIFO1"); + CAN_STATS_RX_OVERRUN_INC(dev); } err = can_mcan_read_reg(dev, CAN_MCAN_IR, &ir); @@ -764,6 +829,7 @@ int can_mcan_get_state(const struct device *dev, enum can_state *state, if (err != 0) { return err; } + can_mcan_psr_update_stats(dev, reg); if (!data->started) { *state = CAN_STATE_STOPPED; @@ -881,6 +947,7 @@ int can_mcan_send(const struct device *dev, const struct can_frame *frame, k_tim if (err != 0) { return err; } + can_mcan_psr_update_stats(dev, reg); if ((reg & CAN_MCAN_PSR_BO) != 0U) { return -ENETUNREACH; @@ -1455,7 +1522,7 @@ int can_mcan_init(const struct device *dev) reg = CAN_MCAN_IE_BOE | CAN_MCAN_IE_EWE | CAN_MCAN_IE_EPE | CAN_MCAN_IE_MRAFE | CAN_MCAN_IE_TEFLE | CAN_MCAN_IE_TEFNE | CAN_MCAN_IE_RF0NE | CAN_MCAN_IE_RF1NE | - CAN_MCAN_IE_RF0LE | CAN_MCAN_IE_RF1LE; + CAN_MCAN_IE_RF0LE | CAN_MCAN_IE_RF1LE | CAN_MCAN_IE_PEAE | CAN_MCAN_IE_PEDE; err = can_mcan_write_reg(dev, CAN_MCAN_IE, reg); if (err != 0) { diff --git a/include/zephyr/drivers/can/can_mcan.h b/include/zephyr/drivers/can/can_mcan.h index c1a1fb9f85d2f1f..c860715a1e8bcd8 100644 --- a/include/zephyr/drivers/can/can_mcan.h +++ b/include/zephyr/drivers/can/can_mcan.h @@ -127,6 +127,15 @@ #define CAN_MCAN_PSR_ACT GENMASK(4, 3) #define CAN_MCAN_PSR_LEC GENMASK(2, 0) +#define CAN_MCAN_PSR_LEC_NO_ERROR 0 +#define CAN_MCAN_PSR_LEC_STUFF_ERROR 1 +#define CAN_MCAN_PSR_LEC_FORM_ERROR 2 +#define CAN_MCAN_PSR_LEC_ACK_ERROR 3 +#define CAN_MCAN_PSR_LEC_BIT1_ERROR 4 +#define CAN_MCAN_PSR_LEC_BIT0_ERROR 5 +#define CAN_MCAN_PSR_LEC_CRC_ERROR 6 +#define CAN_MCAN_PSR_LEC_NO_CHANGE 7 + /* Transmitter Delay Compensation register */ #define CAN_MCAN_TDCR 0x048 #define CAN_MCAN_TDCR_TDCO GENMASK(14, 8)