libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
LibXR::STM32CAN Class Reference

STM32 CAN 驱动实现 / STM32 CAN driver implementation. More...

#include <stm32_can.hpp>

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

Public Member Functions

 STM32CAN (CAN_HandleTypeDef *hcan, uint32_t queue_size)
 构造 CAN 驱动对象 / Construct CAN driver object
 
ErrorCode Init (void)
 初始化驱动 / Initialize driver
 
ErrorCode SetConfig (const CAN::Configuration &cfg) override
 设置 CAN 配置 / Set CAN configuration
 
uint32_t GetClockFreq () const override
 获取 CAN 外设时钟频率(Hz)。 Get CAN peripheral clock frequency in Hz.
 
ErrorCode AddMessage (const ClassicPack &pack) override
 添加经典 CAN 消息 / Add classic CAN message.
 
ErrorCode GetErrorState (CAN::ErrorState &state) const override
 查询当前错误状态(快照)。 Query current CAN controller error state (snapshot).
 
void ProcessRxInterrupt ()
 处理接收中断 / Handle RX interrupt
 
void ProcessErrorInterrupt ()
 处理错误中断 / Handle error interrupt
 
void TxService ()
 
- 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 Member Functions

static void BuildTxHeader (const ClassicPack &p, CAN_TxHeaderTypeDef &h)
 
- 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.
 

Public Attributes

CAN_HandleTypeDef * hcan_
 
stm32_can_id_t id_
 
uint32_t fifo_
 
struct { 
 
   CAN_RxHeaderTypeDef   header 
 
   ClassicPack   pack 
 
} rx_buff_ 
 
struct { 
 
   CAN_TxHeaderTypeDef   header 
 
   ClassicPack   pack 
 
} tx_buff_ 
 
uint32_t txMailbox
 
SlotPool< ClassicPack > tx_queue_
 发送槽池 / TX slot pool.
 
bool tx_retry_valid_ {false}
 待重试帧有效标记 / Pending retry frame flag.
 
ClassicPack tx_retry_pack_ {}
 待重试帧 / Pending retry frame.
 
std::atomic< uint32_t > tx_lock_ {0}
 
std::atomic< uint32_t > tx_pend_ {0}
 

Static Public Attributes

static STM32CAN * map [STM32_CAN_NUMBER] = {nullptr}
 
- Static Public Attributes inherited from LibXR::CAN
static LIBXR_PACKED_END constexpr uint32_t CAN_ERROR_ID_PREFIX = 0xFFFF0000u
 错误 ID 前缀 / Error ID prefix.
 

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.
 
- Protected Member Functions inherited from LibXR::CAN
void OnMessage (const ClassicPack &pack, bool in_isr)
 分发接收到的经典 CAN 帧。 Dispatch a received classic CAN frame.
 

Detailed Description

STM32 CAN 驱动实现 / STM32 CAN driver implementation.

Definition at line 41 of file stm32_can.hpp.

Constructor & Destructor Documentation

◆ STM32CAN()

STM32CAN::STM32CAN ( CAN_HandleTypeDef * hcan,
uint32_t queue_size )

构造 CAN 驱动对象 / Construct CAN driver object

Parameters
hcanHAL CAN 句柄 / HAL CAN handle
queue_size发送队列大小 / TX queue size
Precondition
queue_size 必须大于 1 / queue_size must be greater than 1.

Definition at line 47 of file stm32_can.cpp.

48 : CAN(), hcan_(hcan), id_(STM32_CAN_GetID(hcan->Instance)), tx_queue_(queue_size)
49{
50 map[id_] = this;
51 Init();
52}
CAN()=default
构造函数 / Constructor.
ErrorCode Init(void)
初始化驱动 / Initialize driver
Definition stm32_can.cpp:54
SlotPool< ClassicPack > tx_queue_
发送槽池 / TX slot pool.

Member Function Documentation

◆ AddMessage()

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

添加经典 CAN 消息 / Add classic CAN message.

Parameters
pack经典 CAN 帧 / Classic CAN frame.
Returns
ErrorCode 操作结果 / Error code.

Implements LibXR::CAN.

Definition at line 482 of file stm32_can.cpp.

