2024-09-14 14:24:56 +08:00
/*
* SPDX - FileCopyrightText : 2024 - 2025 Espressif Systems ( Shanghai ) CO LTD
*
* SPDX - License - Identifier : Apache - 2.0
*/
2025-04-27 15:57:46 +08:00
# include <sys/param.h>
2024-09-14 14:24:56 +08:00
# include "esp_twai.h"
# include "esp_private/twai_interface.h"
2025-04-03 15:47:15 +08:00
# include "esp_private/twai_utils.h"
# include "twai_private.h"
2024-09-14 14:24:56 +08:00
/**
* @ 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
}
2025-04-27 15:57:46 +08:00
if ( ( tseg < = ( hw_limit - > tseg1_max + hw_limit - > tseg2_max + 1 ) ) & & ( tseg > = ( hw_limit - > tseg1_min + hw_limit - > tseg2_min ) ) ) {
2024-09-14 14:24:56 +08:00
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 ) ;
2025-04-03 15:47:15 +08:00
uint16_t sample_point = in_param - > sp_permill ? in_param - > sp_permill : default_point ; // default sample point based on bitrate if not configured
2024-09-14 14:24:56 +08:00
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 " ) ;
2025-04-03 15:47:15 +08:00
ESP_RETURN_ON_FALSE ( node - > reconfig_timing , ESP_ERR_NOT_SUPPORTED , TAG , " reconfig_timing func null " ) ;
2024-09-14 14:24:56 +08:00
2025-04-03 15:47:15 +08:00
return node - > reconfig_timing ( node , bit_timing , data_timing ) ;
2024-09-14 14:24:56 +08:00
}
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 ) ;
}
2025-04-27 15:57:46 +08:00
esp_err_t twai_node_receive_from_isr ( twai_node_handle_t node , twai_frame_t * rx_frame )
2024-09-14 14:24:56 +08:00
{
2025-04-27 15:57:46 +08:00
ESP_RETURN_ON_FALSE_ISR ( node & & rx_frame , ESP_ERR_INVALID_ARG , TAG , " invalid argument: null " ) ;
2025-06-26 12:25:43 +08:00
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 " ) ;
2024-09-14 14:24:56 +08:00
ESP_RETURN_ON_FALSE_ISR ( node - > receive_isr , ESP_ERR_NOT_SUPPORTED , TAG , " receive func null " ) ;
2025-04-27 15:57:46 +08:00
return node - > receive_isr ( node , rx_frame ) ;
2024-09-14 14:24:56 +08:00
}
2025-04-03 15:47:15 +08:00
# 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