mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-26 18:14:11 +00:00
161 lines
6.7 KiB
C
161 lines
6.7 KiB
C
/*
|
|
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <sys/param.h>
|
|
#include "esp_twai.h"
|
|
#include "esp_private/twai_interface.h"
|
|
#include "esp_private/twai_utils.h"
|
|
#include "twai_private.h"
|
|
|
|
/**
|
|
* @brief Calculate twai timing param by giving bitrate and hardware limit.
|
|
*
|
|
* +---------------------------------------------------+
|
|
* | bit time in time quanta (total_tq) |
|
|
* +--------------+----------+------------+------------+
|
|
* | sync_seg | prop_seg | phase_seg1 | phase_seg2 |
|
|
* +--------------+----------+------------+------------+
|
|
* | 1 | tseg1 | tseg2 |
|
|
* +--------------+----------+------------+------------+
|
|
* | tseg2/2 ^ ^
|
|
* sjw sample_point
|
|
*/
|
|
uint32_t twai_node_timing_calc_param(const uint32_t source_freq, const twai_timing_basic_config_t *in_param, const twai_timing_constraint_t *hw_limit, twai_timing_advanced_config_t *out_param)
|
|
{
|
|
uint32_t total_div = (source_freq + in_param->bitrate / 2) / in_param->bitrate;
|
|
uint32_t pre_div = hw_limit->brp_min;
|
|
uint16_t tseg = 0;
|
|
for (; pre_div <= hw_limit->brp_max; pre_div ++) {
|
|
tseg = total_div / pre_div;
|
|
if (total_div != tseg * pre_div) {
|
|
continue; // no integer tseg
|
|
}
|
|
if ((tseg <= (hw_limit->tseg1_max + hw_limit->tseg2_max + 1)) && (tseg >= (hw_limit->tseg1_min + hw_limit->tseg2_min))) {
|
|
break;
|
|
}
|
|
}
|
|
if (pre_div > hw_limit->brp_max) { // no valid pre_div
|
|
return 0;
|
|
}
|
|
|
|
uint16_t default_point = (in_param->bitrate >= 800000) ? 750 : ((in_param->bitrate >= 500000) ? 800 : 875);
|
|
uint16_t sample_point = in_param->sp_permill ? in_param->sp_permill : default_point; // default sample point based on bitrate if not configured
|
|
uint16_t tseg_1 = (tseg * sample_point) / 1000;
|
|
tseg_1 = MAX(hw_limit->tseg1_min, MIN(tseg_1, hw_limit->tseg1_max));
|
|
uint16_t tseg_2 = tseg - tseg_1 - 1;
|
|
tseg_2 = MAX(hw_limit->tseg2_min, MIN(tseg_2, hw_limit->tseg2_max));
|
|
tseg_1 = tseg - tseg_2 - 1;
|
|
uint16_t prop = tseg_1 / 2; // distribute tseg1 evenly between prop_seg and tseg_1
|
|
tseg_1 -= prop;
|
|
|
|
out_param->quanta_resolution_hz = 0; // going to deprecated IDF-12725
|
|
out_param->brp = pre_div;
|
|
out_param->prop_seg = prop;
|
|
out_param->tseg_1 = tseg_1;
|
|
out_param->tseg_2 = tseg_2;
|
|
out_param->sjw = MAX(1, MIN(tseg_2 >> 1, hw_limit->sjw_max));
|
|
out_param->ssp_offset = (tseg * in_param->ssp_permill) / 1000; // ssp is optional, default 0 if not configured
|
|
|
|
return source_freq / (pre_div * (prop + tseg_1 + tseg_2 + 1));
|
|
}
|
|
|
|
esp_err_t twai_node_enable(twai_node_handle_t node)
|
|
{
|
|
ESP_RETURN_ON_FALSE(node, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null handle");
|
|
ESP_RETURN_ON_FALSE(node->enable, ESP_ERR_NOT_SUPPORTED, TAG, "enable func null");
|
|
|
|
return node->enable(node);
|
|
}
|
|
|
|
esp_err_t twai_node_disable(twai_node_handle_t node)
|
|
{
|
|
ESP_RETURN_ON_FALSE(node, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null handle");
|
|
ESP_RETURN_ON_FALSE(node->disable, ESP_ERR_NOT_SUPPORTED, TAG, "disable func null");
|
|
|
|
return node->disable(node);
|
|
}
|
|
|
|
esp_err_t twai_node_delete(twai_node_handle_t node)
|
|
{
|
|
ESP_RETURN_ON_FALSE(node, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null handle");
|
|
ESP_RETURN_ON_FALSE(node->del, ESP_ERR_NOT_SUPPORTED, TAG, "delete func null");
|
|
|
|
return node->del(node);
|
|
}
|
|
|
|
esp_err_t twai_node_config_mask_filter(twai_node_handle_t node, uint8_t filter_id, const twai_mask_filter_config_t *mask_cfg)
|
|
{
|
|
ESP_RETURN_ON_FALSE(node && mask_cfg, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null");
|
|
ESP_RETURN_ON_FALSE(node->config_mask_filter, ESP_ERR_NOT_SUPPORTED, TAG, "config_mask_filter func null");
|
|
|
|
return node->config_mask_filter(node, filter_id, mask_cfg);
|
|
}
|
|
|
|
esp_err_t twai_node_config_range_filter(twai_node_handle_t node, uint8_t filter_id, const twai_range_filter_config_t *range_cfg)
|
|
{
|
|
ESP_RETURN_ON_FALSE(node && range_cfg, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null");
|
|
ESP_RETURN_ON_FALSE(node->config_range_filter, ESP_ERR_NOT_SUPPORTED, TAG, "config_range_filter func null");
|
|
|
|
return node->config_range_filter(node, filter_id, range_cfg);
|
|
}
|
|
|
|
esp_err_t twai_node_reconfig_timing(twai_node_handle_t node, const twai_timing_advanced_config_t *bit_timing, const twai_timing_advanced_config_t *data_timing)
|
|
{
|
|
ESP_RETURN_ON_FALSE(node && (bit_timing || data_timing), ESP_ERR_INVALID_ARG, TAG, "invalid argument: null");
|
|
ESP_RETURN_ON_FALSE(node->reconfig_timing, ESP_ERR_NOT_SUPPORTED, TAG, "reconfig_timing func null");
|
|
|
|
return node->reconfig_timing(node, bit_timing, data_timing);
|
|
}
|
|
|
|
esp_err_t twai_node_register_event_callbacks(twai_node_handle_t node, const twai_event_callbacks_t *cbs, void *user_data)
|
|
{
|
|
ESP_RETURN_ON_FALSE(node && cbs, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null");
|
|
ESP_RETURN_ON_FALSE(node->register_cbs, ESP_ERR_NOT_SUPPORTED, TAG, "register_cbs func null");
|
|
|
|
return node->register_cbs(node, cbs, user_data);
|
|
}
|
|
|
|
esp_err_t twai_node_recover(twai_node_handle_t node)
|
|
{
|
|
ESP_RETURN_ON_FALSE(node, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null handle");
|
|
ESP_RETURN_ON_FALSE(node->recover, ESP_ERR_NOT_SUPPORTED, TAG, "recover func null");
|
|
|
|
return node->recover(node);
|
|
}
|
|
|
|
esp_err_t twai_node_get_info(twai_node_handle_t node, twai_node_status_t *status_ret, twai_node_record_t *statistics_ret)
|
|
{
|
|
ESP_RETURN_ON_FALSE(node, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null handle");
|
|
ESP_RETURN_ON_FALSE(node->get_info, ESP_ERR_NOT_SUPPORTED, TAG, "get_info func null");
|
|
|
|
return node->get_info(node, status_ret, statistics_ret);
|
|
}
|
|
|
|
esp_err_t twai_node_transmit(twai_node_handle_t node, const twai_frame_t *frame, int timeout_ms)
|
|
{
|
|
ESP_RETURN_ON_FALSE(node && frame, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null");
|
|
ESP_RETURN_ON_FALSE(node->transmit, ESP_ERR_NOT_SUPPORTED, TAG, "transmit func null");
|
|
|
|
return node->transmit(node, frame, timeout_ms);
|
|
}
|
|
|
|
esp_err_t twai_node_receive_from_isr(twai_node_handle_t node, twai_frame_t *rx_frame)
|
|
{
|
|
ESP_RETURN_ON_FALSE_ISR(node && rx_frame, ESP_ERR_INVALID_ARG, TAG, "invalid argument: null");
|
|
ESP_RETURN_ON_FALSE_ISR((rx_frame->buffer_len == 0) || esp_ptr_in_dram(rx_frame->buffer) || esp_ptr_external_ram(rx_frame->buffer), ESP_ERR_INVALID_ARG, TAG, "invalid 'rx_frame->buffer' pointer or buffer_len");
|
|
ESP_RETURN_ON_FALSE_ISR(node->receive_isr, ESP_ERR_NOT_SUPPORTED, TAG, "receive func null");
|
|
|
|
return node->receive_isr(node, rx_frame);
|
|
}
|
|
|
|
#if CONFIG_TWAI_ENABLE_DEBUG_LOG
|
|
__attribute__((constructor))
|
|
static void twai_override_default_log_level(void)
|
|
{
|
|
esp_log_level_set(TAG, ESP_LOG_VERBOSE);
|
|
}
|
|
#endif
|