483{
484 if (pack.type == Type::ERROR)
485 {
486 return ErrorCode::ARG_ERR;
487 }
488
489 if (tx_queue_.Put(pack) != ErrorCode::OK)
490 {
491 return ErrorCode::FULL;
492 }
493
494 // kick
495 TxService();
496 return ErrorCode::OK;
497}
@ ERROR
错误帧(虚拟事件) / Error frame (virtual event).
ErrorCode Put(const T &value)
便捷入队:Acquire + 拷贝 + Publish / Convenient enqueue: Acquire + copy + Publish.
@ FULL
已满 / Full
@ OK
操作成功 / Operation successful
@ ARG_ERR
参数错误 / Argument error
Type type
帧类型 / Frame type.
Definition can.hpp:132

◆ BuildTxHeader()

void STM32CAN::BuildTxHeader ( const ClassicPack & p,
CAN_TxHeaderTypeDef & h )
inlinestatic

Definition at line 392 of file stm32_can.cpp.

393{
394 const bool IS_EXT = (p.type == Type::EXTENDED) || (p.type == Type::REMOTE_EXTENDED);
395 const bool IS_RTR =
396 (p.type == Type::REMOTE_STANDARD) || (p.type == Type::REMOTE_EXTENDED);
397
398 h.DLC = (p.dlc <= 8u) ? p.dlc : 8u;
399 h.IDE = IS_EXT ? CAN_ID_EXT : CAN_ID_STD;
400 h.RTR = IS_RTR ? CAN_RTR_REMOTE : CAN_RTR_DATA;
401
402 h.StdId = IS_EXT ? 0u : (p.id & 0x7FFu);
403 h.ExtId = IS_EXT ? (p.id & 0x1FFFFFFFu) : 0u;
404
405 h.TransmitGlobalTime = DISABLE;
406}
@ EXTENDED
扩展数据帧(29-bit ID) / Extended data frame (29-bit ID).
@ REMOTE_EXTENDED
扩展远程帧 / Extended remote frame.
@ REMOTE_STANDARD
标准远程帧 / Standard remote frame.

◆ GetClockFreq()

uint32_t STM32CAN::GetClockFreq ( ) const
overridevirtual

获取 CAN 外设时钟频率(Hz)。 Get CAN peripheral clock frequency in Hz.

Implements LibXR::CAN.

Definition at line 386 of file stm32_can.cpp.

387{
388 // 经典 bxCAN 始终挂在 APB1 上
389 return HAL_RCC_GetPCLK1Freq();
390}

◆ GetErrorState()

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

查询当前错误状态(快照)。 Query current CAN controller error state (snapshot).

默认实现返回 ErrorCode::NOT_SUPPORT;具体实现(如 bxCAN/FDCAN)可重载, 从硬件寄存器读取 TEC/REC 及状态位,并填充 ErrorState。

Parameters
state输出参数,用于返回当前错误状态。
Returns
ErrorCode 操作结果;若未实现则返回 ErrorCode::NOT_SUPPORT。

Reimplemented from LibXR::CAN.

Definition at line 597 of file stm32_can.cpp.

598{
599 if (hcan_ == nullptr || hcan_->Instance == nullptr)
600 {
601 return ErrorCode::ARG_ERR;
602 }
603
604 // 直接读取 bxCAN 的错误状态寄存器 ESR
605 uint32_t esr = hcan_->Instance->ESR;
606
607 // TEC: bits 23:16, REC: bits 31:24(参考 RM & CAN_ESR 描述)
608 state.tx_error_counter = static_cast<uint8_t>((esr >> 16) & 0xFFu);
609 state.rx_error_counter = static_cast<uint8_t>((esr >> 24) & 0xFFu);
610
611 // 状态位:BOFF / EPVF / EWGF
612 state.bus_off = (esr & CAN_ESR_BOFF) != 0u;
613 state.error_passive = (esr & CAN_ESR_EPVF) != 0u;
614 state.error_warning = (esr & CAN_ESR_EWGF) != 0u;
615
616 return ErrorCode::OK;
617}
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 STM32CAN::Init ( void )

初始化驱动 / Initialize driver

Returns
ErrorCode 错误码 / Error code

Definition at line 54 of file stm32_can.cpp.

