drv_can.c 15 KB

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