1 /*
2  * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stddef.h>
8 #include "sdkconfig.h"
9 #include "hal/twai_hal.h"
10 #include "hal/efuse_hal.h"
11 #include "soc/soc_caps.h"
12 
13 //Default values written to various registers on initialization
14 #define TWAI_HAL_INIT_TEC    0
15 #define TWAI_HAL_INIT_REC    0
16 #define TWAI_HAL_INIT_EWL    96
17 
18 /* ---------------------------- Init and Config ----------------------------- */
19 
twai_hal_init(twai_hal_context_t * hal_ctx,const twai_hal_config_t * config)20 bool twai_hal_init(twai_hal_context_t *hal_ctx, const twai_hal_config_t *config)
21 {
22     //Initialize HAL context
23     hal_ctx->dev = TWAI_LL_GET_HW(config->controller_id);
24     hal_ctx->state_flags = 0;
25     hal_ctx->clock_source_hz = config->clock_source_hz;
26     //Enable functional clock
27     twai_ll_enable_clock(hal_ctx->dev, true);
28     //Initialize TWAI controller, and set default values to registers
29     twai_ll_enter_reset_mode(hal_ctx->dev);
30     if (!twai_ll_is_in_reset_mode(hal_ctx->dev)) {    //Must enter reset mode to write to config registers
31         return false;
32     }
33 #if SOC_TWAI_SUPPORT_MULTI_ADDRESS_LAYOUT
34     twai_ll_enable_extended_reg_layout(hal_ctx->dev);        //Changes the address layout of the registers
35 #endif
36     twai_ll_set_mode(hal_ctx->dev, TWAI_MODE_LISTEN_ONLY);    //Freeze REC by changing to LOM mode
37     //Both TEC and REC should start at 0
38     twai_ll_set_tec(hal_ctx->dev, TWAI_HAL_INIT_TEC);
39     twai_ll_set_rec(hal_ctx->dev, TWAI_HAL_INIT_REC);
40     twai_ll_set_err_warn_lim(hal_ctx->dev, TWAI_HAL_INIT_EWL);    //Set default value of for EWL
41     return true;
42 }
43 
twai_hal_deinit(twai_hal_context_t * hal_ctx)44 void twai_hal_deinit(twai_hal_context_t *hal_ctx)
45 {
46     //Clear any pending registers
47     (void) twai_ll_get_and_clear_intrs(hal_ctx->dev);
48     twai_ll_set_enabled_intrs(hal_ctx->dev, 0);
49     twai_ll_clear_arb_lost_cap(hal_ctx->dev);
50     twai_ll_clear_err_code_cap(hal_ctx->dev);
51     //Disable functional clock
52     twai_ll_enable_clock(hal_ctx->dev, false);
53     hal_ctx->dev = NULL;
54 }
55 
twai_hal_configure(twai_hal_context_t * hal_ctx,const twai_timing_config_t * t_config,const twai_filter_config_t * f_config,uint32_t intr_mask,uint32_t clkout_divider)56 void twai_hal_configure(twai_hal_context_t *hal_ctx, const twai_timing_config_t *t_config, const twai_filter_config_t *f_config, uint32_t intr_mask, uint32_t clkout_divider)
57 {
58     uint32_t brp = t_config->brp;
59     // both quanta_resolution_hz and brp can affect the baud rate
60     // but a non-zero quanta_resolution_hz takes higher priority
61     if (t_config->quanta_resolution_hz) {
62         brp = hal_ctx->clock_source_hz / t_config->quanta_resolution_hz;
63     }
64 
65     // set clock source
66     twai_clock_source_t clk_src = t_config->clk_src;
67     //for backward compatible, zero value means default a default clock source
68     if (t_config->clk_src == 0) {
69         clk_src = TWAI_CLK_SRC_DEFAULT;
70     }
71     twai_ll_set_clock_source(hal_ctx->dev, clk_src);
72 
73     //Configure bus timing, acceptance filter, CLKOUT, and interrupts
74     twai_ll_set_bus_timing(hal_ctx->dev, brp, t_config->sjw, t_config->tseg_1, t_config->tseg_2, t_config->triple_sampling);
75     twai_ll_set_acc_filter(hal_ctx->dev, f_config->acceptance_code, f_config->acceptance_mask, f_config->single_filter);
76     twai_ll_set_clkout(hal_ctx->dev, clkout_divider);
77     twai_ll_set_enabled_intrs(hal_ctx->dev, intr_mask);
78     (void) twai_ll_get_and_clear_intrs(hal_ctx->dev);    //Clear any latched interrupts
79 }
80 
81 /* -------------------------------- Actions --------------------------------- */
82 
twai_hal_start(twai_hal_context_t * hal_ctx,twai_mode_t mode)83 void twai_hal_start(twai_hal_context_t *hal_ctx, twai_mode_t mode)
84 {
85     twai_ll_set_mode(hal_ctx->dev, mode);                //Set operating mode
86     //Clear the TEC and REC
87     twai_ll_set_tec(hal_ctx->dev, 0);
88 #ifdef CONFIG_TWAI_ERRATA_FIX_LISTEN_ONLY_DOM
89     /*
90     Errata workaround: Prevent transmission of dominant error frame while in listen only mode by setting REC to 128
91     before exiting reset mode. This forces the controller to be error passive (thus only transmits recessive bits).
92     The TEC/REC remain frozen in listen only mode thus ensuring we remain error passive.
93     */
94     if (mode == TWAI_MODE_LISTEN_ONLY) {
95         twai_ll_set_rec(hal_ctx->dev, 128);
96     } else
97 #endif
98     {
99         twai_ll_set_rec(hal_ctx->dev, 0);
100     }
101     (void) twai_ll_get_and_clear_intrs(hal_ctx->dev);    //Clear any latched interrupts
102     TWAI_HAL_SET_BITS(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_RUNNING);
103     twai_ll_exit_reset_mode(hal_ctx->dev);
104 }
105 
twai_hal_stop(twai_hal_context_t * hal_ctx)106 void twai_hal_stop(twai_hal_context_t *hal_ctx)
107 {
108     twai_ll_enter_reset_mode(hal_ctx->dev);
109     (void) twai_ll_get_and_clear_intrs(hal_ctx->dev);
110     twai_ll_set_mode(hal_ctx->dev, TWAI_MODE_LISTEN_ONLY);    //Freeze REC by changing to LOM mode
111     //Any TX is immediately halted on entering reset mode
112     TWAI_HAL_CLEAR_BITS(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED | TWAI_HAL_STATE_FLAG_RUNNING);
113 }
114