/** * \file * * \brief SAM Control Area Network (MCAN) Low Level Driver * * Copyright (c) 2015-2019 Microchip Technology Inc. and its subsidiaries. * * \asf_license_start * * \page License * * Subject to your compliance with these terms, you may use Microchip * software and any derivatives exclusively with Microchip products. * It is your responsibility to comply with third party license terms applicable * to your use of third party software (including open source software) that * may accompany Microchip software. * * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. * * \asf_license_stop * */ /* * Support and FAQ: visit Microchip Support */ #include "CanDriver.h" #if SUPPORT_CAN_EXPANSION #include #include // Values from conf_mcan.h /* * Below is the message RAM setting, it will be stored in the system RAM. * Please adjust the message size according to your application. */ /** Range: 1..64 */ #define CONF_MCAN0_RX_FIFO_0_NUM 16 /** Range: 1..64 */ #define CONF_MCAN0_RX_FIFO_1_NUM 16 /** Range: 1..64 */ #define CONF_MCAN0_RX_BUFFER_NUM 4 /** Range: 1..16 */ #define CONF_MCAN0_TX_BUFFER_NUM 6 /** Range: 1..16 */ #define CONF_MCAN0_TX_FIFO_QUEUE_NUM 8 /** Range: 1..32 */ #define CONF_MCAN0_TX_EVENT_FIFO 8 /** Range: 1..128 */ #define CONF_MCAN0_RX_STANDARD_ID_FILTER_NUM 1 /** Range: 1..64 */ #define CONF_MCAN0_RX_EXTENDED_ID_FILTER_NUM 3 /** Range: 1..64 */ #define CONF_MCAN1_RX_FIFO_0_NUM 16 /** Range: 1..64 */ #define CONF_MCAN1_RX_FIFO_1_NUM 16 /** Range: 1..64 */ #define CONF_MCAN1_RX_BUFFER_NUM 4 /** Range: 1..16 */ #define CONF_MCAN1_TX_BUFFER_NUM 6 /** Range: 1..16 */ #define CONF_MCAN1_TX_FIFO_QUEUE_NUM 8 /** Range: 1..32 */ #define CONF_MCAN1_TX_EVENT_FIFO 8 /** Range: 1..128 */ #define CONF_MCAN1_RX_STANDARD_ID_FILTER_NUM 1 /** Range: 1..64 */ #define CONF_MCAN1_RX_EXTENDED_ID_FILTER_NUM 3 /** * The setting of the nominal bit rate is based on the PCK5 which is 48M which you can * change in the conf_clock.h. Below is the default configuration. The * time quanta is 48MHz. And each bit is (1 + NTSEG1 + 1 + NTSEG2 + 1) = 48 time * quanta which means the bit rate is 48MHz/49 = 1Mbps. */ /** Nominal bit Baud Rate Prescaler */ #define CONF_MCAN_NBTP_NBRP_VALUE (1 - 1) /** Nominal bit (Re)Synchronization Jump Width */ #define CONF_MCAN_NBTP_NSJW_VALUE (8 - 1) /** Nominal bit Time segment before sample point */ #define CONF_MCAN_NBTP_NTSEG1_VALUE (26 - 1) /** Nominal bit Time segment after sample point */ #define CONF_MCAN_NBTP_NTSEG2_VALUE (21 - 1) /* * The setting of the data bit rate is based on the PCK5 which is 48M which you can * change. Below is the default configuration. The * time quanta is 48MHz / (0+1) = 48MHz. And each bit is (1 + FTSEG1 + 1 + FTSEG2 + 1) = 12 time * quanta which means the bit rate is 48MHz/12=4MHz. */ /** Data bit Baud Rate Prescaler */ #define CONF_MCAN_FBTP_FBRP_VALUE (1 - 1) /** Data bit (Re)Synchronization Jump Width */ #define CONF_MCAN_FBTP_FSJW_VALUE (3 - 1) /** Data bit Time segment before sample point */ #define CONF_MCAN_FBTP_FTSEG1_VALUE (8 - 1) /** Data bit Time segment after sample point */ #define CONF_MCAN_FBTP_FTSEG2_VALUE (3 - 1) /* PCK5 ID assigned to MCAN module */ #define PMC_PCK_5 5 /* Get a value of 2 to 15 bit. */ #define BIT_2_TO_15_MASK 0x0000fffc #define __nocache __attribute__((section(".ram_nocache"))) /* Message ram definition. */ alignas(4) __nocache static struct mcan_rx_element mcan0_rx_buffer[CONF_MCAN0_RX_BUFFER_NUM]; alignas(4) __nocache static struct mcan_rx_element mcan0_rx_fifo_0[CONF_MCAN0_RX_FIFO_0_NUM]; alignas(4) __nocache static struct mcan_rx_element mcan0_rx_fifo_1[CONF_MCAN0_RX_FIFO_1_NUM]; alignas(4) __nocache static struct mcan_tx_element mcan0_tx_buffer[CONF_MCAN0_TX_BUFFER_NUM + CONF_MCAN0_TX_FIFO_QUEUE_NUM]; alignas(4) __nocache static struct mcan_tx_event_element mcan0_tx_event_fifo[CONF_MCAN0_TX_EVENT_FIFO]; alignas(4) __nocache static struct mcan_standard_message_filter_element mcan0_rx_standard_filter[CONF_MCAN0_RX_STANDARD_ID_FILTER_NUM]; alignas(4) __nocache static struct mcan_extended_message_filter_element mcan0_rx_extended_filter[CONF_MCAN0_RX_EXTENDED_ID_FILTER_NUM]; alignas(4) __nocache static struct mcan_rx_element mcan1_rx_buffer[CONF_MCAN1_RX_BUFFER_NUM]; alignas(4) __nocache static struct mcan_rx_element mcan1_rx_fifo_0[CONF_MCAN1_RX_FIFO_0_NUM]; alignas(4) __nocache static struct mcan_rx_element mcan1_rx_fifo_1[CONF_MCAN1_RX_FIFO_1_NUM]; alignas(4) __nocache static struct mcan_tx_element mcan1_tx_buffer[CONF_MCAN1_TX_BUFFER_NUM + CONF_MCAN1_TX_FIFO_QUEUE_NUM]; alignas(4) __nocache static struct mcan_tx_event_element mcan1_tx_event_fifo[CONF_MCAN1_TX_EVENT_FIFO]; alignas(4) __nocache static struct mcan_standard_message_filter_element mcan1_rx_standard_filter[CONF_MCAN1_RX_STANDARD_ID_FILTER_NUM]; alignas(4) __nocache static struct mcan_extended_message_filter_element mcan1_rx_extended_filter[CONF_MCAN1_RX_EXTENDED_ID_FILTER_NUM]; /** * \brief initialize MCAN memory . * * \param hw Base address of the MCAN * */ static void _mcan_message_memory_init(Mcan *hw) { if (hw == MCAN0) { hw->MCAN_SIDFC = ((uint32_t)mcan0_rx_standard_filter & BIT_2_TO_15_MASK) | MCAN_SIDFC_LSS(CONF_MCAN0_RX_STANDARD_ID_FILTER_NUM); hw->MCAN_XIDFC = ((uint32_t)mcan0_rx_extended_filter & BIT_2_TO_15_MASK) | MCAN_XIDFC_LSE(CONF_MCAN0_RX_EXTENDED_ID_FILTER_NUM); hw->MCAN_RXF0C = ((uint32_t)mcan0_rx_fifo_0 & BIT_2_TO_15_MASK) | MCAN_RXF0C_F0S(CONF_MCAN0_RX_FIFO_0_NUM); hw->MCAN_RXF1C = ((uint32_t)mcan0_rx_fifo_1 & BIT_2_TO_15_MASK) | MCAN_RXF1C_F1S(CONF_MCAN0_RX_FIFO_1_NUM); hw->MCAN_RXBC = ((uint32_t)mcan0_rx_buffer & BIT_2_TO_15_MASK); hw->MCAN_TXBC = ((uint32_t)mcan0_tx_buffer & BIT_2_TO_15_MASK) | MCAN_TXBC_NDTB(CONF_MCAN0_TX_BUFFER_NUM) | MCAN_TXBC_TFQS(CONF_MCAN0_TX_FIFO_QUEUE_NUM); hw->MCAN_TXEFC = ((uint32_t)mcan0_tx_event_fifo & BIT_2_TO_15_MASK) | MCAN_TXEFC_EFS(CONF_MCAN0_TX_EVENT_FIFO); } else if (hw == MCAN1) { hw->MCAN_SIDFC = ((uint32_t)mcan1_rx_standard_filter & BIT_2_TO_15_MASK) | MCAN_SIDFC_LSS(CONF_MCAN1_RX_STANDARD_ID_FILTER_NUM); hw->MCAN_XIDFC = ((uint32_t)mcan1_rx_extended_filter & BIT_2_TO_15_MASK) | MCAN_XIDFC_LSE(CONF_MCAN1_RX_EXTENDED_ID_FILTER_NUM); hw->MCAN_RXF0C = ((uint32_t)mcan1_rx_fifo_0 & BIT_2_TO_15_MASK) | MCAN_RXF0C_F0S(CONF_MCAN1_RX_FIFO_0_NUM); hw->MCAN_RXF1C = ((uint32_t)mcan1_rx_fifo_1 & BIT_2_TO_15_MASK) | MCAN_RXF1C_F1S(CONF_MCAN1_RX_FIFO_1_NUM); hw->MCAN_RXBC = ((uint32_t)mcan1_rx_buffer & BIT_2_TO_15_MASK); hw->MCAN_TXBC = ((uint32_t)mcan1_tx_buffer & BIT_2_TO_15_MASK) | MCAN_TXBC_NDTB(CONF_MCAN1_TX_BUFFER_NUM) | MCAN_TXBC_TFQS(CONF_MCAN1_TX_FIFO_QUEUE_NUM); hw->MCAN_TXEFC = ((uint32_t)mcan1_tx_event_fifo & BIT_2_TO_15_MASK) | MCAN_TXEFC_EFS(CONF_MCAN1_TX_EVENT_FIFO); } /** * The data size in conf_mcan.h should be 8/12/16/20/24/32/48/64, * The corresponding setting value in register is 0/1//2/3/4/5/6/7. * To simplify the calculation, separate to two group 8/12/16/20/24 which * increased with 4 and 32/48/64 which increased with 16. */ if (CONF_MCAN_ELEMENT_DATA_SIZE <= 24) { hw->MCAN_RXESC = MCAN_RXESC_RBDS((CONF_MCAN_ELEMENT_DATA_SIZE - 8) / 4) | MCAN_RXESC_F0DS((CONF_MCAN_ELEMENT_DATA_SIZE - 8) / 4) | MCAN_RXESC_F1DS((CONF_MCAN_ELEMENT_DATA_SIZE - 8) / 4); hw->MCAN_TXESC = MCAN_TXESC_TBDS((CONF_MCAN_ELEMENT_DATA_SIZE - 8) / 4); } else { hw->MCAN_RXESC = MCAN_RXESC_RBDS((CONF_MCAN_ELEMENT_DATA_SIZE - 32) / 16 + 5) | MCAN_RXESC_F0DS((CONF_MCAN_ELEMENT_DATA_SIZE - 32) / 16 + 5) | MCAN_RXESC_F1DS((CONF_MCAN_ELEMENT_DATA_SIZE - 32) / 16 + 5); hw->MCAN_TXESC = MCAN_TXESC_TBDS((CONF_MCAN_ELEMENT_DATA_SIZE - 32) / 16 + 5); } } /** * \brief set default configuration when initialization. * * \param hw Base address of the MCAN * \param config default configuration parameters. */ static void _mcan_set_configuration(Mcan *hw, struct mcan_config *config) { #if (SAMV71B || SAME70B || SAMV70B) /* Timing setting for Rev B */ hw->MCAN_NBTP = MCAN_NBTP_NBRP(CONF_MCAN_NBTP_NBRP_VALUE) | MCAN_NBTP_NSJW(CONF_MCAN_NBTP_NSJW_VALUE) | MCAN_NBTP_NTSEG1(CONF_MCAN_NBTP_NTSEG1_VALUE) | MCAN_NBTP_NTSEG2(CONF_MCAN_NBTP_NTSEG2_VALUE); hw->MCAN_DBTP = MCAN_DBTP_DBRP(CONF_MCAN_FBTP_FBRP_VALUE) | MCAN_DBTP_DSJW(CONF_MCAN_FBTP_FSJW_VALUE) | MCAN_DBTP_DTSEG1(CONF_MCAN_FBTP_FTSEG1_VALUE) | MCAN_DBTP_DTSEG2(CONF_MCAN_FBTP_FTSEG2_VALUE); hw->MCAN_TDCR = MCAN_TDCR_TDCO(config->delay_compensation_offset) | MCAN_TDCR_TDCF(config->delay_compensation_filter_window_length); if (config->tdc_enable) { hw->MCAN_DBTP |= MCAN_DBTP_TDC_ENABLED; } #else /* Timing setting. */ hw->MCAN_BTP = MCAN_BTP_BRP(CONF_MCAN_NBTP_NBRP_VALUE) | MCAN_BTP_SJW(CONF_MCAN_NBTP_NSJW_VALUE) | MCAN_BTP_TSEG1(CONF_MCAN_NBTP_NTSEG1_VALUE) | MCAN_BTP_TSEG2(CONF_MCAN_NBTP_NTSEG2_VALUE); hw->MCAN_FBTP = MCAN_FBTP_FBRP(CONF_MCAN_FBTP_FBRP_VALUE) | MCAN_FBTP_FSJW(CONF_MCAN_FBTP_FSJW_VALUE) | MCAN_FBTP_FTSEG1(CONF_MCAN_FBTP_FTSEG1_VALUE) | MCAN_FBTP_FTSEG2(CONF_MCAN_FBTP_FTSEG2_VALUE) | MCAN_FBTP_TDCO(config->delay_compensation_offset); if (config->tdc_enable) { hw->MCAN_FBTP |= MCAN_FBTP_TDC_ENABLED; } #endif hw->MCAN_RWD |= MCAN_RWD_WDC(config->watchdog_configuration); if (config->transmit_pause) { hw->MCAN_CCCR |= MCAN_CCCR_TXP; } if (!config->automatic_retransmission) { hw->MCAN_CCCR |= MCAN_CCCR_DAR; } if (config->clock_stop_request) { hw->MCAN_CCCR |= MCAN_CCCR_CSR; } hw->MCAN_TSCC = MCAN_TSCC_TCP(config->timestamp_prescaler) | MCAN_TSCC_TSS_TCP_INC; hw->MCAN_TOCC = MCAN_TOCC_TOP(config->timeout_period) | config->timeout_mode | config->timeout_enable; hw->MCAN_GFC = MCAN_GFC_ANFS(config->nonmatching_frames_action_standard) | MCAN_GFC_ANFE(config->nonmatching_frames_action_extended); if (config->remote_frames_standard_reject) { hw->MCAN_GFC |= MCAN_GFC_RRFS; } if (config->remote_frames_extended_reject) { hw->MCAN_GFC|= MCAN_GFC_RRFE; } hw->MCAN_XIDAM = config->extended_id_mask; if (config->rx_fifo_0_overwrite) { hw->MCAN_RXF0C |= MCAN_RXF0C_F0OM; } hw->MCAN_RXF0C |= MCAN_RXF0C_F0WM(config->rx_fifo_0_watermark); if (config->rx_fifo_1_overwrite) { hw->MCAN_RXF1C |= MCAN_RXF1C_F1OM; } hw->MCAN_RXF1C |= MCAN_RXF1C_F1WM(config->rx_fifo_1_watermark); if (config->tx_queue_mode) { hw->MCAN_TXBC |= MCAN_TXBC_TFQM; } hw->MCAN_TXEFC |= MCAN_TXEFC_EFWM(config->tx_event_fifo_watermark); } /** * \brief enable can module clock. * * \param module_inst MCAN instance * */ static void _mcan_enable_peripheral_clock(struct mcan_module *const module_inst) { if (module_inst->hw == MCAN0) { /* Turn on the digital interface clock. */ pmc_enable_periph_clk(ID_MCAN0); } else if (module_inst->hw == MCAN1) { /* Turn on the digital interface clock. */ pmc_enable_periph_clk(ID_MCAN1); } } /** * \brief initialize can module. * * \param module_inst MCAN instance * \param hw Base address of MCAN. * \param config default configuration . */ void mcan_init(struct mcan_module *const module_inst, Mcan *hw, struct mcan_config *config) { /* Sanity check arguments */ Assert(module_inst); Assert(hw); Assert(config); /* Associate the software module instance with the hardware module */ module_inst->hw = hw; pmc_disable_pck(PMC_PCK_5); #if 1 // dc42 use UPLL not PLLA as recommended in the documentation, so the MCAN clock is independent of the CPU clock frequency pmc_switch_pck_to_upllck(PMC_PCK_5, PMC_PCK_PRES(9)); // run PCLK5 at 48MHz #else pmc_switch_pck_to_pllack(PMC_PCK_5, PMC_PCK_PRES(9)); #endif pmc_enable_pck(PMC_PCK_5); /* Enable peripheral clock */ _mcan_enable_peripheral_clock(module_inst); /* Configuration Change Enable. */ hw->MCAN_CCCR |= MCAN_CCCR_CCE; /* Initialize the message memory address. */ _mcan_message_memory_init(hw); /* Set the configuration. */ _mcan_set_configuration(hw, config); /* Enable the interrupt setting which no need change. */ hw->MCAN_ILE = MCAN_ILE_EINT0 | MCAN_ILE_EINT1; hw->MCAN_TXBTIE = 0xFFFFFFFFul; hw->MCAN_TXBCIE = 0xFFFFFFFFul; } /** * \brief start can module after initialization. * * \param module_inst MCAN instance * */ void mcan_start(struct mcan_module *const module_inst) { module_inst->hw->MCAN_CCCR &= ~MCAN_CCCR_INIT; /* Wait for the sync. */ while (module_inst->hw->MCAN_CCCR & MCAN_CCCR_INIT); } /** * \brief stop mcan module when bus off occurs * * \param module_inst MCAN instance * */ void mcan_stop(struct mcan_module *const module_inst) { module_inst->hw->MCAN_CCCR |= MCAN_CCCR_INIT; /* Wait for the sync. */ while (!(module_inst->hw->MCAN_CCCR & MCAN_CCCR_INIT)); } /** * \brief switch mcan module into fd mode. * * \param module_inst MCAN instance * */ void mcan_enable_fd_mode(struct mcan_module *const module_inst) { module_inst->hw->MCAN_CCCR |= MCAN_CCCR_INIT; /* Wait for the sync. */ while (!(module_inst->hw->MCAN_CCCR & MCAN_CCCR_INIT)); module_inst->hw->MCAN_CCCR |= MCAN_CCCR_CCE; #if (SAMV71B || SAME70B || SAMV70B) module_inst->hw->MCAN_CCCR |= (MCAN_CCCR_FDOE | MCAN_CCCR_BRSE); #else module_inst->hw->MCAN_CCCR |= MCAN_CCCR_CME(2); module_inst->hw->MCAN_CCCR |= MCAN_CCCR_CMR(2); #endif } /** * \brief disable fd mode of mcan module. * * \param module_inst MCAN instance * */ void mcan_disable_fd_mode(struct mcan_module *const module_inst) { module_inst->hw->MCAN_CCCR |= MCAN_CCCR_INIT; /* Wait for the sync. */ while (!(module_inst->hw->MCAN_CCCR & MCAN_CCCR_INIT)); module_inst->hw->MCAN_CCCR |= MCAN_CCCR_CCE; #if (SAMV71B || SAME70B || SAMV70B) module_inst->hw->MCAN_CCCR &= MCAN_CCCR_FDOE; #else module_inst->hw->MCAN_CCCR &= MCAN_CCCR_CME(MCAN_CCCR_CME_ISO11898_1); #endif } /** * \brief enable restricted mode of mcan module. * * \param module_inst MCAN instance * */ void mcan_enable_restricted_operation_mode(struct mcan_module *const module_inst) { module_inst->hw->MCAN_CCCR |= MCAN_CCCR_INIT; /* Wait for the sync. */ while (!(module_inst->hw->MCAN_CCCR & MCAN_CCCR_INIT)); module_inst->hw->MCAN_CCCR |= MCAN_CCCR_CCE; module_inst->hw->MCAN_CCCR |= MCAN_CCCR_ASM; } /** * \brief disable restricted mode of mcan module. * * \param module_inst MCAN instance * */ void mcan_disable_restricted_operation_mode(struct mcan_module *const module_inst) { module_inst->hw->MCAN_CCCR &= ~MCAN_CCCR_ASM; } /** * \brief enable bus monitor mode of mcan module. * * \param module_inst MCAN instance * */ void mcan_enable_bus_monitor_mode(struct mcan_module *const module_inst) { module_inst->hw->MCAN_CCCR |= MCAN_CCCR_INIT; /* Wait for the sync. */ while (!(module_inst->hw->MCAN_CCCR & MCAN_CCCR_INIT)); module_inst->hw->MCAN_CCCR |= MCAN_CCCR_CCE; module_inst->hw->MCAN_CCCR |= MCAN_CCCR_MON; } /** * \brief disable bus monitor mode of mcan module. * * \param module_inst MCAN instance * */ void mcan_disable_bus_monitor_mode(struct mcan_module *const module_inst) { module_inst->hw->MCAN_CCCR &= ~MCAN_CCCR_MON; } /** * \brief enable sleep mode of mcan module. * * \param module_inst MCAN instance * */ void mcan_enable_sleep_mode(struct mcan_module *const module_inst) { module_inst->hw->MCAN_CCCR |= MCAN_CCCR_CSR; /* Wait for the sync. */ while (!(module_inst->hw->MCAN_CCCR & MCAN_CCCR_INIT)); while (!(module_inst->hw->MCAN_CCCR & MCAN_CCCR_CSA)); } /** * \brief disable sleep mode of mcan module. * * \param module_inst MCAN instance * */ void mcan_disable_sleep_mode(struct mcan_module *const module_inst) { /* Enable peripheral clock */ _mcan_enable_peripheral_clock(module_inst); module_inst->hw->MCAN_CCCR &= ~MCAN_CCCR_CSR; while ((module_inst->hw->MCAN_CCCR & MCAN_CCCR_CSA)); } /** * \brief enable test mode of mcan module. * * \param module_inst MCAN instance * */ void mcan_enable_test_mode(struct mcan_module *const module_inst) { module_inst->hw->MCAN_CCCR |= MCAN_CCCR_INIT; /* Wait for the sync. */ while (!(module_inst->hw->MCAN_CCCR & MCAN_CCCR_INIT)); module_inst->hw->MCAN_CCCR |= MCAN_CCCR_CCE; module_inst->hw->MCAN_CCCR |= MCAN_CCCR_TEST; module_inst->hw->MCAN_TEST |= MCAN_TEST_LBCK; } /** * \brief disable test mode of mcan module. * * \param module_inst MCAN instance * */ void mcan_disable_test_mode(struct mcan_module *const module_inst) { module_inst->hw->MCAN_CCCR &= ~MCAN_CCCR_TEST; } /** * \brief set standard receive CAN ID. * * \param module_inst MCAN instance * \param sd_filter structure of CAN ID * \param index CAN messages memory index for different CAN ID * * \return status code. */ enum status_code mcan_set_rx_standard_filter(struct mcan_module *const module_inst, struct mcan_standard_message_filter_element *sd_filter, uint32_t index) { if (module_inst->hw == MCAN0) { mcan0_rx_standard_filter[index].S0.reg = sd_filter->S0.reg; return STATUS_OK; } else if (module_inst->hw == MCAN1) { mcan1_rx_standard_filter[index].S0.reg = sd_filter->S0.reg; return STATUS_OK; } return ERR_INVALID_ARG; } /** * \brief set extended receive CAN ID. * * \param module_inst MCAN instance * \param sd_filter structure of extended CAN ID * \param index CAN messages memory index for different CAN ID * * \return status code. */ enum status_code mcan_set_rx_extended_filter(struct mcan_module *const module_inst, struct mcan_extended_message_filter_element *et_filter, uint32_t index) { if (module_inst->hw == MCAN0) { mcan0_rx_extended_filter[index].F0.reg = et_filter->F0.reg; mcan0_rx_extended_filter[index].F1.reg = et_filter->F1.reg; return STATUS_OK; } else if (module_inst->hw == MCAN1) { mcan1_rx_extended_filter[index].F0.reg = et_filter->F0.reg; mcan1_rx_extended_filter[index].F1.reg = et_filter->F1.reg; return STATUS_OK; } return ERR_INVALID_ARG; } /** * \brief get dedicated rx buffer element . * * \param module_inst MCAN instance * \param rx_element structure of element * \param index CAN messages memory index for receiving CAN ID * * \return status code. */ enum status_code mcan_get_rx_buffer_element(struct mcan_module *const module_inst, struct mcan_rx_element *rx_element, uint32_t index) { if (module_inst->hw == MCAN0) { *rx_element = mcan0_rx_buffer[index]; return STATUS_OK; } else if (module_inst->hw == MCAN1) { *rx_element = mcan1_rx_buffer[index]; return STATUS_OK; } return ERR_INVALID_ARG; } /** * \brief get FIFO rx buffer element . * * \param module_inst MCAN instance * \param rx_element structure of element * \param index CAN messages memory index for receiving CAN ID * * \return status code. */ enum status_code mcan_get_rx_fifo_0_element(struct mcan_module *const module_inst, struct mcan_rx_element *rx_element, uint32_t index) { if (module_inst->hw == MCAN0) { *rx_element = mcan0_rx_fifo_0[index]; return STATUS_OK; } else if (module_inst->hw == MCAN1) { *rx_element = mcan1_rx_fifo_0[index]; return STATUS_OK; } return ERR_INVALID_ARG; } /** * \brief get FIFO rx buffer element . * * \param module_inst MCAN instance * \param rx_element structure of element * \param index CAN messages memory index for receiving CAN ID * * \return status code. */ enum status_code mcan_get_rx_fifo_1_element(struct mcan_module *const module_inst, struct mcan_rx_element *rx_element, uint32_t index) { if (module_inst->hw == MCAN0) { *rx_element = mcan0_rx_fifo_1[index]; return STATUS_OK; } else if (module_inst->hw == MCAN1) { *rx_element = mcan1_rx_fifo_1[index]; return STATUS_OK; } return ERR_INVALID_ARG; } /** * \brief set dedicated transmit buffer element . * * \param module_inst MCAN instance * \param tx_element structure of element * \param index CAN messages memory index for transmitting CAN ID * * \return status code. */ enum status_code mcan_set_tx_buffer_element(struct mcan_module *const module_inst, struct mcan_tx_element *tx_element, uint32_t index) { uint32_t i; if (module_inst->hw == MCAN0) { mcan0_tx_buffer[index].T0.reg = tx_element->T0.reg; mcan0_tx_buffer[index].T1.reg = tx_element->T1.reg; for (i = 0; i < CONF_MCAN_ELEMENT_DATA_SIZE; i++) { mcan0_tx_buffer[index].data[i] = tx_element->data[i]; } return STATUS_OK; } else if (module_inst->hw == MCAN1) { mcan1_tx_buffer[index].T0.reg = tx_element->T0.reg; mcan1_tx_buffer[index].T1.reg = tx_element->T1.reg; for (i = 0; i < CONF_MCAN_ELEMENT_DATA_SIZE; i++) { mcan1_tx_buffer[index].data[i] = tx_element->data[i]; } return STATUS_OK; } return ERR_INVALID_ARG; } /** * \brief set FIFO transmit buffer element . * * \param module_inst MCAN instance * \param tx_element structure of element * \param index CAN messages memory index for transmitting CAN ID * * \return status code. */ enum status_code mcan_get_tx_event_fifo_element(struct mcan_module *const module_inst, struct mcan_tx_event_element *tx_event_element, uint32_t index) { if (module_inst->hw == MCAN0) { tx_event_element->E0.reg = mcan0_tx_event_fifo[index].E0.reg; tx_event_element->E1.reg = mcan0_tx_event_fifo[index].E1.reg; return STATUS_OK; } else if (module_inst->hw == MCAN1) { tx_event_element->E0.reg = mcan1_tx_event_fifo[index].E0.reg; tx_event_element->E1.reg = mcan1_tx_event_fifo[index].E1.reg; return STATUS_OK; } return ERR_INVALID_ARG; } #endif // SUPPORT_CAN_EXPANSION // End