drv_can.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  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.", instance_p->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.", instance_p->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_D("CAN %d is under error.", instance_p->config.instance_id);
  55. LOG_D("error_status is %x.", FCAN_READ_REG32(base_addr, FCAN_INTR_OFFSET));
  56. LOG_D("rxerr_cnt is %x.", FCAN_ERR_CNT_RFN_GET(FCAN_READ_REG32(base_addr, FCAN_ERR_CNT_OFFSET)));
  57. LOG_D("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_D("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. memset(&arb_segment_config, 0, sizeof(arb_segment_config));
  85. 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_D("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_D("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_D("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_D("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;
  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. GetCpuId(&cpu_id);
  164. rt_hw_interrupt_set_target_cpus(drv_can->can_handle.config.irq_num, cpu_id);
  165. argval = (rt_uint32_t) arg;
  166. /*Open different interrupts*/
  167. if (argval == RT_DEVICE_CAN_INT_ERR)
  168. {
  169. intr_event.type = FCAN_INTR_EVENT_ERROR;
  170. intr_event.handler = CanErrorCallback;
  171. intr_event.param = (void *)(&(drv_can->can_handle));
  172. FCanRegisterInterruptHandler(&(drv_can->can_handle), &intr_event);
  173. FCanInterruptEnable(&(drv_can->can_handle), intr_event.type);
  174. }
  175. if (argval == RT_DEVICE_FLAG_INT_TX)
  176. {
  177. intr_event.type = FCAN_INTR_EVENT_SEND;
  178. intr_event.handler = CanTxIrqCallback;
  179. intr_event.param = (void *)(drv_can);
  180. FCanRegisterInterruptHandler(&(drv_can->can_handle), &intr_event);
  181. FCanInterruptEnable(&(drv_can->can_handle), intr_event.type);
  182. }
  183. if (argval == RT_DEVICE_FLAG_INT_RX)
  184. {
  185. intr_event.type = FCAN_INTR_EVENT_RECV;
  186. intr_event.handler = CanRxIrqCallback;
  187. intr_event.param = (void *)(drv_can);
  188. FCanRegisterInterruptHandler(&(drv_can->can_handle), &intr_event);
  189. FCanInterruptEnable(&(drv_can->can_handle), intr_event.type);
  190. }
  191. rt_hw_interrupt_set_priority(drv_can->can_handle.config.irq_num, 16);
  192. rt_hw_interrupt_install(drv_can->can_handle.config.irq_num, FCanIntrHandler, &(drv_can->can_handle), drv_can->name);
  193. rt_hw_interrupt_umask(drv_can->can_handle.config.irq_num);
  194. break;
  195. case RT_CAN_CMD_SET_MODE:
  196. argval = (rt_uint32_t) arg;
  197. FCanEnable(&(drv_can->can_handle), RT_FALSE);
  198. if (argval == RT_CAN_MODE_LISTEN)
  199. {
  200. FCanSetMode(&(drv_can->can_handle), FCAN_PROBE_MONITOR_MODE);
  201. drv_can->device.config.mode = RT_CAN_MODE_LISTEN;
  202. }
  203. else if (argval == RT_CAN_MODE_NORMAL)
  204. {
  205. FCanSetMode(&(drv_can->can_handle), FCAN_PROBE_NORMAL_MODE);
  206. drv_can->device.config.mode = RT_CAN_MODE_NORMAL;
  207. }
  208. FCanEnable(&(drv_can->can_handle), RT_TRUE);
  209. break;
  210. case RT_CAN_CMD_SET_BAUD:
  211. argval = (rt_uint32_t) arg;
  212. if (argval != CAN1MBaud &&
  213. argval != CAN800kBaud &&
  214. argval != CAN500kBaud &&
  215. argval != CAN250kBaud &&
  216. argval != CAN125kBaud &&
  217. argval != CAN100kBaud &&
  218. argval != CAN50kBaud &&
  219. argval != CAN20kBaud &&
  220. argval != CAN10kBaud)
  221. {
  222. return -RT_ERROR;
  223. }
  224. if (argval != drv_can->device.config.baud_rate)
  225. {
  226. FCanBaudrateConfig arb_segment_config;
  227. FCanBaudrateConfig data_segment_config;
  228. memset(&arb_segment_config, 0, sizeof(arb_segment_config));
  229. memset(&data_segment_config, 0, sizeof(data_segment_config));
  230. drv_can->device.config.baud_rate = argval;
  231. FCanEnable(&(drv_can->can_handle), RT_FALSE);
  232. arb_segment_config.auto_calc = TRUE;
  233. arb_segment_config.baudrate = drv_can->device.config.baud_rate;
  234. arb_segment_config.segment = FCAN_ARB_SEGMENT;
  235. status = FCanBaudrateSet(&(drv_can->can_handle), &arb_segment_config);
  236. if (status != FT_SUCCESS)
  237. {
  238. LOG_D("CAN%d set arb segment baudrate failed.", drv_can->can_handle.config.instance_id);
  239. return -RT_ERROR;
  240. }
  241. data_segment_config.auto_calc = TRUE;
  242. data_segment_config.baudrate = drv_can->device.config.baud_rate;
  243. data_segment_config.segment = FCAN_DATA_SEGMENT;
  244. status = FCanBaudrateSet(&(drv_can->can_handle), &data_segment_config);
  245. if (status != FT_SUCCESS)
  246. {
  247. LOG_D("CAN%d set data segment baudrate failed.", drv_can->can_handle.config.instance_id);
  248. return -RT_ERROR;
  249. }
  250. FCanEnable(&(drv_can->can_handle), RT_TRUE);
  251. }
  252. break;
  253. case RT_CAN_CMD_SET_BAUD_FD:
  254. #if defined RT_CAN_USING_CANFD
  255. argval = (rt_uint32_t) arg;
  256. if (argval != drv_can->device.config.baud_rate_fd)
  257. {
  258. FCanBaudrateConfig arb_segment_config;
  259. FCanBaudrateConfig data_segment_config;
  260. memset(&arb_segment_config, 0, sizeof(arb_segment_config));
  261. memset(&data_segment_config, 0, sizeof(data_segment_config));
  262. drv_can->device.config.baud_rate = argval;
  263. FCanEnable(&(drv_can->can_handle), RT_FALSE);
  264. arb_segment_config.auto_calc = TRUE;
  265. arb_segment_config.baudrate = CAN1MBaud;
  266. arb_segment_config.segment = FCAN_ARB_SEGMENT;
  267. status = FCanBaudrateSet(&(drv_can->can_handle), &arb_segment_config);
  268. if (status != FT_SUCCESS)
  269. {
  270. LOG_D("CAN%d set arb segment baudrate failed.", drv_can->can_handle.config.instance_id);
  271. return -RT_ERROR;
  272. }
  273. data_segment_config.auto_calc = TRUE;
  274. data_segment_config.baudrate = drv_can->device.config.baud_rate_fd;
  275. data_segment_config.segment = FCAN_DATA_SEGMENT;
  276. status = FCanBaudrateSet(&(drv_can->can_handle), &data_segment_config);
  277. if (status != FT_SUCCESS)
  278. {
  279. LOG_D("CAN%d set data segment baudrate failed.", drv_can->can_handle.config.instance_id);
  280. return -RT_ERROR;
  281. }
  282. FCanEnable(&(drv_can->can_handle), RT_TRUE);
  283. }
  284. #endif
  285. break;
  286. case RT_CAN_CMD_SET_FILTER:
  287. #ifdef RT_CAN_USING_HDR
  288. filter_cfg = (struct rt_can_filter_config *)arg;
  289. FCanEnable(&(drv_can->can_handle), RT_FALSE);
  290. for (int i = 0; i < filter_cfg->count; i++)
  291. {
  292. drv_can->filter.filter_index = i;
  293. drv_can->filter.mask = filter_cfg->items[i].mask;
  294. drv_can->filter.id = filter_cfg->items[i].id;
  295. drv_can->filter.type = FCAN_STANDARD_FRAME;
  296. status = FCanIdMaskFilterSet(&(drv_can->can_handle), &(drv_can->filter));
  297. if (status != FT_SUCCESS)
  298. {
  299. LOG_E("CAN%d set mask filter failed.", drv_can->can_handle.config.instance_id);
  300. return -RT_ERROR;
  301. }
  302. }
  303. FCanEnable(&(drv_can->can_handle), RT_TRUE);
  304. #endif
  305. break;
  306. }
  307. return RT_EOK;
  308. }
  309. static int _can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t box_num)
  310. {
  311. RT_ASSERT(can);
  312. RT_ASSERT(buf);
  313. struct phytium_can *drv_can;
  314. drv_can = (struct phytium_can *)can->parent.user_data;
  315. RT_ASSERT(drv_can);
  316. struct rt_can_msg *pmsg = (struct rt_can_msg *)buf;
  317. FCanFrame can_frame = {0};
  318. /* Check the parameters */
  319. RT_ASSERT(pmsg->len <= 8U);
  320. if (RT_CAN_STDID == pmsg->ide)
  321. {
  322. can_frame.canid = pmsg->id;
  323. }
  324. else
  325. {
  326. can_frame.canid = pmsg->id;
  327. can_frame.canid |= CAN_EFF_FLAG;
  328. }
  329. if (RT_CAN_DTR == pmsg->rtr)
  330. {
  331. }
  332. else
  333. {
  334. can_frame.canid |= CAN_RTR_FLAG;
  335. }
  336. can_frame.candlc = pmsg->len ;
  337. memcpy(can_frame.data, pmsg->data, 8);
  338. return (FCanSend(&drv_can->can_handle, &can_frame) == RT_EOK) ? RT_EOK : -RT_ERROR;
  339. }
  340. static int _can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t fifo)
  341. {
  342. RT_ASSERT(can);
  343. RT_ASSERT(buf);
  344. struct phytium_can *drv_can;
  345. drv_can = (struct phytium_can *)can->parent.user_data;
  346. RT_ASSERT(drv_can);
  347. struct rt_can_msg *pmsg = (struct rt_can_msg *)buf;
  348. FCanFrame recv_frame;
  349. FError status = FT_SUCCESS;
  350. status = FCanRecv(&(drv_can->can_handle), &recv_frame);
  351. if (status != FT_SUCCESS)
  352. {
  353. LOG_D("CAN%d recv data failed.", drv_can->can_handle.config.instance_id);
  354. return -RT_ERROR;
  355. }
  356. if (CAN_EFF_FLAG & recv_frame.canid)
  357. {
  358. pmsg->ide = RT_CAN_EXTID;
  359. pmsg->id = (recv_frame.canid & ~(RT_CAN_EXTID));
  360. }
  361. else
  362. {
  363. pmsg->ide = RT_CAN_STDID;
  364. pmsg->id = recv_frame.canid;
  365. }
  366. if (CAN_RTR_FLAG & recv_frame.canid)
  367. {
  368. pmsg->id &= ~CAN_RTR_FLAG;
  369. pmsg->rtr = RT_CAN_RTR;
  370. }
  371. else
  372. {
  373. pmsg->rtr = RT_CAN_DTR;
  374. }
  375. /* get len */
  376. pmsg->len = recv_frame.candlc;
  377. for (int i = 0; i < pmsg->len; i++)
  378. {
  379. pmsg->data[i] = recv_frame.data[i];
  380. }
  381. /* get hdr */
  382. pmsg->hdr_index = 0;
  383. return RT_EOK;
  384. }
  385. static const struct rt_can_ops _can_ops =
  386. {
  387. _can_config,
  388. _can_control,
  389. _can_sendmsg,
  390. _can_recvmsg,
  391. };
  392. static int can_init(struct phytium_can *drv_can)
  393. {
  394. rt_err_t ret = RT_EOK;
  395. drv_can->device.config.ticks = 20000;
  396. /*can default baud_rate*/
  397. drv_can->device.config.baud_rate = CAN800kBaud;
  398. #ifdef RT_CAN_USING_CANFD
  399. /*canfd default baud_rate 1M+800K*/
  400. drv_can->device.config.baud_rate_fd = CAN800kBaud;
  401. #endif
  402. drv_can->device.config.mode = RT_CAN_MODE_NORMAL;
  403. drv_can->device.config.sndboxnumber = 1;
  404. drv_can->device.config.msgboxsz = 1;
  405. #ifdef RT_CAN_USING_HDR
  406. drv_can->device.config.maxhdr = 1;
  407. #endif
  408. ret = rt_hw_can_register(&drv_can->device,
  409. drv_can->name,
  410. &_can_ops,
  411. drv_can);
  412. RT_ASSERT(ret == RT_EOK);
  413. return ret;
  414. }
  415. int rt_hw_can_init(void)
  416. {
  417. #if defined(RT_USING_CAN0)
  418. drv_can0.name = "CAN0";
  419. drv_can0.can_handle.config.instance_id = FCAN0_ID;
  420. can_init(&drv_can0);
  421. #endif
  422. #if defined(RT_USING_CAN1)
  423. drv_can1.name = "CAN1";
  424. drv_can1.can_handle.config.instance_id = FCAN1_ID;
  425. can_init(&drv_can1);
  426. #endif
  427. return 0;
  428. }
  429. INIT_BOARD_EXPORT(rt_hw_can_init);