twai_hal_iram.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. // Copyright 2015-2019 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. // http://www.apache.org/licenses/LICENSE-2.0
  7. //
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. #include <stddef.h>
  14. #include <string.h>
  15. #include "sdkconfig.h"
  16. #include "hal/twai_hal.h"
  17. #ifdef CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT
  18. //Errata condition occurs at 64 messages. Threshold set to 62 to prevent the chance of failing to detect errata condition.
  19. #define TWAI_RX_FIFO_CORRUPT_THRESH 62
  20. #endif
  21. /* ----------------------------- Event Handling ----------------------------- */
  22. /**
  23. * Helper functions that can decode what events have been triggered based on
  24. * the values of the interrupt, status, TEC and REC registers. The HAL context's
  25. * state flags are also updated based on the events that have triggered.
  26. */
  27. static inline uint32_t twai_hal_decode_interrupt(twai_hal_context_t *hal_ctx)
  28. {
  29. uint32_t events = 0;
  30. uint32_t interrupts = twai_ll_get_and_clear_intrs(hal_ctx->dev);
  31. uint32_t status = twai_ll_get_status(hal_ctx->dev);
  32. uint32_t tec = twai_ll_get_tec(hal_ctx->dev);
  33. uint32_t rec = twai_ll_get_rec(hal_ctx->dev);
  34. uint32_t state_flags = hal_ctx->state_flags;
  35. //Error Warning Interrupt set whenever Error or Bus Status bit changes
  36. if (interrupts & TWAI_LL_INTR_EI) {
  37. if (status & TWAI_LL_STATUS_BS) { //Currently in BUS OFF state
  38. if (status & TWAI_LL_STATUS_ES) { //EWL is exceeded, thus must have entered BUS OFF
  39. TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_BUS_OFF);
  40. TWAI_HAL_SET_BITS(state_flags, TWAI_HAL_STATE_FLAG_BUS_OFF);
  41. //Any TX would have been halted by entering bus off. Reset its flag
  42. TWAI_HAL_CLEAR_BITS(state_flags, TWAI_HAL_STATE_FLAG_RUNNING | TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED);
  43. } else {
  44. //Below EWL. Therefore TEC is counting down in bus recovery
  45. TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_BUS_RECOV_PROGRESS);
  46. }
  47. } else { //Not in BUS OFF
  48. if (status & TWAI_LL_STATUS_ES) { //Just Exceeded EWL
  49. TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_ABOVE_EWL);
  50. TWAI_HAL_SET_BITS(state_flags, TWAI_HAL_STATE_FLAG_ERR_WARN);
  51. } else if (hal_ctx->state_flags & TWAI_HAL_STATE_FLAG_RECOVERING) {
  52. //Previously undergoing bus recovery. Thus means bus recovery complete
  53. TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_BUS_RECOV_CPLT);
  54. TWAI_HAL_CLEAR_BITS(state_flags, TWAI_HAL_STATE_FLAG_RECOVERING | TWAI_HAL_STATE_FLAG_BUS_OFF);
  55. } else { //Just went below EWL
  56. TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_BELOW_EWL);
  57. TWAI_HAL_CLEAR_BITS(state_flags, TWAI_HAL_STATE_FLAG_ERR_WARN);
  58. }
  59. }
  60. }
  61. //Receive Interrupt set whenever RX FIFO is not empty
  62. if (interrupts & TWAI_LL_INTR_RI) {
  63. TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_RX_BUFF_FRAME);
  64. }
  65. //Transmit interrupt set whenever TX buffer becomes free
  66. #ifdef CONFIG_TWAI_ERRATA_FIX_TX_INTR_LOST
  67. if ((interrupts & TWAI_LL_INTR_TI || hal_ctx->state_flags & TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED) && status & TWAI_LL_STATUS_TBS) {
  68. #else
  69. if (interrupts & TWAI_LL_INTR_TI) {
  70. #endif
  71. TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_TX_BUFF_FREE);
  72. TWAI_HAL_CLEAR_BITS(state_flags, TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED);
  73. }
  74. //Error Passive Interrupt on transition from error active to passive or vice versa
  75. if (interrupts & TWAI_LL_INTR_EPI) {
  76. if (tec >= TWAI_ERR_PASS_THRESH || rec >= TWAI_ERR_PASS_THRESH) {
  77. TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_ERROR_PASSIVE);
  78. TWAI_HAL_SET_BITS(state_flags, TWAI_HAL_STATE_FLAG_ERR_PASSIVE);
  79. } else {
  80. TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_ERROR_ACTIVE);
  81. TWAI_HAL_CLEAR_BITS(state_flags, TWAI_HAL_STATE_FLAG_ERR_PASSIVE);
  82. }
  83. }
  84. //Bus error interrupt triggered on a bus error (e.g. bit, ACK, stuff etc)
  85. if (interrupts & TWAI_LL_INTR_BEI) {
  86. TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_BUS_ERR);
  87. }
  88. //Arbitration Lost Interrupt triggered on losing arbitration
  89. if (interrupts & TWAI_LL_INTR_ALI) {
  90. TWAI_HAL_SET_BITS(events, TWAI_HAL_EVENT_ARB_LOST);
  91. }
  92. hal_ctx->state_flags = state_flags;
  93. return events;
  94. }
  95. uint32_t twai_hal_get_events(twai_hal_context_t *hal_ctx)
  96. {
  97. uint32_t events = twai_hal_decode_interrupt(hal_ctx);
  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. #if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
  144. void twai_hal_prepare_for_reset(twai_hal_context_t *hal_ctx)
  145. {
  146. uint32_t status = twai_ll_get_status(hal_ctx->dev);
  147. if (!(status & TWAI_LL_STATUS_TBS)) { //Transmit buffer is NOT free, indicating an Ongoing TX will be cancelled by the HW reset
  148. TWAI_HAL_SET_BITS(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_TX_NEED_RETRY);
  149. //Note: Even if the TX completes right after this, we still consider it will be retried.
  150. //Worst case the same message will get sent twice.
  151. }
  152. //Some register must saved before entering reset mode
  153. hal_ctx->rx_msg_cnt_save = (uint8_t) twai_ll_get_rx_msg_count(hal_ctx->dev);
  154. twai_ll_enter_reset_mode(hal_ctx->dev); //Enter reset mode to stop the controller
  155. twai_ll_save_reg(hal_ctx->dev, &hal_ctx->reg_save); //Save remaining registers after entering reset mode
  156. }
  157. void twai_hal_recover_from_reset(twai_hal_context_t *hal_ctx)
  158. {
  159. twai_ll_enter_reset_mode(hal_ctx->dev);
  160. twai_ll_enable_extended_reg_layout(hal_ctx->dev);
  161. twai_ll_restore_reg(hal_ctx->dev, &hal_ctx->reg_save);
  162. twai_ll_exit_reset_mode(hal_ctx->dev);
  163. (void) twai_ll_get_and_clear_intrs(hal_ctx->dev);
  164. if (hal_ctx->state_flags & TWAI_HAL_STATE_FLAG_TX_NEED_RETRY) {
  165. //HW reset has cancelled a TX. Re-transmit here
  166. twai_hal_set_tx_buffer_and_transmit(hal_ctx, &hal_ctx->tx_frame_save);
  167. TWAI_HAL_CLEAR_BITS(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_TX_NEED_RETRY);
  168. }
  169. }
  170. #endif //defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
  171. void twai_hal_set_tx_buffer_and_transmit(twai_hal_context_t *hal_ctx, twai_hal_frame_t *tx_frame)
  172. {
  173. //Copy frame into tx buffer
  174. twai_ll_set_tx_buffer(hal_ctx->dev, tx_frame);
  175. //Hit the send command
  176. if (tx_frame->self_reception) {
  177. if (tx_frame->single_shot) {
  178. twai_ll_set_cmd_self_rx_single_shot(hal_ctx->dev);
  179. } else {
  180. twai_ll_set_cmd_self_rx_request(hal_ctx->dev);
  181. }
  182. } else if (tx_frame->single_shot){
  183. twai_ll_set_cmd_tx_single_shot(hal_ctx->dev);
  184. } else {
  185. twai_ll_set_cmd_tx(hal_ctx->dev);
  186. }
  187. TWAI_HAL_SET_BITS(hal_ctx->state_flags, TWAI_HAL_STATE_FLAG_TX_BUFF_OCCUPIED);
  188. #if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
  189. //Save transmitted frame in case we need to retry
  190. memcpy(&hal_ctx->tx_frame_save, tx_frame, sizeof(twai_hal_frame_t));
  191. #endif //defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
  192. }