You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					270 lines
				
				11 KiB
			
		
		
			
		
	
	
					270 lines
				
				11 KiB
			| 
								 
											3 weeks ago
										 
									 | 
							
								#include "fdcan_declarations.h"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								FDCAN_GlobalTypeDef *cans[PANDA_CAN_CNT] = {FDCAN1, FDCAN2, FDCAN3};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static bool can_set_speed(uint8_t can_number) {
							 | 
						||
| 
								 | 
							
								  bool ret = true;
							 | 
						||
| 
								 | 
							
								  FDCAN_GlobalTypeDef *FDCANx = CANIF_FROM_CAN_NUM(can_number);
							 | 
						||
| 
								 | 
							
								  uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  ret &= llcan_set_speed(
							 | 
						||
| 
								 | 
							
								    FDCANx,
							 | 
						||
| 
								 | 
							
								    bus_config[bus_number].can_speed,
							 | 
						||
| 
								 | 
							
								    bus_config[bus_number].can_data_speed,
							 | 
						||
| 
								 | 
							
								    bus_config[bus_number].canfd_non_iso,
							 | 
						||
| 
								 | 
							
								    can_loopback,
							 | 
						||
| 
								 | 
							
								    can_silent
							 | 
						||
| 
								 | 
							
								  );
							 | 
						||
