1 /*
2 * Copyright (c) 2006-2024, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2023-03-24 YangXi the first version.
9 */
10
11 #include <rtdevice.h>
12
13 #ifdef RT_USING_CAN
14
15 #include "fsl_common.h"
16 #include "fsl_flexcan.h"
17
18 #define TX_MB_IDX (6)
19 #define RX_MB_COUNT (1)
20 static flexcan_frame_t frame[RX_MB_COUNT]; /* one frame buffer per RX MB */
21 static rt_uint32_t filter_mask = 0;
22
23
24 enum
25 {
26 #ifdef BSP_USING_CAN0
27 CAN0_INDEX,
28 #endif
29 #ifdef BSP_USING_CAN1
30 CAN1_INDEX,
31 #endif
32 };
33
34 struct imxrt_can
35 {
36 char *name;
37 CAN_Type *base;
38 IRQn_Type irqn;
39 uint32_t instance;
40 clock_div_name_t clock_div_name;
41 clock_attach_id_t clock_attach_id;
42 flexcan_handle_t handle;
43 struct rt_can_device can_dev;
44 };
45
46 struct imxrt_can flexcans[] =
47 {
48 #ifdef BSP_USING_CAN0
49 {
50 .name = "can0",
51 .base = CAN0,
52 .instance = 0,
53 .irqn = CAN0_IRQn,
54 .clock_div_name = kCLOCK_DivFlexcan0Clk,
55 .clock_attach_id = kFRO_HF_to_FLEXCAN0,
56 },
57 #endif
58 #ifdef BSP_USING_CAN1
59 {
60 .name = "can1",
61 .base = CAN1,
62 .instance = 1,
63 .irqn = CAN1_IRQn,
64 .clock_div_name = kCLOCK_DivFlexcan1Clk,
65 .clock_attach_id = kFRO_HF_to_FLEXCAN1,
66 },
67 #endif
68 };
69
70
71
flexcan_callback(CAN_Type * base,flexcan_handle_t * handle,status_t status,uint64_t result,void * userData)72 static void flexcan_callback(CAN_Type *base, flexcan_handle_t *handle, status_t status, uint64_t result, void *userData)
73 {
74 struct imxrt_can *can;
75 flexcan_mb_transfer_t rxXfer;
76
77 can = (struct imxrt_can *)userData;
78
79 switch (status)
80 {
81 case kStatus_FLEXCAN_RxIdle:
82 rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_RX_IND | result << 8);
83 rxXfer.frame = &frame[result - 1];
84 rxXfer.mbIdx = result;
85 FLEXCAN_TransferReceiveNonBlocking(can->base, &can->handle, &rxXfer);
86 break;
87
88 case kStatus_FLEXCAN_TxIdle:
89 rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_TX_DONE | result << 8);
90 break;
91 default:
92 break;
93 }
94 }
95
96
can_cfg(struct rt_can_device * can_dev,struct can_configure * cfg)97 static rt_err_t can_cfg(struct rt_can_device *can_dev, struct can_configure *cfg)
98 {
99 struct imxrt_can *can = (struct imxrt_can *)can_dev->parent.user_data;
100 flexcan_config_t config;
101 rt_uint32_t res = RT_EOK;
102 flexcan_rx_mb_config_t mbConfig;
103 flexcan_mb_transfer_t rxXfer;
104 rt_uint8_t i, mailbox;
105
106 FLEXCAN_GetDefaultConfig(&config);
107 config.baudRate = cfg->baud_rate;
108 config.enableIndividMask = true; /* one filter per MB */
109 config.disableSelfReception = true;
110
111 switch (cfg->mode)
112 {
113 case RT_CAN_MODE_NORMAL:
114 /* default mode */
115 break;
116 case RT_CAN_MODE_LISTEN:
117 break;
118 case RT_CAN_MODE_LOOPBACK:
119 config.enableLoopBack = true;
120 break;
121 case RT_CAN_MODE_LOOPBACKANLISTEN:
122 break;
123 }
124
125 flexcan_timing_config_t timing_config;
126 rt_memset(&timing_config, 0, sizeof(flexcan_timing_config_t));
127
128 if(FLEXCAN_CalculateImprovedTimingValues(can->base, config.baudRate, CLOCK_GetFlexcanClkFreq(can->instance), &timing_config))
129 {
130 /* Update the improved timing configuration*/
131 rt_memcpy(&(config.timingConfig), &timing_config, sizeof(flexcan_timing_config_t));
132 }
133 else
134 {
135 //rt_kprintf("No found Improved Timing Configuration. Just used default configuration\n");
136 }
137
138 FLEXCAN_Init(can->base, &config, CLOCK_GetFlexcanClkFreq(can->instance));
139 FLEXCAN_TransferCreateHandle(can->base, &can->handle, flexcan_callback, can);
140
141 /* init RX_MB_COUNT RX MB to default status */
142 mbConfig.format = kFLEXCAN_FrameFormatStandard; /* standard ID */
143 mbConfig.type = kFLEXCAN_FrameTypeData; /* data frame */
144 mbConfig.id = FLEXCAN_ID_STD(0); /* default ID is 0 */
145 for (i = 0; i < RX_MB_COUNT; i++)
146 {
147 /* the used MB index from 1 to RX_MB_COUNT */
148 mailbox = i + 1;
149
150 /* all ID bit in the filter is "don't care" */
151 FLEXCAN_SetRxIndividualMask(can->base, mailbox, FLEXCAN_RX_MB_STD_MASK(0, 0, 0));
152 FLEXCAN_SetRxMbConfig(can->base, mailbox, &mbConfig, true);
153 /* one frame buffer per MB */
154 rxXfer.frame = &frame[i];
155 rxXfer.mbIdx = mailbox;
156 FLEXCAN_TransferReceiveNonBlocking(can->base, &can->handle, &rxXfer);
157 }
158
159 return res;
160 }
161
162
can_control(struct rt_can_device * can_dev,int cmd,void * arg)163 static rt_err_t can_control(struct rt_can_device *can_dev, int cmd, void *arg)
164 {
165 struct imxrt_can *can;
166 rt_uint32_t argval, mask;
167 rt_uint32_t res = RT_EOK;
168 flexcan_rx_mb_config_t mbConfig;
169 struct rt_can_filter_config *cfg;
170 struct rt_can_filter_item *item;
171 rt_uint8_t i, count, index;
172
173 RT_ASSERT(can_dev != RT_NULL);
174
175 can = (struct imxrt_can *)can_dev->parent.user_data;
176 RT_ASSERT(can != RT_NULL);
177
178 switch (cmd)
179 {
180 case RT_DEVICE_CTRL_SET_INT:
181 argval = (rt_uint32_t) arg;
182 if (argval == RT_DEVICE_FLAG_INT_RX)
183 {
184 mask = kFLEXCAN_RxWarningInterruptEnable;
185 }
186 else if (argval == RT_DEVICE_FLAG_INT_TX)
187 {
188 mask = kFLEXCAN_TxWarningInterruptEnable;
189 }
190 else if (argval == RT_DEVICE_CAN_INT_ERR)
191 {
192 mask = kFLEXCAN_ErrorInterruptEnable;
193 }
194 FLEXCAN_EnableInterrupts(can->base, mask);
195 NVIC_SetPriority(can->irqn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
196 EnableIRQ(can->irqn);
197 break;
198 case RT_DEVICE_CTRL_CLR_INT:
199 /* each CAN device have one IRQ number. */
200 DisableIRQ(can->irqn);
201 break;
202 case RT_CAN_CMD_SET_FILTER:
203 cfg = (struct rt_can_filter_config *)arg;
204 item = cfg->items;
205 count = cfg->count;
206
207 if (filter_mask == 0xffffffff)
208 {
209 rt_kprintf("%s filter is full!\n", can->name);
210 res = -RT_ERROR;
211 break;
212 }
213 else if (filter_mask == 0)
214 {
215 /* deinit all init RX MB */
216 for (i = 0; i < RX_MB_COUNT; i++)
217 {
218 FLEXCAN_SetRxMbConfig(can->base, i + 1, RT_NULL, false);
219 }
220 }
221
222 while (count)
223 {
224 if (item->ide)
225 {
226 mbConfig.format = kFLEXCAN_FrameFormatExtend;
227 mbConfig.id = FLEXCAN_ID_EXT(item->id);
228 mask = FLEXCAN_RX_MB_EXT_MASK(item->mask, 0, 0);
229 }
230 else
231 {
232 mbConfig.format = kFLEXCAN_FrameFormatStandard;
233 mbConfig.id = FLEXCAN_ID_STD(item->id);
234 mask = FLEXCAN_RX_MB_STD_MASK(item->mask, 0, 0);
235 }
236
237 if (item->rtr)
238 {
239 mbConfig.type = kFLEXCAN_FrameTypeRemote;
240 }
241 else
242 {
243 mbConfig.type = kFLEXCAN_FrameTypeData;
244 }
245
246 /* user does not specify hdr index,set hdr_bank from RX MB 1 */
247 if (item->hdr_bank == -1)
248 {
249
250 for (i = 0; i < 32; i++)
251 {
252 if (!(filter_mask & (1 << i)))
253 {
254 index = i;
255 break;
256 }
257 }
258 }
259 else /* use user specified hdr_bank */
260 {
261 if (filter_mask & (1 << item->hdr_bank))
262 {
263 res = -RT_ERROR;
264 rt_kprintf("%s hdr%d filter already set!\n", can->name, item->hdr_bank);
265 break;
266 }
267 else
268 {
269 index = item->hdr_bank;
270 }
271 }
272
273 /* RX MB index from 1 to 32,hdr index 0~31 map RX MB index 1~32. */
274 FLEXCAN_SetRxIndividualMask(can->base, index + 1, mask);
275 FLEXCAN_SetRxMbConfig(can->base, index + 1, &mbConfig, true);
276 filter_mask |= 1 << index;
277
278 item++;
279 count--;
280 }
281
282 break;
283
284 case RT_CAN_CMD_SET_BAUD:
285 {
286 struct can_configure *cfg = (struct can_configure *)arg;
287 if (cfg != RT_NULL)
288 {
289 can->can_dev.config = *cfg;
290 can_cfg(can_dev, cfg);
291 res = RT_EOK;
292 }
293 else
294 {
295 res = -RT_ERROR;
296 }
297 break;
298 }
299 case RT_CAN_CMD_SET_MODE:
300 res = -RT_ERROR;
301 break;
302
303 case RT_CAN_CMD_SET_PRIV:
304 res = -RT_ERROR;
305 break;
306 case RT_CAN_CMD_GET_STATUS:
307 FLEXCAN_GetBusErrCount(can->base, (rt_uint8_t *)(&can->can_dev.status.snderrcnt), (rt_uint8_t *)(&can->can_dev.status.rcverrcnt));
308 rt_memcpy(arg, &can->can_dev.status, sizeof(can->can_dev.status));
309 break;
310 default:
311 res = -RT_ERROR;
312 break;
313 }
314
315 return res;
316 }
317
can_send(struct rt_can_device * can_dev,const void * buf,rt_uint32_t boxno)318 static rt_ssize_t can_send(struct rt_can_device *can_dev, const void *buf, rt_uint32_t boxno)
319 {
320 struct imxrt_can *can;
321 struct rt_can_msg *msg;
322 status_t ret;
323 flexcan_frame_t frame;
324 flexcan_mb_transfer_t txXfer;
325
326 RT_ASSERT(can_dev != RT_NULL);
327 RT_ASSERT(buf != RT_NULL);
328
329 can = (struct imxrt_can *)can_dev->parent.user_data;
330 msg = (struct rt_can_msg *) buf;
331
332 RT_ASSERT(can != RT_NULL);
333 RT_ASSERT(msg != RT_NULL);
334
335 FLEXCAN_SetTxMbConfig(can->base, boxno, true);
336
337 if (RT_CAN_STDID == msg->ide)
338 {
339 frame.id = FLEXCAN_ID_STD(msg->id);
340 frame.format = kFLEXCAN_FrameFormatStandard;
341 }
342 else if (RT_CAN_EXTID == msg->ide)
343 {
344 frame.id = FLEXCAN_ID_EXT(msg->id);
345 frame.format = kFLEXCAN_FrameFormatExtend;
346 }
347
348 if (RT_CAN_DTR == msg->rtr)
349 {
350 frame.type = kFLEXCAN_FrameTypeData;
351 }
352 else if (RT_CAN_RTR == msg->rtr)
353 {
354 frame.type = kFLEXCAN_FrameTypeRemote;
355 }
356
357 frame.length = msg->len;
358 frame.dataByte0 = msg->data[0];
359 frame.dataByte1 = msg->data[1];
360 frame.dataByte2 = msg->data[2];
361 frame.dataByte3 = msg->data[3];
362 frame.dataByte4 = msg->data[4];
363 frame.dataByte5 = msg->data[5];
364 frame.dataByte6 = msg->data[6];
365 frame.dataByte7 = msg->data[7];
366
367 txXfer.mbIdx = boxno;
368 txXfer.frame = &frame;
369
370 ret = FLEXCAN_TransferSendNonBlocking(can->base, &can->handle, &txXfer);
371 switch (ret)
372 {
373 case kStatus_Success:
374 ret = RT_EOK;
375 break;
376 case kStatus_Fail:
377 ret = -RT_ERROR;
378 break;
379 case kStatus_FLEXCAN_TxBusy:
380 ret = -RT_EBUSY;
381 break;
382 }
383
384 return (rt_ssize_t)ret;
385 }
386
can_recv(struct rt_can_device * can_dev,void * buf,rt_uint32_t boxno)387 static rt_ssize_t can_recv(struct rt_can_device *can_dev, void *buf, rt_uint32_t boxno)
388 {
389 struct imxrt_can *can;
390 struct rt_can_msg *pmsg;
391 rt_uint8_t index;
392
393 RT_ASSERT(can_dev != RT_NULL);
394
395 can = (struct imxrt_can *)can_dev->parent.user_data;
396 pmsg = (struct rt_can_msg *) buf;
397 RT_ASSERT(can != RT_NULL);
398
399 index = boxno - 1;
400
401 if (frame[index].format == kFLEXCAN_FrameFormatStandard)
402 {
403 pmsg->ide = RT_CAN_STDID;
404 pmsg->id = frame[index].id >> CAN_ID_STD_SHIFT;
405 }
406 else
407 {
408 pmsg->ide = RT_CAN_EXTID;
409 pmsg->id = frame[index].id >> CAN_ID_EXT_SHIFT;
410 }
411
412 if (frame[index].type == kFLEXCAN_FrameTypeData)
413 {
414 pmsg->rtr = RT_CAN_DTR;
415 }
416 else if (frame[index].type == kFLEXCAN_FrameTypeRemote)
417 {
418 pmsg->rtr = RT_CAN_RTR;
419 }
420 pmsg->hdr_index = index; /* one hdr filter per MB */
421 pmsg->len = frame[index].length;
422 pmsg->data[0] = frame[index].dataByte0;
423 pmsg->data[1] = frame[index].dataByte1;
424 pmsg->data[2] = frame[index].dataByte2;
425 pmsg->data[3] = frame[index].dataByte3;
426 pmsg->data[4] = frame[index].dataByte4;
427 pmsg->data[5] = frame[index].dataByte5;
428 pmsg->data[6] = frame[index].dataByte6;
429 pmsg->data[7] = frame[index].dataByte7;
430
431 return 0;
432 }
433
434
435
436 static struct rt_can_ops imxrt_can_ops =
437 {
438 .configure = can_cfg,
439 .control = can_control,
440 .sendmsg = can_send,
441 .recvmsg = can_recv,
442 };
443
444
rt_hw_can_init(void)445 int rt_hw_can_init(void)
446 {
447 int i;
448 rt_err_t ret = RT_EOK;
449 struct can_configure config = CANDEFAULTCONFIG;
450
451 config.privmode = 0;
452 config.ticks = 50;
453 config.sndboxnumber = 1;
454 config.msgboxsz = RX_MB_COUNT;
455 #ifdef RT_CAN_USING_HDR
456 config.maxhdr = RX_MB_COUNT; /* filter count,one filter per MB */
457 #endif
458
459 for (i = 0; i < sizeof(flexcans) / sizeof(flexcans[0]); i++)
460 {
461 flexcans[i].can_dev.config = config;
462 CLOCK_SetClkDiv(flexcans[i].clock_div_name, 1u);
463 CLOCK_AttachClk(flexcans[i].clock_attach_id);
464
465 ret = rt_hw_can_register(&flexcans[i].can_dev, flexcans[i].name, &imxrt_can_ops, &flexcans[i]);
466 }
467
468 return ret;
469 }
470 INIT_BOARD_EXPORT(rt_hw_can_init);
471
472 #endif /*RT_USING_CAN */
473