canard_stm32.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /*
  2. * Copyright (c) 2017 UAVCAN Team
  3. *
  4. * Distributed under the MIT License, available in the file LICENSE.
  5. *
  6. * Author: Pavel Kirienko <pavel.kirienko@zubax.com>
  7. */
  8. #include "canard_stm32.h"
  9. #include "_internal_bxcan.h"
  10. #include <unistd.h>
  11. #if CANARD_STM32_USE_CAN2
  12. # define BXCAN CANARD_STM32_CAN2
  13. #else
  14. # define BXCAN CANARD_STM32_CAN1
  15. #endif
  16. /*
  17. * State variables
  18. */
  19. static CanardSTM32Stats g_stats;
  20. static bool g_abort_tx_on_error = false;
  21. static bool isFramePriorityHigher(uint32_t a, uint32_t b)
  22. {
  23. const uint32_t clean_a = a & CANARD_CAN_EXT_ID_MASK;
  24. const uint32_t clean_b = b & CANARD_CAN_EXT_ID_MASK;
  25. /*
  26. * STD vs EXT - if 11 most significant bits are the same, EXT loses.
  27. */
  28. const bool ext_a = (a & CANARD_CAN_FRAME_EFF) != 0;
  29. const bool ext_b = (b & CANARD_CAN_FRAME_EFF) != 0;
  30. if (ext_a != ext_b)
  31. {
  32. const uint32_t arb11_a = ext_a ? (clean_a >> 18U) : clean_a;
  33. const uint32_t arb11_b = ext_b ? (clean_b >> 18U) : clean_b;
  34. if (arb11_a != arb11_b)
  35. {
  36. return arb11_a < arb11_b;
  37. }
  38. else
  39. {
  40. return ext_b;
  41. }
  42. }
  43. /*
  44. * RTR vs Data frame - if frame identifiers and frame types are the same, RTR loses.
  45. */
  46. const bool rtr_a = (a & CANARD_CAN_FRAME_RTR) != 0;
  47. const bool rtr_b = (b & CANARD_CAN_FRAME_RTR) != 0;
  48. if ((clean_a == clean_b) && (rtr_a != rtr_b))
  49. {
  50. return rtr_b;
  51. }
  52. /*
  53. * Plain ID arbitration - greater value loses.
  54. */
  55. return clean_a < clean_b;
  56. }
  57. /// Converts libcanard ID value into the bxCAN TX ID register format.
  58. static uint32_t convertFrameIDCanardToRegister(const uint32_t id)
  59. {
  60. uint32_t out = 0;
  61. if (id & CANARD_CAN_FRAME_EFF)
  62. {
  63. out = ((id & CANARD_CAN_EXT_ID_MASK) << 3U) | CANARD_STM32_CAN_TIR_IDE;
  64. }
  65. else
  66. {
  67. out = ((id & CANARD_CAN_STD_ID_MASK) << 21U);
  68. }
  69. if (id & CANARD_CAN_FRAME_RTR)
  70. {
  71. out |= CANARD_STM32_CAN_TIR_RTR;
  72. }
  73. return out;
  74. }
  75. /// Converts bxCAN TX/RX (sic! both RX/TX are supported) ID register value into the libcanard ID format.
  76. static uint32_t convertFrameIDRegisterToCanard(const uint32_t id)
  77. {
  78. #if (CANARD_STM32_CAN_TIR_RTR != CANARD_STM32_CAN_RIR_RTR) ||\
  79. (CANARD_STM32_CAN_TIR_IDE != CANARD_STM32_CAN_RIR_IDE)
  80. # error "RIR bits do not match TIR bits, TIR --> libcanard conversion is not possible"
  81. #endif
  82. uint32_t out = 0;
  83. if ((id & CANARD_STM32_CAN_RIR_IDE) == 0)
  84. {
  85. out = (CANARD_CAN_STD_ID_MASK & (id >> 21U));
  86. }
  87. else
  88. {
  89. out = (CANARD_CAN_EXT_ID_MASK & (id >> 3U)) | CANARD_CAN_FRAME_EFF;
  90. }
  91. if ((id & CANARD_STM32_CAN_RIR_RTR) != 0)
  92. {
  93. out |= CANARD_CAN_FRAME_RTR;
  94. }
  95. return out;
  96. }
  97. static bool waitMSRINAKBitStateChange(volatile const CanardSTM32CANType* const bxcan, const bool target_state)
  98. {
  99. /**
  100. * A properly functioning bus will exhibit 11 consecutive recessive bits at the end of every correct transmission,
  101. * or while the bus is idle. The 11 consecutive recessive bits are made up of:
  102. * 1 bit - acknowledgement delimiter
  103. * 7 bit - end of frame bits
  104. * 3 bit - inter frame space
  105. * This adds up to 11; therefore, it is not really necessary to wait longer than a few frame TX intervals.
  106. */
  107. static const uint16_t TimeoutMilliseconds = 1000;
  108. for (uint16_t wait_ack = 0; wait_ack < TimeoutMilliseconds; wait_ack++)
  109. {
  110. const bool state = (bxcan->MSR & CANARD_STM32_CAN_MSR_INAK) != 0;
  111. if (state == target_state)
  112. {
  113. return true;
  114. }
  115. // Sleep 1 millisecond
  116. usleep(1000); // TODO: This function may be missing on some platforms
  117. }
  118. return false;
  119. }
  120. static void processErrorStatus(void)
  121. {
  122. /*
  123. * Aborting TX transmissions if abort on error was requested
  124. * Updating error counter
  125. */
  126. const uint8_t lec = (uint8_t)((BXCAN->ESR & CANARD_STM32_CAN_ESR_LEC_MASK) >> CANARD_STM32_CAN_ESR_LEC_SHIFT);
  127. if (lec != 0)
  128. {
  129. BXCAN->ESR = 0; // This action does only affect the LEC bits, other bits are read only!
  130. g_stats.error_count++;
  131. // Abort pending transmissions if auto abort on error is enabled, or if we're in bus off mode
  132. if (g_abort_tx_on_error || (BXCAN->ESR & CANARD_STM32_CAN_ESR_BOFF))
  133. {
  134. BXCAN->TSR = CANARD_STM32_CAN_TSR_ABRQ0 | CANARD_STM32_CAN_TSR_ABRQ1 | CANARD_STM32_CAN_TSR_ABRQ2;
  135. }
  136. }
  137. }
  138. int16_t canardSTM32Init(const CanardSTM32CANTimings* const timings,
  139. const CanardSTM32IfaceMode iface_mode)
  140. {
  141. /*
  142. * Paranoia time.
  143. */
  144. if ((iface_mode != CanardSTM32IfaceModeNormal) &&
  145. (iface_mode != CanardSTM32IfaceModeSilent) &&
  146. (iface_mode != CanardSTM32IfaceModeAutomaticTxAbortOnError))
  147. {
  148. return -CANARD_ERROR_INVALID_ARGUMENT;
  149. }
  150. if ((timings == NULL) ||
  151. (timings->bit_rate_prescaler < 1) || (timings->bit_rate_prescaler > 1024) ||
  152. (timings->max_resynchronization_jump_width < 1) || (timings->max_resynchronization_jump_width > 4) ||
  153. (timings->bit_segment_1 < 1) || (timings->bit_segment_1 > 16) ||
  154. (timings->bit_segment_2 < 1) || (timings->bit_segment_2 > 8))
  155. {
  156. return -CANARD_ERROR_INVALID_ARGUMENT;
  157. }
  158. /*
  159. * Initial setup
  160. */
  161. memset(&g_stats, 0, sizeof(g_stats));
  162. g_abort_tx_on_error = (iface_mode == CanardSTM32IfaceModeAutomaticTxAbortOnError);
  163. #if CANARD_STM32_USE_CAN2
  164. // If we're using CAN2, we MUST initialize CAN1 first, because CAN2 is a slave to CAN1.
  165. CANARD_STM32_CAN1->IER = 0; // We need no interrupts
  166. CANARD_STM32_CAN1->MCR &= ~CANARD_STM32_CAN_MCR_SLEEP; // Exit sleep mode
  167. CANARD_STM32_CAN1->MCR |= CANARD_STM32_CAN_MCR_INRQ; // Request init
  168. if (!waitMSRINAKBitStateChange(CANARD_STM32_CAN1, true)) // Wait for synchronization
  169. {
  170. CANARD_STM32_CAN1->MCR = CANARD_STM32_CAN_MCR_RESET;
  171. return -CANARD_STM32_ERROR_MSR_INAK_NOT_SET;
  172. }
  173. // CAN1 will be left in the initialization mode forever, in this mode it does not affect the bus at all.
  174. #endif
  175. BXCAN->IER = 0; // We need no interrupts
  176. BXCAN->MCR &= ~CANARD_STM32_CAN_MCR_SLEEP; // Exit sleep mode
  177. BXCAN->MCR |= CANARD_STM32_CAN_MCR_INRQ; // Request init
  178. if (!waitMSRINAKBitStateChange(BXCAN, true)) // Wait for synchronization
  179. {
  180. BXCAN->MCR = CANARD_STM32_CAN_MCR_RESET;
  181. return -CANARD_STM32_ERROR_MSR_INAK_NOT_SET;
  182. }
  183. /*
  184. * Hardware initialization (the hardware has already confirmed initialization mode, see above)
  185. */
  186. BXCAN->MCR = CANARD_STM32_CAN_MCR_ABOM | CANARD_STM32_CAN_MCR_AWUM | CANARD_STM32_CAN_MCR_INRQ; // RM page 648
  187. BXCAN->BTR = (((timings->max_resynchronization_jump_width - 1U) & 3U) << 24U) |
  188. (((timings->bit_segment_1 - 1U) & 15U) << 16U) |
  189. (((timings->bit_segment_2 - 1U) & 7U) << 20U) |
  190. ((timings->bit_rate_prescaler - 1U) & 1023U) |
  191. ((iface_mode == CanardSTM32IfaceModeSilent) ? CANARD_STM32_CAN_BTR_SILM : 0);
  192. CANARD_ASSERT(0 == BXCAN->IER); // Making sure the iterrupts are indeed disabled
  193. BXCAN->MCR &= ~CANARD_STM32_CAN_MCR_INRQ; // Leave init mode
  194. if (!waitMSRINAKBitStateChange(BXCAN, false))
  195. {
  196. BXCAN->MCR = CANARD_STM32_CAN_MCR_RESET;
  197. return -CANARD_STM32_ERROR_MSR_INAK_NOT_CLEARED;
  198. }
  199. /*
  200. * Default filter configuration. Note that ALL filters are available ONLY via CAN1!
  201. * CAN2 filters are offset by 14.
  202. * We use 14 filters at most always which simplifies the code and ensures compatibility with all
  203. * MCU within the STM32 family.
  204. */
  205. {
  206. uint32_t fmr = CANARD_STM32_CAN1->FMR & 0xFFFFC0F1U;
  207. fmr |= CANARD_STM32_NUM_ACCEPTANCE_FILTERS << 8U; // CAN2 start bank = 14 (if CAN2 is present)
  208. CANARD_STM32_CAN1->FMR = fmr | CANARD_STM32_CAN_FMR_FINIT;
  209. }
  210. CANARD_ASSERT(((CANARD_STM32_CAN1->FMR >> 8U) & 0x3FU) == CANARD_STM32_NUM_ACCEPTANCE_FILTERS);
  211. CANARD_STM32_CAN1->FM1R = 0; // Indentifier Mask mode
  212. CANARD_STM32_CAN1->FS1R = 0x0FFFFFFF; // All 32-bit
  213. // Filters are alternating between FIFO0 and FIFO1 in order to equalize the load.
  214. // This will cause occasional priority inversion and frame reordering on reception,
  215. // but that is acceptable for UAVCAN, and a majority of other protocols will tolerate
  216. // this too, since there will be no reordering within the same CAN ID.
  217. CANARD_STM32_CAN1->FFA1R = 0x0AAAAAAA;
  218. #if CANARD_STM32_USE_CAN2
  219. CANARD_STM32_CAN1->FilterRegister[CANARD_STM32_NUM_ACCEPTANCE_FILTERS].FR1 = 0;
  220. CANARD_STM32_CAN1->FilterRegister[CANARD_STM32_NUM_ACCEPTANCE_FILTERS].FR2 = 0;
  221. CANARD_STM32_CAN1->FA1R = (1 << CANARD_STM32_NUM_ACCEPTANCE_FILTERS); // One filter enabled
  222. #else
  223. CANARD_STM32_CAN1->FilterRegister[0].FR1 = 0;
  224. CANARD_STM32_CAN1->FilterRegister[0].FR2 = 0;
  225. CANARD_STM32_CAN1->FA1R = 1; // One filter enabled
  226. #endif
  227. CANARD_STM32_CAN1->FMR &= ~CANARD_STM32_CAN_FMR_FINIT; // Leave initialization mode
  228. return 0;
  229. }
  230. int16_t canardSTM32Transmit(const CanardCANFrame* const frame)
  231. {
  232. if (frame == NULL)
  233. {
  234. return -CANARD_ERROR_INVALID_ARGUMENT;
  235. }
  236. if (frame->id & CANARD_CAN_FRAME_ERR)
  237. {
  238. return -CANARD_STM32_ERROR_UNSUPPORTED_FRAME_FORMAT;
  239. }
  240. /*
  241. * Handling error status might free up some slots through aborts
  242. */
  243. processErrorStatus();
  244. /*
  245. * Seeking an empty slot, checking if priority inversion would occur if we enqueued now.
  246. * We can always enqueue safely if all TX mailboxes are free and no transmissions are pending.
  247. */
  248. uint8_t tx_mailbox = 0xFF;
  249. static const uint32_t AllTME = CANARD_STM32_CAN_TSR_TME0 | CANARD_STM32_CAN_TSR_TME1 | CANARD_STM32_CAN_TSR_TME2;
  250. if ((BXCAN->TSR & AllTME) != AllTME) // At least one TX mailbox is used, detailed check is needed
  251. {
  252. const bool tme[3] =
  253. {
  254. (BXCAN->TSR & CANARD_STM32_CAN_TSR_TME0) != 0,
  255. (BXCAN->TSR & CANARD_STM32_CAN_TSR_TME1) != 0,
  256. (BXCAN->TSR & CANARD_STM32_CAN_TSR_TME2) != 0
  257. };
  258. for (uint8_t i = 0; i < 3; i++)
  259. {
  260. if (tme[i]) // This TX mailbox is free, we can use it
  261. {
  262. tx_mailbox = i;
  263. }
  264. else // This TX mailbox is pending, check for priority inversion
  265. {
  266. if (!isFramePriorityHigher(frame->id, convertFrameIDRegisterToCanard(BXCAN->TxMailbox[i].TIR)))
  267. {
  268. // There's a mailbox whose priority is higher or equal the priority of the new frame.
  269. return 0; // Priority inversion would occur! Reject transmission.
  270. }
  271. }
  272. }
  273. if (tx_mailbox == 0xFF)
  274. {
  275. /*
  276. * All TX mailboxes are busy (this is highly unlikely); at the same time we know that there is no
  277. * higher or equal priority frame that is currently pending. Therefore, priority inversion has
  278. * just happend (sic!), because we can't enqueue the higher priority frame due to all TX mailboxes
  279. * being busy. This scenario is extremely unlikely, because in order for it to happen, the application
  280. * would need to transmit 4 (four) or more CAN frames with different CAN ID ordered from high ID to
  281. * low ID nearly at the same time. For example:
  282. * 1. 0x123 <-- Takes mailbox 0 (or any other)
  283. * 2. 0x122 <-- Takes mailbox 2 (or any other)
  284. * 3. 0x121 <-- Takes mailbox 1 (or any other)
  285. * 4. 0x120 <-- INNER PRIORITY INVERSION HERE (only if all three TX mailboxes are still busy)
  286. * This situation is even less likely to cause any noticeable disruptions on the CAN bus. Despite that,
  287. * it is better to warn the developer about that during debugging, so we fire an assertion failure here.
  288. * It is perfectly safe to remove it.
  289. */
  290. #if CANARD_STM32_DEBUG_INNER_PRIORITY_INVERSION
  291. CANARD_ASSERT(!"CAN PRIO INV");
  292. #endif
  293. return 0;
  294. }
  295. }
  296. else // All TX mailboxes are free, use first
  297. {
  298. tx_mailbox = 0;
  299. }
  300. CANARD_ASSERT(tx_mailbox < 3); // Index check - the value must be correct here
  301. /*
  302. * By this time we've proved that a priority inversion would not occur, and we've also found a free TX mailbox.
  303. * Therefore it is safe to enqueue the frame now.
  304. */
  305. volatile CanardSTM32TxMailboxType* const mb = &BXCAN->TxMailbox[tx_mailbox];
  306. mb->TDTR = frame->data_len; // DLC equals data length except in CAN FD
  307. mb->TDHR = (((uint32_t)frame->data[7]) << 24U) |
  308. (((uint32_t)frame->data[6]) << 16U) |
  309. (((uint32_t)frame->data[5]) << 8U) |
  310. (((uint32_t)frame->data[4]) << 0U);
  311. mb->TDLR = (((uint32_t)frame->data[3]) << 24U) |
  312. (((uint32_t)frame->data[2]) << 16U) |
  313. (((uint32_t)frame->data[1]) << 8U) |
  314. (((uint32_t)frame->data[0]) << 0U);
  315. mb->TIR = convertFrameIDCanardToRegister(frame->id) | CANARD_STM32_CAN_TIR_TXRQ; // Go.
  316. /*
  317. * The frame is now enqueued and pending transmission.
  318. */
  319. return 1;
  320. }
  321. int16_t canardSTM32Receive(CanardCANFrame* const out_frame)
  322. {
  323. if (out_frame == NULL)
  324. {
  325. return -CANARD_ERROR_INVALID_ARGUMENT;
  326. }
  327. static volatile uint32_t* const RFxR[2] =
  328. {
  329. &BXCAN->RF0R,
  330. &BXCAN->RF1R
  331. };
  332. /*
  333. * This function must be polled periodically, so we use this opportunity to do it.
  334. */
  335. processErrorStatus();
  336. /*
  337. * Reading the TX FIFO
  338. */
  339. for (uint_fast8_t i = 0; i < 2; i++)
  340. {
  341. volatile CanardSTM32RxMailboxType* const mb = &BXCAN->RxMailbox[i];
  342. if (((*RFxR[i]) & CANARD_STM32_CAN_RFR_FMP_MASK) != 0)
  343. {
  344. if (*RFxR[i] & CANARD_STM32_CAN_RFR_FOVR)
  345. {
  346. g_stats.rx_overflow_count++;
  347. }
  348. out_frame->id = convertFrameIDRegisterToCanard(mb->RIR);
  349. out_frame->data_len = (uint8_t)(mb->RDTR & CANARD_STM32_CAN_RDTR_DLC_MASK);
  350. // Caching to regular (non volatile) memory for faster reads
  351. const uint32_t rdlr = mb->RDLR;
  352. const uint32_t rdhr = mb->RDHR;
  353. out_frame->data[0] = (uint8_t)(0xFFU & (rdlr >> 0U));
  354. out_frame->data[1] = (uint8_t)(0xFFU & (rdlr >> 8U));
  355. out_frame->data[2] = (uint8_t)(0xFFU & (rdlr >> 16U));
  356. out_frame->data[3] = (uint8_t)(0xFFU & (rdlr >> 24U));
  357. out_frame->data[4] = (uint8_t)(0xFFU & (rdhr >> 0U));
  358. out_frame->data[5] = (uint8_t)(0xFFU & (rdhr >> 8U));
  359. out_frame->data[6] = (uint8_t)(0xFFU & (rdhr >> 16U));
  360. out_frame->data[7] = (uint8_t)(0xFFU & (rdhr >> 24U));
  361. // Release FIFO entry we just read
  362. *RFxR[i] = CANARD_STM32_CAN_RFR_RFOM | CANARD_STM32_CAN_RFR_FOVR | CANARD_STM32_CAN_RFR_FULL;
  363. // Reading successful
  364. return 1;
  365. }
  366. }
  367. // No frames to read
  368. return 0;
  369. }
  370. int16_t canardSTM32ConfigureAcceptanceFilters(const CanardSTM32AcceptanceFilterConfiguration* const filter_configs,
  371. const uint8_t num_filter_configs)
  372. {
  373. // Note that num_filter_configs = 0 is a valid configuration, which rejects all frames.
  374. if ((filter_configs == NULL) ||
  375. (num_filter_configs > CANARD_STM32_NUM_ACCEPTANCE_FILTERS))
  376. {
  377. return -CANARD_ERROR_INVALID_ARGUMENT;
  378. }
  379. /*
  380. * First we disable all filters. This may cause momentary RX frame losses, but the application
  381. * should be able to tolerate that.
  382. */
  383. CANARD_STM32_CAN1->FA1R = 0;
  384. /*
  385. * Having filters disabled we can update the configuration.
  386. * Register mapping: FR1 - ID, FR2 - Mask
  387. */
  388. for (uint8_t i = 0; i < num_filter_configs; i++)
  389. {
  390. /*
  391. * Converting the ID and the Mask into the representation that can be chewed by the hardware.
  392. * If Mask asks us to accept both STDID and EXTID, we need to use EXT mode on the filter,
  393. * otherwise it will reject all EXTID frames. This logic is not documented in the RM.
  394. *
  395. * The logic of the hardware acceptance filters can be described as follows:
  396. *
  397. * accepted = (received_id & filter_mask) == (filter_id & filter_mask)
  398. *
  399. * Where:
  400. * - accepted - if true, the frame will be accepted by the filter.
  401. * - received_id - the CAN ID of the received frame, either 11-bit or 29-bit, with extension bits
  402. * marking extended frames, error frames, etc.
  403. * - filter_id - the value of the filter ID register.
  404. * - filter_mask - the value of the filter mask register.
  405. *
  406. * There are special bits that are not members of the CAN ID field:
  407. * - EFF - set for extended frames (29-bit), cleared for standard frames (11-bit)
  408. * - RTR - like above, indicates Remote Transmission Request frames.
  409. *
  410. * The following truth table summarizes the logic (where: FM - filter mask, FID - filter ID, RID - received
  411. * frame ID, A - true if accepted, X - any state):
  412. *
  413. * FM FID RID A
  414. * 0 X X 1
  415. * 1 0 0 1
  416. * 1 1 0 0
  417. * 1 0 1 0
  418. * 1 1 1 1
  419. *
  420. * One would expect that for the purposes of hardware filtering, the special bits should be treated
  421. * in the same way as the real ID bits. However, this is not the case with bxCAN. The following truth
  422. * table has been determined empirically (this behavior was not documented as of 2017):
  423. *
  424. * FM FID RID A
  425. * 0 0 0 1
  426. * 0 0 1 0 <-- frame rejected!
  427. * 0 1 X 1
  428. * 1 0 0 1
  429. * 1 1 0 0
  430. * 1 0 1 0
  431. * 1 1 1 1
  432. */
  433. uint32_t id = 0;
  434. uint32_t mask = 0;
  435. const CanardSTM32AcceptanceFilterConfiguration* const cfg = filter_configs + i;
  436. if ((cfg->id & CANARD_CAN_FRAME_EFF) || !(cfg->mask & CANARD_CAN_FRAME_EFF))
  437. {
  438. id = (cfg->id & CANARD_CAN_EXT_ID_MASK) << 3U;
  439. mask = (cfg->mask & CANARD_CAN_EXT_ID_MASK) << 3U;
  440. id |= CANARD_STM32_CAN_RIR_IDE;
  441. }
  442. else
  443. {
  444. id = (cfg->id & CANARD_CAN_STD_ID_MASK) << 21U;
  445. mask = (cfg->mask & CANARD_CAN_STD_ID_MASK) << 21U;
  446. }
  447. if (cfg->id & CANARD_CAN_FRAME_RTR)
  448. {
  449. id |= CANARD_STM32_CAN_RIR_RTR;
  450. }
  451. if (cfg->mask & CANARD_CAN_FRAME_EFF)
  452. {
  453. mask |= CANARD_STM32_CAN_RIR_IDE;
  454. }
  455. if (cfg->mask & CANARD_CAN_FRAME_RTR)
  456. {
  457. mask |= CANARD_STM32_CAN_RIR_RTR;
  458. }
  459. /*
  460. * Applying the converted representation to the registers.
  461. */
  462. const uint8_t filter_index =
  463. #if CANARD_STM32_USE_CAN2
  464. (uint8_t)(i + CANARD_STM32_NUM_ACCEPTANCE_FILTERS);
  465. #else
  466. i;
  467. #endif
  468. CANARD_STM32_CAN1->FilterRegister[filter_index].FR1 = id;
  469. CANARD_STM32_CAN1->FilterRegister[filter_index].FR2 = mask;
  470. CANARD_STM32_CAN1->FA1R |= 1U << filter_index; // Enable
  471. }
  472. return 0;
  473. }
  474. CanardSTM32Stats canardSTM32GetStats(void)
  475. {
  476. return g_stats;
  477. }