| 
								 | 
							
								  return ret;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void can_clear_send(FDCAN_GlobalTypeDef *FDCANx, uint8_t can_number) {
							 | 
						||
| 
								 | 
							
								  static uint32_t last_reset = 0U;
							 | 
						||
| 
								 | 
							
								  uint32_t time = microsecond_timer_get();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Resetting CAN core is a slow blocking operation, limit frequency
							 | 
						||
| 
								 | 
							
								  if (get_ts_elapsed(time, last_reset) > 100000U) {  // 10 Hz
							 | 
						||
| 
								 | 
							
								    can_health[can_number].can_core_reset_cnt += 1U;
							 | 
						||
| 
								 | 
							
								    can_health[can_number].total_tx_lost_cnt += (FDCAN_TX_FIFO_EL_CNT - (FDCANx->TXFQS & FDCAN_TXFQS_TFFL)); // TX FIFO msgs will be lost after reset
							 | 
						||
| 
								 | 
							
								    llcan_clear_send(FDCANx);
							 | 
						||
| 
								 | 
							
								    last_reset = time;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg) {
							 | 
						||
| 
								 | 
							
								  uint8_t can_irq_number[PANDA_CAN_CNT][2] = {
							 | 
						||
| 
								 | 
							
								    { FDCAN1_IT0_IRQn, FDCAN1_IT1_IRQn },
							 | 
						||
| 
								 | 
							
								    { FDCAN2_IT0_IRQn, FDCAN2_IT1_IRQn },
							 | 
						||
| 
								 | 
							
								    { FDCAN3_IT0_IRQn, FDCAN3_IT1_IRQn },
							 | 
						||
| 
								 | 
							
								  };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  FDCAN_GlobalTypeDef *FDCANx = CANIF_FROM_CAN_NUM(can_number);
							 | 
						||
| 
								 | 
							
								  uint32_t psr_reg = FDCANx->PSR;
							 | 
						||
| 
								 | 
							
								  uint32_t ecr_reg = FDCANx->ECR;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  can_health[can_number].bus_off = ((psr_reg & FDCAN_PSR_BO) >> FDCAN_PSR_BO_Pos);
							 | 
						||
| 
								 | 
							
								  can_health[can_number].bus_off_cnt += can_health[can_number].bus_off;
							 | 
						||
| 
								 | 
							
								  can_health[can_number].error_warning = ((psr_reg & FDCAN_PSR_EW) >> FDCAN_PSR_EW_Pos);
							 | 
						||
| 
								 | 
							
								  can_health[can_number].error_passive = ((psr_reg & FDCAN_PSR_EP) >> FDCAN_PSR_EP_Pos);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  can_health[can_number].last_error = ((psr_reg & FDCAN_PSR_LEC) >> FDCAN_PSR_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].last_data_error = ((psr_reg & FDCAN_PSR_DLEC) >> FDCAN_PSR_DLEC_Pos);
							 | 
						||
| 
								 | 
							
								  if ((can_health[can_number].last_data_error != 0U) && (can_health[can_number].last_data_error != 7U)) {
							 | 
						||
| 
								 | 
							
								    can_health[can_number].last_data_stored_error = can_health[can_number].last_data_error;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  can_health[can_number].receive_error_cnt = ((ecr_reg & FDCAN_ECR_REC) >> FDCAN_ECR_REC_Pos);
							 | 
						||
| 
								 | 
							
								  can_health[can_number].transmit_error_cnt = ((ecr_reg & FDCAN_ECR_TEC) >> FDCAN_ECR_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;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (ir_reg != 0U) {
							 | 
						||
| 
								 | 
							
								    // Clear error interrupts
							 | 
						||
| 
								 | 
							
								    FDCANx->IR |= (FDCAN_IR_PED | FDCAN_IR_PEA | FDCAN_IR_EP | FDCAN_IR_BO | FDCAN_IR_RF0L);
							 | 
						||
| 
								 | 
							
								    can_health[can_number].total_error_cnt += 1U;
							 | 
						||
| 
								 | 
							
								    // Check for RX FIFO overflow
							 | 
						||
| 
								 | 
							
								    if ((ir_reg & (FDCAN_IR_RF0L)) != 0U) {
							 | 
						||
| 
								 | 
							
								      can_health[can_number].total_rx_lost_cnt += 1U;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    // Cases:
							 | 
						||
| 
								 | 
							
								    // 1. while multiplexing between buses 1 and 3 we are getting ACK errors that overwhelm CAN core, by resetting it recovers faster
							 | 
						||
| 
								 | 
							
								    // 2. H7 gets stuck in bus off recovery state indefinitely
							 | 
						||
| 
								 | 
							
								    if ((((can_health[can_number].last_error == CAN_ACK_ERROR) || (can_health[can_number].last_data_error == CAN_ACK_ERROR)) && (can_health[can_number].transmit_error_cnt > 127U)) ||
							 | 
						||
| 
								 | 
							
								     ((ir_reg & FDCAN_IR_BO) != 0U)) {
							 | 
						||
| 
								 | 
							
								      can_clear_send(FDCANx, can_number);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// ***************************** CAN *****************************
							 | 
						||
| 
								 | 
							
								// FDFDCANx_IT1 IRQ Handler (TX)
							 | 
						||
| 
								 | 
							
								void process_can(uint8_t can_number) {
							 | 
						||
| 
								 | 
							
								  if (can_number != 0xffU) {
							 | 
						||
| 
								 | 
							
								    ENTER_CRITICAL();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    FDCAN_GlobalTypeDef *FDCANx = CANIF_FROM_CAN_NUM(can_number);
							 | 
						||
| 
								 | 
							
								    uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    FDCANx->IR |= FDCAN_IR_TFE; // Clear Tx FIFO Empty flag
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    if ((FDCANx->TXFQS & FDCAN_TXFQS_TFQF) == 0U) {
							 | 
						||
| 
								 | 
							
								      CANPacket_t to_send;
							 | 
						||
| 
								 | 
							
								      if (can_pop(can_queues[bus_number], &to_send)) {
							 | 
						||
| 
								 | 
							
								        if (can_check_checksum(&to_send)) {
							 | 
						||
| 
								 | 
							
								          can_health[can_number].total_tx_cnt += 1U;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          uint32_t TxFIFOSA = FDCAN_START_ADDRESS + (can_number * FDCAN_OFFSET) + (FDCAN_RX_FIFO_0_EL_CNT * FDCAN_RX_FIFO_0_EL_SIZE);
							 | 
						||
| 
								 | 
							
								          // get the index of the next TX FIFO element (0 to FDCAN_TX_FIFO_EL_CNT - 1)
							 | 
						||
| 
								 | 
							
								          uint32_t tx_index = (FDCANx->TXFQS >> FDCAN_TXFQS_TFQPI_Pos) & 0x1FU;
							 | 
						||
| 
								 | 
							
								          // only send if we have received a packet
							 | 
						||
| 
								 | 
							
								          canfd_fifo *fifo;
							 | 
						||
| 
								 | 
							
								          fifo = (canfd_fifo *)(TxFIFOSA + (tx_index * FDCAN_TX_FIFO_EL_SIZE));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          fifo->header[0] = (to_send.extended << 30) | ((to_send.extended != 0U) ? (to_send.addr) : (to_send.addr << 18));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          // If canfd_auto is set, outgoing packets will be automatically sent as CAN-FD if an incoming CAN-FD packet was seen
							 | 
						||
| 
								 | 
							
								          bool fd = bus_config[can_number].canfd_auto ? bus_config[can_number].canfd_enabled : (bool)(to_send.fd > 0U);
							 | 
						||
| 
								 | 
							
								          uint32_t canfd_enabled_header = fd ? (1UL << 21) : 0UL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          uint32_t brs_enabled_header = bus_config[can_number].brs_enabled ? (1UL << 20) : 0UL;
							 | 
						||
| 
								 | 
							
								          fifo->header[1] = (to_send.data_len_code << 16) | canfd_enabled_header | brs_enabled_header;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          uint8_t data_len_w = (dlc_to_len[to_send.data_len_code] / 4U);
							 | 
						||
| 
								 | 
							
								          data_len_w += ((dlc_to_len[to_send.data_len_code] % 4U) > 0U) ? 1U : 0U;
							 | 
						||
| 
								 | 
							
								          for (unsigned int i = 0; i < data_len_w; i++) {
							 | 
						||
| 
								 | 
							
								            BYTE_ARRAY_TO_WORD(fifo->data_word[i], &to_send.data[i*4U]);
							 | 
						||
| 
								 | 
							
								          }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          FDCANx->TXBAR = (1UL << tx_index);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          // Send back to USB
							 | 
						||
| 
								 | 
							
								          CANPacket_t to_push;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          to_push.fd = fd;
							 | 
						||
| 
								 | 
							
								          to_push.returned = 1U;
							 | 
						||
| 
								 | 
							
								          to_push.rejected = 0U;
							 | 
						||
| 
								 | 
							
								          to_push.extended = to_send.extended;
							 | 
						||
| 
								 | 
							
								          to_push.addr = to_send.addr;
							 | 
						||
| 
								 | 
							
								          to_push.bus = bus_number;
							 | 
						||
| 
								 | 
							
								          to_push.data_len_code = to_send.data_len_code;
							 | 
						||
| 
								 | 
							
								          (void)memcpy(to_push.data, to_send.data, dlc_to_len[to_push.data_len_code]);
							 | 
						||
| 
								 | 
							
								          can_set_checksum(&to_push);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								          rx_buffer_overflow += can_push(&can_rx_q, &to_push) ? 0U : 1U;
							 | 
						||
| 
								 | 
							
								        } else {
							 | 
						||
| 
								 | 
							
								          can_health[can_number].total_tx_checksum_error_cnt += 1U;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        refresh_can_tx_slots_available();
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    EXIT_CRITICAL();
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// FDFDCANx_IT0 IRQ Handler (RX and errors)
							 | 
						||
| 
								 | 
							
								// blink blue when we are receiving CAN messages
							 | 
						||
| 
								 | 
							
								void can_rx(uint8_t can_number) {
							 | 
						||
| 
								 | 
							
								  FDCAN_GlobalTypeDef *FDCANx = CANIF_FROM_CAN_NUM(can_number);
							 | 
						||
| 
								 | 
							
								  uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  uint32_t ir_reg = FDCANx->IR;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Clear all new messages from Rx FIFO 0
							 | 
						||
| 
								 | 
							
								  FDCANx->IR |= FDCAN_IR_RF0N;
							 | 
						||
| 
								 | 
							
								  while ((FDCANx->RXF0S & FDCAN_RXF0S_F0FL) != 0U) {
							 | 
						||
| 
								 | 
							
								    can_health[can_number].total_rx_cnt += 1U;
							 | 
						||
| 
								 | 
							
								    // get the index of the next RX FIFO element (0 to FDCAN_RX_FIFO_0_EL_CNT - 1)
							 | 
						||
| 
								 | 
							
								    uint32_t rx_fifo_idx = (uint8_t)((FDCANx->RXF0S >> FDCAN_RXF0S_F0GI_Pos) & 0x3FU);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Recommended to offset get index by at least +1 if RX FIFO is in overwrite mode and full (datasheet)
							 | 
						||
| 
								 | 
							
								    if ((FDCANx->RXF0S & FDCAN_RXF0S_F0F) == FDCAN_RXF0S_F0F) {
							 | 
						||
| 
								 | 
							
								      rx_fifo_idx = ((rx_fifo_idx + 1U) >= FDCAN_RX_FIFO_0_EL_CNT) ? 0U : (rx_fifo_idx + 1U);
							 | 
						||
| 
								 | 
							
								      can_health[can_number].total_rx_lost_cnt += 1U; // At least one message was lost
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    uint32_t RxFIFO0SA = FDCAN_START_ADDRESS + (can_number * FDCAN_OFFSET);
							 | 
						||
| 
								 | 
							
								    CANPacket_t to_push;
							 | 
						||
| 
								 | 
							
								    canfd_fifo *fifo;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // getting address
							 | 
						||
| 
								 | 
							
								    fifo = (canfd_fifo *)(RxFIFO0SA + (rx_fifo_idx * FDCAN_RX_FIFO_0_EL_SIZE));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    bool canfd_frame = ((fifo->header[1] >> 21) & 0x1U);
							 | 
						||
| 
								 | 
							
								    bool brs_frame = ((fifo->header[1] >> 20) & 0x1U);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    to_push.fd = canfd_frame;
							 | 
						||
| 
								 | 
							
								    to_push.returned = 0U;
							 | 
						||
| 
								 | 
							
								    to_push.rejected = 0U;
							 | 
						||
| 
								 | 
							
								    to_push.extended = (fifo->header[0] >> 30) & 0x1U;
							 | 
						||
| 
								 | 
							
								    to_push.addr = ((to_push.extended != 0U) ? (fifo->header[0] & 0x1FFFFFFFU) : ((fifo->header[0] >> 18) & 0x7FFU));
							 | 
						||
| 
								 | 
							
								    to_push.bus = bus_number;
							 | 
						||
| 
								 | 
							
								    to_push.data_len_code = ((fifo->header[1] >> 16) & 0xFU);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    uint8_t data_len_w = (dlc_to_len[to_push.data_len_code] / 4U);
							 | 
						||
| 
								 | 
							
								    data_len_w += ((dlc_to_len[to_push.data_len_code] % 4U) > 0U) ? 1U : 0U;
							 | 
						||
| 
								 | 
							
								    for (unsigned int i = 0; i < data_len_w; i++) {
							 | 
						||
| 
								 | 
							
								      WORD_TO_BYTE_ARRAY(&to_push.data[i*4U], fifo->data_word[i]);
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    can_set_checksum(&to_push);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // forwarding (panda only)
							 | 
						||
| 
								 | 
							
								    int bus_fwd_num = safety_fwd_hook(bus_number, to_push.addr);
							 | 
						||
| 
								 | 
							
								    if (bus_fwd_num < 0) {
							 | 
						||
| 
								 | 
							
								      bus_fwd_num = bus_config[can_number].forwarding_bus;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (bus_fwd_num != -1) {
							 | 
						||
| 
								 | 
							
								      CANPacket_t to_send;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      to_send.fd = to_push.fd;
							 | 
						||
| 
								 | 
							
								      to_send.returned = 0U;
							 | 
						||
| 
								 | 
							
								      to_send.rejected = 0U;
							 | 
						||
| 
								 | 
							
								      to_send.extended = to_push.extended;
							 | 
						||
| 
								 | 
							
								      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;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // Enable CAN FD and BRS if CAN FD message was received
							 | 
						||
| 
								 | 
							
								    if (!(bus_config[can_number].canfd_enabled) && (canfd_frame)) {
							 | 
						||
| 
								 | 
							
								      bus_config[can_number].canfd_enabled = true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    if (!(bus_config[can_number].brs_enabled) && (brs_frame)) {
							 | 
						||
| 
								 | 
							
								      bus_config[can_number].brs_enabled = true;
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // update read index
							 | 
						||
| 
								 | 
							
								    FDCANx->RXF0A = rx_fifo_idx;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // Error handling
							 | 
						||
| 
								 | 
							
								  if ((ir_reg & (FDCAN_IR_PED | FDCAN_IR_PEA | FDCAN_IR_EP | FDCAN_IR_BO | FDCAN_IR_RF0L)) != 0U) {
							 | 
						||
| 
								 | 
							
								    update_can_health_pkt(can_number, ir_reg);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void FDCAN1_IT0_IRQ_Handler(void) { can_rx(0); }
							 | 
						||
| 
								 | 
							
								static void FDCAN1_IT1_IRQ_Handler(void) { process_can(0); }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void FDCAN2_IT0_IRQ_Handler(void) { can_rx(1); }
							 | 
						||
| 
								 | 
							
								static void FDCAN2_IT1_IRQ_Handler(void) { process_can(1); }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static void FDCAN3_IT0_IRQ_Handler(void) { can_rx(2);  }
							 | 
						||
| 
								 | 
							
								static void FDCAN3_IT1_IRQ_Handler(void) { process_can(2); }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								bool can_init(uint8_t can_number) {
							 | 
						||
| 
								 | 
							
								  bool ret = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  REGISTER_INTERRUPT(FDCAN1_IT0_IRQn, FDCAN1_IT0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
							 | 
						||
| 
								 | 
							
								  REGISTER_INTERRUPT(FDCAN1_IT1_IRQn, FDCAN1_IT1_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
							 | 
						||
| 
								 | 
							
								  REGISTER_INTERRUPT(FDCAN2_IT0_IRQn, FDCAN2_IT0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_2)
							 | 
						||
| 
								 | 
							
								  REGISTER_INTERRUPT(FDCAN2_IT1_IRQn, FDCAN2_IT1_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_2)
							 | 
						||
| 
								 | 
							
								  REGISTER_INTERRUPT(FDCAN3_IT0_IRQn, FDCAN3_IT0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_3)
							 | 
						||
| 
								 | 
							
								  REGISTER_INTERRUPT(FDCAN3_IT1_IRQn, FDCAN3_IT1_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_3)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (can_number != 0xffU) {
							 | 
						||
| 
								 | 
							
								    FDCAN_GlobalTypeDef *FDCANx = CANIF_FROM_CAN_NUM(can_number);
							 | 
						||
| 
								 | 
							
								    ret &= can_set_speed(can_number);
							 | 
						||
| 
								 | 
							
								    ret &= llcan_init(FDCANx);
							 | 
						||
| 
								 | 
							
								    // in case there are queued up messages
							 | 
						||
| 
								 | 
							
								    process_can(can_number);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  return ret;
							 | 
						||
| 
								 | 
							
								}
							 |