libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
LibXR::CH32CAN Class Reference

CH32CAN driver (bxCAN-like) for LibXR::CAN. More...

#include <ch32_can.hpp>

Inheritance diagram for LibXR::CH32CAN:
[legend]
Collaboration diagram for LibXR::CH32CAN:
[legend]

Public Member Functions

 CH32CAN (ch32_can_id_t id, uint32_t pool_size)
 Construct CH32CAN.
 
ErrorCode Init ()
 Initialize filter + IRQ routing. Does NOT force a bitrate; call SetConfig().
 
ErrorCode SetConfig (const CAN::Configuration &cfg) override
 Set CAN configuration (bit timing + mode). Also (re-)enables IRQs.
 
uint32_t GetClockFreq () const override
 CAN clock frequency (Hz). CH32 CAN is on APB1.
 
ErrorCode AddMessage (const ClassicPack &pack) override
 Enqueue a ClassicPack for transmission.
 
ErrorCode GetErrorState (CAN::ErrorState &state) const override
 Read bus error state and counters.
 
void ProcessRxInterrupt ()
 Process RX interrupt (call from CANx_RX0 / CANx_RX1 handlers).
 
void ProcessTxInterrupt ()
 Process TX interrupt (call from CANx_TX handler).
 
void ProcessErrorInterrupt ()
 Process SCE/error interrupt (call from CANx_SCE handler).
 
- Public Member Functions inherited from LibXR::CAN
 CAN ()=default
 构造函数。Constructor.
 
virtual ~CAN ()=default
 虚析构函数。Virtual destructor.
 
void Register (Callback cb, Type type, FilterMode mode=FilterMode::ID_RANGE, uint32_t start_id_mask=0, uint32_t end_id_mask=UINT32_MAX)
 注册经典 CAN 消息回调。 Register classic CAN message callback.
 

Static Public Attributes

static CH32CANmap [CH32_CAN_NUMBER] = {nullptr}
 
- Static Public Attributes inherited from LibXR::CAN
static constexpr uint32_t CAN_ERROR_ID_PREFIX = 0xFFFF0000u
 错误 ID 前缀 Error ID prefix.
 

Private Member Functions

void EnableIRQs ()
 
void DisableIRQs ()
 
void TxService ()
 

Static Private Member Functions

static void BuildTxMsg (const ClassicPack &p, CanTxMsg &m)
 

Private Attributes

CAN_TypeDef * instance_ {nullptr}
 
ch32_can_id_t id_ {CH32_CAN_ID_ERROR}
 
uint8_t fifo_ {0}
 
uint8_t filter_bank_ {0}
 
LockFreePool< ClassicPacktx_pool_
 
std::atomic< uint32_t > tx_lock_ {0}
 
std::atomic< uint32_t > tx_pend_ {0}
 
CAN::Configuration cfg_cache_ {}
 
CanRxMsg rx_msg_ {}
 
CanTxMsg tx_msg_ {}
 

Additional Inherited Members

- Public Types inherited from LibXR::CAN
enum class  Type : uint8_t {
  STANDARD = 0 , EXTENDED = 1 , REMOTE_STANDARD = 2 , REMOTE_EXTENDED = 3 ,
  ERROR = 4 , TYPE_NUM = 5
}
 CAN 消息类型。CAN frame type. More...
 
enum class  ErrorID : uint32_t {
  CAN_ERROR_ID_GENERIC = CAN_ERROR_ID_PREFIX , CAN_ERROR_ID_BUS_OFF = CAN_ERROR_ID_PREFIX + 1 , CAN_ERROR_ID_ERROR_PASSIVE = CAN_ERROR_ID_PREFIX + 2 , CAN_ERROR_ID_ERROR_WARNING = CAN_ERROR_ID_PREFIX + 3 ,
  CAN_ERROR_ID_PROTOCOL = CAN_ERROR_ID_PREFIX + 4 , CAN_ERROR_ID_ACK = CAN_ERROR_ID_PREFIX + 5 , CAN_ERROR_ID_STUFF = CAN_ERROR_ID_PREFIX + 6 , CAN_ERROR_ID_FORM = CAN_ERROR_ID_PREFIX + 7 ,
  CAN_ERROR_ID_BIT0 = CAN_ERROR_ID_PREFIX + 8 , CAN_ERROR_ID_BIT1 = CAN_ERROR_ID_PREFIX + 9 , CAN_ERROR_ID_CRC = CAN_ERROR_ID_PREFIX + 10 , CAN_ERROR_ID_OTHER = CAN_ERROR_ID_PREFIX + 11
}
 ClassicPack::type == Type::ERROR 时使用的虚拟 ID。 Virtual IDs used when ClassicPack::type == Type::ERROR. More...
 
