libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
ch32_can.cpp
1#include "ch32_can.hpp"
2
3using namespace LibXR;
4
5CH32CAN* CH32CAN::map[CH32_CAN_NUMBER] = {nullptr};
6
7static inline uint8_t ch32_can_mode_macro(const CAN::Mode& m)
8{
9 if (m.loopback && m.listen_only)
10 {
11 return CAN_Mode_Silent_LoopBack;
12 }
13 if (m.loopback)
14 {
15 return CAN_Mode_LoopBack;
16 }
17 if (m.listen_only)
18 {
19 return CAN_Mode_Silent;
20 }
21 return CAN_Mode_Normal;
22}
23
32static inline void CH32_CAN_EnableNVIC(ch32_can_id_t id, uint8_t fifo)
33{
34 // ===== TX =====
35 switch (id)
36 {
37#if defined(CAN1)
38 case CH32_CAN1:
39 NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn);
40 break;
41#endif
42
43#if defined(CAN2)
44 case CH32_CAN2:
45 NVIC_EnableIRQ(CAN2_TX_IRQn);
46 break;
47#endif
48 default:
49 break;
50 }
51
52 // ===== RX (FIFO0 -> RX0 vector, FIFO1 -> RX1 vector) =====
53 if (fifo == 0u)
54 {
55 switch (id)
56 {
57#if defined(CAN1)
58 case CH32_CAN1:
59 NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
60 break;
61#endif
62
63#if defined(CAN2)
64 case CH32_CAN2:
65 NVIC_EnableIRQ(CAN2_RX0_IRQn);
66 break;
67#endif
68 default:
69 break;
70 }
71 }
72 else
73 {
74 switch (id)
75 {
76#if defined(CAN1)
77 case CH32_CAN1:
78 NVIC_EnableIRQ(CAN1_RX1_IRQn);
79 break;
80#endif
81
82#if defined(CAN2)
83 case CH32_CAN2:
84 NVIC_EnableIRQ(CAN2_RX1_IRQn);
85 break;
86#endif
87
88 default:
89 break;
90 }
91 }
92
93 // ===== SCE =====
94 switch (id)
95 {
96#if defined(CAN1)
97 case CH32_CAN1:
98 NVIC_EnableIRQ(CAN1_SCE_IRQn);
99 break;
100#endif
101
102#if defined(CAN2)
103 case CH32_CAN2:
104 NVIC_EnableIRQ(CAN2_SCE_IRQn);
105 break;
106#endif
107
108 default:
109 break;
110 }
111}
112
113CH32CAN::CH32CAN(ch32_can_id_t id, uint32_t pool_size)
114 : CAN(), instance_(CH32_CAN_GetInstanceID(id)), id_(id), tx_pool_(pool_size)
115{
116#if defined(CAN2)
117 if (id == CH32_CAN1)
118 {
119 filter_bank_ = 0;
120 fifo_ = CAN_FilterFIFO0; // 0
121 }
122 else
123 {
124 filter_bank_ = 14;
125 fifo_ = CAN_FilterFIFO1; // 1
126 }
127#else
128 filter_bank_ = 0;
129 fifo_ = CAN_FilterFIFO0; // 0
130#endif
131
132 ASSERT(id_ < CH32_CAN_NUMBER);
133 ASSERT(instance_ != nullptr);
134
135 map[id_] = this;
136
137 // Enable peripheral clock
138 RCC_APB1PeriphClockCmd(CH32_CAN_RCC_PERIPH_MAP[id_], ENABLE);
139
140 // Keep CAN in initialization mode until user calls SetConfig().
141 (void)CAN_OperatingModeRequest(instance_, CAN_OperatingMode_Initialization);
142
143#if defined(CAN2)
144 // If dual CAN exists and filters are shared, set a typical split point.
145 CAN_SlaveStartBank(CH32_CAN_DEFAULT_SLAVE_START_BANK);
146#endif
147
148 (void)Init();
149}
150
151ErrorCode CH32CAN::Init()
152{
153 if (instance_ == nullptr)
154 {
155 return ErrorCode::ARG_ERR;
156 }
157
158 // ===== Accept-all filter (ID Mask, all zeros) =====
159 CAN_FilterInitTypeDef f = {};
160 f.CAN_FilterIdHigh = 0u;
161 f.CAN_FilterIdLow = 0u;
162 f.CAN_FilterMaskIdHigh = 0u;
163 f.CAN_FilterMaskIdLow = 0u;
164 f.CAN_FilterFIFOAssignment = fifo_;
165 f.CAN_FilterNumber = filter_bank_;
166 f.CAN_FilterMode = CAN_FilterMode_IdMask;
167 f.CAN_FilterScale = CAN_FilterScale_32bit;
168 f.CAN_FilterActivation = ENABLE;
169
170 CAN_FilterInit(&f);
171
172 EnableIRQs();
173
174 // Enable NVIC for this CAN instance (handles WCH alias IRQ names correctly)
175 CH32_CAN_EnableNVIC(id_, fifo_);
176
177 return ErrorCode::OK;
178}
179
180void CH32CAN::DisableIRQs()
181{
182 if (instance_ == nullptr) return;
183
184 uint32_t it = 0u;
185
186#ifdef CAN_IT_FMP0
187 if (fifo_ == 0u) it |= CAN_IT_FMP0;
188#endif
189#ifdef CAN_IT_FMP1
190 if (fifo_ == 1u) it |= CAN_IT_FMP1;
191#endif
192
193#ifdef CAN_IT_TME
194 it |= CAN_IT_TME;
195#endif
196
197#ifdef CAN_IT_ERR
198 it |= CAN_IT_ERR;
199#endif
200#ifdef CAN_IT_BOF
201 it |= CAN_IT_BOF;
202#endif
203#ifdef CAN_IT_EPV
204 it |= CAN_IT_EPV;
205#endif
206#ifdef CAN_IT_EWG
207 it |= CAN_IT_EWG;
208#endif
209#ifdef CAN_IT_LEC
210 it |= CAN_IT_LEC;
211#endif
212
213 if (it != 0u)
214 {
215 CAN_ITConfig(instance_, it, DISABLE);
216 }
217}
218
219void CH32CAN::EnableIRQs()
220{
221 if (instance_ == nullptr) return;
222
223 uint32_t it = 0u;
224
225#ifdef CAN_IT_FMP0
226 if (fifo_ == 0u) it |= CAN_IT_FMP0;
227#endif
228#ifdef CAN_IT_FMP1
229 if (fifo_ == 1u) it |= CAN_IT_FMP1;
230#endif
231
232#ifdef CAN_IT_TME
233 it |= CAN_IT_TME;
234#endif
235
236#ifdef CAN_IT_ERR
237 it |= CAN_IT_ERR;
238#endif
239#ifdef CAN_IT_BOF
240 it |= CAN_IT_BOF;
241#endif
242#ifdef CAN_IT_EPV
243 it |= CAN_IT_EPV;
244#endif
245#ifdef CAN_IT_EWG
246 it |= CAN_IT_EWG;
247#endif
248#ifdef CAN_IT_LEC
249 it |= CAN_IT_LEC;
250#endif
251
252 if (it != 0u)
253 {
254 // WCH StdPeriph examples: clear pending bits before enabling interrupts
255 // to avoid spurious entry and ensure proper ACK in some variants.
256#ifdef CAN_IT_TME
257 if ((it & CAN_IT_TME) != 0u)
258 {
259 CAN_ClearITPendingBit(instance_, CAN_IT_TME);
260 }
261#endif
262
263#ifdef CAN_IT_FMP0
264 if (fifo_ == 0u && ((it & CAN_IT_FMP0) != 0u))
265 {
266 CAN_ClearITPendingBit(instance_, CAN_IT_FMP0);
267 }
268#endif
269#ifdef CAN_IT_FMP1
270 if (fifo_ == 1u && ((it & CAN_IT_FMP1) != 0u))
271 {
272 CAN_ClearITPendingBit(instance_, CAN_IT_FMP1);
273 }
274#endif
275
276 CAN_ITConfig(instance_, it, ENABLE);
277 }
278}
279
280static inline bool is_nonzero_bit_timing(const CAN::BitTiming& bt)
281{
282 return (bt.brp != 0u) || (bt.prop_seg != 0u) || (bt.phase_seg1 != 0u) ||
283 (bt.phase_seg2 != 0u) || (bt.sjw != 0u);
284}
285
286static inline bool fill_keep_zero_from_cache(CAN::BitTiming& dst,
287 const CAN::BitTiming& cache)
288{
289 auto keep = [&](uint32_t& field, uint32_t cached) -> bool
290 {
291 if (field == 0u)
292 {
293 if (cached == 0u) return false;
294 field = cached;
295 }
296 return true;
297 };
298
299 bool ok = true;
300 ok &= keep(dst.brp, cache.brp);
301 ok &= keep(dst.prop_seg, cache.prop_seg);
302 ok &= keep(dst.phase_seg1, cache.phase_seg1);
303 ok &= keep(dst.phase_seg2, cache.phase_seg2);
304 ok &= keep(dst.sjw, cache.sjw);
305 return ok;
306}
307
309{
310 if (instance_ == nullptr)
311 {
312 return ErrorCode::ARG_ERR;
313 }
314
315 // RAII: ensure IRQs are always restored even if we early-return
316 struct IrqGuard
317 {
318 CH32CAN* self;
319 explicit IrqGuard(CH32CAN* s) : self(s) { self->DisableIRQs(); }
320 ~IrqGuard() { self->EnableIRQs(); }
321 } guard(this);
322
323 ErrorCode ec = ErrorCode::OK;
324 bool entered_init = false;
325
326 // Build an "effective" timing: support "0 means keep last applied".
327 CAN::Configuration cfg = cfg_in;
328
329 // Normalize bit timing (fill zeros from cache)
330 if (!is_nonzero_bit_timing(cfg.bit_timing))
331 {
332 if (!fill_keep_zero_from_cache(cfg.bit_timing, cfg_cache_.bit_timing))
333 {
334 return ErrorCode::ARG_ERR;
335 }
336 }
337 else
338 {
339 if (!fill_keep_zero_from_cache(cfg.bit_timing, cfg_cache_.bit_timing))
340 {
341 return ErrorCode::ARG_ERR;
342 }
343 }
344
345 // ===== Validate timing (bxCAN constraints) =====
346 const CAN::BitTiming& bt = cfg.bit_timing;
347
348 // brp: 1..1024
349 if (bt.brp < 1u || bt.brp > 1024u)
350 {
351 ASSERT(false);
352 return ErrorCode::ARG_ERR;
353 }
354
355 // BS1 = prop + phase1: 1..16
356 const uint32_t bs1 = bt.prop_seg + bt.phase_seg1;
357 if (bs1 < 1u || bs1 > 16u)
358 {
359 ASSERT(false);
360 return ErrorCode::ARG_ERR;
361 }
362
363 // BS2: 1..8
364 if (bt.phase_seg2 < 1u || bt.phase_seg2 > 8u)
365 {
366 ASSERT(false);
367 return ErrorCode::ARG_ERR;
368 }
369
370 // SJW: 1..4 and SJW <= BS2
371 if (bt.sjw < 1u || bt.sjw > 4u || bt.sjw > bt.phase_seg2)
372 {
373 ASSERT(false);
374 return ErrorCode::ARG_ERR;
375 }
376
377 // ===== Enter initialization mode =====
378 if (CAN_OperatingModeRequest(instance_, CAN_OperatingMode_Initialization) ==
379 CAN_ModeStatus_Failed)
380 {
381 return ErrorCode::FAILED;
382 }
383 entered_init = true;
384
385 // ===== Apply init struct =====
386 CAN_InitTypeDef init;
387 std::memset(&init, 0, sizeof(init));
388 CAN_StructInit(&init);
389
390 init.CAN_Prescaler = static_cast<uint16_t>(bt.brp);
391 init.CAN_Mode = ch32_can_mode_macro(cfg.mode);
392
393 init.CAN_SJW = static_cast<uint8_t>(bt.sjw - 1u);
394 init.CAN_BS1 = static_cast<uint8_t>(bs1 - 1u);
395 init.CAN_BS2 = static_cast<uint8_t>(bt.phase_seg2 - 1u);
396
397 // Mode knobs (best-effort mapping)
398 init.CAN_NART = cfg.mode.one_shot ? ENABLE : DISABLE;
399
400 // Reasonable defaults
401 init.CAN_TTCM = DISABLE;
402 init.CAN_ABOM = ENABLE; // auto bus-off management
403 init.CAN_AWUM = DISABLE; // auto wake-up
404 init.CAN_RFLM = DISABLE; // FIFO not locked
405 init.CAN_TXFP = ENABLE; // prioritize by TX request order
406
407 if (CAN_Init(instance_, &init) != CAN_InitStatus_Success)
408 {
409 ec = ErrorCode::FAILED;
410 }
411 else
412 {
413 if (CAN_OperatingModeRequest(instance_, CAN_OperatingMode_Normal) ==
414 CAN_ModeStatus_Failed)
415 {
416 ec = ErrorCode::FAILED;
417 }
418 else
419 {
420 // Update cache only when success
421 cfg_cache_ = cfg;
422 ec = ErrorCode::OK;
423 }
424 }
425
426 // Best-effort: if we entered init but failed later, try to return to normal
427 if (ec != ErrorCode::OK && entered_init)
428 {
429 (void)CAN_OperatingModeRequest(instance_, CAN_OperatingMode_Normal);
430 }
431
432 return ec;
433}
434
435uint32_t CH32CAN::GetClockFreq() const
436{
437 RCC_ClocksTypeDef clocks{};
438 RCC_GetClocksFreq(&clocks);
439 return clocks.PCLK1_Frequency;
440}
441
442inline void CH32CAN::BuildTxMsg(const ClassicPack& p, CanTxMsg& m)
443{
444 const bool is_ext = (p.type == Type::EXTENDED) || (p.type == Type::REMOTE_EXTENDED);
445 const bool is_rtr =
446 (p.type == Type::REMOTE_STANDARD) || (p.type == Type::REMOTE_EXTENDED);
447
448 m.DLC = (p.dlc <= 8u) ? static_cast<uint8_t>(p.dlc) : 8u;
449 m.IDE = is_ext ? CAN_ID_EXT : CAN_ID_STD;
450 m.RTR = is_rtr ? CAN_RTR_REMOTE : CAN_RTR_DATA;
451
452 m.StdId = is_ext ? 0u : (p.id & 0x7FFu);
453 m.ExtId = is_ext ? (p.id & 0x1FFFFFFFu) : 0u;
454
455 std::memcpy(m.Data, p.data, 8);
456}
457
458void CH32CAN::TxService()
459{
460 if (instance_ == nullptr) return;
461
462 tx_pend_.store(1u, std::memory_order_release);
463
464 uint32_t expected = 0u;
465 if (!tx_lock_.compare_exchange_strong(expected, 1u, std::memory_order_acquire,
466 std::memory_order_relaxed))
467 {
468 return;
469 }
470
471 for (;;)
472 {
473 tx_pend_.store(0u, std::memory_order_release);
474
475 for (;;)
476 {
477 ClassicPack p{};
478 if (tx_pool_.Get(p) != ErrorCode::OK)
479 {
480 break;
481 }
482
483 BuildTxMsg(p, tx_msg_);
484
485 uint8_t mb = CAN_Transmit(instance_, &tx_msg_);
486 if (mb == CAN_TxStatus_NoMailBox)
487 {
488 (void)tx_pool_.Put(p);
489 break;
490 }
491 }
492
493 tx_lock_.store(0u, std::memory_order_release);
494
495 if (tx_pend_.load(std::memory_order_acquire) == 0u)
496 {
497 return;
498 }
499
500 expected = 0u;
501 if (!tx_lock_.compare_exchange_strong(expected, 1u, std::memory_order_acquire,
502 std::memory_order_relaxed))
503 {
504 return;
505 }
506 }
507}
508
509ErrorCode CH32CAN::AddMessage(const ClassicPack& pack)
510{
511 if (pack.type == Type::ERROR)
512 {
513 return ErrorCode::ARG_ERR;
514 }
515
516 if (tx_pool_.Put(pack) != ErrorCode::OK)
517 {
518 return ErrorCode::FULL;
519 }
520
521 TxService();
522 return ErrorCode::OK;
523}
524
526{
527#ifdef CAN_IT_TME
528 if (instance_ == nullptr) return;
529
530 if (CAN_GetITStatus(instance_, CAN_IT_TME) != RESET)
531 {
532 CAN_ClearITPendingBit(instance_, CAN_IT_TME);
533 TxService();
534 }
535#else
536 TxService();
537#endif
538}
539
541{
542 if (instance_ == nullptr) return;
543
544 // NOTE:
545 // WCH examples clear FMP pending in RX ISR.
546 // We keep the "drain FIFO" behavior and ACK pending at the end.
547 while (CAN_MessagePending(instance_, fifo_) != 0u)
548 {
549 CAN_Receive(instance_, fifo_, &rx_msg_);
550
551 ClassicPack p{};
552 if (rx_msg_.IDE == CAN_ID_STD)
553 {
554 p.id = rx_msg_.StdId;
555 p.type = Type::STANDARD;
556 }
557 else
558 {
559 p.id = rx_msg_.ExtId;
560 p.type = Type::EXTENDED;
561 }
562
563 if (rx_msg_.RTR == CAN_RTR_REMOTE)
564 {
566 }
567
568 p.dlc = (rx_msg_.DLC <= 8u) ? rx_msg_.DLC : 8u;
569 std::memcpy(p.data, rx_msg_.Data, 8);
570
571 OnMessage(p, true);
572 }
573
574 // ACK RX pending (WCH StdPeriph style)
575#ifdef CAN_IT_FMP0
576 if (fifo_ == 0u)
577 {
578 if (CAN_GetITStatus(instance_, CAN_IT_FMP0) != RESET)
579 {
580 CAN_ClearITPendingBit(instance_, CAN_IT_FMP0);
581 }
582 }
583#endif
584#ifdef CAN_IT_FMP1
585 if (fifo_ == 1u)
586 {
587 if (CAN_GetITStatus(instance_, CAN_IT_FMP1) != RESET)
588 {
589 CAN_ClearITPendingBit(instance_, CAN_IT_FMP1);
590 }
591 }
592#endif
593}
594
596{
597 if (instance_ == nullptr) return;
598
599 // NOTE (Fix #2):
600 // WCH CAN_ClearITPendingBit(CAN_IT_ERR/CAN_IT_LEC) clears ERRSR.
601 // Therefore snapshot flags + LEC BEFORE clearing any pending bits.
602 const bool bof = (CAN_GetFlagStatus(instance_, CAN_FLAG_BOF) != RESET);
603 const bool epv = (CAN_GetFlagStatus(instance_, CAN_FLAG_EPV) != RESET);
604 const bool ewg = (CAN_GetFlagStatus(instance_, CAN_FLAG_EWG) != RESET);
605 const uint8_t lec = CAN_GetLastErrorCode(instance_);
606
607#ifdef CAN_IT_LEC
608 if (CAN_GetITStatus(instance_, CAN_IT_LEC) != RESET)
609 {
610 CAN_ClearITPendingBit(instance_, CAN_IT_LEC);
611 }
612#endif
613#ifdef CAN_IT_ERR
614 if (CAN_GetITStatus(instance_, CAN_IT_ERR) != RESET)
615 {
616 CAN_ClearITPendingBit(instance_, CAN_IT_ERR);
617 }
618#endif
619#ifdef CAN_IT_BOF
620 if (CAN_GetITStatus(instance_, CAN_IT_BOF) != RESET)
621 {
622 CAN_ClearITPendingBit(instance_, CAN_IT_BOF);
623 }
624#endif
625#ifdef CAN_IT_EPV
626 if (CAN_GetITStatus(instance_, CAN_IT_EPV) != RESET)
627 {
628 CAN_ClearITPendingBit(instance_, CAN_IT_EPV);
629 }
630#endif
631#ifdef CAN_IT_EWG
632 if (CAN_GetITStatus(instance_, CAN_IT_EWG) != RESET)
633 {
634 CAN_ClearITPendingBit(instance_, CAN_IT_EWG);
635 }
636#endif
637
638 ClassicPack p{};
639 p.type = Type::ERROR;
640 p.dlc = 0u;
641
642 CAN::ErrorID eid = CAN::ErrorID::CAN_ERROR_ID_GENERIC;
643
644 if (bof)
645 {
646 eid = CAN::ErrorID::CAN_ERROR_ID_BUS_OFF;
647 }
648 else if (epv)
649 {
650 eid = CAN::ErrorID::CAN_ERROR_ID_ERROR_PASSIVE;
651 }
652 else if (ewg)
653 {
654 eid = CAN::ErrorID::CAN_ERROR_ID_ERROR_WARNING;
655 }
656 else
657 {
658 switch (lec)
659 {
660 case CAN_ErrorCode_StuffErr:
661 eid = CAN::ErrorID::CAN_ERROR_ID_STUFF;
662 break;
663 case CAN_ErrorCode_FormErr:
664 eid = CAN::ErrorID::CAN_ERROR_ID_FORM;
665 break;
666 case CAN_ErrorCode_ACKErr:
667 eid = CAN::ErrorID::CAN_ERROR_ID_ACK;
668 break;
669 case CAN_ErrorCode_BitRecessiveErr:
670 eid = CAN::ErrorID::CAN_ERROR_ID_BIT1;
671 break;
672 case CAN_ErrorCode_BitDominantErr:
673 eid = CAN::ErrorID::CAN_ERROR_ID_BIT0;
674 break;
675 case CAN_ErrorCode_CRCErr:
676 eid = CAN::ErrorID::CAN_ERROR_ID_CRC;
677 break;
678 default:
679 eid = CAN::ErrorID::CAN_ERROR_ID_OTHER;
680 break;
681 }
682 }
683
684 p.id = static_cast<uint32_t>(eid);
685 OnMessage(p, true);
686}
687
689{
690 if (instance_ == nullptr)
691 {
692 return ErrorCode::ARG_ERR;
693 }
694
695 state.rx_error_counter = CAN_GetReceiveErrorCounter(instance_);
696 state.tx_error_counter = CAN_GetLSBTransmitErrorCounter(instance_);
697
698 state.bus_off = (CAN_GetFlagStatus(instance_, CAN_FLAG_BOF) != RESET);
699 state.error_passive = (CAN_GetFlagStatus(instance_, CAN_FLAG_EPV) != RESET);
700 state.error_warning = (CAN_GetFlagStatus(instance_, CAN_FLAG_EWG) != RESET);
701
702 return ErrorCode::OK;
703}
704
705#if defined(CAN1)
706extern "C" void USB_HP_CAN1_TX_IRQHandler(void) __attribute__((interrupt));
707extern "C" void USB_HP_CAN1_TX_IRQHandler(void)
708{
709 if (auto* can = LibXR::CH32CAN::map[CH32_CAN1])
710 {
711 can->ProcessTxInterrupt();
712 }
713}
714
715extern "C" void USB_LP_CAN1_RX0_IRQHandler(void) __attribute__((interrupt));
716extern "C" void USB_LP_CAN1_RX0_IRQHandler(void)
717{
718 if (auto* can = LibXR::CH32CAN::map[CH32_CAN1])
719 {
720 can->ProcessRxInterrupt();
721 }
722}
723
724extern "C" void CAN1_TX_IRQHandler(void) __attribute__((interrupt));
725extern "C" void CAN1_TX_IRQHandler(void)
726{
727 if (auto* can = LibXR::CH32CAN::map[CH32_CAN1])
728 {
729 can->ProcessTxInterrupt();
730 }
731}
732
733extern "C" void CAN1_RX1_IRQHandler(void) __attribute__((interrupt));
734extern "C" void CAN1_RX1_IRQHandler(void)
735{
736 if (auto* can = LibXR::CH32CAN::map[CH32_CAN1])
737 {
738 can->ProcessRxInterrupt();
739 }
740}
741
742extern "C" void CAN1_SCE_IRQHandler(void) __attribute__((interrupt));
743extern "C" void CAN1_SCE_IRQHandler(void)
744{
745 if (auto* can = LibXR::CH32CAN::map[CH32_CAN1])
746 {
747 can->ProcessErrorInterrupt();
748 }
749}
750#endif
751
752#if defined(CAN2)
753extern "C" void CAN2_TX_IRQHandler(void) __attribute__((interrupt));
754extern "C" void CAN2_TX_IRQHandler(void)
755{
756 if (auto* can = LibXR::CH32CAN::map[CH32_CAN2])
757 {
758 can->ProcessTxInterrupt();
759 }
760}
761
762extern "C" void CAN2_RX0_IRQHandler(void) __attribute__((interrupt));
763extern "C" void CAN2_RX0_IRQHandler(void)
764{
765 if (auto* can = LibXR::CH32CAN::map[CH32_CAN2])
766 {
767 can->ProcessRxInterrupt();
768 }
769}
770
771extern "C" void CAN2_RX1_IRQHandler(void) __attribute__((interrupt));
772extern "C" void CAN2_RX1_IRQHandler(void)
773{
774 if (auto* can = LibXR::CH32CAN::map[CH32_CAN2])
775 {
776 can->ProcessRxInterrupt();
777 }
778}
779
780extern "C" void CAN2_SCE_IRQHandler(void) __attribute__((interrupt));
781extern "C" void CAN2_SCE_IRQHandler(void)
782{
783 if (auto* can = LibXR::CH32CAN::map[CH32_CAN2])
784 {
785 can->ProcessErrorInterrupt();
786 }
787}
788#endif
CAN 通信抽象类,定义经典 CAN 帧与订阅接口。 Abstract class for CAN communication with classic CAN frames and subscript...
Definition can.hpp:16
@ EXTENDED
扩展数据帧(29-bit ID)。Extended data frame (29-bit ID).
@ REMOTE_EXTENDED
扩展远程帧。Extended remote frame.
@ STANDARD
标准数据帧(11-bit ID)。Standard data frame (11-bit ID).
@ REMOTE_STANDARD
标准远程帧。Standard remote frame.
@ ERROR
错误帧(虚拟事件)。Error frame (virtual event).
void OnMessage(const ClassicPack &pack, bool in_isr)
分发接收到的经典 CAN 帧。 Dispatch a received classic CAN frame.
Definition can.cpp:18
ErrorID
ClassicPack::type == Type::ERROR 时使用的虚拟 ID。 Virtual IDs used when ClassicPack::type == Type::ERROR.
Definition can.hpp:146
CH32CAN driver (bxCAN-like) for LibXR::CAN.
Definition ch32_can.hpp:31
ErrorCode SetConfig(const CAN::Configuration &cfg) override
Set CAN configuration (bit timing + mode). Also (re-)enables IRQs.
Definition ch32_can.cpp:308
void ProcessTxInterrupt()
Process TX interrupt (call from CANx_TX handler).
Definition ch32_can.cpp:525
void ProcessErrorInterrupt()
Process SCE/error interrupt (call from CANx_SCE handler).
Definition ch32_can.cpp:595
ErrorCode AddMessage(const ClassicPack &pack) override
Enqueue a ClassicPack for transmission.
Definition ch32_can.cpp:509
void ProcessRxInterrupt()
Process RX interrupt (call from CANx_RX0 / CANx_RX1 handlers).
Definition ch32_can.cpp:540
ErrorCode Init()
Initialize filter + IRQ routing. Does NOT force a bitrate; call SetConfig().
Definition ch32_can.cpp:151
ErrorCode GetErrorState(CAN::ErrorState &state) const override
Read bus error state and counters.
Definition ch32_can.cpp:688
uint32_t GetClockFreq() const override
CAN clock frequency (Hz). CH32 CAN is on APB1.
Definition ch32_can.cpp:435
CH32CAN(ch32_can_id_t id, uint32_t pool_size)
Construct CH32CAN.
Definition ch32_can.cpp:113
ErrorCode Put(const Data &data)
向池中放入一个元素 / Put an element into the pool
ErrorCode Get(Data &data)
从池中取出一个元素 / Retrieve an element from the pool
LibXR 命名空间
Definition ch32_can.hpp:14
CAN 位时序配置。Bit timing configuration for CAN.
Definition can.hpp:37
uint32_t brp
预分频。Baud rate prescaler.
Definition can.hpp:38
uint32_t sjw
同步跳宽。Synchronization jump width.
Definition can.hpp:42
uint32_t phase_seg2
相位段 2。Phase segment 2.
Definition can.hpp:41
uint32_t prop_seg
传播段。Propagation segment.
Definition can.hpp:39
uint32_t phase_seg1
相位段 1。Phase segment 1.
Definition can.hpp:40
经典 CAN 帧数据结构。Classic CAN frame structure.
Definition can.hpp:129
Type type
帧类型。Frame type.
Definition can.hpp:131
uint8_t dlc
有效数据长度(0~8)。Data length code (0–8).
Definition can.hpp:132
CAN 配置参数。CAN configuration parameters.
Definition can.hpp:62
BitTiming bit_timing
位时序配置。Bit timing configuration.
Definition can.hpp:65
Mode mode
工作模式。Operating mode.
Definition can.hpp:66
CAN 当前错误状态快照(来自硬件计数器/状态机)。 Snapshot of current CAN controller error state (from HW counters/state).
Definition can.hpp:88
bool bus_off
是否处于 BUS-OFF。True if controller is bus-off.
Definition can.hpp:92
bool error_passive
是否处于 Error Passive。True if error-passive.
Definition can.hpp:93
uint8_t tx_error_counter
发送错误计数 TEC。Transmit error counter (TEC).
Definition can.hpp:89
bool error_warning
是否处于 Error Warning。True if error-warning.
Definition can.hpp:94
uint8_t rx_error_counter
接收错误计数 REC。Receive error counter (REC).
Definition can.hpp:90
CAN 工作模式。CAN operating mode.
Definition can.hpp:50
bool loopback
回环模式。Loopback mode.
Definition can.hpp:51
bool one_shot
单次发送模式。One-shot transmission.
Definition can.hpp:54
bool listen_only
只听(静默)模式。Listen-only (silent) mode.
Definition can.hpp:52