can_demo.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  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 Email Notes
  8. * 2022-04-16 Kevin.Liu kevin.liu.mchp@gmail.com First Release
  9. */
  10. #include <rtthread.h>
  11. #include "atmel_start.h"
  12. #include "driver_init.h"
  13. #include "utils.h"
  14. #include "can_demo.h"
  15. #ifdef SAM_CAN_EXAMPLE
  16. #if defined(SOC_SAMC21) || defined(SOC_SAME54)
  17. #define CAN_HARDWARE (void *)CAN1
  18. #elif defined(SOC_SAME70)
  19. #define CAN_HARDWARE (void *)MCAN1
  20. #else
  21. #error "CAN undefined SOC Platform"
  22. #endif
  23. static volatile enum can_async_interrupt_type can_errors;
  24. static rt_sem_t can_txdone;
  25. static rt_sem_t can_rxdone;
  26. static rt_uint8_t can_stack[ 512 ];
  27. static struct rt_thread can_thread;
  28. /**
  29. * @brief Callback function and should be invoked after call can_async_write.
  30. *
  31. * @note
  32. *
  33. * @param descr is CAN device description.
  34. *
  35. * @return None.
  36. */
  37. static void can_tx_callback(struct can_async_descriptor *const descr)
  38. {
  39. rt_err_t result;
  40. rt_interrupt_enter();
  41. result = rt_sem_release(can_txdone);
  42. if (RT_EOK != result)
  43. {
  44. #ifndef RT_USING_FINSH
  45. rt_kprintf("rt_sem_release failed in %s %d\r\n",__FUNCTION__, __LINE__);
  46. #endif
  47. }
  48. rt_interrupt_leave();
  49. }
  50. /**
  51. * @brief Callback function and should be invoked after remote device send.
  52. *
  53. * @note This callback function will be called in CAN interrupt function
  54. *
  55. * @param descr is CAN device description.
  56. *
  57. * @return None.
  58. */
  59. static void can_rx_callback(struct can_async_descriptor *const descr)
  60. {
  61. rt_err_t result;
  62. rt_interrupt_enter();
  63. result = rt_sem_release(can_rxdone);
  64. if (RT_EOK != result)
  65. {
  66. #ifndef RT_USING_FINSH
  67. rt_kprintf("rt_sem_release failed in %s %d\r\n",__FUNCTION__, __LINE__);
  68. #endif
  69. }
  70. rt_interrupt_leave();
  71. }
  72. /**
  73. * @brief Callback function and should be invoked after CAN device IRQ handler detects errors happened.
  74. *
  75. * @note This callback function will be called in CAN interrupt function
  76. *
  77. * @param descr is CAN device description.
  78. *
  79. * @return None.
  80. */
  81. static void can_err_callback(struct can_async_descriptor *const descr,
  82. enum can_async_interrupt_type type)
  83. {
  84. rt_err_t result;
  85. if (type == CAN_IRQ_EW)
  86. {
  87. /* Error warning, Error counter has reached the error warning limit of 96,
  88. * An error count value greater than about 96 indicates a heavily disturbed
  89. * bus. It may be of advantage to provide means to test for this condition.
  90. */
  91. }
  92. else if (type == CAN_IRQ_EA)
  93. {
  94. /* Error Active State, The CAN node normally take part in bus communication
  95. * and sends an ACTIVE ERROR FLAG when an error has been detected.
  96. */
  97. }
  98. else if (type == CAN_IRQ_EP)
  99. {
  100. /* Error Passive State, The Can node goes into error passive state if at least
  101. * one of its error counters is greater than 127. It still takes part in bus
  102. * activities, but it sends a passive error frame only, on errors.
  103. */
  104. }
  105. else if (type == CAN_IRQ_BO)
  106. {
  107. /* Bus Off State, The CAN node is 'bus off' when the TRANSMIT ERROR COUNT is
  108. * greater than or equal to 256.
  109. */
  110. /* Suspend CAN task and re-initialize CAN module. */
  111. can_errors = type;
  112. rt_interrupt_enter();
  113. result = rt_sem_release(can_rxdone);
  114. if (RT_EOK != result)
  115. {
  116. #ifndef RT_USING_FINSH
  117. rt_kprintf("rt_sem_release failed in %s %d\r\n",__FUNCTION__, __LINE__);
  118. #endif
  119. }
  120. rt_interrupt_leave();
  121. }
  122. else if (type == CAN_IRQ_DO)
  123. {
  124. /* Data Overrun in receive queue. A message was lost because the messages in
  125. * the queue was not reading and releasing fast enough. There is not enough
  126. * space for a new message in receive queue.
  127. */
  128. /* Suggest to delete CAN task and re-initialize it. */
  129. can_errors = type;
  130. rt_interrupt_enter();
  131. result = rt_sem_release(can_rxdone);
  132. if (RT_EOK != result)
  133. {
  134. #ifndef RT_USING_FINSH
  135. rt_kprintf("rt_sem_release failed in %s %d\r\n",__FUNCTION__, __LINE__);
  136. #endif
  137. }
  138. rt_interrupt_leave();
  139. }
  140. };
  141. /**
  142. * @brief Initialize CAN module before task run.
  143. *
  144. * @note This function will set CAN Tx/Rx callback function and filters.
  145. *
  146. * @param None.
  147. *
  148. * @return None.
  149. */
  150. static inline void can_demo_init(void)
  151. {
  152. struct can_filter filter;
  153. /**
  154. * CAN_Node0_tx_callback callback should be invoked after call
  155. * can_async_write, and remote device should receive message with ID=0x45A
  156. */
  157. can_async_register_callback(&CAN_0, CAN_ASYNC_TX_CB, (FUNC_PTR)can_tx_callback);
  158. /**
  159. * CAN_0_rx_callback callback should be invoked after call
  160. * can_async_set_filter and remote device send CAN Message with the same
  161. * content as the filter.
  162. */
  163. can_async_register_callback(&CAN_0, CAN_ASYNC_RX_CB, (FUNC_PTR)can_rx_callback);
  164. /* Should set at least one CAN standard & message filter before enable it. */
  165. filter.id = 0x469;
  166. filter.mask = 0;
  167. can_async_set_filter(&CAN_0, 0, CAN_FMT_STDID, &filter);
  168. /* If set second standard message filter, should increase filter index
  169. * and filter algorithm
  170. * For example: index should set to 1, otherwise it will replace filter 0.
  171. * can_async_set_filter(&CAN_0, 1, CAN_FMT_STDID, &filter); */
  172. filter.id = 0x10000096;
  173. filter.mask = 0;
  174. can_async_set_filter(&CAN_0, 0, CAN_FMT_EXTID, &filter);
  175. can_async_enable(&CAN_0);
  176. }
  177. /**
  178. * @brief CAN task.
  179. *
  180. * @note This task will waiting for CAN RX semaphore and then process input.
  181. *
  182. * @param parameter - task input parameter.
  183. *
  184. * @return None.
  185. */
  186. static void can_thread_entry(void* parameter)
  187. {
  188. int32_t ret;
  189. rt_err_t result;
  190. uint8_t data[64];
  191. uint32_t count=0;
  192. struct can_message msg;
  193. while (1)
  194. {
  195. #ifndef RT_USING_FINSH
  196. rt_kprintf("can task run count : %d\r\n",count);
  197. #endif
  198. count++;
  199. result = rt_sem_take(can_rxdone, RT_WAITING_FOREVER);
  200. if (RT_EOK != result)
  201. continue;
  202. do
  203. {
  204. /* Process the incoming packet. */
  205. ret = can_async_read(&CAN_0, &msg);
  206. if (ret == ERR_NONE)
  207. {
  208. #ifndef RT_USING_FINSH
  209. rt_kprintf("CAN RX Message is % frame\r\n",
  210. msg.type == CAN_TYPE_DATA ? "data" : "remote");
  211. rt_kprintf("CAN RX Message is % frame\r\n",
  212. msg.type == CAN_FMT_STDID ? "Standard" : "Extended");
  213. rt_kprintf("can RX Message ID: 0x%X length: %d\r\n", msg.id, msg.len);
  214. rt_kprintf("CAN RX Message content: ");
  215. for (uint8_t i = 0; i < msg.len; i++)
  216. rt_kprintf("0x%02X ", data[i]);
  217. rt_kprintf("\r\n");
  218. #endif
  219. }
  220. } while (ret == ERR_NONE); /* Get all data stored in CAN RX FIFO */
  221. /* CAN task got CAN error message, handler CAN Error Status */
  222. if ((can_errors == CAN_IRQ_BO) || (can_errors == CAN_IRQ_DO))
  223. {
  224. can_async_init(&CAN_0, CAN_HARDWARE);
  225. }
  226. }
  227. }
  228. /**
  229. * @brief Call this function will to send a CAN message.
  230. *
  231. * @note
  232. *
  233. * @param msg - message to be sent, timeouts - wait timeouts for Tx completion.
  234. *
  235. * @return RT_OK or -RT_ERROR.
  236. */
  237. rt_err_t can_send_message(struct can_message *msg, rt_uint32_t timeouts)
  238. {
  239. rt_err_t result;
  240. if (RT_NULL == msg)
  241. {
  242. rt_kprintf("can_send_message input message error\r\n");
  243. return -RT_ERROR;
  244. }
  245. can_async_write(&CAN_0, msg);
  246. result = rt_sem_take(can_rxdone, timeouts);
  247. return result;
  248. }
  249. /**
  250. * @brief Call this function will create a CAN task.
  251. *
  252. * @note Should create Tx/Rx semaphore before run task.
  253. *
  254. * @param None.
  255. *
  256. * @return RT_OK or -RT_ERROR.
  257. */
  258. rt_err_t can_demo_run(void)
  259. {
  260. rt_err_t result;
  261. can_rxdone = rt_sem_create("can_rx", 0, RT_IPC_FLAG_FIFO);
  262. if (RT_NULL == can_rxdone)
  263. {
  264. rt_kprintf("can_rx semaphore create failed\r\n");
  265. return (-RT_ERROR);
  266. }
  267. can_txdone = rt_sem_create("can_tx", 0, RT_IPC_FLAG_FIFO);
  268. if (RT_NULL == can_txdone)
  269. {
  270. rt_kprintf("can_tx semaphore create failed\r\n");
  271. return (-RT_ERROR);
  272. }
  273. can_demo_init();
  274. /* initialize CAN thread */
  275. result = rt_thread_init(&can_thread,
  276. "can",
  277. can_thread_entry,
  278. RT_NULL,
  279. (rt_uint8_t*)&can_stack[0],
  280. sizeof(can_stack),
  281. RT_THREAD_PRIORITY_MAX/3,
  282. 5);
  283. if (result == RT_EOK)
  284. {
  285. rt_thread_startup(&can_thread);
  286. }
  287. return result;
  288. }
  289. #endif
  290. /*@}*/