drv_can.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555
  1. /**************************************************************************//**
  2. *
  3. * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0
  6. *
  7. * Change Logs:
  8. * Date Author Notes
  9. * 2020-12-12 Wayne First version
  10. *
  11. ******************************************************************************/
  12. #include <rtconfig.h>
  13. #if defined(BSP_USING_CAN)
  14. #include <rtdevice.h>
  15. #include <rthw.h>
  16. #include "NuMicro.h"
  17. #include <drv_sys.h>
  18. /* Private Define ---------------------------------------------------------------*/
  19. #define RX_MSG_ID_INDEX 16
  20. #define IS_CAN_STDID(STDID) ((STDID) <= 0x7FFU)
  21. #define IS_CAN_EXTID(EXTID) ((EXTID) <= 0x1FFFFFFFU)
  22. #define IS_CAN_DLC(DLC) ((DLC) <= 8U)
  23. /* Default config for serial_configure structure */
  24. #define NU_CAN_CONFIG_DEFAULT \
  25. { \
  26. CAN1MBaud, /* 1M bits/s */ \
  27. RT_CANMSG_BOX_SZ, /* message box max size */ \
  28. RT_CANSND_BOX_NUM, /* message box number */ \
  29. RT_CAN_MODE_NORMAL, /* Normal mode */ \
  30. 0, /* privmode */ \
  31. 0, /* reserved */ \
  32. 100, /* Timeout Tick */ \
  33. }
  34. enum
  35. {
  36. CAN_START = -1,
  37. #if defined(BSP_USING_CAN0)
  38. CAN0_IDX,
  39. #endif
  40. #if defined(BSP_USING_CAN1)
  41. CAN1_IDX,
  42. #endif
  43. CAN_CNT,
  44. };
  45. /* Private Typedef --------------------------------------------------------------*/
  46. struct nu_can
  47. {
  48. struct rt_can_device dev;
  49. char *name;
  50. CAN_T *base;
  51. IRQn_Type irqn;
  52. E_SYS_IPRST rstidx;
  53. E_SYS_IPCLK clkidx;
  54. uint32_t int_flag;
  55. };
  56. typedef struct nu_can *nu_can_t;
  57. /* Private functions ------------------------------------------------------------*/
  58. static rt_err_t nu_can_configure(struct rt_can_device *can, struct can_configure *cfg);
  59. static rt_err_t nu_can_control(struct rt_can_device *can, int cmd, void *arg);
  60. static int nu_can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t boxno);
  61. static int nu_can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t boxno);
  62. static void nu_can_isr(int vector, void *param);
  63. static struct nu_can nu_can_arr[] =
  64. {
  65. #if defined(BSP_USING_CAN0)
  66. {
  67. .name = "can0",
  68. .base = CAN0,
  69. .irqn = IRQ_CAN0,
  70. .rstidx = CAN0RST,
  71. .clkidx = CAN0CKEN,
  72. },
  73. #endif
  74. #if defined(BSP_USING_CAN1)
  75. {
  76. .name = "can1",
  77. .base = CAN1,
  78. .irqn = IRQ_CAN1,
  79. .rstidx = CAN1RST,
  80. .clkidx = CAN1CKEN,
  81. },
  82. #endif
  83. }; /* struct nu_can */
  84. /* Public functions ------------------------------------------------------------*/
  85. /* Private variables ------------------------------------------------------------*/
  86. static const struct rt_can_ops nu_can_ops =
  87. {
  88. .configure = nu_can_configure,
  89. .control = nu_can_control,
  90. .sendmsg = nu_can_sendmsg,
  91. .recvmsg = nu_can_recvmsg,
  92. };
  93. static const struct can_configure nu_can_default_config = NU_CAN_CONFIG_DEFAULT;
  94. /* Interrupt Handle Function ----------------------------------------------------*/
  95. static void nu_can_isr(int vector, void *param)
  96. {
  97. nu_can_t psNuCAN = (nu_can_t)param;
  98. /* Get base address of CAN register */
  99. CAN_T *base = psNuCAN->base;
  100. /* Get interrupt event */
  101. uint32_t u32IIDRstatus = CAN_GET_INT_PENDING_STATUS(base) & CAN_IIDR_INTID_Msk;
  102. /* Check Status Interrupt Flag (Error status Int and Status change Int) */
  103. if (u32IIDRstatus == 0x00008000)
  104. {
  105. /**************************/
  106. /* Status Change interrupt*/
  107. /**************************/
  108. if (base->STATUS & CAN_STATUS_TXOK_Msk)
  109. {
  110. base->STATUS &= ~CAN_STATUS_TXOK_Msk; /* Clear Tx Ok status*/
  111. #ifndef RT_CAN_USING_HDR
  112. if (psNuCAN->int_flag & RT_DEVICE_FLAG_INT_TX)
  113. {
  114. /*Using as Lisen,Loopback,Loopback+Lisen mode*/
  115. rt_hw_can_isr(&psNuCAN->dev, RT_CAN_EVENT_TX_DONE);
  116. }
  117. #endif
  118. }
  119. if (base->STATUS & CAN_STATUS_RXOK_Msk)
  120. {
  121. base->STATUS &= ~CAN_STATUS_RXOK_Msk; /* Clear Rx Ok status*/
  122. #ifndef RT_CAN_USING_HDR
  123. if (psNuCAN->int_flag & RT_DEVICE_FLAG_INT_RX)
  124. {
  125. /*Using as Lisen,Loopback,Loopback+Lisen mode*/
  126. rt_hw_can_isr(&psNuCAN->dev, RT_CAN_EVENT_RX_IND);
  127. }
  128. #endif
  129. }
  130. /**************************/
  131. /* Error Status interrupt */
  132. /**************************/
  133. if (base->STATUS & CAN_STATUS_EWARN_Msk)
  134. {
  135. rt_kprintf("[%s]EWARN INT\n", psNuCAN->name) ;
  136. }
  137. if (base->STATUS & CAN_STATUS_BOFF_Msk)
  138. {
  139. rt_kprintf("[%s]BUSOFF INT\n", psNuCAN->name) ;
  140. /* To release busoff pin */
  141. CAN_EnterInitMode(base, CAN_CON_INIT_Msk | CAN_CON_CCE_Msk);
  142. CAN_LeaveInitMode(base);
  143. }
  144. if (base->STATUS & CAN_STATUS_LEC_Msk)
  145. {
  146. rt_kprintf("[%s] Last Error Code %03x\n", psNuCAN->name, base->STATUS & CAN_STATUS_LEC_Msk) ;
  147. }
  148. }
  149. #ifdef RT_CAN_USING_HDR
  150. /*IntId: 0x0001-0x0020, Number of Message Object which caused the interrupt.*/
  151. else if (u32IIDRstatus > 0 && u32IIDRstatus <= 32)
  152. {
  153. if ((psNuCAN->int_flag & RT_DEVICE_FLAG_INT_TX) &&
  154. (u32IIDRstatus <= RX_MSG_ID_INDEX))
  155. {
  156. /*Message RAM 0~RX_MSG_ID_INDEX for CAN Tx using*/
  157. rt_hw_can_isr(&psNuCAN->dev, RT_CAN_EVENT_TX_DONE);
  158. }
  159. else if (psNuCAN->int_flag & RT_DEVICE_FLAG_INT_RX)
  160. {
  161. /*Message RAM RX_MSG_ID_INDEX~31 for CAN Rx using*/
  162. rt_hw_can_isr(&psNuCAN->dev, (RT_CAN_EVENT_RX_IND | ((u32IIDRstatus - 1) << 8)));
  163. }
  164. CAN_CLR_INT_PENDING_BIT(base, (u32IIDRstatus - 1)); /* Clear Interrupt Pending */
  165. }
  166. #endif
  167. }
  168. static void nu_can_ie(nu_can_t psNuCAN)
  169. {
  170. uint32_t u32CanIE = CAN_CON_IE_Msk;
  171. if (psNuCAN->int_flag & (RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX))
  172. {
  173. u32CanIE |= CAN_CON_SIE_Msk;
  174. }
  175. else
  176. {
  177. u32CanIE &= ~CAN_CON_SIE_Msk;
  178. }
  179. if (psNuCAN->int_flag & RT_DEVICE_CAN_INT_ERR)
  180. {
  181. u32CanIE |= CAN_CON_EIE_Msk;
  182. }
  183. else
  184. {
  185. u32CanIE &= ~CAN_CON_EIE_Msk;
  186. }
  187. if (u32CanIE & (CAN_CON_SIE_Msk | CAN_CON_EIE_Msk))
  188. {
  189. CAN_EnableInt(psNuCAN->base, u32CanIE);
  190. /* Enable interrupt. */
  191. rt_hw_interrupt_umask(psNuCAN->irqn);
  192. }
  193. else
  194. {
  195. u32CanIE |= (CAN_CON_IE_Msk | CAN_CON_SIE_Msk);
  196. CAN_DisableInt(psNuCAN->base, u32CanIE);
  197. /* Disable interrupt. */
  198. rt_hw_interrupt_mask(psNuCAN->irqn);
  199. }
  200. }
  201. static rt_err_t nu_can_configure(struct rt_can_device *can, struct can_configure *cfg)
  202. {
  203. nu_can_t psNuCAN = (nu_can_t)can;
  204. uint32_t u32CANMode;
  205. RT_ASSERT(can);
  206. RT_ASSERT(cfg);
  207. /* Get base address of CAN register */
  208. CAN_T *base = psNuCAN->base;
  209. /* Reset this module */
  210. nu_sys_ip_reset(psNuCAN->rstidx);
  211. u32CANMode = (cfg->mode == RT_CAN_MODE_NORMAL) ? CAN_NORMAL_MODE : CAN_BASIC_MODE;
  212. /*Set the CAN Bit Rate and Operating mode*/
  213. if (CAN_Open(base, cfg->baud_rate, u32CANMode) != cfg->baud_rate)
  214. goto exit_nu_can_configure;
  215. switch (cfg->mode)
  216. {
  217. case RT_CAN_MODE_NORMAL:
  218. #ifdef RT_CAN_USING_HDR
  219. CAN_LeaveTestMode(base);
  220. #else
  221. CAN_EnterTestMode(base, CAN_TEST_BASIC_Msk);
  222. #endif
  223. break;
  224. case RT_CAN_MODE_LISEN:
  225. CAN_EnterTestMode(base, CAN_TEST_BASIC_Msk | CAN_TEST_SILENT_Msk);
  226. break;
  227. case RT_CAN_MODE_LOOPBACK:
  228. CAN_EnterTestMode(base, CAN_TEST_BASIC_Msk | CAN_TEST_LBACK_Msk);
  229. break;
  230. case RT_CAN_MODE_LOOPBACKANLISEN:
  231. CAN_EnterTestMode(base, CAN_TEST_BASIC_Msk | CAN_TEST_SILENT_Msk | CAN_TEST_LBACK_Msk);
  232. break;
  233. default:
  234. rt_kprintf("Unsupported Operating mode");
  235. goto exit_nu_can_configure;
  236. }
  237. nu_can_ie(psNuCAN);
  238. return RT_EOK;
  239. exit_nu_can_configure:
  240. CAN_Close(base);
  241. return -(RT_ERROR);
  242. }
  243. static rt_err_t nu_can_control(struct rt_can_device *can, int cmd, void *arg)
  244. {
  245. rt_uint32_t argval = (rt_uint32_t)arg;
  246. nu_can_t psNuCAN = (nu_can_t)can;
  247. RT_ASSERT(can);
  248. switch (cmd)
  249. {
  250. case RT_DEVICE_CTRL_SET_INT:
  251. psNuCAN->int_flag |= argval;
  252. nu_can_ie(psNuCAN);
  253. break;
  254. case RT_DEVICE_CTRL_CLR_INT:
  255. psNuCAN->int_flag &= ~argval;
  256. nu_can_ie(psNuCAN);
  257. break;
  258. case RT_CAN_CMD_SET_FILTER:
  259. {
  260. struct rt_can_filter_config *filter_cfg = (struct rt_can_filter_config *)arg;
  261. for (int i = 0; i < filter_cfg->count; i++)
  262. {
  263. /*set the filter message object*/
  264. if (filter_cfg->items[i].mode == 1)
  265. {
  266. if (CAN_SetRxMsgObjAndMsk(psNuCAN->base, MSG(filter_cfg->items[i].hdr + RX_MSG_ID_INDEX), filter_cfg->items[i].ide, filter_cfg->items[i].id, filter_cfg->items[i].mask, FALSE) == FALSE)
  267. {
  268. return -(RT_ERROR);
  269. }
  270. }
  271. else
  272. {
  273. /*set the filter message object*/
  274. if (CAN_SetRxMsgAndMsk(psNuCAN->base, MSG(filter_cfg->items[i].hdr + RX_MSG_ID_INDEX), filter_cfg->items[i].ide, filter_cfg->items[i].id, filter_cfg->items[i].mask) == FALSE)
  275. {
  276. return -(RT_ERROR);
  277. }
  278. }
  279. }
  280. }
  281. break;
  282. case RT_CAN_CMD_SET_MODE:
  283. if ((argval == RT_CAN_MODE_NORMAL) ||
  284. (argval == RT_CAN_MODE_LISEN) ||
  285. (argval == RT_CAN_MODE_LOOPBACK) ||
  286. (argval == RT_CAN_MODE_LOOPBACKANLISEN))
  287. {
  288. if (argval != can->config.mode)
  289. {
  290. can->config.mode = argval;
  291. return nu_can_configure(can, &can->config);
  292. }
  293. }
  294. else
  295. {
  296. return -(RT_ERROR);
  297. }
  298. break;
  299. case RT_CAN_CMD_SET_BAUD:
  300. {
  301. if ((argval == CAN1MBaud) ||
  302. (argval == CAN800kBaud) ||
  303. (argval == CAN500kBaud) ||
  304. (argval == CAN250kBaud) ||
  305. (argval == CAN125kBaud) ||
  306. (argval == CAN100kBaud) ||
  307. (argval == CAN50kBaud) ||
  308. (argval == CAN20kBaud) ||
  309. (argval == CAN10kBaud))
  310. {
  311. if (argval != can->config.baud_rate)
  312. {
  313. can->config.baud_rate = argval;
  314. return nu_can_configure(can, &can->config);
  315. }
  316. }
  317. else
  318. {
  319. return -(RT_ERROR);
  320. }
  321. }
  322. break;
  323. case RT_CAN_CMD_SET_PRIV:
  324. if (argval != RT_CAN_MODE_PRIV &&
  325. argval != RT_CAN_MODE_NOPRIV)
  326. {
  327. return -(RT_ERROR);
  328. }
  329. if (argval != can->config.privmode)
  330. {
  331. can->config.privmode = argval;
  332. return nu_can_configure(can, &can->config);
  333. }
  334. break;
  335. case RT_CAN_CMD_GET_STATUS:
  336. {
  337. rt_uint32_t errtype = psNuCAN->base->ERR;
  338. RT_ASSERT(arg);
  339. /*Receive Error Counter, return value is with Receive Error Passive.*/
  340. can->status.rcverrcnt = (errtype >> 8);
  341. /*Transmit Error Counter*/
  342. can->status.snderrcnt = (errtype & 0xFF);
  343. /*Last Error Type*/
  344. can->status.lasterrtype = CAN_GET_INT_STATUS(psNuCAN->base) & 0x8000;
  345. /*Status error code*/
  346. can->status.errcode = CAN_GET_INT_STATUS(psNuCAN->base) & 0x07;
  347. rt_memcpy(arg, &can->status, sizeof(struct rt_can_status));
  348. }
  349. break;
  350. default:
  351. return -(RT_EINVAL);
  352. }
  353. return RT_EOK;
  354. }
  355. static int nu_can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t boxno)
  356. {
  357. STR_CANMSG_T tMsg;
  358. struct rt_can_msg *pmsg;
  359. nu_can_t psNuCAN = (nu_can_t)can;
  360. RT_ASSERT(can);
  361. RT_ASSERT(buf);
  362. pmsg = (struct rt_can_msg *) buf;
  363. if (pmsg->ide == RT_CAN_STDID && IS_CAN_STDID(pmsg->id))
  364. {
  365. /* Standard ID (11 bits)*/
  366. tMsg.IdType = CAN_STD_ID;
  367. tMsg.Id = pmsg->id ;
  368. }
  369. else if (pmsg->ide == RT_CAN_EXTID && IS_CAN_EXTID(pmsg->id))
  370. {
  371. /* Extended ID (29 bits)*/
  372. tMsg.IdType = CAN_EXT_ID;
  373. tMsg.Id = pmsg->id ;
  374. }
  375. else
  376. {
  377. goto exit_nu_can_sendmsg;
  378. }
  379. if (pmsg->rtr == RT_CAN_DTR)
  380. {
  381. /* Data frame */
  382. tMsg.FrameType = CAN_DATA_FRAME;
  383. }
  384. else if (pmsg->rtr == RT_CAN_RTR)
  385. {
  386. /* Remote frame */
  387. tMsg.FrameType = CAN_REMOTE_FRAME;
  388. }
  389. else
  390. {
  391. goto exit_nu_can_sendmsg;
  392. }
  393. /* Check the parameters */
  394. if (IS_CAN_DLC(pmsg->len))
  395. {
  396. tMsg.DLC = pmsg->len;
  397. }
  398. else
  399. {
  400. goto exit_nu_can_sendmsg;
  401. }
  402. if (pmsg->data && pmsg->len)
  403. {
  404. rt_memcpy(&tMsg.Data[0], pmsg->data, pmsg->len);
  405. }
  406. else
  407. {
  408. goto exit_nu_can_sendmsg;
  409. }
  410. /* Configure Msg RAM and send the Msg in the RAM. */
  411. if (CAN_Transmit(psNuCAN->base, MSG(boxno), &tMsg) == FALSE)
  412. {
  413. goto exit_nu_can_sendmsg;
  414. }
  415. return RT_EOK;
  416. exit_nu_can_sendmsg:
  417. return -(RT_ERROR);
  418. }
  419. static int nu_can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t boxno)
  420. {
  421. STR_CANMSG_T tMsg;
  422. struct rt_can_msg *pmsg;
  423. nu_can_t psNuCAN = (nu_can_t)can;
  424. RT_ASSERT(can);
  425. RT_ASSERT(buf);
  426. pmsg = (struct rt_can_msg *) buf;
  427. /* get data */
  428. if (CAN_Receive(psNuCAN->base, boxno, &tMsg) == FALSE)
  429. {
  430. rt_kprintf("No available RX Msg.\n");
  431. return -(RT_ERROR);
  432. }
  433. #ifdef RT_CAN_USING_HDR
  434. /* Hardware filter messages are valid */
  435. pmsg->hdr = boxno - RX_MSG_ID_INDEX;
  436. can->hdr[pmsg->hdr].connected = 1;
  437. #endif
  438. pmsg->ide = (tMsg.IdType == CAN_STD_ID) ? RT_CAN_STDID : RT_CAN_EXTID;
  439. pmsg->rtr = (tMsg.FrameType == CAN_DATA_FRAME) ? RT_CAN_DTR : RT_CAN_RTR;
  440. pmsg->id = tMsg.Id;
  441. pmsg->len = tMsg.DLC ;
  442. if (pmsg->data && pmsg->len)
  443. rt_memcpy(pmsg->data, &tMsg.Data[0], pmsg->len);
  444. return RT_EOK;
  445. }
  446. /**
  447. * Hardware CAN Initialization
  448. */
  449. static int rt_hw_can_init(void)
  450. {
  451. int i;
  452. rt_err_t ret = RT_EOK;
  453. for (i = (CAN_START + 1); i < CAN_CNT; i++)
  454. {
  455. nu_can_arr[i].dev.config = nu_can_default_config;
  456. #ifdef RT_CAN_USING_HDR
  457. nu_can_arr[i].dev.config.maxhdr = RT_CANMSG_BOX_SZ;
  458. #endif
  459. /* Register CAN ISR */
  460. rt_hw_interrupt_install(nu_can_arr[i].irqn, nu_can_isr, &nu_can_arr[i], nu_can_arr[i].name);
  461. /* Enable IP engine clock */
  462. nu_sys_ipclk_enable(nu_can_arr[i].clkidx);
  463. /* Register can device */
  464. ret = rt_hw_can_register(&nu_can_arr[i].dev, nu_can_arr[i].name, &nu_can_ops, NULL);
  465. RT_ASSERT(ret == RT_EOK);
  466. }
  467. return (int)ret;
  468. }
  469. INIT_DEVICE_EXPORT(rt_hw_can_init);
  470. #endif //#if defined(BSP_USING_CAN)