828eco基于GD32H7mcu
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.

2494 lines
98 KiB

5 months ago
/*!
\file gd32h75e_can.c
\brief CAN driver
\version 2025-08-07, V1.2.0, firmware for GD32H75E
*/
/*
Copyright (c) 2025, GigaDevice Semiconductor Inc.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors
may be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.
*/
#include "gd32h75e_can.h"
/* DLC to data size in bytes definitions */
static const uint8_t dlc_to_databytes[16] = {0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 12U, 16U, 20U, 24U, 32U, 48U, 64U};
/* computes the maximum payload size (in bytes) */
static uint32_t can_payload_size_compute(uint32_t mdes0);
/* swap data to little endian */
static void can_data_to_little_endian_swap(uint32_t dest[], uint32_t src[], uint32_t len);
/* swap data to big endian */
static void can_data_to_big_endian_swap(uint32_t dest[], uint32_t src[], uint32_t len);
/* computes the dlc field value, given a payload size (in bytes) */
static uint32_t can_dlc_value_compute(uint32_t payload_size);
/*!
\brief deinitialize CAN (API_ID:0x0001U)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_deinit(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0001U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
if(CAN0 == can_periph) {
/* reset CAN0 */
rcu_periph_reset_enable(RCU_CAN0RST);
rcu_periph_reset_disable(RCU_CAN0RST);
}
if(CAN1 == can_periph) {
/* reset CAN1 */
rcu_periph_reset_enable(RCU_CAN1RST);
rcu_periph_reset_disable(RCU_CAN1RST);
}
if(CAN2 == can_periph) {
/* reset CAN2 */
rcu_periph_reset_enable(RCU_CAN2RST);
rcu_periph_reset_disable(RCU_CAN2RST);
}
}
}
/*!
\brief reset CAN internal state machines and CAN registers (API_ID:0x0002U)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval ERROR or SUCCESS
*/
ErrStatus can_software_reset(uint32_t can_periph)
{
uint32_t timeout = CAN_DELAY;
ErrStatus status = ERROR;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0002U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* reset internal state machines and CAN registers */
CAN_CTL0(can_periph) |= CAN_CTL0_SWRST;
/* wait reset complete */
while((CAN_CTL0(can_periph) & CAN_CTL0_SWRST) && (timeout)) {
timeout--;
}
if(CAN_CTL0(can_periph) & CAN_CTL0_SWRST) {
status = ERROR;
}
status = SUCCESS;
}
return status;
}
/*!
\brief CAN module initialization (API_ID:0x0003U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] can_parameter_init: can parameter struct
internal_counter_source: CAN_TIMER_SOURCE_BIT_CLOCK, CAN_TIMER_SOURCE_EXTERNAL_TIME_TICK
self_reception: ENABLE, DISABLE
mb_tx_order: CAN_TX_HIGH_PRIORITY_MB_FIRST, CAN_TX_LOW_NUM_MB_FIRST
mb_tx_abort_enable: ENABLE, DISABLE
local_priority_enable: ENABLE, DISABLE
mb_rx_ide_rtr_type: CAN_IDE_RTR_COMPARED, CAN_IDE_RTR_FILTERED
mb_remote_frame: CAN_GEN_REMOTE_RESPONSE_FRAME, CAN_STORE_REMOTE_REQUEST_FRAME
rx_private_filter_queue_enable: ENABLE, DISABLE
edge_filter_enable: ENABLE, DISABLE
protocol_exception_enable: ENABLE, DISABLE
rx_filter_order: CAN_RX_FILTER_ORDER_FIFO_FIRST, CAN_RX_FILTER_ORDER_MAILBOX_FIRST
memory_size: CAN_MEMSIZE_1_UNIT, CAN_MEMSIZE_2_UNIT, CAN_MEMSIZE_3_UNIT, CAN_MEMSIZE_4_UNIT,
CAN_MEMSIZE_5_UNIT, CAN_MEMSIZE_6_UNIT, CAN_MEMSIZE_7_UNIT, CAN_MEMSIZE_8_UNIT,
CAN_MEMSIZE_9_UNIT, CAN_MEMSIZE_10_UNIT, CAN_MEMSIZE_11_UNIT, CAN_MEMSIZE_12_UNIT,
CAN_MEMSIZE_13_UNIT, CAN_MEMSIZE_14_UNIT, CAN_MEMSIZE_15_UNIT, CAN_MEMSIZE_16_UNIT,
CAN_MEMSIZE_17_UNIT, CAN_MEMSIZE_18_UNIT, CAN_MEMSIZE_19_UNIT, CAN_MEMSIZE_20_UNIT,
CAN_MEMSIZE_21_UNIT, CAN_MEMSIZE_22_UNIT, CAN_MEMSIZE_23_UNIT, CAN_MEMSIZE_24_UNIT,
CAN_MEMSIZE_25_UNIT, CAN_MEMSIZE_26_UNIT, CAN_MEMSIZE_27_UNIT, CAN_MEMSIZE_28_UNIT,
CAN_MEMSIZE_29_UNIT, CAN_MEMSIZE_30_UNIT, CAN_MEMSIZE_31_UNIT, CAN_MEMSIZE_32_UNIT
mb_public_filter: 0x00000000 ~ 0xFFFFFFFF
prescaler: 1~1024
resync_jump_width: 1~32
prop_time_segment: 1~64
time_segment_1: 1~32
time_segment_2: 1~32
\param[out] none
\retval ERROR or SUCCESS
*/
ErrStatus can_init(uint32_t can_periph, can_parameter_struct *can_parameter_init)
{
uint32_t i;
ErrStatus status = ERROR;
uint32_t canram = CAN_RAM(can_periph);
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PERIPH);
} else if(NOT_VALID_POINTER(can_parameter_init)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_POINTER);
} else if(NOT_CAN_CONTROL_STATUS(can_parameter_init->edge_filter_enable)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_TIMER_SOURCE(can_parameter_init->internal_counter_source)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_CONTROL_STATUS(can_parameter_init->local_priority_enable)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_RRFRMS(can_parameter_init->mb_remote_frame)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_IDERTR_RMF(can_parameter_init->mb_rx_ide_rtr_type)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_CONTROL_STATUS(can_parameter_init->mb_tx_abort_enable)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_MB_TX_ORDER(can_parameter_init->mb_tx_order)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_MEMORY_SIZE(can_parameter_init->memory_size)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_PRESCALER(can_parameter_init->prescaler)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_PROP_TIME_SEGMENT(can_parameter_init->prop_time_segment)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_CONTROL_STATUS(can_parameter_init->protocol_exception_enable)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_RESYNC_JUMP_WIDTH(can_parameter_init->resync_jump_width)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_RX_FILTER_ORDER(can_parameter_init->rx_filter_order)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_CONTROL_STATUS(can_parameter_init->rx_private_filter_queue_enable)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_CONTROL_STATUS(can_parameter_init->self_reception)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_TIME_SEGMENT_1(can_parameter_init->time_segment_1)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_TIME_SEGMENT_2(can_parameter_init->time_segment_2)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0003U), ERR_PARAM_OUT_OF_RANGE);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* clear CAN RAM */
for(i = 0U; i < CAN_MAX_RAM_SIZE; i++) {
*((uint32_t *)canram) = 0U;
canram = canram + 4U;
}
/* reset CAN_RFIFOMPFx */
for(i = 0U; i < CAN_MAX_MAILBOX_NUM; i++) {
CAN_RFIFOMPF(can_periph, i) = 0x00000000U;
}
/* reset internal state machines and CAN registers */
if(ERROR == can_software_reset(can_periph)) {
status = ERROR;
}
/* reset CAN_INTEN */
CAN_INTEN(can_periph) = 0U;
/* reset CAN_STAT */
CAN_STAT(can_periph) = (uint32_t)0xFFFFFFFFU;
CAN_TIMER(can_periph);
while(CAN_STAT(can_periph) & CAN_STAT_MS5_RFNE) {
CAN_STAT(can_periph) = CAN_STAT_MS5_RFNE;
}
/* clear register bits */
CAN_CTL0(can_periph) &= ~(CAN_CTL0_RFEN | CAN_CTL0_FDEN | CAN_CTL0_SRDIS | CAN_CTL0_LAPRIOEN | CAN_CTL0_MST | CAN_CTL0_RPFQEN | CAN_CTL0_MSZ);
CAN_CTL2(can_periph) &= ~(CAN_CTL2_ITSRC | CAN_CTL2_IDERTR_RMF | CAN_CTL2_RRFRMS | CAN_CTL2_RFO | CAN_CTL2_EFDIS | CAN_CTL2_PREEN);
CAN_CTL1(can_periph) &= ~CAN_CTL1_MTO;
CAN_BT(can_periph) &= ~(CAN_BT_BAUDPSC | CAN_BT_SJW | CAN_BT_PTS | CAN_BT_PBS1 | CAN_BT_PBS2);
/* set self reception */
if((uint8_t)DISABLE == can_parameter_init->self_reception) {
CAN_CTL0(can_periph) |= CAN_CTL0_SRDIS;
}
/* enable local arbitration priority */
if((uint8_t)ENABLE == can_parameter_init->local_priority_enable) {
CAN_CTL0(can_periph) |= CAN_CTL0_LAPRIOEN;
}
/* set rx private filters and mailbox queue */
if((uint8_t)ENABLE == can_parameter_init->rx_private_filter_queue_enable) {
CAN_CTL0(can_periph) |= CAN_CTL0_RPFQEN;
}
/* configure edge filtering */
if((uint32_t)DISABLE == can_parameter_init->edge_filter_enable) {
CAN_CTL2(can_periph) |= CAN_CTL2_EFDIS;
}
/* configure protocol exception */
if((uint32_t)ENABLE == can_parameter_init->protocol_exception_enable) {
CAN_CTL2(can_periph) |= CAN_CTL2_PREEN;
}
/* set mailbox stop transmission */
if((uint8_t)ENABLE == can_parameter_init->mb_tx_abort_enable) {
CAN_CTL0(can_periph) |= CAN_CTL0_MST;
}
/* set internal counter source */
CAN_CTL2(can_periph) |= can_parameter_init->internal_counter_source;
/* set mailbox arbitration process order */
CAN_CTL1(can_periph) |= can_parameter_init->mb_tx_order;
/* set IDE and RTR field filter type */
CAN_CTL2(can_periph) |= can_parameter_init->mb_rx_ide_rtr_type;
/* configure remote request frame */
CAN_CTL2(can_periph) |= can_parameter_init->mb_remote_frame;
/* set mailbox public filter */
CAN_RMPUBF(can_periph) = can_parameter_init->mb_public_filter;
/* configure receive filter order */
CAN_CTL2(can_periph) |= can_parameter_init->rx_filter_order;
/* set memory size */
CAN_CTL0(can_periph) |= can_parameter_init->memory_size;
/* set time segment */
CAN_BT(can_periph) |= (uint32_t)(BT_BAUDPSC(can_parameter_init->prescaler - 1U) |
BT_SJW((uint32_t)can_parameter_init->resync_jump_width - 1U) |
BT_PTS((uint32_t)can_parameter_init->prop_time_segment - 1U) |
BT_PBS1((uint32_t)can_parameter_init->time_segment_1 - 1U) |
BT_PBS2((uint32_t)can_parameter_init->time_segment_2 - 1U));
status = SUCCESS;
}
return status;
}
/*!
\brief initialize CAN parameter structure with a default value (API_ID:0x0004U)
\param[in] type: the type of CAN parameter struct
only one parameter can be selected which is shown as below:
\arg CAN_INIT_STRUCT: the CAN initial struct
\arg CAN_FD_INIT_STRUCT: the CAN FD initial struct
\arg CAN_FIFO_INIT_STRUCT: the CAN FIFO initial struct
\arg CAN_PN_MODE_INIT_STRUCT: the CAN Pretended Networking mode initial struct
\arg CAN_PN_MODE_FILTER_STRUCT: the CAN Pretended Networking mode filter struct
\arg CAN_MDSC_STRUCT: mailbox descriptor strcut
\arg CAN_FDES_STRUCT: Rx fifo descriptor strcut
\arg CAN_FIFO_ID_FILTER_STRUCT: Rx fifo id filter strcut
\arg CAN_CRC_STRUCT: CRC strcut
\arg CAN_ERRCNT_STRUCT: error counter strcut
\param[in] p_struct: the pointer of the specific struct
\param[out] none
\retval none
*/
void can_struct_para_init(can_struct_type_enum type, void *p_struct)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_VALID_POINTER(p_struct)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0004U), ERR_PARAM_POINTER);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* get type of the struct */
switch(type) {
/* used for initialize can_parameter_struct */
case CAN_INIT_STRUCT:
((can_parameter_struct *)p_struct)->self_reception = (uint8_t)DISABLE;
((can_parameter_struct *)p_struct)->internal_counter_source = CAN_TIMER_SOURCE_BIT_CLOCK;
((can_parameter_struct *)p_struct)->mb_tx_order = CAN_TX_HIGH_PRIORITY_MB_FIRST;
((can_parameter_struct *)p_struct)->mb_tx_abort_enable = (uint8_t)ENABLE;
((can_parameter_struct *)p_struct)->local_priority_enable = (uint8_t)DISABLE;
((can_parameter_struct *)p_struct)->mb_rx_ide_rtr_type = CAN_IDE_RTR_COMPARED;
((can_parameter_struct *)p_struct)->mb_remote_frame = CAN_STORE_REMOTE_REQUEST_FRAME;
((can_parameter_struct *)p_struct)->rx_private_filter_queue_enable = (uint8_t)DISABLE;
((can_parameter_struct *)p_struct)->edge_filter_enable = (uint32_t)DISABLE;
((can_parameter_struct *)p_struct)->protocol_exception_enable = (uint32_t)DISABLE;
((can_parameter_struct *)p_struct)->rx_filter_order = CAN_RX_FILTER_ORDER_FIFO_FIRST;
((can_parameter_struct *)p_struct)->memory_size = CAN_MEMSIZE_32_UNIT;
((can_parameter_struct *)p_struct)->mb_public_filter = 0xFFFFFFFFU;
((can_parameter_struct *)p_struct)->prescaler = 0x00000001U;
((can_parameter_struct *)p_struct)->resync_jump_width = 0x01U;
((can_parameter_struct *)p_struct)->prop_time_segment = 0x01U;
((can_parameter_struct *)p_struct)->time_segment_1 = 0x01U;
((can_parameter_struct *)p_struct)->time_segment_2 = 0x01U;
break;
/* used for initialize can_fd_parameter_struct */
case CAN_FD_INIT_STRUCT:
((can_fd_parameter_struct *)p_struct)->iso_can_fd_enable = (uint32_t)DISABLE;
((can_fd_parameter_struct *)p_struct)->bitrate_switch_enable = (uint32_t)ENABLE;
((can_fd_parameter_struct *)p_struct)->mailbox_data_size = CAN_MAILBOX_DATA_SIZE_8_BYTES;
((can_fd_parameter_struct *)p_struct)->tdc_enable = (uint32_t)DISABLE;
((can_fd_parameter_struct *)p_struct)->tdc_offset = 0x00U;
((can_fd_parameter_struct *)p_struct)->prescaler = 0x00000001U;
((can_fd_parameter_struct *)p_struct)->resync_jump_width = 0x01U;
((can_fd_parameter_struct *)p_struct)->prop_time_segment = 0x00U;
((can_fd_parameter_struct *)p_struct)->time_segment_1 = 0x01U;
((can_fd_parameter_struct *)p_struct)->time_segment_2 = 0x01U;
break;
/* used for initialize can_fifo_parameter_struct */
case CAN_FIFO_INIT_STRUCT:
((can_fifo_parameter_struct *)p_struct)->dma_enable = (uint8_t)DISABLE;
((can_fifo_parameter_struct *)p_struct)->filter_format_and_number = CAN_RXFIFO_FILTER_A_NUM_8;
((can_fifo_parameter_struct *)p_struct)->fifo_public_filter = 0xFFFFFFFFU;
break;
/* used for initialize can_pn_mode_config_struct */
case CAN_PN_MODE_INIT_STRUCT:
((can_pn_mode_config_struct *)p_struct)->timeout_int = (uint32_t)DISABLE;
((can_pn_mode_config_struct *)p_struct)->match_int = (uint32_t)DISABLE;
((can_pn_mode_config_struct *)p_struct)->num_matches = 0x01U;
((can_pn_mode_config_struct *)p_struct)->match_timeout = 0x0000U;
((can_pn_mode_config_struct *)p_struct)->frame_filter = CAN_PN_FRAME_FILTERING_ID;
((can_pn_mode_config_struct *)p_struct)->id_filter = CAN_PN_ID_FILTERING_EXACT;
((can_pn_mode_config_struct *)p_struct)->data_filter = CAN_PN_DATA_FILTERING_EXACT;
break;
/* used for initialize can_pn_mode_filter_struct */
case CAN_PN_MODE_FILTER_STRUCT:
((can_pn_mode_filter_struct *)p_struct)->rtr = (uint32_t)RESET;
((can_pn_mode_filter_struct *)p_struct)->ide = (uint32_t)RESET;
((can_pn_mode_filter_struct *)p_struct)->id = 0x00000000U;
((can_pn_mode_filter_struct *)p_struct)->dlc_high_threshold = 0x00000000U;
((can_pn_mode_filter_struct *)p_struct)->dlc_low_threshold = 0x00000000U;
((can_pn_mode_filter_struct *)p_struct)->payload[0] = 0x00000000U;
((can_pn_mode_filter_struct *)p_struct)->payload[1] = 0x00000000U;
break;
/* used for initialize can_mailbox_descriptor_struct */
case CAN_MDSC_STRUCT:
((can_mailbox_descriptor_struct *)p_struct)->timestamp = 0x00000000U;
((can_mailbox_descriptor_struct *)p_struct)->dlc = 0x00000000U;
((can_mailbox_descriptor_struct *)p_struct)->rtr = 0x00000000U;
((can_mailbox_descriptor_struct *)p_struct)->ide = 0x00000000U;
((can_mailbox_descriptor_struct *)p_struct)->srr = 0x00000000U;
((can_mailbox_descriptor_struct *)p_struct)->reserve1 = 0x00000000U;
((can_mailbox_descriptor_struct *)p_struct)->code = 0x00000000U;
((can_mailbox_descriptor_struct *)p_struct)->reserve2 = 0x00000000U;
((can_mailbox_descriptor_struct *)p_struct)->esi = 0x00000000U;
((can_mailbox_descriptor_struct *)p_struct)->brs = 0x00000000U;
((can_mailbox_descriptor_struct *)p_struct)->fdf = 0x00000000U;
((can_mailbox_descriptor_struct *)p_struct)->id = 0x00000000U;
((can_mailbox_descriptor_struct *)p_struct)->prio = 0x00000000U;
((can_mailbox_descriptor_struct *)p_struct)->data_bytes = 0x00000000U;
((can_mailbox_descriptor_struct *)p_struct)->padding = 0x0000U;
break;
/* used for initialize can_rx_fifo_struct */
case CAN_FDES_STRUCT:
((can_rx_fifo_struct *)p_struct)->timestamp = 0x00000000U;
((can_rx_fifo_struct *)p_struct)->dlc = 0x00000000U;
((can_rx_fifo_struct *)p_struct)->rtr = 0x00000000U;
((can_rx_fifo_struct *)p_struct)->ide = 0x00000000U;
((can_rx_fifo_struct *)p_struct)->srr = 0x00000000U;
((can_rx_fifo_struct *)p_struct)->idhit = 0x00000000U;
((can_rx_fifo_struct *)p_struct)->id = 0x00000000U;
((can_rx_fifo_struct *)p_struct)->data[0] = 0x00000000U;
((can_rx_fifo_struct *)p_struct)->data[1] = 0x00000000U;
break;
/* used for initialize can_rx_fifo_id_filter_struct */
case CAN_FIFO_ID_FILTER_STRUCT:
((can_rx_fifo_id_filter_struct *)p_struct)->remote_frame = 0x00000000U;
((can_rx_fifo_id_filter_struct *)p_struct)->extended_frame = 0x00000000U;
((can_rx_fifo_id_filter_struct *)p_struct)->id = 0x00000000U;
break;
/* used for initialize can_crc_struct */
case CAN_CRC_STRUCT:
((can_crc_struct *)p_struct)->classical_frm_mb_number = 0x00000000U;
((can_crc_struct *)p_struct)->classical_frm_transmitted_crc = 0x00000000U;
((can_crc_struct *)p_struct)->classical_fd_frm_mb_number = 0x00000000U;
((can_crc_struct *)p_struct)->classical_fd_frm_transmitted_crc = 0x00000000U;
break;
/* used for initialize can_crc_struct */
case CAN_ERRCNT_STRUCT:
((can_error_counter_struct *)p_struct)->fd_data_phase_rx_errcnt = 0x00U;
((can_error_counter_struct *)p_struct)->fd_data_phase_tx_errcnt = 0x00U;
((can_error_counter_struct *)p_struct)->rx_errcnt = 0x00U;
((can_error_counter_struct *)p_struct)->tx_errcnt = 0x00U;
break;
default:
break;
}
}
}
/*!
\brief configure receive fifo/mailbox private filter (API_ID:0x0005U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] index: mailbox index
\param[in] filter_data: filter data to configure
\param[out] none
\retval none
*/
void can_private_filter_config(uint32_t can_periph, uint32_t index, uint32_t filter_data)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0005U), ERR_PERIPH);
} else if(NOT_CAN_MAILBOX_INDEX(index)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0005U), ERR_PARAM_OUT_OF_RANGE);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_RFIFOMPF(can_periph, index) = filter_data;
}
}
/*!
\brief enter the corresponding mode (API_ID:0x0006U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] mode: the mode to enter
only one parameter can be selected which is shown as below:
\arg CAN_NORMAL_MODE: normal mode
\arg CAN_MONITOR_MODE: monitor mode
\arg CAN_LOOPBACK_SILENT_MODE: loopback mode
\arg CAN_INACTIVE_MODE: inactive mode
\arg CAN_DISABLE_MODE: disable mode
\arg CAN_PN_MODE: Pretended Networking mode
\param[out] none
\retval ERROR or SUCCESS
*/
ErrStatus can_operation_mode_enter(uint32_t can_periph, can_operation_modes_enum mode)
{
uint32_t timeout;
ErrStatus status = SUCCESS;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0006U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
status = SUCCESS;
/* enter INACTIVE mode */
/* exit can_disable mode */
CAN_CTL0(can_periph) &= ~CAN_CTL0_CANDIS;
/* enter inactive mode */
CAN_CTL0(can_periph) |= CAN_CTL0_HALT | CAN_CTL0_INAMOD;
/* exit Pretended Networking mode */
CAN_CTL0(can_periph) &= ~(CAN_CTL0_PNEN | CAN_CTL0_PNMOD);
timeout = CAN_DELAY;
/* wait for inactive mode state */
while(((CAN_CTL0_NRDY | CAN_CTL0_INAS) != (CAN_CTL0(can_periph) & (CAN_CTL0_NRDY | CAN_CTL0_INAS))) && (timeout)) {
timeout--;
}
if((CAN_CTL0_NRDY | CAN_CTL0_INAS) != (CAN_CTL0(can_periph) & (CAN_CTL0_NRDY | CAN_CTL0_INAS))) {
return ERROR;
}
/* configure the modes */
switch(mode) {
case CAN_NORMAL_MODE:
CAN_CTL1(can_periph) &= ~(CAN_CTL1_LSCMOD | CAN_CTL1_MMOD);
break;
case CAN_MONITOR_MODE:
CAN_CTL1(can_periph) &= ~CAN_CTL1_LSCMOD;
CAN_CTL1(can_periph) |= CAN_CTL1_MMOD;
break;
case CAN_LOOPBACK_SILENT_MODE:
CAN_CTL1(can_periph) &= ~CAN_CTL1_MMOD;
CAN_CTL0(can_periph) &= ~CAN_CTL0_SRDIS;
CAN_FDCTL(can_periph) &= ~CAN_FDCTL_TDCEN;
CAN_CTL1(can_periph) |= CAN_CTL1_LSCMOD;
break;
case CAN_INACTIVE_MODE:
break;
case CAN_DISABLE_MODE:
CAN_CTL0(can_periph) |= CAN_CTL0_CANDIS;
break;
case CAN_PN_MODE:
CAN_CTL0(can_periph) |= (CAN_CTL0_PNEN | CAN_CTL0_PNMOD);
break;
default:
break;
}
/* exit INACTIVE mode */
if(CAN_INACTIVE_MODE != mode) {
/* exit inactive mode */
CAN_CTL0(can_periph) &= ~(CAN_CTL0_HALT | CAN_CTL0_INAMOD);
timeout = CAN_DELAY;
while((CAN_CTL0(can_periph) & CAN_CTL0_INAS) && (timeout)) {
timeout--;
}
if(CAN_CTL0(can_periph) & CAN_CTL0_INAS) {
status = ERROR;
}
}
if(CAN_PN_MODE == mode) {
timeout = CAN_DELAY;
while((0U == (CAN_CTL0(can_periph) & CAN_CTL0_PNS)) && (timeout)) {
timeout--;
}
if(0U == (CAN_CTL0(can_periph) & CAN_CTL0_PNS)) {
status = ERROR;
}
}
}
return status;
}
/*!
\brief get operation mode (API_ID:0x0007U)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval can_operation_modes_enum
*/
can_operation_modes_enum can_operation_mode_get(uint32_t can_periph)
{
uint32_t reg;
can_operation_modes_enum state = CAN_NORMAL_MODE;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0007U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
reg = CAN_CTL0(can_periph);
reg &= (CAN_CTL0_NRDY | CAN_CTL0_INAS | CAN_CTL0_PNS | CAN_CTL0_LPS);
if((CAN_CTL0_NRDY | CAN_CTL0_LPS) == reg) {
state = CAN_DISABLE_MODE;
} else if((CAN_CTL0_NRDY | CAN_CTL0_INAS) == reg) {
state = CAN_INACTIVE_MODE;
} else if(0U == reg) {
if(CAN_CTL1(can_periph)&CAN_CTL1_MMOD) {
state = CAN_MONITOR_MODE;
} else if(CAN_CTL1(can_periph)&CAN_CTL1_LSCMOD) {
state = CAN_LOOPBACK_SILENT_MODE;
} else {
state = CAN_NORMAL_MODE;
}
} else if(CAN_CTL0_PNS == reg) {
state = CAN_PN_MODE;
} else {
/* should not get here */
}
}
return state;
}
/*!
\brief exit inactive mode (API_ID:0x0008U)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval ERROR or SUCCESS
*/
ErrStatus can_inactive_mode_exit(uint32_t can_periph)
{
ErrStatus status = ERROR;
uint32_t timeout;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0008U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* exit inactive mode */
CAN_CTL0(can_periph) &= ~CAN_CTL0_HALT;
timeout = CAN_DELAY;
while((CAN_CTL0(can_periph) & CAN_CTL0_INAS) && (timeout)) {
timeout--;
}
if(CAN_CTL0(can_periph) & CAN_CTL0_INAS) {
status = ERROR;
} else {
status = SUCCESS;
}
}
return status;
}
/*!
\brief exit Pretended Networking mode (API_ID:0x0009U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] none
\param[out] none
\retval ERROR or SUCCESS
*/
ErrStatus can_pn_mode_exit(uint32_t can_periph)
{
ErrStatus status = ERROR;
uint32_t timeout;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0009U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_CTL0(can_periph) &= ~(CAN_CTL0_PNEN | CAN_CTL0_PNMOD);
timeout = CAN_DELAY;
while((CAN_CTL0(can_periph) & CAN_CTL0_PNS) && (timeout)) {
timeout--;
}
if(CAN_CTL0(can_periph) & CAN_CTL0_PNS) {
status = ERROR;
} else {
status = SUCCESS;
}
}
return status;
}
/*!
\brief can FD initialize (API_ID:0x000AU)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] can_fd_para_init: can fd parameter struct
iso_can_fd_enable: ENABLE, DISABLE
bitrate_switch_enable: ENABLE, DISABLE
mailbox_data_size: CAN_MAILBOX_DATA_SIZE_8_BYTES, CAN_MAILBOX_DATA_SIZE_16_BYTES,
CAN_MAILBOX_DATA_SIZE_32_BYTES, CAN_MAILBOX_DATA_SIZE_64_BYTES
tdc_enable: ENABLE, DISABLE
tdc_offset: 0 ~ 31
prescaler: 1~1024
resync_jump_width: 1~8
prop_time_segment: 0~31
time_segment_1: 1~8
time_segment_2: 2~8
\param[out] none
\retval none
*/
void can_fd_config(uint32_t can_periph, can_fd_parameter_struct *can_fd_para_init)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000AU), ERR_PERIPH);
} else if(NOT_VALID_POINTER(can_fd_para_init)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000AU), ERR_PARAM_POINTER);
} else if(NOT_CAN_CONTROL_STATUS(can_fd_para_init->bitrate_switch_enable)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000AU), ERR_PARAM_OUT_OF_RANGE);
}else if(NOT_CAN_CONTROL_STATUS(can_fd_para_init->iso_can_fd_enable)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000AU), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_MAILBOX_DATA_SIZE(can_fd_para_init->mailbox_data_size)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000AU), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_FD_PRESCALER(can_fd_para_init->prescaler)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000AU), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_FD_PROP_TIME_SEGMENT(can_fd_para_init->prop_time_segment)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000AU), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_FD_RESYNC_JUMP_WIDTH(can_fd_para_init->resync_jump_width)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000AU), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_CONTROL_STATUS(can_fd_para_init->tdc_enable)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000AU), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_FD_TDC_OFFSET(can_fd_para_init->tdc_offset)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000AU), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_FD_TIME_SEGMENT_1(can_fd_para_init->time_segment_1)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000AU), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_FD_TIME_SEGMENT_1(can_fd_para_init->time_segment_2)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000AU), ERR_PARAM_OUT_OF_RANGE);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* clear register bits, then enable FD mode */
CAN_CTL0(can_periph) &= ~CAN_CTL0_RFEN;
CAN_CTL1(can_periph) &= ~CAN_CTL1_BSPMOD;
CAN_CTL2(can_periph) &= ~CAN_CTL2_ISO;
CAN_FDCTL(can_periph) &= ~(CAN_FDCTL_BRSEN | CAN_FDCTL_MDSZ | CAN_FDCTL_TDCEN | CAN_FDCTL_TDCO);
CAN_FDBT(can_periph) &= ~(CAN_FDBT_DBAUDPSC | CAN_FDBT_DSJW | CAN_FDBT_DPTS | CAN_FDBT_DPBS1 | CAN_FDBT_DPBS2);
CAN_CTL0(can_periph) |= CAN_CTL0_FDEN;
/* support ISO or non-ISO mode */
if((uint32_t)ENABLE == can_fd_para_init->iso_can_fd_enable) {
CAN_CTL2(can_periph) |= CAN_CTL2_ISO;
}
/* set TDC parameter */
if((uint32_t)ENABLE == can_fd_para_init->tdc_enable) {
CAN_FDCTL(can_periph) |= CAN_FDCTL_TDCEN;
}
/* set data bit rate */
if((uint32_t)ENABLE == can_fd_para_init->bitrate_switch_enable) {
CAN_FDCTL(can_periph) |= CAN_FDCTL_BRSEN;
}
/* set mailbox data size */
CAN_FDCTL(can_periph) |= can_fd_para_init->mailbox_data_size;
/* configure FD bit timing */
CAN_FDBT(can_periph) |= (uint32_t)(FDBT_DBAUDPSC(can_fd_para_init->prescaler - 1U) |
FDBT_DSJW((uint32_t)can_fd_para_init->resync_jump_width - 1U) |
FDBT_DPTS(can_fd_para_init->prop_time_segment) |
FDBT_DPBS1((uint32_t)can_fd_para_init->time_segment_1 - 1U) |
FDBT_DPBS2((uint32_t)can_fd_para_init->time_segment_2 - 1U));
/* configure transmitter delay compensation offset */
CAN_FDCTL(can_periph) |= FDCTL_TDCO(can_fd_para_init->tdc_offset);
}
}
/*!
\brief enable bit rate switching (API_ID:0x000BU)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_bitrate_switch_enable(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000BU), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_FDCTL(can_periph) |= CAN_FDCTL_BRSEN;
}
}
/*!
\brief disable bit rate switching (API_ID:0x000CU)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_bitrate_switch_disable(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000CU), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_FDCTL(can_periph) &= ~CAN_FDCTL_BRSEN;
}
}
/*!
\brief get transmitter delay compensation value (API_ID:0x000DU)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval 0 - 0x3F
*/
uint32_t can_tdc_get(uint32_t can_periph)
{
uint32_t ret = 0U;
uint32_t reg;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000DU), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
reg = CAN_FDCTL(can_periph);
ret = GET_FDCTL_TDCV(reg);
}
return ret;
}
/*!
\brief enable transmitter delay compensation (API_ID:0x000EU)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_tdc_enable(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000EU), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_FDCTL(can_periph) |= CAN_FDCTL_TDCEN;
}
}
/*!
\brief disable transmitter delay compensation (API_ID:0x000FU)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_tdc_disable(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x000FU), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_FDCTL(can_periph) &= ~CAN_FDCTL_TDCEN;
}
}
/*!
\brief configure rx FIFO (API_ID:0x00010U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] can_fifo_para_init: fifo parameter struct
dma_enable: ENABLE, DISABLE
filter_format_and_number: CAN_RXFIFO_FILTER_A_NUM_8, CAN_RXFIFO_FILTER_A_NUM_16, CAN_RXFIFO_FILTER_A_NUM_24, CAN_RXFIFO_FILTER_A_NUM_32,
CAN_RXFIFO_FILTER_A_NUM_40, CAN_RXFIFO_FILTER_A_NUM_48, CAN_RXFIFO_FILTER_A_NUM_56, CAN_RXFIFO_FILTER_A_NUM_64,
CAN_RXFIFO_FILTER_A_NUM_72, CAN_RXFIFO_FILTER_A_NUM_80, CAN_RXFIFO_FILTER_A_NUM_88, CAN_RXFIFO_FILTER_A_NUM_96, CAN_RXFIFO_FILTER_A_NUM_104,
CAN_RXFIFO_FILTER_B_NUM_16, CAN_RXFIFO_FILTER_B_NUM_32, CAN_RXFIFO_FILTER_B_NUM_48, CAN_RXFIFO_FILTER_B_NUM_64,
CAN_RXFIFO_FILTER_B_NUM_80, CAN_RXFIFO_FILTER_B_NUM_96, CAN_RXFIFO_FILTER_B_NUM_112, CAN_RXFIFO_FILTER_B_NUM_128,
CAN_RXFIFO_FILTER_B_NUM_144, CAN_RXFIFO_FILTER_B_NUM_160, CAN_RXFIFO_FILTER_B_NUM_176, CAN_RXFIFO_FILTER_B_NUM_192, CAN_RXFIFO_FILTER_B_NUM_208,
CAN_RXFIFO_FILTER_C_NUM_32, CAN_RXFIFO_FILTER_C_NUM_64, CAN_RXFIFO_FILTER_C_NUM_96, CAN_RXFIFO_FILTER_C_NUM_128,
CAN_RXFIFO_FILTER_C_NUM_160, CAN_RXFIFO_FILTER_C_NUM_192, CAN_RXFIFO_FILTER_C_NUM_224, CAN_RXFIFO_FILTER_C_NUM_256,
CAN_RXFIFO_FILTER_C_NUM_288, CAN_RXFIFO_FILTER_C_NUM_320, CAN_RXFIFO_FILTER_C_NUM_352, CAN_RXFIFO_FILTER_C_NUM_384, CAN_RXFIFO_FILTER_C_NUM_416,
CAN_RXFIFO_FILTER_D
fifo_public_filter: 0x00000000 ~ 0xFFFFFFFF
\param[out] none
\retval none
*/
void can_rx_fifo_config(uint32_t can_periph, can_fifo_parameter_struct *can_fifo_para_init)
{
uint32_t num;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0010U), ERR_PERIPH);
} else if(NOT_VALID_POINTER(can_fifo_para_init)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0010U), ERR_PARAM_POINTER);
} else if(NOT_CAN_CONTROL_STATUS(can_fifo_para_init->dma_enable)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0010U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_RXFIFO_FILTER_FN(can_fifo_para_init->filter_format_and_number)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0010U), ERR_PARAM_OUT_OF_RANGE);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* clear register bits, disable FD mode, then enable rx FIFO mode */
CAN_CTL0(can_periph) &= ~(CAN_CTL0_FDEN | CAN_CTL0_DMAEN | CAN_CTL0_FS);
CAN_CTL2(can_periph) &= ~CAN_CTL2_RFFN;
CAN_CTL0(can_periph) |= CAN_CTL0_RFEN;
/* clear FIFO status */
CAN_STAT(can_periph) = (uint32_t)0xFFFFFFFFU;
while(CAN_STAT(can_periph) & CAN_STAT_MS5_RFNE) {
CAN_STAT(can_periph) = CAN_STAT_MS5_RFNE;
}
/* set DMA mode */
if((uint8_t)ENABLE == can_fifo_para_init->dma_enable) {
CAN_CTL0(can_periph) |= CAN_CTL0_DMAEN;
}
/* configure filter format */
CAN_CTL0(can_periph) |= (can_fifo_para_init->filter_format_and_number & CAN_CTL0_FS);
/* configure filter number */
CAN_CTL2(can_periph) |= (can_fifo_para_init->filter_format_and_number & CAN_CTL2_RFFN);
/* configure fifo public fiter */
CAN_RFIFOPUBF(can_periph) = can_fifo_para_init->fifo_public_filter;
/* configure fifo private fiter */
if(!(CAN_CTL0(can_periph) & CAN_CTL0_RPFQEN)) {
for(num = 0U; num < CAN_MAX_MAILBOX_NUM; num++) {
CAN_RFIFOMPF(can_periph, num) = can_fifo_para_init->fifo_public_filter;
}
}
}
}
/*!
\brief configure rx FIFO filter table (API_ID:0x0011U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] id_filter_table: id filter table struct
remote_frame: CAN_DATA_FRAME_ACCEPTED, CAN_REMOTE_FRAME_ACCEPTED
extended_frame: CAN_STANDARD_FRAME_ACCEPTED, CAN_EXTENDED_FRAME_ACCEPTED
id: 11 bits for standard frame, 29 bits for extended frame
\param[out] none
\retval none
*/
void can_rx_fifo_filter_table_config(uint32_t can_periph, can_rx_fifo_id_filter_struct id_filter_table[])
{
/* set rx FIFO ID filter table elements */
uint32_t i = 0U, j = 0U, num_of_filters = 0U;
uint32_t val = 0U;
uint32_t id_format = 0U;
uint32_t filter_table;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0011U), ERR_PERIPH);
} else if(NOT_VALID_POINTER(id_filter_table)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0011U), ERR_PARAM_POINTER);
} else if(NOT_CAN_EXTENDED_FRAME(id_filter_table->extended_frame)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0011U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_ID(id_filter_table->extended_frame, id_filter_table->id)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0011U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_REMOTE_FRAME(id_filter_table->remote_frame)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0011U), ERR_PARAM_OUT_OF_RANGE);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
filter_table = (uint32_t)(CAN_RAM(can_periph) + 0x00000060U);
num_of_filters = (GET_CTL2_RFFN(CAN_CTL2(can_periph)) + 1U) * 8U;
id_format = CAN_CTL0(can_periph) & CAN_CTL0_FS;
switch(id_format) {
case(CAN_FIFO_FILTER_FORMAT_A):
/* one full id (standard and extended) per id filter table element */
for(i = 0U; i < num_of_filters; i++) {
val = 0U;
if(CAN_REMOTE_FRAME_ACCEPTED == id_filter_table[i].remote_frame) {
val |= CAN_FDESX_RTR_A;
}
if(CAN_EXTENDED_FRAME_ACCEPTED == id_filter_table[i].extended_frame) {
val |= CAN_FDESX_IDE_A;
val |= (uint32_t)FIFO_FILTER_ID_EXD_A(id_filter_table[i].id);
} else {
val |= (uint32_t)FIFO_FILTER_ID_STD_A(id_filter_table[i].id);
}
*(uint32_t *)filter_table = val;
filter_table = filter_table + 4U;
}
break;
case(CAN_FIFO_FILTER_FORMAT_B):
/* two full standard id or two partial 14-bit (standard and extended) id */
j = 0U;
for(i = 0U; i < num_of_filters; i++) {
val = 0U;
if(CAN_REMOTE_FRAME_ACCEPTED == id_filter_table[j].remote_frame) {
val |= CAN_FDESX_RTR_B0;
}
if(CAN_EXTENDED_FRAME_ACCEPTED == id_filter_table[j].extended_frame) {
val |= CAN_FDESX_IDE_B0;
val |= (uint32_t)FIFO_FILTER_ID_EXD_B0(id_filter_table[j].id);
} else {
val |= (uint32_t)FIFO_FILTER_ID_STD_B0(id_filter_table[j].id);
}
j++;
if(CAN_REMOTE_FRAME_ACCEPTED == id_filter_table[j].remote_frame) {
val |= CAN_FDESX_RTR_B1;
}
if(CAN_EXTENDED_FRAME_ACCEPTED == id_filter_table[j].extended_frame) {
val |= CAN_FDESX_IDE_B1;
val |= (uint32_t)FIFO_FILTER_ID_EXD_B1(id_filter_table[j].id);
} else {
val |= (uint32_t)FIFO_FILTER_ID_STD_B1(id_filter_table[j].id);
}
j++;
*(uint32_t *)filter_table = val;
filter_table = filter_table + 4U;
}
break;
case(CAN_FIFO_FILTER_FORMAT_C):
/* four partial 8-bit standard id per id filter table element */
j = 0U;
for(i = 0U; i < num_of_filters; i++) {
val = 0U;
if(CAN_EXTENDED_FRAME_ACCEPTED == id_filter_table[j].extended_frame) {
val |= (uint32_t)FIFO_FILTER_ID_EXD_C0(id_filter_table[j].id);
} else {
val |= (uint32_t)FIFO_FILTER_ID_STD_C0(id_filter_table[j].id);
}
j++;
if(CAN_EXTENDED_FRAME_ACCEPTED == id_filter_table[j].extended_frame) {
val |= (uint32_t)FIFO_FILTER_ID_EXD_C1(id_filter_table[j].id);
} else {
val |= (uint32_t)FIFO_FILTER_ID_STD_C1(id_filter_table[j].id);
}
j++;
if(CAN_EXTENDED_FRAME_ACCEPTED == id_filter_table[j].extended_frame) {
val |= (uint32_t)FIFO_FILTER_ID_EXD_C2(id_filter_table[j].id);
} else {
val |= (uint32_t)FIFO_FILTER_ID_STD_C2(id_filter_table[j].id);
}
j++;
if(CAN_EXTENDED_FRAME_ACCEPTED == id_filter_table[j].extended_frame) {
val |= (uint32_t)FIFO_FILTER_ID_EXD_C3(id_filter_table[j].id);
} else {
val |= (uint32_t)FIFO_FILTER_ID_STD_C3(id_filter_table[j].id);
}
j++;
*(uint32_t *)filter_table = val;
filter_table = filter_table + 4U;
}
break;
case(CAN_FIFO_FILTER_FORMAT_D):
/* all frames rejected */
break;
default:
/* should not get here */
break;
}
}
}
/*!
\brief read rx FIFO data (API_ID:0x0012U)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] rx_fifo: rx FIFO struct
\retval none
*/
void can_rx_fifo_read(uint32_t can_periph, can_rx_fifo_struct *rx_fifo)
{
uint32_t *rx_fifo_addr;
uint32_t can_mb;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0012U), ERR_PERIPH);
} else if(NOT_VALID_POINTER(rx_fifo)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0012U), ERR_PARAM_POINTER);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
rx_fifo_addr = (uint32_t *)rx_fifo;
can_mb = CAN_RAM(can_periph);
/* read FIFO descriptor 0 */
*rx_fifo_addr = *((uint32_t *)can_mb );
rx_fifo->id = *((uint32_t *)((uint32_t)(can_mb + 0x04U)));
rx_fifo->data[0] = *((uint32_t *)((uint32_t)(can_mb + 0x08U)));
rx_fifo->data[1] = *((uint32_t *)((uint32_t)(can_mb + 0x0CU)));
/* clear FIFO status */
CAN_STAT(can_periph) = CAN_STAT_MS5_RFNE;
/* read FIFO id field */
if(rx_fifo->ide) {
rx_fifo->id = GET_FDES1_ID_EXD(rx_fifo->id);
} else {
rx_fifo->id = GET_FDES1_ID_STD(rx_fifo->id);
}
/* read FIFO data */
can_data_to_little_endian_swap(rx_fifo->data, rx_fifo->data, rx_fifo->dlc);
}
}
/*!
\brief get rx FIFO filter matching number (API_ID:0x0013U)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval filter number
*/
uint32_t can_rx_fifo_filter_matching_number_get(uint32_t can_periph)
{
uint32_t ret = 0U;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0013U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
ret = GET_RFIFOIFMN_IDFMN(CAN_RFIFOIFMN(can_periph));
}
return ret;
}
/*!
\brief clear rx FIFO (API_ID:0x0014U)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_rx_fifo_clear(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0014U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_STAT(can_periph) = CAN_STAT_MS0_RFC;
}
}
/*!
\brief get mailbox RAM address (API_ID:0x0015U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] index: mailbox index, 0-31
\param[out] none
\retval pointer to the mailbox address
*/
uint32_t can_ram_address_get(uint32_t can_periph, uint32_t index)
{
uint32_t payload_size;
uint32_t address = 0U;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0015U), ERR_PERIPH);
} else if(NOT_CAN_MAILBOX_INDEX(index)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0015U), ERR_PARAM_OUT_OF_RANGE);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* if CAN FD mode is enabled */
if(CAN_CTL0(can_periph) & CAN_CTL0_FDEN) {
payload_size = (uint32_t)1U << (GET_FDCTL_MDSZ(CAN_FDCTL(can_periph)) + 3U);
} else {
payload_size = 8U;
}
address = (uint32_t)(CAN_RAM(can_periph) + (payload_size + 8U) * index);
}
return address;
}
/*!
\brief configure mailbox (API_ID:0x0016U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] index: mailbox index
only one parameter can be selected which is shown as below:
\arg 0 - 31
\param[in] mdpara: mailbox descriptor struct
rtr: 0, 1
ide: 0, 1
id: 0 - 0x1FFFFFFF
code: CAN_MB_RX_STATUS_INACTIVE, CAN_MB_RX_STATUS_FULL, CAN_MB_RX_STATUS_EMPTY,
CAN_MB_RX_STATUS_OVERRUN, CAN_MB_RX_STATUS_RANSWER, CAN_MB_RX_STATUS_BUSY,
CAN_MB_TX_STATUS_INACTIVE, CAN_MB_TX_STATUS_ABORT, CAN_MB_TX_STATUS_DATA
data_bytes: 0 - 64
data: point to the data
esi: 0, 1
fdf: 0, 1
brs: 0, 1
prio: 0 - 7
\param[out] none
\retval none
*/
void can_mailbox_config(uint32_t can_periph, uint32_t index, can_mailbox_descriptor_struct *mdpara)
{
uint32_t dlc;
uint32_t mdes0 = 0U;
uint32_t mdes1;
uint32_t mdes2;
uint32_t mdes3;
uint32_t length;
uint32_t mdes;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0016U), ERR_PERIPH);
} else if(NOT_CAN_MAILBOX_INDEX(index)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0016U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_VALID_POINTER(mdpara)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0016U), ERR_PARAM_POINTER);
} else if(NOT_CAN_MDES0_CODE(mdpara->code)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0016U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_VALID_POINTER(mdpara->data)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0016U), ERR_PARAM_POINTER);
} else if(NOT_CAN_DATA_BYTES(mdpara->data_bytes)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0016U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_ID(mdpara->ide, mdpara->id)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0016U), ERR_PARAM_OUT_OF_RANGE);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* clear mailbox status */
CAN_STAT(can_periph) = STAT_MS(index);
/* get mailbox base address */
mdes = can_ram_address_get(can_periph, index);
mdes1 = mdes + 0x04U;
mdes2 = mdes + 0x08U;
mdes3 = mdes + 0x0CU;
*(uint32_t *)mdes = 0U;
*(uint32_t *)mdes1 = 0U;
*(uint32_t *)mdes2 = 0U;
*(uint32_t *)mdes3 = 0U;
/* set RTR bit */
if(mdpara->rtr) {
mdes0 |= CAN_MDES0_RTR;
}
/* set IDE bit and ID field */
if(mdpara->ide) {
mdes0 |= CAN_MDES0_IDE;
mdes0 |= CAN_MDES0_SRR;
*(uint32_t *)mdes1 |= MDES1_ID_EXD(mdpara->id);
} else {
*(uint32_t *)mdes1 |= MDES1_ID_STD(mdpara->id);
}
/* set CODE field */
mdes0 |= MDES0_CODE(mdpara->code);
if(mdpara->code != CAN_MB_RX_STATUS_EMPTY) {
/* copy user's buffer into the mailbox data area */
if(mdpara->data_bytes) {
dlc = can_dlc_value_compute(mdpara->data_bytes);
mdes0 |= MDES0_DLC(dlc);
length = (uint32_t)1U << (GET_FDCTL_MDSZ(CAN_FDCTL(can_periph)) + 3U);
if(mdpara->data_bytes < length) {
length = mdpara->data_bytes;
}
can_data_to_big_endian_swap((uint32_t *)mdes2, (uint32_t *)mdpara->data, length);
}
/* prepare mailbox for transmission */
if(CAN_MB_TX_STATUS_DATA == mdpara->code) {
/* set ESI bit */
if(mdpara->esi) {
mdes0 |= CAN_MDES0_ESI;
}
/* set FDF and BRS bit */
if(mdpara->fdf) {
mdes0 |= CAN_MDES0_FDF;
if(mdpara->brs) {
mdes0 |= CAN_MDES0_BRS;
}
mdes0 &= ~CAN_MDES0_RTR;
}
}
/* set PRIO field */
*(uint32_t *)mdes1 |= MDES1_PRIO(mdpara->prio);
}
/* set mailbox descriptor 0 */
*(uint32_t *)mdes = mdes0;
}
}
/*!
\brief abort mailbox transmit (API_ID:0x0017U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] index: mailbox index
only one parameter can be selected which is shown as below:
\arg 0 - 31
\param[out] none
\retval none
*/
void can_mailbox_transmit_abort(uint32_t can_periph, uint32_t index)
{
uint32_t mdes0;
uint32_t mdes;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0017U), ERR_PERIPH);
} else if(NOT_CAN_MAILBOX_INDEX(index)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0017U), ERR_PARAM_OUT_OF_RANGE);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* abort transmit mailbox */
mdes = can_ram_address_get(can_periph, index);
mdes0 = *(uint32_t *)mdes;
mdes0 &= ~CAN_MDES0_CODE;
mdes0 |= MDES0_CODE(CAN_MB_TX_STATUS_ABORT);
*(uint32_t *)mdes = mdes0;
}
}
/*!
\brief inactive transmit mailbox (API_ID:0x0018U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] index: mailbox index
only one parameter can be selected which is shown as below:
\arg 0 - 31
\param[out] none
\retval none
*/
void can_mailbox_transmit_inactive(uint32_t can_periph, uint32_t index)
{
uint32_t mdes0;
uint32_t mdes;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0018U), ERR_PERIPH);
} else if(NOT_CAN_MAILBOX_INDEX(index)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0018U), ERR_PARAM_OUT_OF_RANGE);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* inactive transmit mailbox */
mdes = can_ram_address_get(can_periph, index);
mdes0 = *(uint32_t *)mdes;
mdes0 &= ~CAN_MDES0_CODE;
mdes0 |= MDES0_CODE(CAN_MB_TX_STATUS_INACTIVE);
*(uint32_t *)mdes = mdes0;
}
}
/*!
\brief read receive mailbox data (API_ID:0x0019U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] index: mailbox index
only one parameter can be selected which is shown as below:
\arg 0 - 31
\param[out] mdpara: mailbox descriptor struct
\retval ERROR or SUCCESS
*/
ErrStatus can_mailbox_receive_data_read(uint32_t can_periph, uint32_t index, can_mailbox_descriptor_struct *mdpara)
{
ErrStatus status = ERROR;
uint32_t i;
uint32_t cnt;
uint32_t timeout;
uint32_t mdes;
uint32_t *mdaddr;
uint32_t mdes1;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0019U), ERR_PERIPH);
} else if(NOT_CAN_MAILBOX_INDEX(index)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0019U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_VALID_POINTER(mdpara)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0019U), ERR_PARAM_POINTER);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
mdes = can_ram_address_get(can_periph, index);
mdaddr = (uint32_t *)mdpara;
/* wait mailbox data ready */
timeout = CAN_DELAY;
while(((*(uint32_t *)mdes) & MDES0_CODE(CAN_MB_RX_STATUS_BUSY)) && (timeout)) {
timeout--;
}
if((*(uint32_t *)mdes) & MDES0_CODE(CAN_MB_RX_STATUS_BUSY)) {
status = ERROR;
}
/* get mailbox descriptor 0 */
*mdaddr = *(uint32_t *)mdes;
mdes1 = *(uint32_t *)((uint32_t)(mdes + 0x04U));
mdpara->id = (mdes1 & 0x1FFFFFFFU);
mdpara->prio = (mdes1 & 0xE0000000U) >> 29U;
mdpara->data_bytes = can_payload_size_compute(*mdaddr);
cnt = (mdpara->data_bytes + 3U) / 4U;
mdes = mdes + 0x08U;
for(i = 0U; i < cnt; i++) {
*((uint32_t *)(&mdpara->data[i * 4U])) = *(uint32_t *)mdes;
mdes = mdes + 4U;
}
/* clear mailbox status */
CAN_STAT(can_periph) = STAT_MS(index);
/* unlock mailbox */
CAN_TIMER(can_periph);
/* get mailbox ID */
if(mdpara->ide) {
mdpara->id = GET_MDES1_ID_EXD(mdpara->id);
} else {
mdpara->id = GET_MDES1_ID_STD(mdpara->id);
}
/* get mailbox data */
if(mdpara->data_bytes) {
can_data_to_little_endian_swap((uint32_t *)mdpara->data, (uint32_t *)mdpara->data, mdpara->data_bytes);
}
status = SUCCESS;
}
return status;
}
/*!
\brief lock the receive mailbox (API_ID:0x001AU)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] index: mailbox index
only one parameter can be selected which is shown as below:
\arg 0 - 31
\param[out] none
\retval none
*/
void can_mailbox_receive_lock(uint32_t can_periph, uint32_t index)
{
uint32_t mdes;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x001AU), ERR_PERIPH);
} else if(NOT_CAN_MAILBOX_INDEX(index)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x001AU), ERR_PARAM_OUT_OF_RANGE);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
mdes = can_ram_address_get(can_periph, index);
REG32(mdes);
}
}
/*!
\brief unlock the receive mailbox (API_ID:0x001BU)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_mailbox_receive_unlock(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x001BU), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_TIMER(can_periph);
}
}
/*!
\brief inactive the receive mailbox (API_ID:0x001CU)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] index: mailbox index
only one parameter can be selected which is shown as below:
\arg 0 - 31
\param[out] none
\retval none
*/
void can_mailbox_receive_inactive(uint32_t can_periph, uint32_t index)
{
uint32_t mdes0;
uint32_t mdes;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x001CU), ERR_PERIPH);
} else if(NOT_CAN_MAILBOX_INDEX(index)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x001CU), ERR_PARAM_OUT_OF_RANGE);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* inactive receive mailbox */
mdes = can_ram_address_get(can_periph, index);
mdes0 = *(uint32_t *)mdes;
mdes0 &= ~CAN_MDES0_CODE;
mdes0 |= MDES0_CODE(CAN_MB_RX_STATUS_INACTIVE);
*(uint32_t *)mdes = mdes0;
}
}
/*!
\brief get mailbox code value (API_ID:0x001DU)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] index: mailbox index(0~31)
only one parameter can be selected which is shown as below:
\arg 0 - 31
\param[out] none
\retval mailbox code
*/
uint32_t can_mailbox_code_get(uint32_t can_periph, uint32_t index)
{
uint32_t code = 0U;
uint32_t mdes;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x001DU), ERR_PERIPH);
} else if(NOT_CAN_MAILBOX_INDEX(index)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x001DU), ERR_PARAM_OUT_OF_RANGE);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
mdes = can_ram_address_get(can_periph, index);
code = GET_MDES0_CODE(*(uint32_t *)mdes);
}
return code;
}
/*!
\brief configure error counter (API_ID:0x001EU)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] errcnt_struct
fd_data_phase_rx_errcnt: 0-255
fd_data_phase_tx_errcnt: 0-255
rx_errcnt: 0-255
tx_errcnt: 0-255
\retval none
*/
void can_error_counter_config(uint32_t can_periph, can_error_counter_struct *errcnt_struct)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x001EU), ERR_PERIPH);
} else if(NOT_VALID_POINTER(errcnt_struct)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x001EU), ERR_PARAM_POINTER);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_ERR0(can_periph) = ERR0_REFCNT(errcnt_struct->fd_data_phase_rx_errcnt) | ERR0_TEFCNT(errcnt_struct->fd_data_phase_tx_errcnt) | \
ERR0_RECNT(errcnt_struct->rx_errcnt) | ERR0_TECNT(errcnt_struct->tx_errcnt);
}
}
/*!
\brief get error counter (API_ID:0x001FU)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] errcnt_struct
fd_data_phase_rx_errcnt: 0-255
fd_data_phase_tx_errcnt: 0-255
rx_errcnt: 0-255
tx_errcnt: 0-255
\retval none
*/
void can_error_counter_get(uint32_t can_periph, can_error_counter_struct *errcnt_struct)
{
uint32_t reg;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x001FU), ERR_PERIPH);
} else if(NOT_VALID_POINTER(errcnt_struct)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x001FU), ERR_PARAM_POINTER);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
reg = CAN_ERR0(can_periph);
errcnt_struct->fd_data_phase_rx_errcnt = (uint8_t)GET_ERR0_REFCNT(reg);
errcnt_struct->fd_data_phase_tx_errcnt = (uint8_t)GET_ERR0_TEFCNT(reg);
errcnt_struct->rx_errcnt = (uint8_t)GET_ERR0_RECNT(reg);
errcnt_struct->tx_errcnt = (uint8_t)GET_ERR0_TECNT(reg);
}
}
/*!
\brief get error state indicator (API_ID:0x0020U)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval CAN_ERROR_STATE_ACTIVE, CAN_ERROR_STATE_PASSIVE or CAN_ERROR_STATE_BUS_OFF
*/
can_error_state_enum can_error_state_get(uint32_t can_periph)
{
can_error_state_enum ret = CAN_ERROR_STATE_ACTIVE;
uint32_t reg;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0020U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
reg = GET_ERR1_ERRSI(CAN_ERR1(can_periph));
if(reg >= (uint32_t)CAN_ERROR_STATE_BUS_OFF) {
reg = (uint32_t)CAN_ERROR_STATE_BUS_OFF;
}
ret = (can_error_state_enum)reg;
}
return ret;
}
/*!
\brief get mailbox CRC value (API_ID:0x0021U)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] crc_struct:
classical_frm_mb_number: 0 - 0x1F
classical_frm_transmitted_crc: 0 - 0x7FFF
classical_fd_frm_mb_number: 0 - 0x1F
classical_fd_frm_transmitted_crc: 0 - 0x1FFFFF
\retval none
*/
void can_crc_get(uint32_t can_periph, can_crc_struct *crc_struct)
{
uint32_t reg1, reg2;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0021U), ERR_PERIPH);
} else if(NOT_VALID_POINTER(crc_struct)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0021U), ERR_PARAM_POINTER);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
reg1 = CAN_CRCC(can_periph);
reg2 = CAN_CRCCFD(can_periph);
crc_struct->classical_frm_mb_number = GET_CRCC_ANTM(reg1);
crc_struct->classical_frm_transmitted_crc = GET_CRCC_CRCTC(reg1);
crc_struct->classical_fd_frm_mb_number = GET_CRCCFD_ANTM(reg2);
crc_struct->classical_fd_frm_transmitted_crc = GET_CRCCFD_CRCTCI(reg2);
}
}
/*!
\brief configure Pretended Networking mode parameter (API_ID:0x0022U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] pnmod_config: Pretended Networking mode config struct
timeout_int: ENABLE, DISABLE
match_int: ENABLE, DISABLE
num_matches: 1 ~ 255
match_timeout: 0 ~ 0xFFFF
frame_filter: CAN_PN_FRAME_FILTERING_ID, CAN_PN_FRAME_FILTERING_ID_DATA
CAN_PN_FRAME_FILTERING_ID_NMM, CAN_PN_FRAME_FILTERING_ID_DATA_NMM
id_filter: CAN_PN_ID_FILTERING_EXACT, CAN_PN_ID_FILTERING_GREATER
CAN_PN_ID_FILTERING_SMALLER, CAN_PN_ID_FILTERING_RANGE
data_filter: CAN_PN_DATA_FILTERING_EXACT, CAN_PN_DATA_FILTERING_GREATER
CAN_PN_DATA_FILTERING_SMALLER, CAN_PN_DATA_FILTERING_RANGE
\param[out] none
\retval none
*/
void can_pn_mode_config(uint32_t can_periph, can_pn_mode_config_struct *pnmod_config)
{
uint32_t tmp;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0022U), ERR_PERIPH);
} else if(NOT_VALID_POINTER(pnmod_config)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0022U), ERR_PARAM_POINTER);
} else if(NOT_CAN_PN_DATA_FILTER(pnmod_config->data_filter)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0022U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_PN_FRAME_FILTER(pnmod_config->frame_filter)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0022U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_PN_ID_FILTER(pnmod_config->id_filter)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0022U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_CONTROL_STATUS(pnmod_config->match_int)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0022U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_PN_MATCH_TIMEOUT(pnmod_config->match_timeout)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0022U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_PN_NUM_MATCHES(pnmod_config->num_matches)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0022U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_CONTROL_STATUS(pnmod_config->timeout_int)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0022U), ERR_PARAM_OUT_OF_RANGE);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* configure specific Pretended Networking mode settings */
tmp = CAN_PN_CTL0(can_periph);
tmp &= ~(CAN_PN_CTL0_FFT | CAN_PN_CTL0_IDFT | CAN_PN_CTL0_DATAFT |
CAN_PN_CTL0_NMM | CAN_PN_CTL0_WMIE | CAN_PN_CTL0_WTOIE);
tmp |= (uint32_t)PN_CTL0_WTOIE(pnmod_config->timeout_int) | PN_CTL0_WMIE(pnmod_config->match_int) | \
PN_CTL0_NMM(pnmod_config->num_matches) | pnmod_config->data_filter | \
pnmod_config->id_filter | pnmod_config->frame_filter;
CAN_PN_CTL0(can_periph) = tmp;
/* set timeout value */
CAN_PN_TO(can_periph) &= ~CAN_PN_TO_WTO;
CAN_PN_TO(can_periph) |= (uint32_t)PN_TO_WTO(pnmod_config->match_timeout);
/* enable Pretended Networking mode */
CAN_CTL0(can_periph) |= CAN_CTL0_PNMOD;
}
}
/*!
\brief configure Pretended Networking mode filter (API_ID:0x0023U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] expect: Pretended Networking mode struct of expected wakeup frame
rtr: SET, RESET
ide: SET, RESET
id: 0~0x7FF | CAN_STANDARD, or 0~0x1FFFFFFF | CAN_EXTENDED
dlc_high_threshold: 0~8
dlc_low_threshold: 0~8
payload[0]: 0x00000000~0xFFFFFFFF
payload[1]: 0x00000000~0xFFFFFFFF
\param[in] filter: Pretended Networking mode struct of filter data
remote_frame: SET, RESET
extended_frame: SET, RESET
id: 0~0x7FF | CAN_STANDARD, or 0~0x1FFFFFFF | CAN_EXTENDED. Used as id filter data, or id expected high threshold.
payload[0]: 0x00000000~0xFFFFFFFF. Used as payload filter data, or payload expected high threshold.
payload[1]: 0x00000000~0xFFFFFFFF. Used as payload filter data, or payload expected high threshold.
\param[out] none
\retval none
*/
void can_pn_mode_filter_config(uint32_t can_periph, can_pn_mode_filter_struct *expect, can_pn_mode_filter_struct *filter)
{
uint32_t reg, temp;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0023U), ERR_PERIPH);
} else if(NOT_VALID_POINTER(expect)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0023U), ERR_PARAM_POINTER);
} else if(NOT_VALID_POINTER(filter)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0023U), ERR_PARAM_POINTER);
} else if(NOT_CAN_FLAG_STATUS(expect->rtr)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0023U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_FLAG_STATUS(expect->ide)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0023U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_DLC_THRESHOLD(expect->dlc_high_threshold, expect->dlc_low_threshold)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0023U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_PN_ID(expect->id)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0023U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_PN_ID(filter->id)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0023U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_FLAG_STATUS(filter->rtr)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0023U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_CAN_FLAG_STATUS(filter->ide)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0023U), ERR_PARAM_OUT_OF_RANGE);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* set filter identifier 0 */
reg = 0U;
if((uint32_t)SET == expect->ide) {
reg |= CAN_PN_EID0_EIDE;
}
if((uint32_t)SET == expect->rtr) {
reg |= CAN_PN_EID0_ERTR;
}
if(CAN_STANDARD == (expect->id & BIT(31))){
reg |= (uint32_t)PN_EID0_EIDF_ELT_STD(expect->id);
}else{
reg |= (uint32_t)PN_EID0_EIDF_ELT_EXD(expect->id);
}
CAN_PN_EID0(can_periph) = reg;
temp = CAN_PN_CTL0(can_periph);
reg = 0U;
/* ID field 1 is used when ID filtering type is EXACT or RANGE */
if(((temp & CAN_PN_CTL0_IDFT) == CAN_PN_ID_FILTERING_EXACT) || ((temp & CAN_PN_CTL0_IDFT) == CAN_PN_ID_FILTERING_RANGE)) {
if(CAN_STANDARD == (filter->id & BIT(31))){
reg |= (uint32_t)PN_IFEID1_IDEFD_STD(filter->id);
}else{
reg |= (uint32_t)PN_IFEID1_IDEFD_EXD(filter->id);
}
}
if((uint32_t)SET == filter->ide) {
reg |= CAN_PN_IFEID1_IDEFD;
}
if((uint32_t)SET == filter->rtr) {
reg |= CAN_PN_IFEID1_RTRFD;
}
/* set filter identifier 1 */
CAN_PN_IFEID1(can_periph) = reg;
/* data field is used when frame filtering type is not MATCH or MATCH NMM */
if(((temp & CAN_PN_CTL0_FFT) == CAN_PN_FRAME_FILTERING_ID_DATA) ||
((temp & CAN_PN_CTL0_FFT) == CAN_PN_FRAME_FILTERING_ID_DATA_NMM)) {
/* set filter data payload 0 */
CAN_PN_EDLC(can_periph) = PN_EDLC_DLCEHT(expect->dlc_high_threshold) | PN_EDLC_DLCELT(expect->dlc_low_threshold);
CAN_PN_EDL0(can_periph) = ((expect->payload[0] << 24U) & CAN_PN_EDL0_DB0ELT) |
((expect->payload[0] << 8U) & CAN_PN_EDL0_DB1ELT) |
((expect->payload[0] >> 8U) & CAN_PN_EDL0_DB2ELT) |
((expect->payload[0] >> 24U) & CAN_PN_EDL0_DB3ELT);
CAN_PN_EDL1(can_periph) = ((expect->payload[1] << 24U) & CAN_PN_EDL1_DB4ELT) |
((expect->payload[1] << 8U) & CAN_PN_EDL1_DB5ELT) |
((expect->payload[1] >> 8U) & CAN_PN_EDL1_DB6ELT) |
((expect->payload[1] >> 24U) & CAN_PN_EDL1_DB7ELT);
/* data field 1 is used when data filtering type is EXACT or RANGE */
if(((temp & CAN_PN_CTL0_DATAFT) == CAN_PN_DATA_FILTERING_EXACT)
|| ((temp & CAN_PN_CTL0_DATAFT) == CAN_PN_DATA_FILTERING_RANGE)) {
/* set filter data payload 1 */
CAN_PN_DF0EDH0(can_periph) = ((filter->payload[0] << 24U) & CAN_PN_DF0EDH0_DB0FD_EHT) |
((filter->payload[0] << 8U) & CAN_PN_DF0EDH0_DB1FD_EHT) |
((filter->payload[0] >> 8U) & CAN_PN_DF0EDH0_DB2FD_EHT) |
((filter->payload[0] >> 24U) & CAN_PN_DF0EDH0_DB3FD_EHT);
CAN_PN_DF1EDH1(can_periph) = ((filter->payload[1] << 24U) & CAN_PN_DF1EDH1_DB4FD_EHT) |
((filter->payload[1] << 8U) & CAN_PN_DF1EDH1_DB5FD_EHT) |
((filter->payload[1] >> 8U) & CAN_PN_DF1EDH1_DB6FD_EHT) |
((filter->payload[1] >> 24U) & CAN_PN_DF1EDH1_DB7FD_EHT);
}
}
}
}
/*!
\brief get matching message counter of Pretended Networking mode (API_ID:0x0024U)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval 0~255 or -1
*/
int32_t can_pn_mode_num_of_match_get(uint32_t can_periph)
{
int32_t ret = -1;
uint32_t reg;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0024U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
reg = CAN_PN_STAT(can_periph);
if(0U != (reg & CAN_PN_STAT_MMCNTS)) {
ret = (int32_t)(uint32_t)GET_PN_STAT_MMCNT(reg);
} else {
ret = -1;
}
}
return ret;
}
/*!
\brief get matching message (API_ID:0x0025U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] index: Pretended Networking mailbox index
only one parameter can be selected which is shown as below:
\arg 0 - 31
\param[out] mdpara: wakeup message information
\retval none
*/
void can_pn_mode_data_read(uint32_t can_periph, uint32_t index, can_mailbox_descriptor_struct *mdpara)
{
uint32_t *mdaddr;
uint32_t pnram;
uint32_t pnram1 = 0U;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0025U), ERR_PERIPH);
} else if(NOT_CAN_PN_MB_INDEX(index)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0025U), ERR_PARAM_OUT_OF_RANGE);
} else if(NOT_VALID_POINTER(mdpara)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0025U), ERR_PARAM_POINTER);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
mdaddr = (uint32_t *)mdpara;
pnram = (uint32_t)(CAN_PN_RAM(can_periph) + index * 16U);
*mdaddr = *(uint32_t *)pnram;
pnram1 = *(uint32_t *)((uint32_t)(pnram + 0x04U));
mdpara->id = (pnram1 & 0x1FFFFFFFU);
mdpara->prio = (pnram1 & 0xE0000000U) >> 29U;
/* get mailbox ID */
if(0U != mdpara->ide) {
mdpara->id = GET_MDES1_ID_EXD(mdpara->id);
} else {
mdpara->id = GET_MDES1_ID_STD(mdpara->id);
}
mdpara->data_bytes = mdpara->dlc;
/* remote frame */
if(0U != ((*mdaddr) & CAN_PN_RWMXCS_RRTR)){
mdpara->data_bytes = 0U;
}else{
/* classical frame */
if(mdpara->dlc <= 8U) {
mdpara->data_bytes = mdpara->dlc;
}else{
mdpara->data_bytes = 8U;
}
}
if(mdpara->data_bytes) {
can_data_to_little_endian_swap((uint32_t *)mdpara->data, (uint32_t *)((uint32_t)(pnram + 0x08U)), mdpara->data_bytes);
}
}
}
/*!
\brief enable self reception (API_ID:0x0026U)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_self_reception_enable(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0026U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_CTL0(can_periph) &= ~CAN_CTL0_SRDIS;
}
}
/*!
\brief disable self reception (API_ID:0x0027U)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_self_reception_disable(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0027U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_CTL0(can_periph) |= CAN_CTL0_SRDIS;
}
}
/*!
\brief enable transmit abort (API_ID:0x0028U)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_transmit_abort_enable(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0028U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_CTL0(can_periph) |= CAN_CTL0_MST;
}
}
/*!
\brief disable transmit abort (API_ID:0x0029U)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_transmit_abort_disable(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0029U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_CTL0(can_periph) &= ~CAN_CTL0_MST;
}
}
/*!
\brief enable auto bus off recovery mode (API_ID:0x002AU)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_auto_busoff_recovery_enable(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x002AU), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_CTL1(can_periph) &= ~CAN_CTL1_ABORDIS;
}
}
/*!
\brief disable auto bus off recovery mode (API_ID:0x002BU)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_auto_busoff_recovery_disable(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x002BU), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_CTL1(can_periph) |= CAN_CTL1_ABORDIS;
}
}
/*!
\brief enable time sync mode (API_ID:0x002CU)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_time_sync_enable(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x002CU), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_CTL1(can_periph) |= CAN_CTL1_TSYNC;
}
}
/*!
\brief disable time sync mode (API_ID:0x002DU)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_time_sync_disable(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x002DU), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_CTL1(can_periph) &= ~CAN_CTL1_TSYNC;
}
}
/*!
\brief enable edge filter mode (API_ID:0x002EU)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_edge_filter_mode_enable(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x002EU), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_CTL2(can_periph) &= ~CAN_CTL2_EFDIS;
}
}
/*!
\brief disable edge filter mode (API_ID:0x002FU)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_edge_filter_mode_disable(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x002FU), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_CTL2(can_periph) |= CAN_CTL2_EFDIS;
}
}
/*!
\brief enable protocol exception detection mode (API_ID:0x0030U)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_ped_mode_enable(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0030U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_CTL2(can_periph) |= CAN_CTL2_PREEN;
}
}
/*!
\brief disable protocol exception detection mode (API_ID:0x0031U)
\param[in] can_periph: CANx(x=0,1,2)
\param[out] none
\retval none
*/
void can_ped_mode_disable(uint32_t can_periph)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0031U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_CTL2(can_periph) &= ~CAN_CTL2_PREEN;
}
}
/*!
\brief configure arbitration delay bits (API_ID:0x0032U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] delay_bits: delay bits
only one parameter can be selected which is shown as below:
\arg 0 - 31
\param[out] none
\retval none
*/
void can_arbitration_delay_bits_config(uint32_t can_periph, uint32_t delay_bits)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0032U), ERR_PERIPH);
} else if(NOT_CAN_DELAY_BITS(delay_bits)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0032U), ERR_PARAM_OUT_OF_RANGE);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_CTL2(can_periph) &= ~CAN_CTL2_ASD;
CAN_CTL2(can_periph) |= (uint32_t)CTL2_ASD(delay_bits);
}
}
/*!
\brief configure bit sampling mode (API_ID:0x0033U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] sampling_mode: bit sampling mode
only one parameter can be selected which is shown as below:
\arg CAN_BSP_MODE_ONE_SAMPLE: one sample for received bit
\arg CAN_BSP_MODE_THREE_SAMPLES: three samples for received bit
\param[out] none
\retval none
*/
void can_bsp_mode_config(uint32_t can_periph, uint32_t sampling_mode)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0033U), ERR_PERIPH);
} else if(NOT_CAN_BSP_MODE(sampling_mode)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0033U), ERR_PARAM_OUT_OF_RANGE);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
if(CAN_BSP_MODE_ONE_SAMPLE == sampling_mode) {
CAN_CTL1(can_periph) &= ~CAN_CTL1_BSPMOD;
} else {
CAN_CTL1(can_periph) |= CAN_CTL1_BSPMOD;
}
}
}
/*!
\brief get CAN flag (API_ID:0x0034U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] flag: CAN flags, refer to can_flag_enum
only one parameter can be selected which is shown as below:
\arg CAN_FLAG_CAN_PN: Pretended Networking state flag
\arg CAN_FLAG_SOFT_RST: software reset flag
\arg CAN_FLAG_ERR_SUMMARY: error summary flag
\arg CAN_FLAG_BUSOFF: bus off flag
\arg CAN_FLAG_RECEIVING: receiving state flag
\arg CAN_FLAG_TRANSMITTING: transmitting state flag
\arg CAN_FLAG_IDLE: IDLE state flag
\arg CAN_FLAG_RX_WARNING: receive warning flag
\arg CAN_FLAG_TX_WARNING: transmit warning flag
\arg CAN_FLAG_STUFF_ERR: stuff error flag
\arg CAN_FLAG_FORM_ERR: form error flag
\arg CAN_FLAG_CRC_ERR: CRC error flag
\arg CAN_FLAG_ACK_ERR: ACK error flag
\arg CAN_FLAG_BIT_DOMINANT_ERR: bit dominant error flag
\arg CAN_FLAG_BIT_RECESSIVE_ERR: bit recessive error flag
\arg CAN_FLAG_SYNC_ERR: synchronization flag
\arg CAN_FLAG_BUSOFF_RECOVERY: bus off recovery flag
\arg CAN_FLAG_ERR_SUMMARY_FD: fd error summary flag
\arg CAN_FLAG_ERR_OVERRUN: error overrun flag
\arg CAN_FLAG_STUFF_ERR_FD: stuff error in FD data phase flag
\arg CAN_FLAG_FORM_ERR_FD: form error in FD data phase flag
\arg CAN_FLAG_CRC_ERR_FD: CRC error in FD data phase flag
\arg CAN_FLAG_BIT_DOMINANT_ERR_FD: bit dominant error in FD data phase flag
\arg CAN_FLAG_BIT_RECESSIVE_ERR_FD: bit recessive error in FD data phase flag
\arg CAN_FLAG_MBx(x=0~31): mailbox x flag
\arg CAN_FLAG_FIFO_AVAILABLE: fifo available flag
\arg CAN_FLAG_FIFO_WARNING: fifo warning flag
\arg CAN_FLAG_FIFO_OVERFLOW: fifo overflow flag
\arg CAN_FLAG_WAKEUP_MATCH: Pretended Networking match flag
\arg CAN_FLAG_WAKEUP_TIMEOUT: Pretended Networking timeout wakeup flag
\arg CAN_FLAG_TDC_OUT_OF_RANGE: transmitter delay is out of compensation range flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus can_flag_get(uint32_t can_periph, can_flag_enum flag)
{
FlagStatus status = RESET;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0034U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
if(CAN_REG_VAL(can_periph, flag) & BIT(CAN_BIT_POS(flag))) {
status = SET;
} else {
status = RESET;
}
}
return status;
}
/*!
\brief clear CAN flag (API_ID:0x0035U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] flag: CAN flags, refer to can_flag_enum
only one parameter can be selected which is shown as below:
\arg CAN_FLAG_ERR_SUMMARY: error summary flag
\arg CAN_FLAG_BUSOFF: bus off flag
\arg CAN_FLAG_BUSOFF_RECOVERY: bus off recovery flag
\arg CAN_FLAG_ERR_SUMMARY_FD: fd error summary flag
\arg CAN_FLAG_ERR_OVERRUN: error overrun flag
\arg CAN_FLAG_MBx(x=0~31): mailbox x flag
\arg CAN_FLAG_FIFO_AVAILABLE: fifo available flag
\arg CAN_FLAG_FIFO_WARNING: fifo warning flag
\arg CAN_FLAG_FIFO_OVERFLOW: fifo overflow flag
\arg CAN_FLAG_WAKEUP_MATCH: Pretended Networking match flag
\arg CAN_FLAG_WAKEUP_TIMEOUT: Pretended Networking timeout wakeup flag
\arg CAN_FLAG_TDC_OUT_OF_RANGE: transmitter delay is out of compensation range flag
\param[out] none
\retval none
*/
void can_flag_clear(uint32_t can_periph, can_flag_enum flag)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0035U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
if(CAN_FLAG_TDC_OUT_OF_RANGE == flag) {
CAN_FDCTL(can_periph) |= CAN_FDCTL_TDCS;
} else {
CAN_REG_VAL(can_periph, flag) = BIT(CAN_BIT_POS(flag));
}
}
}
/*!
\brief enable CAN interrupt (API_ID:0x0036U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] interrupt: CAN interrupt, refer to can_interrupt_enum
only one parameter can be selected which is shown as below:
\arg CAN_INT_ERR_SUMMARY: error interrupt
\arg CAN_INT_RX_WARNING: receive warning interrupt
\arg CAN_INT_TX_WARNING: transmit warning interrupt
\arg CAN_INT_BUSOFF: bus off interrupt
\arg CAN_INT_BUSOFF_RECOVERY: bus off recovery interrupt
\arg CAN_INT_ERR_SUMMARY_FD: fd error interrupt
\arg CAN_INT_MBx(x=0~31): mailbox x interrupt
\arg CAN_INT_FIFO_AVAILABLE: fifo available interrupt
\arg CAN_INT_FIFO_WARNING: fifo warning interrupt
\arg CAN_INT_FIFO_OVERFLOW: fifo overflow interrupt
\arg CAN_INT_WAKEUP_MATCH: Pretended Networking match interrupt
\arg CAN_INT_WAKEUP_TIMEOUT: Pretended Networking timeout wakeup interrupt
\param[out] none
\retval ERROR or SUCCESS
*/
ErrStatus can_interrupt_enable(uint32_t can_periph, can_interrupt_enum interrupt)
{
can_operation_modes_enum mode;
ErrStatus status = ERROR;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0036U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* enable receive or transmit warning error interrupt should enable error warning in CTL0 register */
if((CAN_INT_RX_WARNING == interrupt) || (CAN_INT_TX_WARNING == interrupt)) {
mode = can_operation_mode_get(can_periph);
/* in INACTIVE mode */
if(CAN_INACTIVE_MODE == mode){
CAN_CTL0(can_periph) |= CAN_CTL0_WERREN;
}else{
status = can_operation_mode_enter(can_periph, CAN_INACTIVE_MODE);
if(SUCCESS == status){
CAN_CTL0(can_periph) |= CAN_CTL0_WERREN;
status = can_operation_mode_enter(can_periph, mode);
}
}
}
CAN_REG_VAL(can_periph, interrupt) |= BIT(CAN_BIT_POS(interrupt));
}
return status;
}
/*!
\brief disable CAN interrupt (API_ID:0x0037U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] interrupt: CAN interrupt, refer to can_interrupt_enum
only one parameter can be selected which is shown as below:
\arg CAN_INT_ERR_SUMMARY: error interrupt
\arg CAN_INT_RX_WARNING: receive warning interrupt
\arg CAN_INT_TX_WARNING: transmit warning interrupt
\arg CAN_INT_BUSOFF: bus off interrupt
\arg CAN_INT_BUSOFF_RECOVERY: bus off recovery interrupt
\arg CAN_INT_ERR_SUMMARY_FD: fd error interrupt
\arg CAN_INT_MBx(x=0~31): mailbox x interrupt
\arg CAN_INT_FIFO_AVAILABLE: fifo available interrupt
\arg CAN_INT_FIFO_WARNING: fifo warning interrupt
\arg CAN_INT_FIFO_OVERFLOW: fifo overflow interrupt
\arg CAN_INT_WAKEUP_MATCH: Pretended Networking match interrupt
\arg CAN_INT_WAKEUP_TIMEOUT: Pretended Networking timeout wakeup interrupt
\param[out] none
\retval ERROR or SUCCESS
*/
ErrStatus can_interrupt_disable(uint32_t can_periph, can_interrupt_enum interrupt)
{
can_operation_modes_enum mode;
ErrStatus status = ERROR;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0037U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
/* disable receive or transmit warning error interrupt should enable error warning in CTL0 register */
if((0U == (CAN_CTL0(can_periph) & CAN_CTL0_WERREN)) && ((CAN_INT_RX_WARNING == interrupt) || (CAN_INT_TX_WARNING == interrupt))) {
mode = can_operation_mode_get(can_periph);
/* in INACTIVE mode */
if(CAN_INACTIVE_MODE == mode){
CAN_CTL0(can_periph) |= CAN_CTL0_WERREN;
}else{
status = can_operation_mode_enter(can_periph, CAN_INACTIVE_MODE);
if(SUCCESS == status){
CAN_CTL0(can_periph) |= CAN_CTL0_WERREN;
status = can_operation_mode_enter(can_periph, mode);
}
}
}
CAN_REG_VAL(can_periph, interrupt) &= ~BIT(CAN_BIT_POS(interrupt));
}
return status;
}
/*!
\brief get CAN interrupt flag (API_ID:0x0038U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] int_flag: CAN interrupt flags, refer to can_interrupt_flag_enum
only one parameter can be selected which is shown as below:
\arg CAN_INT_FLAG_ERR_SUMMARY: error summary interrupt flag
\arg CAN_INT_FLAG_BUSOFF: bus off interrupt flag
\arg CAN_INT_FLAG_RX_WARNING: receive warning interrupt flag
\arg CAN_INT_FLAG_TX_WARNING: transmit warning interrupt flag
\arg CAN_INT_FLAG_BUSOFF_RECOVERY: bus off recovery interrupt flag
\arg CAN_INT_FLAG_ERR_SUMMARY_FD: fd error summary interrupt flag
\arg CAN_INT_FLAG_MBx(x=0~31): mailbox x interrupt flag
\arg CAN_INT_FLAG_FIFO_AVAILABLE: fifo available interrupt flag
\arg CAN_INT_FLAG_FIFO_WARNING: fifo warning interrupt flag
\arg CAN_INT_FLAG_FIFO_OVERFLOW: fifo overflow interrupt flag
\arg CAN_INT_FLAG_WAKEUP_MATCH: Pretended Networking match interrupt flag
\arg CAN_INT_FLAG_WAKEUP_TIMEOUT: Pretended Networking timeout wakeup interrupt flag
\param[out] none
\retval FlagStatus: SET or RESET
*/
FlagStatus can_interrupt_flag_get(uint32_t can_periph, can_interrupt_flag_enum int_flag)
{
FlagStatus status = RESET;
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0038U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
if(CAN_REG_VAL(can_periph, int_flag) & BIT(CAN_BIT_POS(int_flag))) {
status = SET;
} else {
status = RESET;
}
}
return status;
}
/*!
\brief clear CAN interrupt flag (API_ID:0x0039U)
\param[in] can_periph: CANx(x=0,1,2)
\param[in] int_flag: CAN interrupt flags, refer to can_interrupt_flag_enum
only one parameter can be selected which is shown as below:
\arg CAN_INT_FLAG_ERR_SUMMARY: error summary interrupt flag
\arg CAN_INT_FLAG_BUSOFF: bus off interrupt flag
\arg CAN_INT_FLAG_RX_WARNING: receive warning interrupt flag
\arg CAN_INT_FLAG_TX_WARNING: transmit warning interrupt flag
\arg CAN_INT_FLAG_BUSOFF_RECOVERY: bus off recovery interrupt flag
\arg CAN_INT_FLAG_ERR_SUMMARY_FD: fd error summary interrupt flag
\arg CAN_INT_FLAG_MBx(x=0~31): mailbox x interrupt flag
\arg CAN_INT_FLAG_FIFO_AVAILABLE: fifo available interrupt flag
\arg CAN_INT_FLAG_FIFO_WARNING: fifo warning interrupt flag
\arg CAN_INT_FLAG_FIFO_OVERFLOW: fifo overflow interrupt flag
\arg CAN_INT_FLAG_WAKEUP_MATCH: Pretended Networking match interrupt flag
\arg CAN_INT_FLAG_WAKEUP_TIMEOUT: Pretended Networking timeout wakeup interrupt flag
\param[out] none
\retval none
*/
void can_interrupt_flag_clear(uint32_t can_periph, can_interrupt_flag_enum int_flag)
{
#ifdef FW_DEBUG_ERR_REPORT
if(NOT_CAN_PERIPH(can_periph)) {
fw_debug_report_err(CAN_MODULE_ID, API_ID(0x0039U), ERR_PERIPH);
} else
#endif /* FW_DEBUG_ERR_REPORT */
{
CAN_REG_VAL(can_periph, int_flag) = BIT(CAN_BIT_POS(int_flag));
}
}
/*!
\brief computes the maximum payload size (in bytes), given a dlc
\param[in] mdes0: mailbox descriptor 0 data
\param[out] none
\retval payload_size
*/
static uint32_t can_payload_size_compute(uint32_t mdes0)
{
uint8_t ret = 0U;
uint32_t dlc_value = GET_MDES0_DLC(mdes0);
/* remote frame */
if(0U != (mdes0 & CAN_MDES0_RTR)){
ret = 0U;
}else{
/* FD frame */
if(0U != (mdes0 & CAN_MDES0_FDF)){
if(dlc_value <= 15U) {
ret = dlc_to_databytes[dlc_value];
}
/* classical frame */
}else{
if(dlc_value <= 8U) {
ret = (uint8_t)dlc_value;
}else{
ret = 8U;
}
}
}
return (uint32_t)ret;
}
/*!
\brief swap data to little endian
\param[in] src: data source address
\param[in] len: data length be byte
\param[out] dest: data destination address
\retval none
*/
static void can_data_to_little_endian_swap(uint32_t dest[], uint32_t src[], uint32_t len)
{
volatile uint32_t i = 0U;
uint32_t cnt;
uint32_t temp_src = 0U;
/* get the word length of the data */
cnt = (len + 3U) / 4U;
/* change each word from big endian to little endian */
for(i = 0U; i < cnt; i++) {
temp_src = src[i];
dest[i] = ((uint32_t)(temp_src >> 24U) & 0x000000FFU) |
((uint32_t)(temp_src >> 8U) & 0x0000FF00U) |
((uint32_t)(temp_src << 8U) & 0x00FF0000U) |
((uint32_t)(temp_src << 24U) & 0xFF000000U);
}
cnt = len % 4U;
if(cnt) {
dest[i - 1U] &= ((uint32_t)1U << (cnt * 8U)) - 1U;
}
}
/*!
\brief swap data to big endian
\param[in] src: data source address
\param[in] len: data length be byte
\param[out] dest: data destination address
\retval none
*/
static void can_data_to_big_endian_swap(uint32_t dest[], uint32_t src[], uint32_t len)
{
volatile uint32_t i = 0U;
uint32_t cnt;
uint32_t temp_src = 0U;
/* get the word length of the data */
cnt = (len + 3U) / 4U;
for(i = 0U; i < cnt; i++) {
/* change each word from little endian to big endian */
temp_src = src[i];
dest[i] = ((uint32_t)(temp_src >> 24U) & 0x000000FFU) |
((uint32_t)(temp_src >> 8U) & 0x0000FF00U) |
((uint32_t)(temp_src << 8U) & 0x00FF0000U) |
((uint32_t)(temp_src << 24U) & 0xFF000000U);
}
cnt = len % 4U;
if(cnt) {
dest[i - 1U] &= ~(((uint32_t)1U << ((4U - cnt) * 8U)) - 1U);
}
}
/*!
\brief computes the DLC field value, given a payload size (in bytes)
\param[in] payload_size: payload size
\param[out] none
\retval DLC value
*/
static uint32_t can_dlc_value_compute(uint32_t payload_size)
{
uint32_t ret = 8U;
if(payload_size <= 8U) {
ret = payload_size;
} else if(payload_size <= 24U) {
ret = (payload_size - 9U) / 4U + 9U;
} else if(payload_size <= 64U) {
ret = (payload_size - 17U) / 16U + 13U;
} else {
ret = 8U;
}
return ret;
}