libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
stm32_canfd.hpp
1#pragma once
2
3#include <cstdint>
4#include <type_traits>
5#include <utility>
6
7#include "libxr_def.hpp"
8#include "main.h"
9
10#ifdef HAL_FDCAN_MODULE_ENABLED
11
12#ifdef FDCAN
13#undef FDCAN
14#endif
15
16#include "can.hpp"
17#include "libxr.hpp"
18
19#ifndef FDCAN_MESSAGE_RAM_WORDS_MAX
20#define FDCAN_MESSAGE_RAM_WORDS_MAX 2560u
21#endif
22
23typedef enum : uint8_t
24{
25#ifdef FDCAN1
26 STM32_FDCAN1,
27#endif
28#ifdef FDCAN2
29 STM32_FDCAN2,
30#endif
31#ifdef FDCAN3
32 STM32_FDCAN3,
33#endif
34 STM32_FDCAN_NUMBER,
35 STM32_FDCAN_ID_ERROR
36} stm32_fdcan_id_t;
37
38stm32_fdcan_id_t STM32_FDCAN_GetID(FDCAN_GlobalTypeDef* addr); // NOLINT
39
40template <typename, typename = void>
41struct HasTxFifoQueueElmtsNbr : std::false_type
42{
43};
44
45template <typename T>
47 T, std::void_t<decltype(std::declval<T>()->Init.TxFifoQueueElmtsNbr)>>
48 : std::true_type
49{
50};
51
52// 当没有TxFifoQueueElmtsNbr成员时的处理函数
53template <typename T>
54typename std::enable_if<!HasTxFifoQueueElmtsNbr<T>::value, uint32_t>::type
55GetTxFifoTotalElements(T& hcan) // NOLINT
56{
57 UNUSED(hcan);
58 return 3;
59}
60
61// 当有TxFifoQueueElmtsNbr成员时的处理函数
62template <typename T>
63typename std::enable_if<HasTxFifoQueueElmtsNbr<T>::value, uint32_t>::type
64GetTxFifoTotalElements(T& hcan) // NOLINT
65{
66 return hcan->Init.TxFifoQueueElmtsNbr;
67}
68
69namespace LibXR
70{
74class STM32CANFD : public FDCAN
75{
76 public:
77 template <typename, typename = void>
78 struct HasMessageRAMOffset : std::false_type
79 {
80 };
81
82 template <typename T>
84 T, std::void_t<decltype(std::declval<T>()->Init.MessageRAMOffset)>> : std::true_type
85 {
86 };
87
88 template <typename T>
89 typename std::enable_if<!HasMessageRAMOffset<T>::value, void>::type
90 CheckMessageRAMOffset(T&, uint32_t = FDCAN_MESSAGE_RAM_WORDS_MAX)
91 {
92 }
93
94 template <typename T>
95 typename std::enable_if<HasMessageRAMOffset<T>::value, void>::type
96 CheckMessageRAMOffset(T& fdcan_handle, uint32_t max_words = FDCAN_MESSAGE_RAM_WORDS_MAX)
97 {
98 using HandleT = std::remove_reference_t<decltype(*fdcan_handle)>;
99 using InitT = decltype(HandleT{}.Init);
100
101 // NOLINTNEXTLINE
102 static const auto FDCAN_ElmtWords = [](uint32_t sz) -> uint32_t
103 {
104#if defined(FDCAN_DATA_BYTES_8)
105 switch (sz)
106 {
107 case FDCAN_DATA_BYTES_8:
108 return 4; // 2 words header + 2 words data(0..8B)
109 case FDCAN_DATA_BYTES_12:
110 return 5;
111 case FDCAN_DATA_BYTES_16:
112 return 6;
113 case FDCAN_DATA_BYTES_20:
114 return 7;
115 case FDCAN_DATA_BYTES_24:
116 return 8;
117 case FDCAN_DATA_BYTES_32:
118 return 10;
119 case FDCAN_DATA_BYTES_48:
120 return 14;
121 case FDCAN_DATA_BYTES_64:
122 return 18;
123 default:
124 return 4;
125 }
126#else
127 ASSERT(false);
128 return 4;
129#endif
130 };
131
132 const uint32_t TX_FIFO_ELEMS =
133 HasTxFifoQueueElmtsNbr<T>::value ? fdcan_handle->Init.TxFifoQueueElmtsNbr : 0u;
134
135 // NOLINTNEXTLINE
136 const auto FDCAN_MessageRAMWords = [&](const InitT& c) -> uint32_t
137 {
138 return c.StdFiltersNbr * 1u + c.ExtFiltersNbr * 2u +
139 c.RxFifo0ElmtsNbr * FDCAN_ElmtWords(c.RxFifo0ElmtSize) +
140 c.RxFifo1ElmtsNbr * FDCAN_ElmtWords(c.RxFifo1ElmtSize) +
141 c.RxBuffersNbr * FDCAN_ElmtWords(c.RxBufferSize) + c.TxEventsNbr * 2u +
142 (c.TxBuffersNbr + TX_FIFO_ELEMS) * FDCAN_ElmtWords(c.TxElmtSize);
143 };
144
145 static struct
146 {
147 bool inited;
148 uint32_t offset;
149 uint32_t size;
150 } offset_map[STM32_FDCAN_NUMBER] = {}; // NOLINT
151
152 auto id = STM32_FDCAN_GetID(fdcan_handle->Instance);
153 ASSERT(id >= 0 && id < STM32_FDCAN_NUMBER);
154
155 offset_map[id].offset = fdcan_handle->Init.MessageRAMOffset;
156 offset_map[id].size = FDCAN_MessageRAMWords(fdcan_handle->Init);
157
158 const uint32_t START = offset_map[id].offset;
159 const uint32_t END = START + offset_map[id].size;
160
161 /* 内存越界 */
162 ASSERT(START <= max_words);
163 ASSERT(END <= max_words);
164
165 for (auto& it : offset_map)
166 {
167 if (!it.inited)
168 {
169 continue;
170 }
171
172 const uint32_t A0 = it.offset, A1 = it.offset + it.size;
173 const uint32_t B0 = START, B1 = END;
174 if (A0 < B1 && B0 < A1)
175 {
176 /* 内存区域重叠 */
177 ASSERT(false);
178 }
179 }
180
181 offset_map[id].inited = true;
182 }
183
190 STM32CANFD(FDCAN_HandleTypeDef* hcan, uint32_t queue_size);
191
197 ErrorCode Init(void);
198
205 ErrorCode SetConfig(const CAN::Configuration& cfg) override;
206
213 ErrorCode SetConfig(const FDCAN::Configuration& cfg) override;
214
218 uint32_t GetClockFreq() const override;
219
220 ErrorCode AddMessage(const ClassicPack& pack) override;
221
222 ErrorCode AddMessage(const FDPack& pack) override;
223
227 ErrorCode GetErrorState(CAN::ErrorState& state) const override;
228
234 void ProcessRxInterrupt(uint32_t fifo);
235
241 void ProcessErrorStatusInterrupt(uint32_t error_status_its);
242
249 {
250 auto free = HAL_FDCAN_GetTxFifoFreeLevel(hcan_);
251 return free;
252 }
253
254 static inline void BuildTxHeader(const ClassicPack& p, FDCAN_TxHeaderTypeDef& h);
255 static inline void BuildTxHeader(const FDPack& p, FDCAN_TxHeaderTypeDef& h);
256
257 void TxService();
258
259 std::atomic<uint32_t> tx_lock_{0};
260 std::atomic<uint32_t> tx_pend_{0};
261
262 FDCAN_HandleTypeDef* hcan_;
263
264 stm32_fdcan_id_t id_;
265 LockFreePool<ClassicPack> tx_pool_;
266 LockFreePool<FDPack> tx_pool_fd_;
267
268 static STM32CANFD* map[STM32_FDCAN_NUMBER]; // NOLINT
269
270 struct
271 {
272 FDCAN_RxHeaderTypeDef header;
273 ClassicPack pack;
274 FDPack pack_fd;
275 } rx_buff_;
276
277 struct
278 {
279 FDCAN_TxHeaderTypeDef header;
280 ClassicPack pack;
281 FDPack pack_fd;
282 } tx_buff_;
283
284 uint32_t txMailbox;
285};
286} // namespace LibXR
287
288#endif
FDCAN 通信抽象类,扩展支持 CAN FD 帧。 Abstract class for FDCAN communication with CAN FD frame support.
Definition can.hpp:247
STM32 FDCAN 驱动实现 / STM32 FDCAN driver implementation.
void ProcessErrorStatusInterrupt(uint32_t error_status_its)
处理错误状态中断 / Handle error-status interrupt
uint32_t GetClockFreq() const override
获取 FDCAN 外设时钟 / Get FDCAN kernel clock
ErrorCode Init(void)
初始化驱动 / Initialize driver
void ProcessRxInterrupt(uint32_t fifo)
处理接收中断 / Handle RX interrupt
STM32CANFD(FDCAN_HandleTypeDef *hcan, uint32_t queue_size)
构造 FDCAN 驱动对象 / Construct FDCAN driver object
ErrorCode GetErrorState(CAN::ErrorState &state) const override
查询当前错误状态 / Query current FDCAN error state
ErrorCode AddMessage(const ClassicPack &pack) override
添加经典 CAN 消息。Add classic CAN message.
size_t HardwareTxQueueEmptySize()
获取硬件发送队列空闲数 / Get free level of hardware TX queue
ErrorCode SetConfig(const CAN::Configuration &cfg) override
设置 CAN/FDCAN 配置 / Set CAN/FDCAN configuration
LibXR 命名空间
Definition ch32_can.hpp:14