55{
56 CAN_FilterTypeDef can_filter = {};
57
58 can_filter.FilterIdHigh = 0;
59 can_filter.FilterIdLow = 0;
60 can_filter.FilterMode = CAN_FILTERMODE_IDMASK;
61 can_filter.FilterScale = CAN_FILTERSCALE_32BIT;
62 can_filter.FilterMaskIdHigh = 0;
63 can_filter.FilterMaskIdLow = 0;
64 can_filter.FilterActivation = ENABLE;
65
66#ifdef CAN3
67 if (id_ == STM32_CAN1)
68 {
69 can_filter.FilterBank = 0;
70 can_filter.SlaveStartFilterBank = 14;
71 fifo_ = CAN_RX_FIFO0;
72 }
73 else if (id_ == STM32_CAN2)
74 {
75 can_filter.FilterBank = 14;
76 can_filter.SlaveStartFilterBank = 14;
77 fifo_ = CAN_RX_FIFO0;
78 }
79 else if (id_ == STM32_CAN3)
80 {
81 can_filter.FilterBank = 0;
82 fifo_ = CAN_RX_FIFO1;
83 }
84#else
85#ifdef CAN2
86 if (id_ == STM32_CAN1)
87 {
88 can_filter.FilterBank = 0;
89 can_filter.SlaveStartFilterBank = 14;
90 fifo_ = CAN_RX_FIFO0;
91 }
92 else if (id_ == STM32_CAN2)
93 {
94 can_filter.FilterBank = 14;
95 can_filter.SlaveStartFilterBank = 14;
96 fifo_ = CAN_RX_FIFO1;
97 }
98#else
99 if (id_ == STM32_CAN1)
100 {
101 can_filter.FilterBank = 0;
102 can_filter.SlaveStartFilterBank = 14;
103 fifo_ = CAN_RX_FIFO0;
104 }
105#endif
106#endif
107 else
108 {
109 ASSERT(false);
110 }
111
112 can_filter.FilterFIFOAssignment = fifo_;
113
114 if (HAL_CAN_ConfigFilter(hcan_, &can_filter) != HAL_OK)
115 {
116 return ErrorCode::FAILED;
117 }
118
119 if (HAL_CAN_Start(hcan_) != HAL_OK)
120 {
121 return ErrorCode::FAILED;
122 }
123
124 if (fifo_ == CAN_RX_FIFO0)
125 {
126 HAL_CAN_ActivateNotification(hcan_, CAN_IT_RX_FIFO0_MSG_PENDING);
127 }
128 else
129 {
130 HAL_CAN_ActivateNotification(hcan_, CAN_IT_RX_FIFO1_MSG_PENDING);
131 }
132
133 HAL_CAN_ActivateNotification(hcan_, CAN_IT_ERROR);
134 HAL_CAN_ActivateNotification(hcan_, CAN_IT_BUSOFF);
135 HAL_CAN_ActivateNotification(hcan_, CAN_IT_ERROR_PASSIVE);
136 HAL_CAN_ActivateNotification(hcan_, CAN_IT_ERROR_WARNING);
137 HAL_CAN_ActivateNotification(hcan_, CAN_IT_TX_MAILBOX_EMPTY);
138
139 return ErrorCode::OK;
140}
@ FAILED
操作失败 / Operation failed

◆ ProcessErrorInterrupt()

void STM32CAN::ProcessErrorInterrupt ( )

处理错误中断 / Handle error interrupt

Definition at line 534 of file stm32_can.cpp.

535{
536 if (hcan_ == nullptr || hcan_->Instance == nullptr)
537 {
538 return;
539 }
540
541 uint32_t esr = hcan_->Instance->ESR;
542
543 CAN::ClassicPack pack{};
544 pack.type = CAN::Type::ERROR;
545 pack.dlc = 0;
546
547 CAN::ErrorID eid = CAN::ErrorID::CAN_ERROR_ID_GENERIC;
548
549 if (esr & CAN_ESR_BOFF)
550 {
551 eid = CAN::ErrorID::CAN_ERROR_ID_BUS_OFF;
552 }
553 else if (esr & CAN_ESR_EPVF)
554 {
555 eid = CAN::ErrorID::CAN_ERROR_ID_ERROR_PASSIVE;
556 }
557 else if (esr & CAN_ESR_EWGF)
558 {
559 eid = CAN::ErrorID::CAN_ERROR_ID_ERROR_WARNING;
560 }
561 else
562 {
563 uint32_t lec = (esr >> 4) & 0x7u;
564
565 switch (lec)
566 {
567 case 0x01:
568 eid = CAN::ErrorID::CAN_ERROR_ID_STUFF;
569 break;
570 case 0x02:
571 eid = CAN::ErrorID::CAN_ERROR_ID_FORM;
572 break;
573 case 0x03:
574 eid = CAN::ErrorID::CAN_ERROR_ID_ACK;
575 break;
576 case 0x04:
577 eid = CAN::ErrorID::CAN_ERROR_ID_BIT1;
578 break;
579 case 0x05:
580 eid = CAN::ErrorID::CAN_ERROR_ID_BIT0;
581 break;
582 case 0x06:
583 eid = CAN::ErrorID::CAN_ERROR_ID_CRC;
584 break;
585 default:
586 eid = CAN::ErrorID::CAN_ERROR_ID_OTHER;
587 break;
588 }
589 }
590
591 pack.id = static_cast<uint32_t>(eid);
592
593 // 在中断上下文中分发错误帧
594 OnMessage(pack, true);
595}
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:147
经典 CAN 帧数据结构 / Classic CAN frame structure.
Definition can.hpp:129
uint8_t dlc
有效数据长度(0~8) / Data length code (0–8).
Definition can.hpp:133

