#include "bxcan_declarations.h" // IRQs: CAN1_TX, CAN1_RX0, CAN1_SCE // CAN2_TX, CAN2_RX0, CAN2_SCE // CAN3_TX, CAN3_RX0, CAN3_SCE CAN_TypeDef *cans[CAN_ARRAY_SIZE] = {CAN1, CAN2, CAN3}; uint8_t can_irq_number[CAN_IRQS_ARRAY_SIZE][CAN_IRQS_ARRAY_SIZE] = { { CAN1_TX_IRQn, CAN1_RX0_IRQn, CAN1_SCE_IRQn }, { CAN2_TX_IRQn, CAN2_RX0_IRQn, CAN2_SCE_IRQn }, { CAN3_TX_IRQn, CAN3_RX0_IRQn, CAN3_SCE_IRQn }, }; bool can_set_speed(uint8_t can_number) { bool ret = true; CAN_TypeDef *CANx = CANIF_FROM_CAN_NUM(can_number); uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number); ret &= llcan_set_speed( CANx, bus_config[bus_number].can_speed, can_loopback, (unsigned int)(can_silent) & (1U << can_number) ); return ret; } void can_clear_send(CAN_TypeDef *CANx, uint8_t can_number) { can_health[can_number].can_core_reset_cnt += 1U; llcan_clear_send(CANx); } void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg) { CAN_TypeDef *CANx = CANIF_FROM_CAN_NUM(can_number); uint32_t esr_reg = CANx->ESR; can_health[can_number].bus_off = ((esr_reg & CAN_ESR_BOFF) >> CAN_ESR_BOFF_Pos); can_health[can_number].bus_off_cnt += can_health[can_number].bus_off; can_health[can_number].error_warning = ((esr_reg & CAN_ESR_EWGF) >> CAN_ESR_EWGF_Pos); can_health[can_number].error_passive = ((esr_reg & CAN_ESR_EPVF) >> CAN_ESR_EPVF_Pos); can_health[can_number].last_error = ((esr_reg & CAN_ESR_LEC) >> CAN_ESR_LEC_Pos); if ((can_health[can_number].last_error != 0U) && (can_health[can_number].last_error != 7U)) { can_health[can_number].last_stored_error = can_health[can_number].last_error; } can_health[can_number].receive_error_cnt = ((esr_reg & CAN_ESR_REC) >> CAN_ESR_REC_Pos); can_health[can_number].transmit_error_cnt = ((esr_reg & CAN_ESR_TEC) >> CAN_ESR_TEC_Pos); can_health[can_number].irq0_call_rate = interrupts[can_irq_number[can_number][0]].call_rate; can_health[can_number].irq1_call_rate = interrupts[can_irq_number[can_number][1]].call_rate; can_health[can_number].irq2_call_rate = interrupts[can_irq_number[can_number][2]].call_rate; if (ir_reg != 0U) { can_health[can_number].total_error_cnt += 1U; // RX message lost due to FIFO overrun if ((CANx->RF0R & (CAN_RF0R_FOVR0)) != 0U) { can_health[can_number].total_rx_lost_cnt += 1U; CANx->RF0R &= ~(CAN_RF0R_FOVR0); } can_clear_send(CANx, can_number); } } // ***************************** CAN ***************************** // CANx_SCE IRQ Handler static void can_sce(uint8_t can_number) { update_can_health_pkt(can_number, 1U); } // CANx_TX IRQ Handler void process_can(uint8_t can_number) { if (can_number != 0xffU) { ENTER_CRITICAL(); CAN_TypeDef *CANx = CANIF_FROM_CAN_NUM(can_number); uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number); // check for empty mailbox CANPacket_t to_send; if ((CANx->TSR & (CAN_TSR_TERR0 | CAN_TSR_ALST0)) != 0U) { // last TX failed due to error arbitration lost can_health[can_number].total_tx_lost_cnt += 1U; CANx->TSR |= (CAN_TSR_TERR0 | CAN_TSR_ALST0); } if ((CANx->TSR & CAN_TSR_TME0) == CAN_TSR_TME0) { // add successfully transmitted message to my fifo if ((CANx->TSR & CAN_TSR_RQCP0) == CAN_TSR_RQCP0) { if ((CANx->TSR & CAN_TSR_TXOK0) == CAN_TSR_TXOK0) { CANPacket_t to_push; to_push.fd = 0U; to_push.returned = 1U; to_push.rejected = 0U; to_push.extended = (CANx->sTxMailBox[0].TIR >> 2) & 0x1U; to_push.addr = (to_push.extended != 0U) ? (CANx->sTxMailBox[0].TIR >> 3) : (CANx->sTxMailBox[0].TIR >> 21); to_push.data_len_code = CANx->sTxMailBox[0].TDTR & 0xFU; to_push.bus = bus_number; WORD_TO_BYTE_ARRAY(&to_push.data[0], CANx->sTxMailBox[0].TDLR); WORD_TO_BYTE_ARRAY(&to_push.data[4], CANx->sTxMailBox[0].TDHR); can_set_checksum(&to_push); rx_buffer_overflow += can_push(&can_rx_q, &to_push) ? 0U : 1U; } // clear interrupt // careful, this can also be cleared by requesting a transmission CANx->TSR |= CAN_TSR_RQCP0; } if (can_pop(can_queues[bus_number], &to_send)) { if (can_check_checksum(&to_send)) { can_health[can_number].total_tx_cnt += 1U; // only send if we have received a packet CANx->sTxMailBox[0].TIR = ((to_send.extended != 0U) ? (to_send.addr << 3) : (to_send.addr << 21)) | (to_send.extended << 2); CANx->sTxMailBox[0].TDTR = to_send.data_len_code; BYTE_ARRAY_TO_WORD(CANx->sTxMailBox[0].TDLR, &to_send.data[0]); BYTE_ARRAY_TO_WORD(CANx->sTxMailBox[0].TDHR, &to_send.data[4]); // Send request TXRQ CANx->sTxMailBox[0].TIR |= 0x1U; } else { can_health[can_number].total_tx_checksum_error_cnt += 1U; } refresh_can_tx_slots_available(); } } EXIT_CRITICAL(); } } // CANx_RX0 IRQ Handler // blink blue when we are receiving CAN messages void can_rx(uint8_t can_number) { CAN_TypeDef *CANx = CANIF_FROM_CAN_NUM(can_number); uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number); while ((CANx->RF0R & CAN_RF0R_FMP0) != 0U) { can_health[can_number].total_rx_cnt += 1U; // can is live pending_can_live = 1; // add to my fifo CANPacket_t to_push; to_push.fd = 0U; to_push.returned = 0U; to_push.rejected = 0U; to_push.extended = (CANx->sFIFOMailBox[0].RIR >> 2) & 0x1U; to_push.addr = (to_push.extended != 0U) ? (CANx->sFIFOMailBox[0].RIR >> 3) : (CANx->sFIFOMailBox[0].RIR >> 21); to_push.data_len_code = CANx->sFIFOMailBox[0].RDTR & 0xFU; to_push.bus = bus_number; WORD_TO_BYTE_ARRAY(&to_push.data[0], CANx->sFIFOMailBox[0].RDLR); WORD_TO_BYTE_ARRAY(&to_push.data[4], CANx->sFIFOMailBox[0].RDHR); can_set_checksum(&to_push); // forwarding (panda only) int bus_fwd_num = safety_fwd_hook(bus_number, to_push.addr); if (bus_fwd_num != -1) { CANPacket_t to_send; to_send.fd = 0U; to_send.returned = 0U; to_send.rejected = 0U; to_send.extended = to_push.extended; // TXRQ to_send.addr = to_push.addr; to_send.bus = to_push.bus; to_send.data_len_code = to_push.data_len_code; (void)memcpy(to_send.data, to_push.data, dlc_to_len[to_push.data_len_code]); can_set_checksum(&to_send); can_send(&to_send, bus_fwd_num, true); can_health[can_number].total_fwd_cnt += 1U; } safety_rx_invalid += safety_rx_hook(&to_push) ? 0U : 1U; ignition_can_hook(&to_push); led_set(LED_BLUE, true); rx_buffer_overflow += can_push(&can_rx_q, &to_push) ? 0U : 1U; // next CANx->RF0R |= CAN_RF0R_RFOM0; } } static void CAN1_TX_IRQ_Handler(void) { process_can(0); } static void CAN1_RX0_IRQ_Handler(void) { can_rx(0); } static void CAN1_SCE_IRQ_Handler(void) { can_sce(0); } static void CAN2_TX_IRQ_Handler(void) { process_can(1); } static void CAN2_RX0_IRQ_Handler(void) { can_rx(1); } static void CAN2_SCE_IRQ_Handler(void) { can_sce(1); } static void CAN3_TX_IRQ_Handler(void) { process_can(2); } static void CAN3_RX0_IRQ_Handler(void) { can_rx(2); } static void CAN3_SCE_IRQ_Handler(void) { can_sce(2); } bool can_init(uint8_t can_number) { bool ret = false; REGISTER_INTERRUPT(CAN1_TX_IRQn, CAN1_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1) REGISTER_INTERRUPT(CAN1_RX0_IRQn, CAN1_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1) REGISTER_INTERRUPT(CAN1_SCE_IRQn, CAN1_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1) REGISTER_INTERRUPT(CAN2_TX_IRQn, CAN2_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_2) REGISTER_INTERRUPT(CAN2_RX0_IRQn, CAN2_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_2) REGISTER_INTERRUPT(CAN2_SCE_IRQn, CAN2_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_2) REGISTER_INTERRUPT(CAN3_TX_IRQn, CAN3_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_3) REGISTER_INTERRUPT(CAN3_RX0_IRQn, CAN3_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_3) REGISTER_INTERRUPT(CAN3_SCE_IRQn, CAN3_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_3) if (can_number != 0xffU) { CAN_TypeDef *CANx = CANIF_FROM_CAN_NUM(can_number); ret &= can_set_speed(can_number); ret &= llcan_init(CANx); // in case there are queued up messages process_can(can_number); } return ret; }