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