◆ ProcessRxInterrupt()

void STM32CAN::ProcessRxInterrupt ( )

处理接收中断 / Handle RX interrupt

Definition at line 499 of file stm32_can.cpp.

500{
501 while (HAL_CAN_GetRxMessage(hcan_, fifo_, &rx_buff_.header, rx_buff_.pack.data) ==
502 HAL_OK)
503 {
504 if (rx_buff_.header.IDE == CAN_ID_STD)
505 {
506 rx_buff_.pack.id = rx_buff_.header.StdId;
507 rx_buff_.pack.type = Type::STANDARD;
508 }
509 else
510 {
511 rx_buff_.pack.id = rx_buff_.header.ExtId;
512 rx_buff_.pack.type = Type::EXTENDED;
513 }
514
515 if (rx_buff_.header.RTR == CAN_RTR_REMOTE)
516 {
517 if (rx_buff_.pack.type == Type::STANDARD)
518 {
519 rx_buff_.pack.type = Type::REMOTE_STANDARD;
520 }
521 else
522 {
523 rx_buff_.pack.type = Type::REMOTE_EXTENDED;
524 }
525 }
526
527 uint8_t dlc = (rx_buff_.header.DLC <= 8u) ? rx_buff_.header.DLC : 8u;
528 rx_buff_.pack.dlc = dlc;
529
530 OnMessage(rx_buff_.pack, true);
531 }
532}
@ STANDARD
标准数据帧(11-bit ID) / Standard data frame (11-bit ID).

◆ SetConfig()

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

设置 CAN 配置 / Set CAN configuration

Parameters
cfgCAN 配置参数 / CAN configuration
Returns
ErrorCode 操作结果 / Operation result

Implements LibXR::CAN.

Definition at line 142 of file stm32_can.cpp.

143{
144 ASSERT(hcan_ != nullptr && hcan_->Instance != nullptr);
145
146 CAN_TypeDef* can = hcan_->Instance;
147
148 // 先关掉与 Init 对应的中断
149 uint32_t it_mask = 0u;
150
151#ifdef CAN_IT_RX_FIFO0_MSG_PENDING
152 if (fifo_ == CAN_RX_FIFO0)
153 {
154 it_mask |= CAN_IT_RX_FIFO0_MSG_PENDING;
155 }
156#endif
157
158#ifdef CAN_IT_RX_FIFO1_MSG_PENDING
159 if (fifo_ == CAN_RX_FIFO1)
160 {
161 it_mask |= CAN_IT_RX_FIFO1_MSG_PENDING;
162 }
163#endif
164
165#ifdef CAN_IT_ERROR
166 it_mask |= CAN_IT_ERROR;
167#endif
168
169#ifdef CAN_IT_TX_MAILBOX_EMPTY
170 it_mask |= CAN_IT_TX_MAILBOX_EMPTY;
171#endif
172
173 if (it_mask != 0u)
174 {
175 HAL_CAN_DeactivateNotification(hcan_, it_mask);
176 }
177
178 // 停止 CAN,进入配置状态
179 if (HAL_CAN_Stop(hcan_) != HAL_OK)
180 {
181 return ErrorCode::FAILED;
182 }
183
184 // 一次发送模式(不自动重发)→ NART
185#ifdef CAN_MCR_NART
186 if (cfg.mode.one_shot)
187 {
188 SET_BIT(can->MCR, CAN_MCR_NART);
189 }
190 else
191 {
192 CLEAR_BIT(can->MCR, CAN_MCR_NART);
193 }
194#endif
195
196 const auto& bt = cfg.bit_timing;
197
198 // 参数范围校验(0 表示保留原值)。
199 // Derive field maxima from masks instead of hard-coded constants.
200 constexpr uint32_t BRP_FIELD_MAX =
201 (CAN_BTR_BRP_Msk >> CAN_BTR_BRP_Pos); // 存的是 brp-1
202 constexpr uint32_t TS1_FIELD_MAX =
203 (CAN_BTR_TS1_Msk >> CAN_BTR_TS1_Pos); // 存的是 ts1-1
204 constexpr uint32_t TS2_FIELD_MAX =
205 (CAN_BTR_TS2_Msk >> CAN_BTR_TS2_Pos); // 存的是 ts2-1
206 constexpr uint32_t SJW_FIELD_MAX =
207 (CAN_BTR_SJW_Msk >> CAN_BTR_SJW_Pos); // 存的是 sjw-1
208
209 // 实际可配置的量(寄存器值 + 1)
210 constexpr uint32_t BRP_MAX = BRP_FIELD_MAX + 1u; // 1..1024
211 constexpr uint32_t TS1_MAX = TS1_FIELD_MAX + 1u; // 1..16
212 constexpr uint32_t TS2_MAX = TS2_FIELD_MAX + 1u; // 1..8
213 constexpr uint32_t SJW_MAX = SJW_FIELD_MAX + 1u; // 1..4
214
215 // brp 范围检查
216 if (bt.brp != 0u)
217 {
218 if (bt.brp < 1u || bt.brp > BRP_MAX)
219 {
220 return ErrorCode::ARG_ERR;
221 }
222 }
223
224 // tseg1 = prop_seg + phase_seg1
225 uint32_t tseg1 = bt.prop_seg + bt.phase_seg1;
226 if (bt.prop_seg != 0u || bt.phase_seg1 != 0u)
227 {
228 if (tseg1 < 1u || tseg1 > TS1_MAX)
229 {
230 return ErrorCode::ARG_ERR;
231 }
232 }
233
234 if (bt.phase_seg2 != 0u)
235 {
236 if (bt.phase_seg2 < 1u || bt.phase_seg2 > TS2_MAX)
237 {
238 return ErrorCode::ARG_ERR;
239 }
240 }
241
242 if (bt.sjw != 0u)
243 {
244 if (bt.sjw < 1u || bt.sjw > SJW_MAX)
245 {
246 return ErrorCode::ARG_ERR;
247 }
248
249 // 规范上 SJW ≤ TSEG2(只在二者都要更新时检查)
250 if (bt.phase_seg2 != 0u && bt.sjw > bt.phase_seg2)
251 {
252 return ErrorCode::ARG_ERR;
253 }
254 }
255
256 uint32_t btr_old = can->BTR;
257 uint32_t btr_new = btr_old;
258 uint32_t btr_mask = 0u;
259
260 // BRP:bt.brp == 0 → 保持原值
261 if (bt.brp != 0u)
262 {
263 uint32_t brp = (bt.brp - 1u) & BRP_FIELD_MAX;
264 uint32_t mask = CAN_BTR_BRP_Msk;
265 btr_mask |= mask;
266 btr_new &= ~mask;
267 btr_new |= (brp << CAN_BTR_BRP_Pos);
268 }
269
270 // TSEG1 = PROP_SEG + PHASE_SEG1,两者都为 0 → 保持原值
271 if (bt.prop_seg != 0u || bt.phase_seg1 != 0u)
272 {
273 uint32_t ts1 = (tseg1 - 1u) & TS1_FIELD_MAX;
274 uint32_t mask = CAN_BTR_TS1_Msk;
275 btr_mask |= mask;
276 btr_new &= ~mask;
277 btr_new |= (ts1 << CAN_BTR_TS1_Pos);
278 }
279
280 // TSEG2 = PHASE_SEG2,phase_seg2 == 0 → 保持原值
281 if (bt.phase_seg2 != 0u)
282 {
283 uint32_t ts2 = (bt.phase_seg2 - 1u) & TS2_FIELD_MAX;
284 uint32_t mask = CAN_BTR_TS2_Msk;
285 btr_mask |= mask;
286 btr_new &= ~mask;
287 btr_new |= (ts2 << CAN_BTR_TS2_Pos);
288 }
289
290 // SJW,sjw == 0 → 保持原值
291 if (bt.sjw != 0u)
292 {
293 uint32_t sjw = (bt.sjw - 1u) & SJW_FIELD_MAX;
294 uint32_t mask = CAN_BTR_SJW_Msk;
295 btr_mask |= mask;
296 btr_new &= ~mask;
297 btr_new |= (sjw << CAN_BTR_SJW_Pos);
298 }
299
300 // 三采样:只有 HAL 定义了 CAN_BTR_SAM 才动;否则忽略 triple_sampling
301#ifdef CAN_BTR_SAM
302 {
303 uint32_t mask = CAN_BTR_SAM;
304 btr_mask |= mask;
305 btr_new &= ~mask;
306 if (cfg.mode.triple_sampling)
307 {
308 btr_new |= mask;
309 }
310 }
311#else
312 (void)cfg.mode.triple_sampling;
313#endif
314
315 // Loopback:bool 两态,强制覆盖
316#ifdef CAN_BTR_LBKM
317 {
318 uint32_t mask = CAN_BTR_LBKM;
319 btr_mask |= mask;
320 btr_new &= ~mask;
321 if (cfg.mode.loopback)
322 {
323 btr_new |= mask;
324 }
325 }
326#endif
327
328 // Listen-only:bool 两态,强制覆盖
329#ifdef CAN_BTR_SILM
330 {
331 uint32_t mask = CAN_BTR_SILM;
332 btr_mask |= mask;
333 btr_new &= ~mask;
334 if (cfg.mode.listen_only)
335 {
336 btr_new |= mask;
337 }
338 }
339#endif
340
341 // 只改被 btr_mask 覆盖到的位,其余保持原值
342 if (btr_mask != 0u)
343 {
344 btr_old &= ~btr_mask;
345 btr_old |= (btr_new & btr_mask);
346 can->BTR = btr_old;
347 }
348
349 // 重新启动 CAN
350 if (HAL_CAN_Start(hcan_) != HAL_OK)
351 {
352 return ErrorCode::FAILED;
353 }
354
355 // 按 Init 的方式恢复中断
356 uint32_t it_rx = 0u;
357
358#ifdef CAN_IT_RX_FIFO0_MSG_PENDING
359 if (fifo_ == CAN_RX_FIFO0)
360 {
361 it_rx = CAN_IT_RX_FIFO0_MSG_PENDING;
362 }
363#endif
364
365#ifdef CAN_IT_RX_FIFO1_MSG_PENDING
366 if (fifo_ == CAN_RX_FIFO1)
367 {
368 it_rx = CAN_IT_RX_FIFO1_MSG_PENDING;
369 }
370#endif
371
372 if (it_rx != 0u)
373 {
374 HAL_CAN_ActivateNotification(hcan_, it_rx);
375 }
376
377 HAL_CAN_ActivateNotification(hcan_, CAN_IT_ERROR);
378 HAL_CAN_ActivateNotification(hcan_, CAN_IT_BUSOFF);
379 HAL_CAN_ActivateNotification(hcan_, CAN_IT_ERROR_PASSIVE);
380 HAL_CAN_ActivateNotification(hcan_, CAN_IT_ERROR_WARNING);
381 HAL_CAN_ActivateNotification(hcan_, CAN_IT_TX_MAILBOX_EMPTY);
382
383 return ErrorCode::OK;
384}
uint32_t prop_seg
传播段 / Propagation segment.
Definition can.hpp:39
BitTiming bit_timing
位时序配置 / Bit timing configuration.
Definition can.hpp:65
Mode mode
工作模式 / Operating mode.
Definition can.hpp:66
bool triple_sampling
三采样 / Triple sampling.
Definition can.hpp:53
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

◆ TxService()

void STM32CAN::TxService ( )

Definition at line 408 of file stm32_can.cpp.

409{
410 if (hcan_ == nullptr || hcan_->Instance == nullptr)
411 {
412 return;
413 }
414
415 // 标记:需要一次 TX 服务(无论本次是否抢到锁)
416 tx_pend_.store(1u, std::memory_order_release);
417
418 // 尝试抢占服务锁:0 -> 1
419 uint32_t expected = 0u;
420 if (!tx_lock_.compare_exchange_strong(expected, 1u, std::memory_order_acquire,
421 std::memory_order_relaxed))
422 {
423 // 有别的上下文在服务;PEND 已置位,它会在结束时看到并再服务
424 return;
425 }
426
427 constexpr uint32_t TME_MASK = (CAN_TSR_TME0 | CAN_TSR_TME1 | CAN_TSR_TME2);
428
429 for (;;)
430 {
431 // 本轮服务开始:消费掉 pend(期间如有新 kick,会再次置 1)
432 tx_pend_.store(0u, std::memory_order_release);
433
434 // 尽可能把空 mailbox 填满:一直到队列空或者 AddTxMessage 失败(邮箱满/忙)
435 while ((hcan_->Instance->TSR & TME_MASK) != 0u)
436 {
437 ClassicPack p{};
438 if (tx_retry_valid_)
439 {
440 p = tx_retry_pack_;
441 }
442 else if (tx_queue_.Get(p) != ErrorCode::OK)
443 {
444 break; // 队列空 / Queue empty.
445 }
446
447 CAN_TxHeaderTypeDef hdr{};
448 BuildTxHeader(p, hdr);
449
450 uint32_t mailbox = 0u;
451 if (HAL_CAN_AddTxMessage(hcan_, &hdr, p.data, &mailbox) != HAL_OK)
452 {
453 tx_retry_pack_ = p;
454 tx_retry_valid_ = true;
455 break;
456 }
457
458 tx_retry_valid_ = false;
459 txMailbox = mailbox;
460 }
461
462 // 先解锁,再检查是否仍有待处理发送请求。
463 // Release lock first, then check whether pending TX work remains.
464 tx_lock_.store(0u, std::memory_order_release);
465
466 // 再看是否还有 pend:若没有,直接退出
467 if (tx_pend_.load(std::memory_order_acquire) == 0u)
468 {
469 return;
470 }
471
472 // 允许出现 PEND=1, LOCK=0 的“无人服务”状态:尝试重新加锁再服务
473 expected = 0u;
474 if (!tx_lock_.compare_exchange_strong(expected, 1u, std::memory_order_acquire,
475 std::memory_order_relaxed))
476 {
477 return;
478 }
479 }
480}
ClassicPack tx_retry_pack_
待重试帧 / Pending retry frame.
bool tx_retry_valid_
待重试帧有效标记 / Pending retry frame flag.
ErrorCode Get(T &value)
便捷出队:Take + 拷贝 + Release / Convenient dequeue: Take + copy + Release.

