1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2021-05-11 Carl the first version
9 */
10
11 #include "drv_can.h"
12 #include "interrupt.h"
13 #include <string.h>
14
15 #ifdef BSP_USE_CAN
16
17 #define LOG_TAG "drv_can"
18 #include <drv_log.h>
19
20 #define _CAN0_NAME "can0"
21 #define _CAN1_NAME "can1"
22
23 #define RTHW_CAN_WAIT(_can) rt_sem_take(&_can->recv_semaphore, RT_WAITING_FOREVER);
24 #define RTHW_CAN_SEND(_can) rt_sem_release(&_can->recv_semaphore);
25
26 #ifdef BSP_USING_CAN0
27 struct ft2004_can drv_can0 =
28 {
29 .name = _CAN0_NAME,
30 .can_handle.Config.InstanceId = 0};
31 #endif
32
33 #ifdef BSP_USING_CAN1
34 struct ft2004_can drv_can1 =
35 {
36 .name = _CAN1_NAME,
37 .can_handle.Config.InstanceId = 1};
38 #endif
39
_can_recv_irq(void * args)40 static void _can_recv_irq(void *args)
41 {
42 struct ft2004_can *drv_can = (struct ft2004_can *)args;
43 RTHW_CAN_SEND(drv_can);
44 }
45
rt_hw_inner_can_isr(int irqno,void * param)46 static void rt_hw_inner_can_isr(int irqno, void *param)
47 {
48 FCan_IntrHandler(param);
49 }
50
_can_config(struct rt_can_device * can,struct can_configure * cfg)51 static rt_err_t _can_config(struct rt_can_device *can, struct can_configure *cfg)
52 {
53 struct FCan_Bittiming bit_timing = {0};
54 struct ft2004_can *drv_can;
55 RT_ASSERT(can);
56 RT_ASSERT(cfg);
57 drv_can = (struct ft2004_can *)can->parent.user_data;
58 RT_ASSERT(drv_can);
59
60 FCan_CfgInitialize(&drv_can->can_handle, FCan_LookupConfig(drv_can->can_handle.Config.InstanceId));
61
62 FCan_SetHandler(&drv_can->can_handle, FCAN_HANDLER_RECV, _can_recv_irq, drv_can);
63
64 bit_timing.bitrate = cfg->baud_rate;
65
66 if (FCan_CalcBittiming(&bit_timing) != FCAN_SUCCESS)
67 {
68 LOG_E("Setting baud rate %x is not valid \r\n", bit_timing.bitrate);
69 return -RT_ERROR;
70 }
71
72 FCan_SetTiming(&drv_can->can_handle, &bit_timing);
73
74 rt_hw_interrupt_set_priority(drv_can->can_handle.Config.IrqNum, 16);
75 rt_hw_interrupt_install(drv_can->can_handle.Config.IrqNum, rt_hw_inner_can_isr, &drv_can->can_handle, drv_can->name);
76 rt_hw_interrupt_umask(drv_can->can_handle.Config.IrqNum);
77
78 FCan_Enable(&drv_can->can_handle);
79
80 return RT_EOK;
81 }
82
_can_control(struct rt_can_device * can,int cmd,void * arg)83 static rt_err_t _can_control(struct rt_can_device *can, int cmd, void *arg)
84 {
85 return RT_EOK;
86 }
87
_can_sendmsg(struct rt_can_device * can,const void * buf,rt_uint32_t box_num)88 static int _can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t box_num)
89 {
90 struct ft2004_can *drv_can;
91 struct rt_can_msg *pmsg = (struct rt_can_msg *)buf;
92 struct FCan_Frame can_frame = {0};
93 RT_ASSERT(can);
94 drv_can = (struct ft2004_can *)can->parent.user_data;
95 RT_ASSERT(drv_can);
96
97 /* Check the parameters */
98 RT_ASSERT(pmsg->len <= 8U);
99
100 if (RT_CAN_STDID == pmsg->ide)
101 {
102 can_frame.CanId = pmsg->id;
103 }
104 else
105 {
106 can_frame.CanId = pmsg->id;
107 can_frame.CanId |= CAN_EFF_FLAG;
108 }
109
110 if (RT_CAN_DTR == pmsg->rtr)
111 {
112 }
113 else
114 {
115 can_frame.CanId |= CAN_RTR_FLAG;
116 }
117
118 can_frame.CanDlc = pmsg->len & 0x0FU;
119 memcpy(can_frame.data, pmsg->data, 8);
120
121 return (FCan_SendByIrq(&drv_can->can_handle, &can_frame, 1, RT_NULL) == 1) ? RT_EOK : -RT_ERROR;
122 }
123
_can_recvmsg(struct rt_can_device * can,void * buf,rt_uint32_t fifo)124 static int _can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t fifo)
125 {
126 struct ft2004_can *drv_can;
127 struct rt_can_msg *pmsg = (struct rt_can_msg *)buf;
128 RT_ASSERT(can);
129 struct FCan_Frame recv_frame = {0};
130 drv_can = (struct ft2004_can *)can->parent.user_data;
131 RT_ASSERT(drv_can);
132
133 RTHW_CAN_WAIT(drv_can);
134
135 if (FCan_RecvByIrq(&drv_can->can_handle, &recv_frame, 1) == 0)
136 {
137 LOG_E("rx msg is error");
138 return -RT_ERROR;
139 }
140
141 if (CAN_EFF_FLAG & recv_frame.CanId)
142 {
143 pmsg->ide = RT_CAN_EXTID;
144 pmsg->id = (recv_frame.CanId & ~(RT_CAN_EXTID));
145 }
146 else
147 {
148 pmsg->ide = RT_CAN_STDID;
149 pmsg->id = recv_frame.CanId;
150 }
151
152 if (CAN_RTR_FLAG & recv_frame.CanId)
153 {
154 pmsg->id &= ~CAN_RTR_FLAG;
155 pmsg->rtr = RT_CAN_RTR;
156 }
157 else
158 {
159 pmsg->rtr = RT_CAN_DTR;
160 }
161
162 /* get len */
163 pmsg->len = recv_frame.CanDlc;
164 return RT_EOK;
165 }
166
167 static const struct rt_can_ops _can_ops =
168 {
169 _can_config,
170 _can_control,
171 _can_sendmsg,
172 _can_recvmsg,
173 };
174
rt_hw_can_init(void)175 int rt_hw_can_init(void)
176 {
177 #ifdef BSP_USING_CAN0
178 drv_can0.can_handle.Config.InstanceId = 0;
179 rt_sem_init(&drv_can0.recv_semaphore, "can0_recv", 0, RT_IPC_FLAG_FIFO);
180 drv_can0.device.config.ticks = 20000;
181 drv_can0.device.config.baud_rate = 1000000;
182 rt_hw_can_register(&drv_can0.device,
183 drv_can0.name,
184 &_can_ops,
185 &drv_can0);
186
187 #endif
188
189 #ifdef BSP_USING_CAN1
190 drv_can1.can_handle.Config.InstanceId = 1;
191 drv_can1.device.config.ticks = 20000;
192 drv_can1.device.config.baud_rate = 1000000;
193 rt_sem_init(&drv_can1.recv_semaphore, "can1_recv", 0, RT_IPC_FLAG_FIFO);
194 rt_hw_can_register(&drv_can1.device,
195 drv_can1.name,
196 &_can_ops,
197 &drv_can1);
198
199 #endif
200 return 0;
201 }
202
203 INIT_BOARD_EXPORT(rt_hw_can_init);
204
205 #ifdef BSP_USING_CAN0_DEBUG
206
207 struct can_test_struct
208 {
209 const char *name;
210 struct rt_can_filter_config *filter;
211 rt_device_t candev;
212 struct rt_semaphore _sem;
213 };
214
215 static struct can_test_struct can0_test_obj = {
216 .name = _CAN0_NAME};
217
can_recv_irq(void * param)218 void can_recv_irq(void *param)
219 {
220 struct can_test_struct *_can_obj = (struct can_test_struct *)param;
221 rt_kprintf("can_recv_iqr \r\n");
222 rt_sem_release(&_can_obj->_sem);
223 }
224
rt_can_test_loopback_thread_entry(void * param)225 static void rt_can_test_loopback_thread_entry(void *param)
226 {
227 struct can_test_struct *_can_obj = (struct can_test_struct *)param;
228 struct FCan_Frame recv_frame;
229 struct ft2004_can *drv_can;
230 rt_uint32_t i;
231 _can_obj->candev = rt_device_find(_can_obj->name);
232 RT_ASSERT(_can_obj->candev);
233 drv_can = (struct ft2004_can *)_can_obj->candev->user_data;
234 rt_sem_init(&_can_obj->_sem, "canrx_wait", 0, RT_IPC_FLAG_FIFO);
235 rt_device_open(_can_obj->candev, RT_DEVICE_OFLAG_RDWR);
236
237 while (1)
238 {
239 rt_kprintf(" start to wait loopback \r\n");
240 RTHW_CAN_WAIT(drv_can);
241 while (0 != FCan_RecvByIrq(&drv_can->can_handle, &recv_frame, 1))
242 {
243 rt_kprintf("CanId %x \r\n", recv_frame.CanId);
244 rt_kprintf("CanDlc %x \r\n", recv_frame.CanDlc);
245 for (i = 0; i < recv_frame.CanDlc; i++)
246 {
247 rt_kprintf("data [%d] %x \r\n", i, recv_frame.data[i]);
248 }
249 FCan_SendByIrq(&drv_can->can_handle, &recv_frame, 1, RT_NULL);
250 }
251 }
252 }
253
rt_can0_test(void)254 int rt_can0_test(void)
255 {
256 rt_thread_t tid;
257
258 tid = rt_thread_create("can0_loopback",
259 rt_can_test_loopback_thread_entry, &can0_test_obj,
260 1024, 16, 20);
261 if (tid != RT_NULL)
262 rt_thread_startup(tid);
263
264 return 0;
265 }
266
267 INIT_APP_EXPORT(rt_can0_test);
268
269 #endif
270
271 #endif
272