CANDriver.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /*
  2. CAN driver class for ESP32
  3. */
  4. #include <Arduino.h>
  5. #include "options.h"
  6. #if AP_DRONECAN_ENABLED
  7. #include "CANDriver.h"
  8. #include <freertos/FreeRTOS.h>
  9. #include "freertos/task.h"
  10. #include "freertos/queue.h"
  11. #include "freertos/semphr.h"
  12. #include "esp_err.h"
  13. #include "esp_log.h"
  14. #include "driver/twai.h"
  15. #include "board_config.h"
  16. #define CAN1_TX_IRQ_Handler ESP32_CAN1_TX_HANDLER
  17. #define CAN1_RX0_IRQ_Handler ESP32_CAN1_RX0_HANDLER
  18. #define CAN1_RX1_IRQ_Handler ESP32_CAN1_RX1_HANDLER
  19. #define CAN2_TX_IRQ_Handler ESP32_CAN2_TX_HANDLER
  20. #define CAN2_RX0_IRQ_Handler ESP32_CAN2_RX0_HANDLER
  21. #define CAN2_RX1_IRQ_Handler ESP32_CAN2_RX1_HANDLER
  22. // from canard.h
  23. #define CANARD_CAN_FRAME_EFF (1UL << 31U) ///< Extended frame format
  24. #define CANARD_CAN_FRAME_RTR (1UL << 30U) ///< Remote transmission (not used by UAVCAN)
  25. #define CANARD_CAN_FRAME_ERR (1UL << 29U) ///< Error frame (not used by UAVCAN)
  26. // constructor
  27. CANDriver::CANDriver()
  28. {}
  29. static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_1MBITS();
  30. static twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
  31. void CANDriver::init(uint32_t bitrate, uint32_t acceptance_code, uint32_t acceptance_mask)
  32. {
  33. f_config.acceptance_code = acceptance_code;
  34. f_config.acceptance_mask = acceptance_mask;
  35. f_config.single_filter = true;
  36. init_bus(bitrate);
  37. }
  38. static const twai_general_config_t g_config = {.mode = TWAI_MODE_NORMAL, .tx_io = PIN_CAN_TX, .rx_io = PIN_CAN_RX, \
  39. .clkout_io = TWAI_IO_UNUSED, .bus_off_io = TWAI_IO_UNUSED, \
  40. .tx_queue_len = 5, .rx_queue_len = 50, \
  41. .alerts_enabled = TWAI_ALERT_NONE, .clkout_divider = 0, \
  42. .intr_flags = ESP_INTR_FLAG_LEVEL2
  43. };
  44. void CANDriver::init_once(bool enable_irq)
  45. {
  46. if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK)
  47. {
  48. Serial.printf("CAN/TWAI Driver installed\n");
  49. }
  50. else
  51. {
  52. Serial.printf("Failed to install CAN/TWAI driver\n");
  53. return;
  54. }
  55. //Reconfigure alerts to detect rx-related stuff only...
  56. uint32_t alerts_to_enable = TWAI_ALERT_RX_DATA | TWAI_ALERT_RX_QUEUE_FULL;
  57. if (twai_reconfigure_alerts(alerts_to_enable, NULL) == ESP_OK) {
  58. Serial.printf("CAN/TWAI Alerts reconfigured\n");
  59. } else {
  60. Serial.printf("Failed to reconfigure CAN/TWAI alerts");
  61. }
  62. //Start TWAI driver
  63. if (twai_start() == ESP_OK)
  64. {
  65. Serial.printf("CAN/TWAI Driver started\n");
  66. }
  67. else
  68. {
  69. Serial.printf("Failed to start CAN/TWAI driver\n");
  70. return;
  71. }
  72. }
  73. bool CANDriver::init_bus(const uint32_t _bitrate)
  74. {
  75. bitrate = _bitrate;
  76. init_once(true);
  77. Timings timings;
  78. if (!computeTimings(bitrate, timings)) {
  79. return false;
  80. }
  81. Serial.printf("Timings: presc=%u sjw=%u bs1=%u bs2=%u",
  82. unsigned(timings.prescaler), unsigned(timings.sjw), unsigned(timings.bs1), unsigned(timings.bs2));
  83. return true;
  84. }
  85. bool CANDriver::computeTimings(uint32_t target_bitrate, Timings& out_timings)
  86. {
  87. if (target_bitrate < 1) {
  88. return false;
  89. }
  90. /*
  91. * Hardware configuration
  92. */
  93. const uint32_t pclk = 100000;
  94. static const int MaxBS1 = 16;
  95. static const int MaxBS2 = 8;
  96. /*
  97. * Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
  98. * CAN in Automation, 2003
  99. *
  100. * According to the source, optimal quanta per bit are:
  101. * Bitrate Optimal Maximum
  102. * 1000 kbps 8 10
  103. * 500 kbps 16 17
  104. * 250 kbps 16 17
  105. * 125 kbps 16 17
  106. */
  107. const int max_quanta_per_bit = (target_bitrate >= 1000000) ? 10 : 17;
  108. static const int MaxSamplePointLocation = 900;
  109. /*
  110. * Computing (prescaler * BS):
  111. * BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2)) -- See the Reference Manual
  112. * BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2)) -- Simplified
  113. * let:
  114. * BS = 1 + BS1 + BS2 -- Number of time quanta per bit
  115. * PRESCALER_BS = PRESCALER * BS
  116. * ==>
  117. * PRESCALER_BS = PCLK / BITRATE
  118. */
  119. const uint32_t prescaler_bs = pclk / target_bitrate;
  120. /*
  121. * Searching for such prescaler value so that the number of quanta per bit is highest.
  122. */
  123. uint8_t bs1_bs2_sum = uint8_t(max_quanta_per_bit - 1);
  124. while ((prescaler_bs % (1 + bs1_bs2_sum)) != 0) {
  125. if (bs1_bs2_sum <= 2) {
  126. return false; // No solution
  127. }
  128. bs1_bs2_sum--;
  129. }
  130. const uint32_t prescaler = prescaler_bs / (1 + bs1_bs2_sum);
  131. if ((prescaler < 1U) || (prescaler > 1024U)) {
  132. return false; // No solution
  133. }
  134. /*
  135. * Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
  136. * We need to find the values so that the sample point is as close as possible to the optimal value.
  137. *
  138. * Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2] (* Where 7/8 is 0.875, the recommended sample point location *)
  139. * {{bs2 -> (1 + bs1)/7}}
  140. *
  141. * Hence:
  142. * bs2 = (1 + bs1) / 7
  143. * bs1 = (7 * bs1_bs2_sum - 1) / 8
  144. *
  145. * Sample point location can be computed as follows:
  146. * Sample point location = (1 + bs1) / (1 + bs1 + bs2)
  147. *
  148. * Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one:
  149. * - With rounding to nearest
  150. * - With rounding to zero
  151. */
  152. struct BsPair {
  153. uint8_t bs1;
  154. uint8_t bs2;
  155. uint16_t sample_point_permill;
  156. BsPair() :
  157. bs1(0),
  158. bs2(0),
  159. sample_point_permill(0)
  160. { }
  161. BsPair(uint8_t bs1_bs2_sum, uint8_t arg_bs1) :
  162. bs1(arg_bs1),
  163. bs2(uint8_t(bs1_bs2_sum - bs1)),
  164. sample_point_permill(uint16_t(1000 * (1 + bs1) / (1 + bs1 + bs2)))
  165. {}
  166. bool isValid() const
  167. {
  168. return (bs1 >= 1) && (bs1 <= MaxBS1) && (bs2 >= 1) && (bs2 <= MaxBS2);
  169. }
  170. };
  171. // First attempt with rounding to nearest
  172. BsPair solution(bs1_bs2_sum, uint8_t(((7 * bs1_bs2_sum - 1) + 4) / 8));
  173. if (solution.sample_point_permill > MaxSamplePointLocation) {
  174. // Second attempt with rounding to zero
  175. solution = BsPair(bs1_bs2_sum, uint8_t((7 * bs1_bs2_sum - 1) / 8));
  176. }
  177. if ((target_bitrate != (pclk / (prescaler * (1 + solution.bs1 + solution.bs2)))) || !solution.isValid()) {
  178. return false;
  179. }
  180. Serial.printf("Timings: quanta/bit: %d, sample point location: %.1f%%",
  181. int(1 + solution.bs1 + solution.bs2), float(solution.sample_point_permill) / 10.F);
  182. out_timings.prescaler = uint16_t(prescaler - 1U);
  183. out_timings.sjw = 0; // Which means one
  184. out_timings.bs1 = uint8_t(solution.bs1 - 1);
  185. out_timings.bs2 = uint8_t(solution.bs2 - 1);
  186. return true;
  187. }
  188. bool CANDriver::send(const CANFrame &frame)
  189. {
  190. if (frame.isErrorFrame() || frame.dlc > 8) {
  191. return false;
  192. }
  193. twai_message_t message {};
  194. message.identifier = frame.id;
  195. message.extd = frame.isExtended() ? 1 : 0;
  196. message.data_length_code = frame.dlc;
  197. memcpy(message.data, frame.data, 8);
  198. twai_status_info_t info {};
  199. twai_get_status_info(&info);
  200. switch (info.state) {
  201. case TWAI_STATE_STOPPED:
  202. twai_start();
  203. break;
  204. case TWAI_STATE_RUNNING:
  205. case TWAI_STATE_RECOVERING:
  206. break;
  207. case TWAI_STATE_BUS_OFF: {
  208. uint32_t now = millis();
  209. if (now - last_bus_recovery_ms > 2000) {
  210. last_bus_recovery_ms = now;
  211. twai_initiate_recovery();
  212. }
  213. break;
  214. }
  215. }
  216. const esp_err_t sts = twai_transmit(&message, pdMS_TO_TICKS(5));
  217. if (sts == ESP_OK) {
  218. last_bus_recovery_ms = 0;
  219. }
  220. return (sts == ESP_OK);
  221. }
  222. bool CANDriver::receive(CANFrame &out_frame)
  223. {
  224. twai_message_t message {};
  225. esp_err_t recverr = twai_receive(&message, pdMS_TO_TICKS(5));
  226. if (recverr != ESP_OK) {
  227. return false;
  228. }
  229. memcpy(out_frame.data, message.data, 8);// copy new data
  230. out_frame.dlc = message.data_length_code;
  231. out_frame.id = message.identifier;
  232. if (message.extd) {
  233. out_frame.id |= CANARD_CAN_FRAME_EFF;
  234. }
  235. if (out_frame.id & CANFrame::FlagERR) { // same as a message.isErrorFrame() if done later.
  236. return false;
  237. }
  238. return true;
  239. }
  240. #endif // AP_DRONECAN_ENABLED