1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

Merge pull request #20667 from firas-hamdi/feat/samd5x_can_handle_errors

cpu/samd5x: handle CAN errors
This commit is contained in:
Dylan Laduranty 2024-05-23 20:12:08 +00:00 committed by GitHub
commit 47b74fc021
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 157 additions and 0 deletions

View File

@ -75,6 +75,16 @@ extern "C" {
#define CANDEV_SAMD5X_MAX_TX_BUFFER 32
#define CANDEV_SAMD5X_MSG_RAM_MAX_SIZE 448
/* SAMD5x CAN controller error codes (values from datasheet section 39.8.14) */
#define CANDEV_SAMD5X_NO_ERROR 0
#define CANDEV_SAMD5X_STUFF_ERROR 1
#define CANDEV_SAMD5X_FORM_ERROR 2
#define CANDEV_SAMD5X_ACK_ERROR 3
#define CANDEV_SAMD5X_BIT1_ERROR 4
#define CANDEV_SAMD5X_BIT0_ERROR 5
#define CANDEV_SAMD5X_CRC_ERROR 6
#define CANDEV_SAMD5X_NO_CHANGE_ERROR 7
/**
* @brief CAN device configuration descriptor
*/

View File

@ -386,6 +386,8 @@ static int _init(candev_t *candev)
dev->conf->can->IE.reg |= CAN_IE_RF0NE | CAN_IE_RF1NE;
/* Enable transmission events interrupts */
dev->conf->can->IE.reg |= CAN_IE_TEFNE;
/* Enable errors interrupts */
dev->conf->can->IE.reg |= CAN_IE_PEDE | CAN_IE_PEAE | CAN_IE_BOE | CAN_IE_EWE | CAN_IE_EPE;
/* Enable the interrupt lines */
dev->conf->can->ILE.reg = CAN_ILE_EINT0 | CAN_ILE_EINT1;
@ -779,6 +781,148 @@ static void _isr(candev_t *candev)
}
}
static uint8_t last_error_code = 0;
/* Interrupt triggered due to protocol error in data phase */
if (irq_reg & CAN_IR_PED) {
DEBUG_PUTS("protocol error in data phase");
dev->conf->can->IR.reg |= CAN_IR_PED;
/* Extract the Tx and Rx error counters */
uint8_t tx_err_cnt = (uint8_t)dev->conf->can->ECR.bit.TEC;
DEBUG("tx error counter = %u\n", tx_err_cnt);
uint8_t rx_err_cnt = (uint8_t)dev->conf->can->ECR.bit.REC;
DEBUG("rx error counter = %u\n", rx_err_cnt);
/* Check the CAN error type */
uint8_t error_code = (uint8_t)dev->conf->can->PSR.bit.LEC;
DEBUG("error code = %u\n", error_code);
if (error_code == CANDEV_SAMD5X_NO_CHANGE_ERROR) {
error_code = last_error_code;
}
switch (error_code) {
case CANDEV_SAMD5X_STUFF_ERROR:
DEBUG_PUTS("STUFF error");
if (dev->candev.event_callback) {
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_RX_ERROR, NULL);
}
break;
case CANDEV_SAMD5X_FORM_ERROR:
DEBUG_PUTS("FORM error");
if (dev->candev.event_callback) {
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_RX_ERROR, NULL);
}
break;
case CANDEV_SAMD5X_ACK_ERROR:
DEBUG_PUTS("ACK error");
if (dev->candev.event_callback) {
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_TX_ERROR, NULL);
}
break;
case CANDEV_SAMD5X_BIT1_ERROR:
DEBUG_PUTS("BIT1 error");
if (dev->candev.event_callback) {
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_TX_ERROR, NULL);
}
break;
case CANDEV_SAMD5X_BIT0_ERROR:
DEBUG_PUTS("BIT0 error");
if (dev->candev.event_callback) {
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_TX_ERROR, NULL);
}
break;
case CANDEV_SAMD5X_CRC_ERROR:
DEBUG_PUTS("CRC error");
if (dev->candev.event_callback) {
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_RX_ERROR, NULL);
}
break;
default:
break;
}
last_error_code = error_code;
}
/* Interrupt triggered due to protocol error in arbitration phase */
if (irq_reg & CAN_IR_PEA) {
DEBUG_PUTS("protocol error in arbitration phase");
dev->conf->can->IR.reg |= CAN_IR_PEA;
/* Extract the Tx and Rx error counters */
uint8_t tx_err_cnt = (uint8_t)dev->conf->can->ECR.bit.TEC;
DEBUG("tx error counter = %u\n", tx_err_cnt);
uint8_t rx_err_cnt = (uint8_t)dev->conf->can->ECR.bit.REC;
DEBUG("rx error counter = %u\n", rx_err_cnt);
/* Check the CAN error type */
uint8_t error_code = (uint8_t)dev->conf->can->PSR.bit.LEC;
DEBUG("error code = %u\n", error_code);
if (error_code == CANDEV_SAMD5X_NO_CHANGE_ERROR) {
error_code = last_error_code;
}
switch (error_code) {
case CANDEV_SAMD5X_STUFF_ERROR:
DEBUG_PUTS("STUFF error");
if (dev->candev.event_callback) {
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_RX_ERROR, NULL);
}
break;
case CANDEV_SAMD5X_FORM_ERROR:
DEBUG_PUTS("FORM error");
if (dev->candev.event_callback) {
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_RX_ERROR, NULL);
}
break;
case CANDEV_SAMD5X_ACK_ERROR:
DEBUG_PUTS("ACK error");
if (dev->candev.event_callback) {
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_TX_ERROR, NULL);
}
break;
case CANDEV_SAMD5X_BIT0_ERROR:
DEBUG_PUTS("BIT0 error");
if (dev->candev.event_callback) {
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_TX_ERROR, NULL);
}
break;
case CANDEV_SAMD5X_CRC_ERROR:
DEBUG_PUTS("CRC error");
if (dev->candev.event_callback) {
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_RX_ERROR, NULL);
}
break;
default:
break;
}
last_error_code = error_code;
}
/* Interrupt triggered due to Bus_Off status */
if (irq_reg & CAN_IR_BO) {
DEBUG_PUTS("Bus off");
dev->conf->can->IR.reg |= CAN_IR_BO;
if (dev->candev.event_callback) {
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_BUS_OFF, NULL);
}
}
/* Interrupt triggered due to Error warning status */
if (irq_reg & CAN_IR_EW) {
DEBUG_PUTS("Error warning");
dev->conf->can->IR.reg |= CAN_IR_EW;
if (dev->candev.event_callback) {
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_ERROR_WARNING, NULL);
}
}
/* Interrupt triggered due to Error passive status */
if (irq_reg & CAN_IR_EP) {
DEBUG_PUTS("Error Passive");
dev->conf->can->IR.reg |= CAN_IR_EP;
if (dev->candev.event_callback) {
dev->candev.event_callback(&(dev->candev), CANDEV_EVENT_ERROR_PASSIVE, NULL);
}
}
/* Enable the peripheral's interrupt */
if (dev->conf->can == CAN0) {
NVIC_EnableIRQ(CAN0_IRQn);

View File

@ -256,12 +256,15 @@ static void _can_event_callback(candev_t *dev, candev_event_t event, void *arg)
DEBUG("_can_event: CANDEV_EVENT_RX_ERROR\n");
break;
case CANDEV_EVENT_BUS_OFF:
DEBUG("_can_event: CANDEV_EVENT_BUS_OFF\n");
dev->state = CAN_STATE_BUS_OFF;
break;
case CANDEV_EVENT_ERROR_PASSIVE:
DEBUG("_can_event: CANDEV_EVENT_ERROR_PASSIVE\n");
dev->state = CAN_STATE_ERROR_PASSIVE;
break;
case CANDEV_EVENT_ERROR_WARNING:
DEBUG("_can_event: CANDEV_EVENT_ERROR_WARNING\n");
dev->state = CAN_STATE_ERROR_WARNING;
break;
default: