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