Perform CAN Transceiver self test on microcontroller boot
I am using CAN on an STM32F042F6P6. I want to detect if an attached CAN transceiver is working or not. While there is no guarantee that there are other CAN nodes present on the bus, a 120 ohm termination resistor is always present.
My original plan was to try transmitting something on the bus and checking for errors. If I only get an acknowledgement error, then the transceiver is probably OK. If I get a bit error, bit stuffing error or a bus off error, something is wrong with the transceiver.
However, when I tried to put this in practice, I found that the STM was never throwing any errors. If I removed my transceiver and reattached it to simulate a failure, I found that although CAN transmission stopped, no errors were triggered and the hcan was stuck in HAL_CAN_STATE_LISTENING state. What could be going wrong here?
All parameters except Automatic Retransmission have been disabled in the ioc file. Global interrupt for CAN has been enabled. Attached code for reference.
#include <can.h>
const CAN_TxHeaderTypeDef transmitBuffer = {
.StdId = 0x00,
.ExtId = 0x1EFEFEFE,
.IDE = CAN_ID_EXT,
.RTR = CAN_RTR_DATA,
.DLC = 8,
.TransmitGlobalTime = DISABLE
};
const uint8_t data[8] = {0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88};
uint32_t mailbox = 0;
volatile uint32_t error = 0;
void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan) {
error = hcan->ErrorCode;
HAL_CAN_ActivateNotification(hcan, CAN_IT_ERROR_PASSIVE | CAN_IT_BUSOFF);
}
// Called once before while loop
void initialiseCAN() {
if (HAL_CAN_Start(&hcan) != HAL_OK) {
Error_Handler();
}
HAL_CAN_ActivateNotification(&hcan, CAN_IT_ERROR_PASSIVE | CAN_IT_BUSOFF);
}
// Running inside a while loop for now
uint8_t performCANSelfTest() {
if (HAL_CAN_AddTxMessage(&hcan, &transmitBuffer, data, &mailbox) != HAL_OK) {
return 255;
}
while (HAL_CAN_IsTxMessagePending(&hcan, mailbox)) {
HAL_Delay(1);
}
HAL_Delay(10);
if (error & HAL_CAN_ERROR_STF || error & HAL_CAN_ERROR_BOF || error & HAL_CAN_ERROR_BR || error & HAL_CAN_ERROR_BD) {
return 254;
}
return 1;
}
