mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-26 18:14:11 +00:00
200 lines
8.4 KiB
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;
|
|
}
|