enum class  FilterMode : uint8_t { ID_MASK = 0 , ID_RANGE = 1 }
 CAN 过滤器模式。CAN filter mode. More...
 
using Callback = LibXR::Callback<const ClassicPack &>
 回调类型。Callback type.
 
- Static Public Member Functions inherited from LibXR::CAN
static constexpr uint32_t FromErrorID (ErrorID e) noexcept
 将 ErrorID 转为 id。Convert ErrorID to ClassicPack::id.
 
static constexpr bool IsErrorId (uint32_t id) noexcept
 判断 id 是否处于错误 ID 空间。Check if id is in error ID space.
 
static constexpr ErrorID ToErrorID (uint32_t id) noexcept
 将 id 解释为 ErrorID。Interpret id as ErrorID.
 
- Protected Member Functions inherited from LibXR::CAN
void OnMessage (const ClassicPack &pack, bool in_isr)
 分发接收到的经典 CAN 帧。 Dispatch a received classic CAN frame.
 

Detailed Description

CH32CAN driver (bxCAN-like) for LibXR::CAN.

Design goals (aligned with your STM32CAN driver):

Notes:

  • This driver is written against WCH StdPeriph CAN API (CAN_Init / CAN_Transmit / CAN_Receive / CAN_ITConfig...).
  • Bit timing fields in Configuration are interpreted as: BRP, (PROP_SEG + PHASE_SEG1) -> BS1, PHASE_SEG2 -> BS2, SJW.
  • triple_sampling is ignored (WCH StdPeriph init struct has no such field).

Definition at line 30 of file ch32_can.hpp.

Constructor & Destructor Documentation

◆ CH32CAN()

CH32CAN::CH32CAN ( ch32_can_id_t id,
uint32_t pool_size )
explicit

Construct CH32CAN.

Parameters
idCAN instance ID.
pool_sizeTX pool size (number of ClassicPack entries).

Definition at line 113 of file ch32_can.cpp.

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}
CAN()=default
构造函数。Constructor.
ErrorCode Init()
Initialize filter + IRQ routing. Does NOT force a bitrate; call SetConfig().
Definition ch32_can.cpp:151

Member Function Documentation

◆ AddMessage()

ErrorCode CH32CAN::AddMessage ( const ClassicPack & pack)
overridevirtual

Enqueue a ClassicPack for transmission.

Implements LibXR::CAN.

Definition at line 509 of file ch32_can.cpp.

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}
@ ERROR
错误帧(虚拟事件)。Error frame (virtual event).
ErrorCode Put(const Data &data)
向池中放入一个元素 / Put an element into the pool

◆ BuildTxMsg()

void CH32CAN::BuildTxMsg ( const ClassicPack & p,
CanTxMsg & m )
inlinestaticprivate

Definition at line 442 of file ch32_can.cpp.

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}
@ EXTENDED
扩展数据帧(29-bit ID)。Extended data frame (29-bit ID).
@ REMOTE_EXTENDED
扩展远程帧。Extended remote frame.
@ REMOTE_STANDARD
标准远程帧。Standard remote frame.

◆ DisableIRQs()

void CH32CAN::DisableIRQs ( )
private

Definition at line 180 of file ch32_can.cpp.

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}

◆ EnableIRQs()

void CH32CAN::EnableIRQs ( )
private

Definition at line 219 of file ch32_can.cpp.

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}

◆ GetClockFreq()

uint32_t CH32CAN::GetClockFreq ( ) const
overridevirtual

CAN clock frequency (Hz). CH32 CAN is on APB1.

Implements LibXR::CAN.

Definition at line 435 of file ch32_can.cpp.

