aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2025-01-14 16:06:45 -0500
committerKevin O'Connor <kevin@koconnor.net>2025-02-02 18:43:34 -0500
commit61fb5fe29c0c38049c173aa13fdbcffb386aa1c8 (patch)
tree5fc2500983fce4055f32764d792a8541ee3154e1
parent9fd415d3f55e4be7e0b0b49a0b65cd8c174e01da (diff)
downloadkutter-61fb5fe29c0c38049c173aa13fdbcffb386aa1c8.tar.gz
kutter-61fb5fe29c0c38049c173aa13fdbcffb386aa1c8.tar.xz
kutter-61fb5fe29c0c38049c173aa13fdbcffb386aa1c8.zip
atsamd: Add support for reporting canbus state
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
-rw-r--r--src/atsamd/fdcan.c49
1 files changed, 47 insertions, 2 deletions
diff --git a/src/atsamd/fdcan.c b/src/atsamd/fdcan.c
index 5ad62c0f..e8c10765 100644
--- a/src/atsamd/fdcan.c
+++ b/src/atsamd/fdcan.c
@@ -1,11 +1,12 @@
// CANbus support on atsame51 chips
//
-// Copyright (C) 2021-2022 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2021-2025 Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2019 Eug Krashtan <eug.krashtan@gmail.com>
// Copyright (C) 2020 Pontus Borg <glpontus@gmail.com>
//
// This file may be distributed under the terms of the GNU GPLv3 license.
+#include "board/irq.h" // irq_save
#include "command.h" // DECL_CONSTANT_STR
#include "generic/armcm_boot.h" // armcm_enable_irq
#include "generic/canbus.h" // canbus_notify_tx
@@ -163,6 +164,38 @@ canhw_set_filter(uint32_t id)
CANx->CCCR.reg &= ~CAN_CCCR_INIT;
}
+static struct {
+ uint32_t rx_error, tx_error;
+} CAN_Errors;
+
+// Report interface status
+void
+canhw_get_status(struct canbus_status *status)
+{
+ irqstatus_t flag = irq_save();
+ uint32_t psr = CANx->PSR.reg, lec = psr & CAN_PSR_LEC_Msk;
+ if (lec && lec != 7) {
+ // Reading PSR clears it - so update state here
+ if (lec >= 3 && lec <= 5)
+ CAN_Errors.tx_error += 1;
+ else
+ CAN_Errors.rx_error += 1;
+ }
+ uint32_t rx_error = CAN_Errors.rx_error, tx_error = CAN_Errors.tx_error;
+ irq_restore(flag);
+
+ status->rx_error = rx_error;
+ status->tx_error = tx_error;
+ if (psr & CAN_PSR_BO)
+ status->bus_state = CANBUS_STATE_OFF;
+ else if (psr & CAN_PSR_EP)
+ status->bus_state = CANBUS_STATE_PASSIVE;
+ else if (psr & CAN_PSR_EW)
+ status->bus_state = CANBUS_STATE_WARN;
+ else
+ status->bus_state = 0;
+}
+
// This function handles CAN global interrupts
void
CAN_IRQHandler(void)
@@ -199,6 +232,18 @@ CAN_IRQHandler(void)
CANx->IR.reg = FDCAN_IE_TC;
canbus_notify_tx();
}
+ if (ir & (CAN_IR_PED | CAN_IR_PEA)) {
+ // Bus error
+ uint32_t psr = CANx->PSR.reg;
+ CANx->IR.reg = CAN_IR_PED | CAN_IR_PEA;
+ uint32_t lec = psr & CAN_PSR_LEC_Msk;
+ if (lec && lec != 7) {
+ if (lec >= 3 && lec <= 5)
+ CAN_Errors.tx_error += 1;
+ else
+ CAN_Errors.rx_error += 1;
+ }
+ }
}
static inline const uint32_t
@@ -309,6 +354,6 @@ can_init(void)
/*##-3- Configure Interrupts #################################*/
armcm_enable_irq(CAN_IRQHandler, CANx_IRQn, 1);
CANx->ILE.reg = CAN_ILE_EINT0;
- CANx->IE.reg = CAN_IE_RF0NE | FDCAN_IE_TC;
+ CANx->IE.reg = CAN_IE_RF0NE | FDCAN_IE_TC | CAN_IE_PEDE | CAN_IE_PEAE;
}
DECL_INIT(can_init);