Member Data Documentation

◆ fifo_

uint32_t LibXR::STM32CAN::fifo_

Definition at line 89 of file stm32_can.hpp.

◆ hcan_

CAN_HandleTypeDef* LibXR::STM32CAN::hcan_

Definition at line 86 of file stm32_can.hpp.

◆ header [1/2]

CAN_RxHeaderTypeDef LibXR::STM32CAN::header

Definition at line 94 of file stm32_can.hpp.

◆ header [2/2]

CAN_TxHeaderTypeDef LibXR::STM32CAN::header

Definition at line 100 of file stm32_can.hpp.

◆ id_

stm32_can_id_t LibXR::STM32CAN::id_

Definition at line 88 of file stm32_can.hpp.

◆ map

STM32CAN * STM32CAN::map = {nullptr}
static

Definition at line 90 of file stm32_can.hpp.

◆ pack

ClassicPack LibXR::STM32CAN::pack

Definition at line 95 of file stm32_can.hpp.

◆ tx_lock_

std::atomic<uint32_t> LibXR::STM32CAN::tx_lock_ {0}

Definition at line 113 of file stm32_can.hpp.

113{0};

◆ tx_pend_

std::atomic<uint32_t> LibXR::STM32CAN::tx_pend_ {0}

Definition at line 114 of file stm32_can.hpp.

114{0};

◆ tx_queue_

SlotPool<ClassicPack> LibXR::STM32CAN::tx_queue_

发送槽池 / TX slot pool.

Definition at line 107 of file stm32_can.hpp.

◆ tx_retry_pack_

ClassicPack LibXR::STM32CAN::tx_retry_pack_ {}

待重试帧 / Pending retry frame.

Definition at line 111 of file stm32_can.hpp.

111{};

◆ tx_retry_valid_

bool LibXR::STM32CAN::tx_retry_valid_ {false}

待重试帧有效标记 / Pending retry frame flag.

Definition at line 109 of file stm32_can.hpp.

109{false};

◆ txMailbox

uint32_t LibXR::STM32CAN::txMailbox

Definition at line 104 of file stm32_can.hpp.


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