Files
esp-idf/components/hal/twai_hal_ctufd.c

200 lines
8.4 KiB
C

/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <sys/param.h>
#include "hal/twai_hal.h"
#include "hal/twaifd_ll.h"
size_t twai_hal_get_mem_requirment(void) {
return sizeof(twai_hal_context_t);
}
bool twai_hal_init(twai_hal_context_t *hal_ctx, const twai_hal_config_t *config)
{
hal_ctx->dev = TWAIFD_LL_GET_HW(config->controller_id);
hal_ctx->retry_cnt = config->retry_cnt;
hal_ctx->enable_self_test = config->enable_self_test;
hal_ctx->enable_loopback = config->enable_loopback;
hal_ctx->enable_listen_only = config->enable_listen_only;
twaifd_ll_reset(hal_ctx->dev);
twaifd_ll_enable_hw(hal_ctx->dev, false); //mode should be changed under disabled
twaifd_ll_set_mode(hal_ctx->dev, config->enable_listen_only, config->enable_self_test, config->enable_loopback);
twaifd_ll_set_tx_retrans_limit(hal_ctx->dev, config->retry_cnt);
twaifd_ll_filter_block_rtr(hal_ctx->dev, config->no_receive_rtr);
twaifd_ll_enable_filter_mode(hal_ctx->dev, true); // each filter still has independent enable control
twaifd_ll_enable_fd_mode(hal_ctx->dev, true); // fd frame still controlled by `header.fdf`
twaifd_ll_enable_rxfifo_auto_incrase(hal_ctx->dev, true);
twaifd_ll_enable_intr(hal_ctx->dev, config->intr_mask);
return true;
}
void twai_hal_deinit(twai_hal_context_t *hal_ctx)
{
twaifd_ll_set_operate_cmd(hal_ctx->dev, TWAIFD_LL_HW_CMD_RST_TX_CNT);
twaifd_ll_set_operate_cmd(hal_ctx->dev, TWAIFD_LL_HW_CMD_RST_RX_CNT);
memset(hal_ctx, 0, sizeof(twai_hal_context_t));
hal_ctx->dev = NULL;
}
bool twai_hal_check_brp_validation(twai_hal_context_t *hal_ctx, uint32_t brp)
{
return twaifd_ll_check_brp_validation(brp);
}
void twai_hal_configure_timing(twai_hal_context_t *hal_ctx, const twai_timing_config_t *t_config)
{
twaifd_ll_set_nominal_bitrate(hal_ctx->dev, t_config);
if (t_config->ssp_offset) {
// the underlying hardware calculates the ssp in system clock cycles, not in quanta time
twaifd_ll_config_secondary_sample_point(hal_ctx->dev, TWAIFD_LL_SSP_SRC_MEAS_OFFSET, t_config->ssp_offset * t_config->brp);
}
}
void twai_hal_configure_timing_fd(twai_hal_context_t *hal_ctx, const twai_timing_config_t *t_config_fd)
{
twaifd_ll_set_fd_bitrate(hal_ctx->dev, t_config_fd);
if (t_config_fd->ssp_offset) {
// the underlying hardware calculates the ssp in system clock cycles, not in quanta time
twaifd_ll_config_secondary_sample_point(hal_ctx->dev, TWAIFD_LL_SSP_SRC_MEAS_OFFSET, t_config_fd->ssp_offset * t_config_fd->brp);
}
}
void twai_hal_configure_filter(twai_hal_context_t *hal_ctx, uint8_t filter_id, const twai_mask_filter_config_t *f_config)
{
uint32_t id = f_config->num_of_ids ? f_config->id_list[0] : f_config->id;
bool full_open = (f_config->mask == 0) && (id == 0);
bool full_close = (f_config->mask == UINT32_MAX) && (id == UINT32_MAX);
bool cc_ext = full_open || (!full_close && f_config->is_ext && !f_config->no_classic);
bool fd_ext = full_open || (!full_close && f_config->is_ext && !f_config->no_fd);
bool cc_std = full_open || (!full_close && !f_config->is_ext && !f_config->no_classic);
bool fd_std = full_open || (!full_close && !f_config->is_ext && !f_config->no_fd);
twaifd_ll_filter_enable_basic_ext(hal_ctx->dev, filter_id, false, cc_ext);
twaifd_ll_filter_enable_fd_ext(hal_ctx->dev, filter_id, false, fd_ext);
twaifd_ll_filter_enable_basic_std(hal_ctx->dev, filter_id, false, cc_std);
twaifd_ll_filter_enable_fd_std(hal_ctx->dev, filter_id, false, fd_std);
twaifd_ll_filter_set_id_mask(hal_ctx->dev, filter_id, f_config->is_ext, id, f_config->mask);
}
void twai_hal_configure_range_filter(twai_hal_context_t *hal_ctx, uint8_t filter_id, const twai_range_filter_config_t *f_config)
{
bool cc_ext = f_config->is_ext && !f_config->no_classic;
bool fd_ext = f_config->is_ext && !f_config->no_fd;
bool cc_std = !f_config->is_ext && !f_config->no_classic;
bool fd_std = !f_config->is_ext && !f_config->no_fd;
twaifd_ll_filter_enable_basic_ext(hal_ctx->dev, filter_id, true, cc_ext);
twaifd_ll_filter_enable_fd_ext(hal_ctx->dev, filter_id, true, fd_ext);
twaifd_ll_filter_enable_basic_std(hal_ctx->dev, filter_id, true, cc_std);
twaifd_ll_filter_enable_fd_std(hal_ctx->dev, filter_id, true, fd_std);
twaifd_ll_filter_set_range(hal_ctx->dev, 0, f_config->is_ext, f_config->range_high, f_config->range_low);
}
void twai_hal_start(twai_hal_context_t *hal_ctx)
{
twaifd_ll_enable_hw(hal_ctx->dev, true);
twaifd_ll_waiting_state_change(hal_ctx->dev);
}
void twai_hal_stop(twai_hal_context_t *hal_ctx)
{
twaifd_ll_enable_hw(hal_ctx->dev, false);
}
twai_error_state_t twai_hal_get_err_state(twai_hal_context_t *hal_ctx)
{
return twaifd_ll_get_fault_state(hal_ctx->dev);
}
void twai_hal_start_bus_recovery(twai_hal_context_t *hal_ctx)
{
twaifd_ll_set_operate_cmd(hal_ctx->dev, TWAIFD_LL_HW_CMD_RST_ERR_CNT);
}
// /* ------------------------------------ IRAM Content ------------------------------------ */
void twai_hal_format_frame(const twai_hal_trans_desc_t *trans_desc, twai_hal_frame_t *frame)
{
const twai_frame_header_t *header = trans_desc->frame.header;
int final_dlc = (header->dlc) ? header->dlc : twaifd_len2dlc(trans_desc->frame.buffer_len);
twaifd_ll_format_frame_header(header, final_dlc, frame);
if (!header->rtr) {
int data_len = (header->dlc) ? twaifd_dlc2len(header->dlc) : trans_desc->frame.buffer_len;
data_len = (header->fdf) ? MIN(data_len, TWAIFD_FRAME_MAX_LEN) : MIN(data_len, TWAI_FRAME_MAX_LEN);
twaifd_ll_format_frame_data(trans_desc->frame.buffer, data_len, frame);
}
}
void twai_hal_parse_frame(const twai_hal_frame_t *frame, twai_frame_header_t *header, uint8_t *buffer, uint8_t buffer_len)
{
twaifd_ll_parse_frame_header(frame, header);
if (!header->rtr) {
int frame_data_len = twaifd_dlc2len(header->dlc);
// limit data_len for twai classic non-iso mode.
frame_data_len = (header->fdf) ? MIN(frame_data_len, TWAIFD_FRAME_MAX_LEN) : MIN(frame_data_len, TWAI_FRAME_MAX_LEN);
uint8_t final_len = MIN(frame_data_len, buffer_len);
twaifd_ll_parse_frame_data(frame, buffer, final_len);
}
}
void twai_hal_set_tx_buffer_and_transmit(twai_hal_context_t *hal_ctx, twai_hal_frame_t *tx_frame, uint8_t buffer_idx)
{
twaifd_ll_mount_tx_buffer(hal_ctx->dev, tx_frame, buffer_idx);
twaifd_ll_set_tx_cmd(hal_ctx->dev, buffer_idx, TWAIFD_LL_TX_CMD_READY);
}
uint32_t twai_hal_get_rx_msg_count(twai_hal_context_t *hal_ctx)
{
return twaifd_ll_get_rx_frame_count(hal_ctx->dev);
}
bool twai_hal_read_rx_fifo(twai_hal_context_t *hal_ctx, twai_hal_frame_t *rx_frame)
{
twaifd_ll_get_rx_frame(hal_ctx->dev, rx_frame);
return true;
}
uint32_t twai_hal_get_events(twai_hal_context_t *hal_ctx)
{
uint32_t hal_events = 0;
uint32_t int_stat = twaifd_ll_get_intr_status(hal_ctx->dev);
uint32_t tec = twaifd_ll_get_tec(hal_ctx->dev);
uint32_t rec = twaifd_ll_get_rec(hal_ctx->dev);
twaifd_ll_clr_intr_status(hal_ctx->dev, int_stat);
if (int_stat & (TWAIFD_LL_INTR_TX_DONE)) {
hal_events |= TWAI_HAL_EVENT_TX_BUFF_FREE;
if (int_stat & TWAIFD_LL_INTR_TX_SUCCESS) {
hal_events |= TWAI_HAL_EVENT_TX_SUCCESS;
}
}
if (int_stat & TWAIFD_LL_INTR_RX_NOT_EMPTY) {
hal_events |= TWAI_HAL_EVENT_RX_BUFF_FRAME;
}
if (int_stat & (TWAIFD_LL_INTR_BUS_ERR | TWAIFD_LL_INTR_DATA_OVERRUN | TWAIFD_LL_INTR_RX_FULL)) {
hal_ctx->errors = twaifd_ll_get_err_reason(hal_ctx->dev);
hal_events |= TWAI_HAL_EVENT_BUS_ERR;
}
if (int_stat & TWAIFD_LL_INTR_ARBI_LOST) {
hal_events |= TWAI_HAL_EVENT_ARB_LOST;
}
if (int_stat & (TWAIFD_LL_INTR_FSM_CHANGE | TWAIFD_LL_INTR_ERR_WARN)) {
twai_error_state_t curr_sta = twaifd_ll_get_fault_state(hal_ctx->dev);
uint32_t limit = twaifd_ll_get_err_warn_limit(hal_ctx->dev);
if (curr_sta == TWAI_ERROR_BUS_OFF) {
hal_events |= TWAI_HAL_EVENT_BUS_OFF;
} else if (curr_sta == TWAI_ERROR_PASSIVE) {
hal_events |= TWAI_HAL_EVENT_ERROR_PASSIVE;
} else {
if ((tec >= limit) || (rec >= limit)) {
hal_events |= TWAI_HAL_EVENT_ERROR_WARNING;
} else {
hal_events |= TWAI_HAL_EVENT_ERROR_ACTIVE;
}
}
}
return hal_events;
}