RT_insight.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. #include "RT_insight.h"
  2. /* ============================================================
  3. * Hardware / System Configuration
  4. * ============================================================ */
  5. // #define BOARD_SYSTICK_FREQ_IN_HZ (168000000ULL) /**< CPU Systick frequency */
  6. #define RT_INSIGHT_TUNNEL_ID (0x52544953UL) /**< Unique ID for RT Insight tunnel ("RTIS") */
  7. #define Frame_Header_Reserve_Value (0x55AA0000UL) /**< Frame header reserved pattern */
  8. #define SysTick_IRQ_ID (0x0000000FUL) /**< SysTick IRQ ID */
  9. #define SysTick_Cnt_Register (0xE000E018UL) /**< SysTick current count register */
  10. #define SysTick_Reload_Register (0xE000E014UL) /**< SysTick reload value register */
  11. #define Interrupt_Control_State_Register (0xE000ED04UL) /**< Interrupt control/state register */
  12. #define DWT_CYCCNT (0xE0001004UL) /**< DWT cycle counter register */
  13. #define DWT_CTRL (0xE0001000UL) /**< DWT control register */
  14. #define CoreDebug_DEMCR (0xE000EDFCUL) /**< Debug control register */
  15. #define DWT_CTRL_CYCCNTENA_Msk (1UL << 0) /**< Enable cycle counter */
  16. #define CoreDebug_DEMCR_TRCENA_Msk (1UL << 24) /**< Enable DWT & ITM */
  17. #define TEMP_BUFFER_SIZE 64 /**< The maximum number of entries that can be stored in the temporary buffer */
  18. /* ============================================================
  19. * Global Variables
  20. * ============================================================ */
  21. rt_tick_t Time_Stamp_Tick; /**< Current OS tick count */
  22. uint64_t Time_Stamp_ns; /**< Current time in nanoseconds */
  23. uint64_t Per_OSTick_ns; /**< Duration of one OS tick (ns) */
  24. double Per_SysTick_Cnt_ns; /**< Duration per SysTick count (ns) */
  25. uint32_t SysTick_Timer_Cnt; /**< Current SysTick counter value */
  26. uint32_t SysTick_Timer_Reload; /**< SysTick reload value */
  27. RT_tunnel_t Tunnel; /**< Tunnel instance for transmitting insight events */
  28. uint32_t Event_Num_Cnt; /**< Sequential event number counter */
  29. uint32_t DWT_Last_Cnt = 0; /**< Last DWT counter value */
  30. uint32_t DWT_Timer_hi = 0; /**< Overflow counter for DWT */
  31. RT_insight_info Temp_Info_Buffer[TEMP_BUFFER_SIZE] = {0}; /**< Backup buffer for failed writes */
  32. uint32_t Temp_Info_Buffer_Index = 0; /**< Current write index of the temporary buffer */
  33. uint32_t Temp_Info_Buffer_Last_Index = 0; /**< Last successfully written index in the temporary buffer */
  34. /* ============================================================
  35. * Time & Event Utilities
  36. * ============================================================ */
  37. /**
  38. * @brief Initialize DWT timer for precise CPU time measurement.
  39. */
  40. int CPU_TS_TmrInit(void)
  41. {
  42. /* Enable DWT trace and cycle counter */
  43. *(volatile uint32_t *)CoreDebug_DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
  44. /* Reset DWT cycle counter */
  45. *(volatile uint32_t *)DWT_CYCCNT = 0;
  46. /* Enable DWT cycle counter */
  47. *(volatile uint32_t *)DWT_CTRL |= DWT_CTRL_CYCCNTENA_Msk;
  48. return 0;
  49. }
  50. /**
  51. * @brief Get current CPU timestamp in nanoseconds.
  52. * @note Combines DWT low/high counter to form 64-bit time.
  53. */
  54. static uint64_t Get_Time_Stamp_ns(void)
  55. {
  56. uint32_t DWT_Cnt = *(volatile uint32_t *)DWT_CYCCNT;
  57. /* Handle DWT counter overflow */
  58. if (DWT_Cnt < DWT_Last_Cnt)
  59. {
  60. DWT_Timer_hi += 1;
  61. }
  62. DWT_Last_Cnt = DWT_Cnt;
  63. uint64_t full_cycle = ((uint64_t)DWT_Timer_hi << 32) | DWT_Cnt;
  64. uint64_t time_ns = (uint64_t)(Per_SysTick_Cnt_ns * full_cycle);
  65. return time_ns;
  66. }
  67. /* ============================================================
  68. * Event Recording Logic
  69. * ============================================================ */
  70. /**
  71. * @brief Record an insight event to tunnel.
  72. *
  73. * @param[in] ID Event ID or object identifier
  74. * @param[in] track_type Event type (thread, ISR, object, timer)
  75. */
  76. static void Event_Record(uint32_t ID, uint32_t track_type)
  77. {
  78. int32_t write_res = 0;
  79. RT_insight_info Insight_Info = {0};
  80. /* Generate timestamp */
  81. Time_Stamp_ns = Get_Time_Stamp_ns();
  82. /* Fill event structure */
  83. Insight_Info.Frame_Header = Frame_Header_Reserve_Value | (Event_Num_Cnt & 0xFFFF);
  84. Insight_Info.ID = ID;
  85. Insight_Info.Track_Type = track_type;
  86. Insight_Info.Time_Stamp_ns_lo = (uint32_t)(Time_Stamp_ns & 0xFFFFFFFF);
  87. Insight_Info.Time_Stamp_ns_hi = (uint32_t)(Time_Stamp_ns >> 32);
  88. /* Handle pending buffer (atomic update) */
  89. rt_base_t level = rt_hw_interrupt_disable();
  90. uint32_t Last_Index = Temp_Info_Buffer_Last_Index;
  91. uint32_t Index = Temp_Info_Buffer_Index;
  92. Temp_Info_Buffer_Last_Index = Temp_Info_Buffer_Index;
  93. rt_hw_interrupt_enable(level);
  94. /* Try to flush previous buffered events first */
  95. if (Index != Last_Index)
  96. {
  97. uint32_t len = (Index > Last_Index) ? (Index - Last_Index) : (Index + TEMP_BUFFER_SIZE - Last_Index);
  98. for (uint32_t i = 0; i < len; i++)
  99. {
  100. write_res = Tunnel->write(Tunnel, (void *)&Temp_Info_Buffer[Last_Index], sizeof(RT_insight_info));
  101. if (write_res != sizeof(RT_insight_info))
  102. {
  103. break;
  104. }
  105. Last_Index = (Last_Index + 1) % TEMP_BUFFER_SIZE;
  106. }
  107. Temp_Info_Buffer_Last_Index = Last_Index;
  108. }
  109. /* Attempt to write the new event */
  110. write_res = Tunnel->write(Tunnel, (void *)&Insight_Info, sizeof(RT_insight_info));
  111. /* If write fails (-2 = tunnel busy), store into temp buffer */
  112. if ((write_res == TUNNEL_BUSY_CODE) && ((Tunnel->status & STATUS_BUFFER_Msk) == STATUS_BUFFER_AVAILABLE))
  113. {
  114. rt_memcpy(&Temp_Info_Buffer[Temp_Info_Buffer_Index], &Insight_Info, sizeof(Insight_Info));
  115. Temp_Info_Buffer_Index = (Temp_Info_Buffer_Index + 1) % TEMP_BUFFER_SIZE;
  116. }
  117. /* Update event counter */
  118. Event_Num_Cnt++;
  119. }
  120. /* ============================================================
  121. * RT-Thread Hook Implementations
  122. * ============================================================ */
  123. /**
  124. * @brief Scheduler hook: called during thread switch.
  125. *
  126. * @param[in] from_thread Thread being switched out
  127. * @param[in] to_thread Thread being switched in
  128. */
  129. static void rt_view_scheduler_hook(rt_thread_t from_thread, rt_thread_t to_thread)
  130. {
  131. if (from_thread)
  132. {
  133. Event_Record((uint32_t)&from_thread->sp, THREAD_EXIT);
  134. Event_Record((uint32_t)&to_thread->sp, THREAD_RUN);
  135. }
  136. }
  137. /**
  138. * @brief Called when a thread is resumed.
  139. *
  140. * @param[in] thread Thread being resumed
  141. */
  142. static void rt_view_thread_resume_hook(rt_thread_t thread)
  143. {
  144. Event_Record((uint32_t)&thread->sp, THREAD_RESUME);
  145. }
  146. /**
  147. * @brief Called when a thread is suspended.
  148. *
  149. * @param[in] thread Thread being suspended
  150. */
  151. static void rt_view_thread_suspend_hook(rt_thread_t thread)
  152. {
  153. Event_Record((uint32_t)&thread->sp, THREAD_SUSPEND);
  154. }
  155. /**
  156. * @brief Called when entering an ISR.
  157. */
  158. static void rt_view_ISR_enter_hook(void)
  159. {
  160. uint32_t ISR_ID = (*(volatile uint32_t *)Interrupt_Control_State_Register) & 0xFF;
  161. Event_Record(ISR_ID, IRQ_ENTER);
  162. }
  163. /**
  164. * @brief Called when leaving an ISR.
  165. */
  166. static void rt_view_ISR_leave_hook(void)
  167. {
  168. uint32_t ISR_ID = (*(volatile uint32_t *)Interrupt_Control_State_Register) & 0xFF;
  169. Event_Record(ISR_ID, IRQ_EXIT);
  170. }
  171. /**
  172. * @brief Called when taking an RTOS object (semaphore, mutex, etc.)
  173. *
  174. * @param[in] object Pointer to the RTOS object
  175. */
  176. static void rt_view_object_take_hook(struct rt_object *object)
  177. {
  178. switch (object->type & (~RT_Object_Class_Static))
  179. {
  180. case RT_Object_Class_Semaphore:
  181. Event_Record((uint32_t)object->name, SEM_TAKE);
  182. break;
  183. case RT_Object_Class_Mutex:
  184. Event_Record((uint32_t)object->name, MUTEX_TAKE);
  185. break;
  186. case RT_Object_Class_Event:
  187. Event_Record((uint32_t)object->name, EVENT_TAKE);
  188. break;
  189. case RT_Object_Class_MailBox:
  190. Event_Record((uint32_t)object->name, MAILBOX_TAKE);
  191. break;
  192. case RT_Object_Class_MessageQueue:
  193. Event_Record((uint32_t)object->name, QUEUE_TAKE);
  194. break;
  195. }
  196. }
  197. /**
  198. * @brief Called when trying to take an RTOS object (non-blocking).
  199. *
  200. * @param[in] object Pointer to the RTOS object
  201. */
  202. static void rt_view_object_trytake_hook(struct rt_object *object)
  203. {
  204. switch (object->type & (~RT_Object_Class_Static))
  205. {
  206. case RT_Object_Class_Semaphore:
  207. Event_Record((uint32_t)object->name, SEM_TRYTAKE);
  208. break;
  209. case RT_Object_Class_Mutex:
  210. Event_Record((uint32_t)object->name, MUTEX_TRYTAKE);
  211. break;
  212. case RT_Object_Class_Event:
  213. Event_Record((uint32_t)object->name, EVENT_TRYTAKE);
  214. break;
  215. case RT_Object_Class_MailBox:
  216. Event_Record((uint32_t)object->name, MAILBOX_TRYTAKE);
  217. break;
  218. case RT_Object_Class_MessageQueue:
  219. Event_Record((uint32_t)object->name, QUEUE_TRYTAKE);
  220. break;
  221. }
  222. }
  223. /**
  224. * @brief Called when releasing an RTOS object.
  225. *
  226. * @param[in] object Pointer to the RTOS object
  227. */
  228. static void rt_view_object_relase_hook(struct rt_object *object)
  229. {
  230. switch (object->type & (~RT_Object_Class_Static))
  231. {
  232. case RT_Object_Class_Semaphore:
  233. Event_Record((uint32_t)object->name, SEM_RELEASE);
  234. break;
  235. case RT_Object_Class_Mutex:
  236. Event_Record((uint32_t)object->name, MUTEX_RELEASE);
  237. break;
  238. case RT_Object_Class_Event:
  239. Event_Record((uint32_t)object->name, EVENT_RELEASE);
  240. break;
  241. case RT_Object_Class_MailBox:
  242. Event_Record((uint32_t)object->name, MAILBOX_RELEASE);
  243. break;
  244. case RT_Object_Class_MessageQueue:
  245. Event_Record((uint32_t)object->name, QUEUE_RELEASE);
  246. break;
  247. }
  248. }
  249. /**
  250. * @brief Called when a timer callback starts.
  251. *
  252. * @param[in] t Timer instance
  253. */
  254. static void rt_view_timer_enter_hook(rt_timer_t t)
  255. {
  256. Event_Record((uint32_t)t->parent.name, TIMER_ENTER);
  257. }
  258. /**
  259. * @brief Called when a timer callback ends.
  260. *
  261. * @param[in] t Timer instance
  262. */
  263. static void rt_view_timer_exit_hook(rt_timer_t t)
  264. {
  265. Event_Record((uint32_t)t->parent.name, TIMER_EXIT);
  266. }
  267. /* ============================================================
  268. * RT Insight Initialization
  269. * ============================================================ */
  270. /**
  271. * @brief Initialize RT Insight module and register all RT-Thread hooks.
  272. *
  273. * @retval int 0 on success, non-zero on failure.
  274. */
  275. int RT_Insight_Init(void)
  276. {
  277. Event_Num_Cnt = 0;
  278. SysTick_Timer_Reload = *(volatile uint32_t *)SysTick_Reload_Register;
  279. Per_OSTick_ns = 1000000000ULL / RT_TICK_PER_SECOND;
  280. Per_SysTick_Cnt_ns = 1000000000.0 / BOARD_SYSTICK_FREQ_IN_HZ;
  281. /* Get a free tunnel instance */
  282. Tunnel = Get_Free_Tunnel();
  283. if (Tunnel == RT_NULL)
  284. {
  285. LOG_ERROR("Get free tunnel error");
  286. return -1;
  287. }
  288. /* Configure tunnel */
  289. if (Set_Tunnel_ID(Tunnel, RT_INSIGHT_TUNNEL_ID) != 0)
  290. {
  291. LOG_ERROR("Set tunnel ID error");
  292. return -1;
  293. }
  294. if (Set_Tunnel_Operation(Tunnel, tunnel_write) != 0)
  295. {
  296. LOG_ERROR("Set tunnel operation error");
  297. return -1;
  298. }
  299. /* Initialize timestamp source */
  300. CPU_TS_TmrInit();
  301. /* Register RT-Thread system hooks */
  302. rt_scheduler_sethook(rt_view_scheduler_hook);
  303. rt_thread_resume_sethook(rt_view_thread_resume_hook);
  304. rt_thread_suspend_sethook(rt_view_thread_suspend_hook);
  305. rt_interrupt_enter_sethook(rt_view_ISR_enter_hook);
  306. rt_interrupt_leave_sethook(rt_view_ISR_leave_hook);
  307. rt_object_trytake_sethook(rt_view_object_trytake_hook);
  308. rt_object_take_sethook(rt_view_object_take_hook);
  309. rt_object_put_sethook(rt_view_object_relase_hook);
  310. rt_timer_enter_sethook(rt_view_timer_enter_hook);
  311. rt_timer_exit_sethook(rt_view_timer_exit_hook);
  312. return 0;
  313. }
  314. MSH_CMD_EXPORT(RT_Insight_Init, RT_Insight_Init);