drv_can.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. /*
  2. * Copyright (c) 2006-2023, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Email: opensource_embedded@phytium.com.cn
  7. *
  8. * Change Logs:
  9. * Date Author Notes
  10. * 2023-03-20 zhangyan first version
  11. *
  12. */
  13. #include "rtconfig.h"
  14. #include <rtdevice.h>
  15. #include "drv_can.h"
  16. #define LOG_TAG "can_drv"
  17. #include "drv_log.h"
  18. #include "fcan.h"
  19. #include "fio_mux.h"
  20. #include "interrupt.h"
  21. #include "fcpu_info.h"
  22. #ifdef RT_USING_SMART
  23. #include <ioremap.h>
  24. #endif
  25. struct phytium_can
  26. {
  27. const char *name;
  28. FCanCtrl can_handle;
  29. FCanIdMaskConfig filter;
  30. struct rt_can_device device; /* inherit from can device */
  31. };
  32. #if defined(RT_USING_CAN0)
  33. static struct phytium_can drv_can0;
  34. #endif
  35. #if defined(RT_USING_CAN1)
  36. static struct phytium_can drv_can1;
  37. #endif
  38. static void CanRxIrqCallback(void *args)
  39. {
  40. struct phytium_can *drv_can = (struct phytium_can *)args;
  41. rt_hw_can_isr(&(drv_can->device), RT_CAN_EVENT_RX_IND);
  42. LOG_D("CAN%d irq recv frame callback.", drv_can->can_handle.config.instance_id);
  43. }
  44. static void CanTxIrqCallback(void *args)
  45. {
  46. struct phytium_can *drv_can = (struct phytium_can *)args;
  47. rt_hw_can_isr(&(drv_can->device), RT_CAN_EVENT_TX_DONE);
  48. LOG_D("CAN%d irq send frame callback.", drv_can->can_handle.config.instance_id);
  49. }
  50. static void CanErrorCallback(void *args)
  51. {
  52. FCanCtrl *instance_p = (FCanCtrl *)args;
  53. uintptr base_addr = instance_p->config.base_address;
  54. LOG_E("CAN %d is under error.", instance_p->config.instance_id);
  55. LOG_E("error_status is %x.", FCAN_READ_REG32(base_addr, FCAN_INTR_OFFSET));
  56. LOG_E("rxerr_cnt is %x.", FCAN_ERR_CNT_RFN_GET(FCAN_READ_REG32(base_addr, FCAN_ERR_CNT_OFFSET)));
  57. LOG_E("txerr_cnt is %x.", FCAN_ERR_CNT_TFN_GET(FCAN_READ_REG32(base_addr, FCAN_ERR_CNT_OFFSET)));
  58. }
  59. static rt_err_t _can_config(struct rt_can_device *can, struct can_configure *cfg)
  60. {
  61. RT_ASSERT(can);
  62. RT_ASSERT(cfg);
  63. struct phytium_can *drv_can;
  64. drv_can = (struct phytium_can *)can->parent.user_data;
  65. RT_ASSERT(drv_can);
  66. FError status = FT_SUCCESS;
  67. rt_kprintf("CAN%d begin to config.\n", drv_can->can_handle.config.instance_id);
  68. FIOPadSetCanMux(drv_can->can_handle.config.instance_id);
  69. FCanConfig *config_p;
  70. config_p = FCanLookupConfig(drv_can->can_handle.config.instance_id);
  71. #ifdef RT_USING_SMART
  72. config_p->base_address = (uintptr)rt_ioremap((void *)config_p->base_address, 0x1000);
  73. #endif
  74. /*CAN config init*/
  75. status = FCanCfgInitialize(&(drv_can->can_handle), config_p);
  76. if (status != FT_SUCCESS)
  77. {
  78. LOG_E("CAN %d initialize error, status = %#x.", drv_can->can_handle.config.instance_id, status);
  79. return -RT_ERROR;
  80. }
  81. /*Set the baudrate*/
  82. FCanBaudrateConfig arb_segment_config;
  83. FCanBaudrateConfig data_segment_config;
  84. rt_memset(&arb_segment_config, 0, sizeof(arb_segment_config));
  85. rt_memset(&data_segment_config, 0, sizeof(data_segment_config));
  86. #if defined(RT_CAN_USING_CANFD)
  87. FCanFdEnable(&(drv_can->can_handle), TRUE);
  88. arb_segment_config.auto_calc = TRUE;
  89. arb_segment_config.baudrate = CAN1MBaud; /*CANFD arb baud defaults to 1M ,allowed to be modified*/
  90. arb_segment_config.segment = FCAN_ARB_SEGMENT;
  91. status = FCanBaudrateSet(&(drv_can->can_handle), &arb_segment_config);
  92. if (status != RT_EOK)
  93. {
  94. LOG_E("CAN%d set arb segment baudrate failed.", drv_can->can_handle.config.instance_id);
  95. return -RT_ERROR;
  96. }
  97. data_segment_config.auto_calc = TRUE;
  98. data_segment_config.baudrate = cfg->baud_rate_fd;
  99. data_segment_config.segment = FCAN_DATA_SEGMENT;
  100. status = FCanBaudrateSet(&(drv_can->can_handle), &data_segment_config);
  101. if (status != RT_EOK)
  102. {
  103. LOG_E("CAN%d set data segment baudrate failed.", drv_can->can_handle.config.instance_id);
  104. return -RT_ERROR;
  105. }
  106. #else
  107. arb_segment_config.auto_calc = TRUE;
  108. arb_segment_config.baudrate = cfg->baud_rate;
  109. arb_segment_config.segment = FCAN_ARB_SEGMENT;
  110. status = FCanBaudrateSet(&(drv_can->can_handle), &arb_segment_config);
  111. if (status != FT_SUCCESS)
  112. {
  113. LOG_E("CAN%d set arb segment baudrate failed.", drv_can->can_handle.config.instance_id);
  114. return -RT_ERROR;
  115. }
  116. data_segment_config.auto_calc = TRUE;
  117. data_segment_config.baudrate = cfg->baud_rate;
  118. data_segment_config.segment = FCAN_DATA_SEGMENT;
  119. status = FCanBaudrateSet(&(drv_can->can_handle), &data_segment_config);
  120. if (status != FT_SUCCESS)
  121. {
  122. LOG_E("CAN%d set data segment baudrate failed.", drv_can->can_handle.config.instance_id);
  123. return -RT_ERROR;
  124. }
  125. #endif
  126. /*CAN filter function init*/
  127. for (int i = 0; i < FCAN_ACC_ID_REG_NUM; i++)
  128. {
  129. drv_can->filter.filter_index = i;
  130. drv_can->filter.id = 0;
  131. drv_can->filter.mask = FCAN_ACC_IDN_MASK;
  132. status |= FCanIdMaskFilterSet(&(drv_can->can_handle), &(drv_can->filter));
  133. }
  134. if (status != FT_SUCCESS)
  135. {
  136. LOG_E("CAN%d set mask filter failed.", drv_can->can_handle.config.instance_id);
  137. return -RT_ERROR;
  138. }
  139. /* Identifier mask enable */
  140. FCanIdMaskFilterEnable(&(drv_can->can_handle));
  141. /* Transmit mode init , the default setting is normal mode */
  142. FCanSetMode(&(drv_can->can_handle), FCAN_PROBE_NORMAL_MODE);
  143. /* enable can transfer */
  144. FCanEnable(&(drv_can->can_handle), RT_TRUE);
  145. return RT_EOK;
  146. }
  147. static rt_err_t _can_control(struct rt_can_device *can, int cmd, void *arg)
  148. {
  149. RT_ASSERT(can);
  150. rt_uint32_t argval;
  151. struct phytium_can *drv_can;
  152. drv_can = (struct phytium_can *)can->parent.user_data;
  153. RT_ASSERT(drv_can != RT_NULL);
  154. rt_uint32_t cpu_id = rt_hw_cpu_id();
  155. FCanIntrEventConfig intr_event;
  156. FError status = FT_SUCCESS;
  157. #ifdef RT_CAN_USING_HDR
  158. struct rt_can_filter_config *filter_cfg;
  159. #endif
  160. switch (cmd)
  161. {
  162. case RT_DEVICE_CTRL_SET_INT:
  163. rt_hw_interrupt_set_target_cpus(drv_can->can_handle.config.irq_num, cpu_id);
  164. argval = (rt_uint32_t) arg;
  165. /*Open different interrupts*/
  166. if (argval == RT_DEVICE_CAN_INT_ERR)
  167. {
  168. intr_event.type = FCAN_INTR_EVENT_ERROR;
  169. intr_event.handler = CanErrorCallback;
  170. intr_event.param = (void *)(&(drv_can->can_handle));
  171. FCanRegisterInterruptHandler(&(drv_can->can_handle), &intr_event);
  172. FCanInterruptEnable(&(drv_can->can_handle), intr_event.type);
  173. }
  174. if (argval == RT_DEVICE_FLAG_INT_TX)
  175. {
  176. intr_event.type = FCAN_INTR_EVENT_SEND;
  177. intr_event.handler = CanTxIrqCallback;
  178. intr_event.param = (void *)(drv_can);
  179. FCanRegisterInterruptHandler(&(drv_can->can_handle), &intr_event);
  180. FCanInterruptEnable(&(drv_can->can_handle), intr_event.type);
  181. }
  182. if (argval == RT_DEVICE_FLAG_INT_RX)
  183. {
  184. intr_event.type = FCAN_INTR_EVENT_RECV;
  185. intr_event.handler = CanRxIrqCallback;
  186. intr_event.param = (void *)(drv_can);
  187. FCanRegisterInterruptHandler(&(drv_can->can_handle), &intr_event);
  188. FCanInterruptEnable(&(drv_can->can_handle), intr_event.type);
  189. }
  190. rt_hw_interrupt_set_priority(drv_can->can_handle.config.irq_num, 16);
  191. rt_hw_interrupt_install(drv_can->can_handle.config.irq_num, FCanIntrHandler, &(drv_can->can_handle), drv_can->name);
  192. rt_hw_interrupt_umask(drv_can->can_handle.config.irq_num);
  193. break;
  194. case RT_CAN_CMD_SET_MODE:
  195. argval = (rt_uint32_t) arg;
  196. FCanEnable(&(drv_can->can_handle), RT_FALSE);
  197. if (argval == RT_CAN_MODE_LISTEN)
  198. {
  199. FCanSetMode(&(drv_can->can_handle), FCAN_PROBE_MONITOR_MODE);
  200. drv_can->device.config.mode = RT_CAN_MODE_LISTEN;
  201. }
  202. else if (argval == RT_CAN_MODE_NORMAL)
  203. {
  204. FCanSetMode(&(drv_can->can_handle), FCAN_PROBE_NORMAL_MODE);
  205. drv_can->device.config.mode = RT_CAN_MODE_NORMAL;
  206. }
  207. FCanEnable(&(drv_can->can_handle), RT_TRUE);
  208. break;
  209. case RT_CAN_CMD_SET_BAUD:
  210. argval = (rt_uint32_t) arg;
  211. if (argval != CAN1MBaud &&
  212. argval != CAN800kBaud &&
  213. argval != CAN500kBaud &&
  214. argval != CAN250kBaud &&
  215. argval != CAN125kBaud &&
  216. argval != CAN100kBaud &&
  217. argval != CAN50kBaud &&
  218. argval != CAN20kBaud &&
  219. argval != CAN10kBaud)
  220. {
  221. return -RT_ERROR;
  222. }
  223. if (argval != drv_can->device.config.baud_rate)
  224. {
  225. FCanBaudrateConfig arb_segment_config;
  226. FCanBaudrateConfig data_segment_config;
  227. rt_memset(&arb_segment_config, 0, sizeof(arb_segment_config));
  228. rt_memset(&data_segment_config, 0, sizeof(data_segment_config));
  229. drv_can->device.config.baud_rate = argval;
  230. FCanEnable(&(drv_can->can_handle), RT_FALSE);
  231. arb_segment_config.auto_calc = TRUE;
  232. arb_segment_config.baudrate = drv_can->device.config.baud_rate;
  233. arb_segment_config.segment = FCAN_ARB_SEGMENT;
  234. status = FCanBaudrateSet(&(drv_can->can_handle), &arb_segment_config);
  235. if (status != FT_SUCCESS)
  236. {
  237. LOG_E("CAN%d set arb segment baudrate failed.", drv_can->can_handle.config.instance_id);
  238. return -RT_ERROR;
  239. }
  240. data_segment_config.auto_calc = TRUE;
  241. data_segment_config.baudrate = drv_can->device.config.baud_rate;
  242. data_segment_config.segment = FCAN_DATA_SEGMENT;
  243. status = FCanBaudrateSet(&(drv_can->can_handle), &data_segment_config);
  244. if (status != FT_SUCCESS)
  245. {
  246. LOG_E("CAN%d set data segment baudrate failed.", drv_can->can_handle.config.instance_id);
  247. return -RT_ERROR;
  248. }
  249. FCanEnable(&(drv_can->can_handle), RT_TRUE);
  250. }
  251. break;
  252. case RT_CAN_CMD_SET_BAUD_FD:
  253. #if defined RT_CAN_USING_CANFD
  254. argval = (rt_uint32_t) arg;
  255. if (argval != drv_can->device.config.baud_rate_fd)
  256. {
  257. FCanBaudrateConfig arb_segment_config;
  258. FCanBaudrateConfig data_segment_config;
  259. rt_memset(&arb_segment_config, 0, sizeof(arb_segment_config));
  260. rt_memset(&data_segment_config, 0, sizeof(data_segment_config));
  261. drv_can->device.config.baud_rate = argval;
  262. FCanEnable(&(drv_can->can_handle), RT_FALSE);
  263. arb_segment_config.auto_calc = TRUE;
  264. arb_segment_config.baudrate = CAN1MBaud;
  265. arb_segment_config.segment = FCAN_ARB_SEGMENT;
  266. status = FCanBaudrateSet(&(drv_can->can_handle), &arb_segment_config);
  267. if (status != FT_SUCCESS)
  268. {
  269. LOG_E("CAN%d set arb segment baudrate failed.", drv_can->can_handle.config.instance_id);
  270. return -RT_ERROR;
  271. }
  272. data_segment_config.auto_calc = TRUE;
  273. data_segment_config.baudrate = drv_can->device.config.baud_rate_fd;
  274. data_segment_config.segment = FCAN_DATA_SEGMENT;
  275. status = FCanBaudrateSet(&(drv_can->can_handle), &data_segment_config);
  276. if (status != FT_SUCCESS)
  277. {
  278. LOG_E("CAN%d set data segment baudrate failed.", drv_can->can_handle.config.instance_id);
  279. return -RT_ERROR;
  280. }
  281. FCanEnable(&(drv_can->can_handle), RT_TRUE);
  282. }
  283. #endif
  284. break;
  285. case RT_CAN_CMD_SET_FILTER:
  286. #ifdef RT_CAN_USING_HDR
  287. filter_cfg = (struct rt_can_filter_config *)arg;
  288. FCanEnable(&(drv_can->can_handle), RT_FALSE);
  289. for (int i = 0; i < filter_cfg->count; i++)
  290. {
  291. drv_can->filter.filter_index = i;
  292. drv_can->filter.mask = filter_cfg->items[i].mask;
  293. drv_can->filter.id = filter_cfg->items[i].id;
  294. drv_can->filter.type = FCAN_STANDARD_FRAME;
  295. status = FCanIdMaskFilterSet(&(drv_can->can_handle), &(drv_can->filter));
  296. if (status != FT_SUCCESS)
  297. {
  298. LOG_E("CAN%d set mask filter failed.", drv_can->can_handle.config.instance_id);
  299. return -RT_ERROR;
  300. }
  301. }
  302. FCanEnable(&(drv_can->can_handle), RT_TRUE);
  303. #endif
  304. break;
  305. }
  306. return RT_EOK;
  307. }
  308. static rt_ssize_t _can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t box_num)
  309. {
  310. RT_ASSERT(can);
  311. RT_ASSERT(buf);
  312. struct phytium_can *drv_can;
  313. drv_can = (struct phytium_can *)can->parent.user_data;
  314. RT_ASSERT(drv_can);
  315. struct rt_can_msg *pmsg = (struct rt_can_msg *)buf;
  316. FCanFrame can_frame = {0};
  317. /* Check the parameters */
  318. RT_ASSERT(pmsg->len <= 8U);
  319. if (RT_CAN_STDID == pmsg->ide)
  320. {
  321. can_frame.canid = pmsg->id;
  322. }
  323. else
  324. {
  325. can_frame.canid = pmsg->id;
  326. can_frame.canid |= CAN_EFF_FLAG;
  327. }
  328. if (RT_CAN_DTR == pmsg->rtr)
  329. {
  330. }
  331. else
  332. {
  333. can_frame.canid |= CAN_RTR_FLAG;
  334. }
  335. can_frame.candlc = pmsg->len ;
  336. memcpy(can_frame.data, pmsg->data, 8);
  337. return (FCanSend(&drv_can->can_handle, &can_frame) == RT_EOK) ? RT_EOK : -RT_ERROR;
  338. }
  339. static rt_ssize_t _can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t fifo)
  340. {
  341. RT_ASSERT(can);
  342. RT_ASSERT(buf);
  343. struct phytium_can *drv_can;
  344. drv_can = (struct phytium_can *)can->parent.user_data;
  345. RT_ASSERT(drv_can);
  346. struct rt_can_msg *pmsg = (struct rt_can_msg *)buf;
  347. FCanFrame recv_frame;
  348. FError status = FT_SUCCESS;
  349. status = FCanRecv(&(drv_can->can_handle), &recv_frame);
  350. if (status != FT_SUCCESS)
  351. {
  352. LOG_D("CAN%d recv data failed.", drv_can->can_handle.config.instance_id);
  353. return -RT_ERROR;
  354. }
  355. if (CAN_EFF_FLAG & recv_frame.canid)
  356. {
  357. pmsg->ide = RT_CAN_EXTID;
  358. pmsg->id = (recv_frame.canid & ~(RT_CAN_EXTID));
  359. }
  360. else
  361. {
  362. pmsg->ide = RT_CAN_STDID;
  363. pmsg->id = recv_frame.canid;
  364. }
  365. if (CAN_RTR_FLAG & recv_frame.canid)
  366. {
  367. pmsg->id &= ~CAN_RTR_FLAG;
  368. pmsg->rtr = RT_CAN_RTR;
  369. }
  370. else
  371. {
  372. pmsg->rtr = RT_CAN_DTR;
  373. }
  374. /* get len */
  375. pmsg->len = recv_frame.candlc;
  376. for (int i = 0; i < pmsg->len; i++)
  377. {
  378. pmsg->data[i] = recv_frame.data[i];
  379. }
  380. /* get hdr */
  381. pmsg->hdr_index = 0;
  382. return RT_EOK;
  383. }
  384. static const struct rt_can_ops _can_ops =
  385. {
  386. _can_config,
  387. _can_control,
  388. _can_sendmsg,
  389. _can_recvmsg,
  390. };
  391. static int can_init(struct phytium_can *drv_can)
  392. {
  393. rt_err_t ret = RT_EOK;
  394. drv_can->device.config.ticks = 20000;
  395. /*can default baud_rate*/
  396. drv_can->device.config.baud_rate = CAN800kBaud;
  397. #ifdef RT_CAN_USING_CANFD
  398. /*canfd default baud_rate 1M+800K*/
  399. drv_can->device.config.baud_rate_fd = CAN800kBaud;
  400. #endif
  401. drv_can->device.config.mode = RT_CAN_MODE_NORMAL;
  402. drv_can->device.config.sndboxnumber = 1;
  403. drv_can->device.config.msgboxsz = 1;
  404. #ifdef RT_CAN_USING_HDR
  405. drv_can->device.config.maxhdr = 1;
  406. #endif
  407. ret = rt_hw_can_register(&drv_can->device,
  408. drv_can->name,
  409. &_can_ops,
  410. drv_can);
  411. RT_ASSERT(ret == RT_EOK);
  412. return ret;
  413. }
  414. int rt_hw_can_init(void)
  415. {
  416. #if defined(RT_USING_CAN0)
  417. drv_can0.name = "CAN0";
  418. drv_can0.can_handle.config.instance_id = FCAN0_ID;
  419. can_init(&drv_can0);
  420. #endif
  421. #if defined(RT_USING_CAN1)
  422. drv_can1.name = "CAN1";
  423. drv_can1.can_handle.config.instance_id = FCAN1_ID;
  424. can_init(&drv_can1);
  425. #endif
  426. return 0;
  427. }
  428. INIT_BOARD_EXPORT(rt_hw_can_init);