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 <string.h>
9 #include "sdkconfig.h"
10 #include "hal/twai_hal.h"
11
12 #ifdef CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT
13 //Errata condition occurs at 64 messages. Threshold set to 62 to prevent the chance of failing to detect errata condition.
14 #define TWAI_RX_FIFO_CORRUPT_THRESH 62
15 #endif
16
17 /* ----------------------------- Event Handling ----------------------------- */
18
19 /**
20 * Helper functions that can decode what events have been triggered based on
21 * the values of the interrupt, status, TEC and REC registers. The HAL context's
22 * state flags are also updated based on the events that have triggered.
23 */
twai_hal_decode_interrupt(twai_hal_context_t * hal_ctx)24 static inline uint32_t twai_hal_decode_interrupt(twai_hal_context_t *hal_ctx)
25 {
26 uint32_t events = 0;
27 uint32_t interrupts = twai_ll_get_and_clear_intrs(hal_ctx->dev);
28 uint32_t status = twai_ll_get_status(hal_ctx->dev);
29 uint32_t tec = twai_ll_get_tec(hal_ctx->dev);
30 uint32_t rec = twai_ll_get_rec(hal_ctx->dev);
31 uint32_t state_flags = hal_ctx->state_flags;
32
33 //Error Warning Interrupt set whenever Error or Bus Status bit changes
34 if (interrupts & TWAI_LL_INTR_EI) {
35 if (status & TWAI_LL_STATUS_BS) { //Currently in BUS OFF state
36 if (status & TWAI_LL_STATUS_ES) { //EWL is exceeded, thus must have entered BUS OFF
37 TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_BUS_OFF);
38 TWAI_HAL_SET_BITS(state_flags, TWAI_HAL_STATE_FLAG_BUS_OFF);
39 //Any TX would have been halted by entering bus off. Reset its flag
40 TWAI_HAL_CLEAR_BITS(state_flags, TWAI_HAL_STATE_FLAG_RUNNING | TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED);
41 } else {
42 //Below EWL. Therefore TEC is counting down in bus recovery
43 TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_BUS_RECOV_PROGRESS);
44 }
45 } else { //Not in BUS OFF
46 if (status & TWAI_LL_STATUS_ES) { //Just Exceeded EWL
47 TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_ABOVE_EWL);
48 TWAI_HAL_SET_BITS(state_flags, TWAI_HAL_STATE_FLAG_ERR_WARN);
49 } else if (hal_ctx->state_flags & TWAI_HAL_STATE_FLAG_RECOVERING) {
50 //Previously undergoing bus recovery. Thus means bus recovery complete
51 TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_BUS_RECOV_CPLT);
52 TWAI_HAL_CLEAR_BITS(state_flags, TWAI_HAL_STATE_FLAG_RECOVERING | TWAI_HAL_STATE_FLAG_BUS_OFF);
53 } else { //Just went below EWL
54 TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_BELOW_EWL);
55 TWAI_HAL_CLEAR_BITS(state_flags, TWAI_HAL_STATE_FLAG_ERR_WARN);
56 }
57 }
58 }
59 //Receive Interrupt set whenever RX FIFO is not empty
60 if (interrupts & TWAI_LL_INTR_RI) {
61 TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_RX_BUFF_FRAME);
62 }
63 //Transmit interrupt set whenever TX buffer becomes free
64 #ifdef CONFIG_TWAI_ERRATA_FIX_TX_INTR_LOST
65 if ((interrupts & TWAI_LL_INTR_TI || hal_ctx->state_flags & TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED) && status & TWAI_LL_STATUS_TBS) {
66 #else
67 if (interrupts & TWAI_LL_INTR_TI) {
68 #endif
69 TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_TX_BUFF_FREE);
70 TWAI_HAL_CLEAR_BITS(state_flags, TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED);
71 }
72 //Error Passive Interrupt on transition from error active to passive or vice versa
73 if (interrupts & TWAI_LL_INTR_EPI) {
74 if (tec >= TWAI_ERR_PASS_THRESH || rec >= TWAI_ERR_PASS_THRESH) {
75 TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_ERROR_PASSIVE);
76 TWAI_HAL_SET_BITS(state_flags, TWAI_HAL_STATE_FLAG_ERR_PASSIVE);
77 } else {
78 TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_ERROR_ACTIVE);
79 TWAI_HAL_CLEAR_BITS(state_flags, TWAI_HAL_STATE_FLAG_ERR_PASSIVE);
80 }
81 }
82 //Bus error interrupt triggered on a bus error (e.g. bit, ACK, stuff etc)
83 if (interrupts & TWAI_LL_INTR_BEI) {
84 TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_BUS_ERR);
85 }
86 //Arbitration Lost Interrupt triggered on losing arbitration
87 if (interrupts & TWAI_LL_INTR_ALI) {
88 TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_ARB_LOST);
89 }
90 hal_ctx->state_flags = state_flags;
91 return events;
92 }
93
94 uint32_t twai_hal_get_events(twai_hal_context_t *hal_ctx)
95 {
96 uint32_t events = twai_hal_decode_interrupt(hal_ctx);
97
98 //Handle low latency events
99 if (events & TWAI_HAL_EVENT_BUS_OFF) {
100 twai_ll_set_mode(hal_ctx->dev, TWAI_MODE_LISTEN_ONLY); //Freeze TEC/REC by entering LOM
101 #ifdef CONFIG_TWAI_ERRATA_FIX_BUS_OFF_REC
102 //Errata workaround: Force REC to 0 by re-triggering bus-off (by setting TEC to 0 then 255)
103 twai_ll_set_tec(hal_ctx->dev, 0);
104 twai_ll_set_tec(hal_ctx->dev, 255);
105 (void) twai_ll_get_and_clear_intrs(hal_ctx->dev); //Clear the re-triggered bus-off interrupt
106 #endif
107 }
108 if (events & TWAI_HAL_EVENT_BUS_RECOV_CPLT) {
109 twai_ll_enter_reset_mode(hal_ctx->dev); //Enter reset mode to stop the controller
110 }
111 if (events & TWAI_HAL_EVENT_BUS_ERR) {
112 #ifdef CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID
113 twai_ll_err_type_t type;
114 twai_ll_err_dir_t dir;
115 twai_ll_err_seg_t seg;
116 twai_ll_parse_err_code_cap(hal_ctx->dev, &type, &dir, &seg); //Decode error interrupt
117 //Check for errata condition (RX message has bus error at particular segments)
118 if (dir == TWAI_LL_ERR_DIR_RX &&
119 ((seg == TWAI_LL_ERR_SEG_DATA || seg == TWAI_LL_ERR_SEG_CRC_SEQ) ||
120 (seg == TWAI_LL_ERR_SEG_ACK_DELIM && type == TWAI_LL_ERR_OTHER))) {
121 TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_NEED_PERIPH_RESET);
122 }
123 #endif
124 twai_ll_clear_err_code_cap(hal_ctx->dev);
125 }
126 if (events & TWAI_HAL_EVENT_ARB_LOST) {
127 twai_ll_clear_arb_lost_cap(hal_ctx->dev);
128 }
129 #ifdef CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT
130 //Check for errata condition (rx_msg_count >= corruption_threshold)
131 if (events & TWAI_HAL_EVENT_RX_BUFF_FRAME && twai_ll_get_rx_msg_count(hal_ctx->dev) >= TWAI_RX_FIFO_CORRUPT_THRESH) {
132 TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_NEED_PERIPH_RESET);
133 }
134 #endif
135 #if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
136 if (events & TWAI_HAL_EVENT_NEED_PERIPH_RESET) {
137 //A peripheral reset will invalidate an RX event;
138 TWAI_HAL_CLEAR_BITS(events, (TWAI_HAL_EVENT_RX_BUFF_FRAME));
139 }
140 #endif
141 return events;
142 }
143
144 #if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
145 void twai_hal_prepare_for_reset(twai_hal_context_t *hal_ctx)
146 {
147 uint32_t status = twai_ll_get_status(hal_ctx->dev);
148 if (!(status & TWAI_LL_STATUS_TBS)) { //Transmit buffer is NOT free, indicating an Ongoing TX will be cancelled by the HW reset
149 TWAI_HAL_SET_BITS(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_TX_NEED_RETRY);
150 //Note: Even if the TX completes right after this, we still consider it will be retried.
151 //Worst case the same message will get sent twice.
152 }
153 //Some register must saved before entering reset mode
154 hal_ctx->rx_msg_cnt_save = (uint8_t) twai_ll_get_rx_msg_count(hal_ctx->dev);
155 twai_ll_enter_reset_mode(hal_ctx->dev); //Enter reset mode to stop the controller
156 twai_ll_save_reg(hal_ctx->dev, &hal_ctx->reg_save); //Save remaining registers after entering reset mode
157 }
158
159 void twai_hal_recover_from_reset(twai_hal_context_t *hal_ctx)
160 {
161 twai_ll_enter_reset_mode(hal_ctx->dev);
162 twai_ll_enable_extended_reg_layout(hal_ctx->dev);
163 twai_ll_restore_reg(hal_ctx->dev, &hal_ctx->reg_save);
164 twai_ll_exit_reset_mode(hal_ctx->dev);
165 (void) twai_ll_get_and_clear_intrs(hal_ctx->dev);
166
167 if (hal_ctx->state_flags & TWAI_HAL_STATE_FLAG_TX_NEED_RETRY) {
168 //HW reset has cancelled a TX. Re-transmit here
169 twai_hal_set_tx_buffer_and_transmit(hal_ctx, &hal_ctx->tx_frame_save);
170 TWAI_HAL_CLEAR_BITS(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_TX_NEED_RETRY);
171 }
172 }
173 #endif //defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
174
175 void twai_hal_set_tx_buffer_and_transmit(twai_hal_context_t *hal_ctx, twai_hal_frame_t *tx_frame)
176 {
177 //Copy frame into tx buffer
178 twai_ll_set_tx_buffer(hal_ctx->dev, tx_frame);
179 //Hit the send command
180 if (tx_frame->self_reception) {
181 if (tx_frame->single_shot) {
182 twai_ll_set_cmd_self_rx_single_shot(hal_ctx->dev);
183 } else {
184 twai_ll_set_cmd_self_rx_request(hal_ctx->dev);
185 }
186 } else if (tx_frame->single_shot){
187 twai_ll_set_cmd_tx_single_shot(hal_ctx->dev);
188 } else {
189 twai_ll_set_cmd_tx(hal_ctx->dev);
190 }
191 TWAI_HAL_SET_BITS(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED);
192 #if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
193 //Save transmitted frame in case we need to retry
194 memcpy(&hal_ctx->tx_frame_save, tx_frame, sizeof(twai_hal_frame_t));
195 #endif //defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
196 }
197