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:
commit
47b74fc021
@ -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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user