436{
437 RCC_ClocksTypeDef clocks{};
438 RCC_GetClocksFreq(&clocks);
439 return clocks.PCLK1_Frequency;
440}

◆ GetErrorState()

ErrorCode CH32CAN::GetErrorState ( CAN::ErrorState & state) const
overridevirtual

Read bus error state and counters.

Reimplemented from LibXR::CAN.

Definition at line 688 of file ch32_can.cpp.

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}
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

◆ Init()

ErrorCode CH32CAN::Init ( )

Initialize filter + IRQ routing. Does NOT force a bitrate; call SetConfig().

Definition at line 151 of file ch32_can.cpp.

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}

◆ ProcessErrorInterrupt()

void CH32CAN::ProcessErrorInterrupt ( )

Process SCE/error interrupt (call from CANx_SCE handler).

Definition at line 595 of file ch32_can.cpp.

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}
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

◆ ProcessRxInterrupt()

void CH32CAN::ProcessRxInterrupt ( )

Process RX interrupt (call from CANx_RX0 / CANx_RX1 handlers).

Definition at line 540 of file ch32_can.cpp.

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}
Type
CAN 消息类型。CAN frame type.
Definition can.hpp:23
@ STANDARD
标准数据帧(11-bit ID)。Standard data frame (11-bit ID).

◆ ProcessTxInterrupt()

void CH32CAN::ProcessTxInterrupt ( )

Process TX interrupt (call from CANx_TX handler).

Definition at line 525 of file ch32_can.cpp.

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}

◆ SetConfig()

ErrorCode CH32CAN::SetConfig ( const CAN::Configuration & cfg)
overridevirtual

Set CAN configuration (bit timing + mode). Also (re-)enables IRQs.

Implements LibXR::CAN.

Definition at line 308 of file ch32_can.cpp.

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}
CH32CAN driver (bxCAN-like) for LibXR::CAN.
Definition ch32_can.hpp:31
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 配置参数。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
bool one_shot
单次发送模式。One-shot transmission.
Definition can.hpp:54

◆ TxService()

void CH32CAN::TxService ( )
private

Definition at line 458 of file ch32_can.cpp.

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}
ErrorCode Get(Data &data)
从池中取出一个元素 / Retrieve an element from the pool

Field Documentation

◆ cfg_cache_

CAN::Configuration LibXR::CH32CAN::cfg_cache_ {}
private

Definition at line 105 of file ch32_can.hpp.

105{};

◆ fifo_

uint8_t LibXR::CH32CAN::fifo_ {0}
private

Definition at line 96 of file ch32_can.hpp.

96{0};

◆ filter_bank_

uint8_t LibXR::CH32CAN::filter_bank_ {0}
private

Definition at line 97 of file ch32_can.hpp.

97{0};

◆ id_

ch32_can_id_t LibXR::CH32CAN::id_ {CH32_CAN_ID_ERROR}
private

Definition at line 94 of file ch32_can.hpp.

94{CH32_CAN_ID_ERROR};

◆ instance_

CAN_TypeDef* LibXR::CH32CAN::instance_ {nullptr}
private

Definition at line 93 of file ch32_can.hpp.

93{nullptr};

◆ map

CH32CAN * CH32CAN::map = {nullptr}
static

Definition at line 82 of file ch32_can.hpp.

◆ rx_msg_

CanRxMsg LibXR::CH32CAN::rx_msg_ {}
private

Definition at line 108 of file ch32_can.hpp.

108{};

◆ tx_lock_

std::atomic<uint32_t> LibXR::CH32CAN::tx_lock_ {0}
private

Definition at line 101 of file ch32_can.hpp.

101{0};

◆ tx_msg_

CanTxMsg LibXR::CH32CAN::tx_msg_ {}
private

Definition at line 109 of file ch32_can.hpp.

109{};

◆ tx_pend_

std::atomic<uint32_t> LibXR::CH32CAN::tx_pend_ {0}
private

Definition at line 102 of file ch32_can.hpp.

102{0};

◆ tx_pool_

LockFreePool<ClassicPack> LibXR::CH32CAN::tx_pool_
private

Definition at line 99 of file ch32_can.hpp.


The documentation for this class was generated from the following files: