ustimer.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /******************************************************************************
  2. 版权所有:
  3. 文件名称: ustimer.c
  4. 文件版本: 01.01
  5. 创建作者: sunxi
  6. 创建日期: 2009-06-04
  7. 功能说明: US定时器模块驱动程序。
  8. 其它说明:
  9. 修改记录:
  10. */
  11. #include "bspconfig.h"
  12. #include "bsp.h"
  13. #include "rt.h"
  14. #include <semaphore.h>
  15. #include <signal.h>
  16. #include <time.h>
  17. #include <sys/prctl.h>
  18. #if CFG_BSP_DEBUG
  19. #define DTIM_DEBUG
  20. #endif
  21. #define DTIM_DELAY_MAX_US (10UL*60*USTIMER_SEC) //10分钟
  22. #ifdef __LIGHT_DIFF_ACT_PRO__ // sunxi 20190904 光差保护
  23. #define DTIM_CLOCK_12_5M (CFG_CPU_CLK/2/12500000) // 12.5M的频率,80纳秒一次计数
  24. #endif // __LIGHT_DIFF_ACT_PRO__
  25. void ustimer_isr(void);
  26. pthread_t UsTimerPthread;
  27. sem_t UsCounterSem;
  28. timer_t timerid;
  29. volatile unsigned int uscounter=0;
  30. static pthread_t thread_id = 0;
  31. static int exit_flag = 0;
  32. //返回us
  33. unsigned int GetUsCounterValue(void)
  34. {
  35. unsigned int us;
  36. us=uscounter*500; //定时器精度在500us
  37. return us;
  38. }
  39. #if 0
  40. void timer_thread(union sigval v)
  41. {
  42. static int cnt = 0;//sunxi for test
  43. uscounter++;
  44. if(++cnt >= 20)
  45. {
  46. cnt = 0;
  47. _led_run_err();//sunxi for test
  48. }
  49. }
  50. #endif
  51. static void *timer_thread(void *arg)
  52. {
  53. struct sched_param sch_par;
  54. sch_par.sched_priority = 11;
  55. pthread_setschedparam(pthread_self(), SCHED_RR, &sch_par); // 设置当前线程优先级
  56. prctl(PR_SET_NAME, "timer_thread");
  57. while(!exit_flag)
  58. {
  59. usleep(500);//定时器精度在500us
  60. uscounter++;
  61. }
  62. printf("timer_thread exit\r\n");
  63. pthread_exit(NULL);
  64. }
  65. /******************************************************************************
  66. 函数名称: dtim_init
  67. 函数版本: 01.01
  68. 创建作者: sunxi
  69. 创建日期: 2008-06-26
  70. 函数说明: dtim初始化。使用dtim0做为延时函数参考定时器。
  71. 参数说明: 无
  72. 返回值: 无
  73. 修改记录:
  74. */
  75. int ustimer_init(void)
  76. {
  77. #if 0
  78. //int ret;
  79. struct sigevent evp;
  80. struct itimerspec it;
  81. memset(&evp, 0, sizeof(struct sigevent)); //清零初始化
  82. evp.sigev_value.sival_int = 0x5A5A; //也是标识定时器的,这和timerid有什么区别?回调函数可以获得
  83. evp.sigev_notify = SIGEV_THREAD; //线程通知的方式,派驻新线程
  84. evp.sigev_notify_function = timer_thread; //线程函数地址
  85. if (timer_create(CLOCK_REALTIME, &evp, &timerid) == -1)
  86. {
  87. rt_printf("fail to timer_create\r\n");
  88. return -1;
  89. }
  90. it.it_interval.tv_sec = 0;
  91. it.it_interval.tv_nsec = 500000; //间隔500US //sunxi for test 20220411 暂时精度定为500us
  92. it.it_value.tv_sec = 1;
  93. it.it_value.tv_nsec = 0;
  94. if (timer_settime(timerid, 0, &it, NULL) == -1)
  95. {
  96. rt_printf("fail to timer_settime\r\n");
  97. return -1;
  98. }
  99. #ifdef __LIGHT_DIFF_ACT_PRO__ // sunxi 20190904 光差保护
  100. //设置DTIM扩展模式寄存器。
  101. MCF_REG08(MCF_DTIM_DTXMR(CFG_DTIM_80NSTIMER)) = 0;
  102. MCF_REG16(MCF_DTIM_DTMR(CFG_DTIM_80NSTIMER)) = (unsigned short)(0
  103. | MCF_DTIM_DTMR_RST //允许定时器
  104. | MCF_DTIM_DTMR_CLK_DIV1 //输入clock除1
  105. | MCF_DTIM_DTMR_PS(DTIM_CLOCK_12_5M - 1));//将定时器clock周期设为80ns。
  106. #endif // __LIGHT_DIFF_ACT_PRO__
  107. #endif
  108. //noted by sunxi: 经测试,这种RR线程比定时器还要准确。
  109. int ret;
  110. ret = pthread_create(&thread_id, NULL, timer_thread, NULL);
  111. if(ret)
  112. {
  113. printf("thread timer_thread fail ret=%d\r\n", ret);
  114. thread_id = 0;
  115. return ret;
  116. }
  117. return 0;
  118. }
  119. int ustimer_exit(void)
  120. {
  121. //timer_delete(timerid);
  122. exit_flag = 1;
  123. pthread_join(thread_id, NULL);
  124. return 0;
  125. }
  126. //us定时器函数
  127. /******************************************************************************
  128. 函数名称: ustimer_get_origin
  129. 函数版本: 01.01
  130. 创建作者: sunxi
  131. 创建日期: 2008-07-01
  132. 函数说明: 得到当前时刻定时器的值,用作ustimer_get_duration、
  133. ustimer_delay_origin函数的origin参数。
  134. 参数说明: 无
  135. 返回值: 当前时刻定时器的值。
  136. 修改记录:
  137. */
  138. uint32_t ustimer_get_origin(void)
  139. {
  140. return GetUsCounterValue();
  141. }
  142. #ifdef __LIGHT_DIFF_ACT_PRO__ // sunxi 20190904 光差保护
  143. // 8纳秒定时器,每8纳秒一个单位
  144. uint32_t timer80ns_get_origin(void)
  145. {
  146. return MCF_REG32(MCF_DTIM_DTCN(CFG_DTIM_80NSTIMER));
  147. }
  148. uint32_t timer80ns_get_duration(uint32_t origin);
  149. #endif // __LIGHT_DIFF_ACT_PRO__
  150. /******************************************************************************
  151. 函数名称: ustimer_get_duration
  152. 函数版本: 01.01
  153. 创建作者: sunxi
  154. 创建日期: 2008-06-26
  155. 函数说明: 得到当前时刻相对于指定时间原点的时间间隔,以us为单位。
  156. 参数说明:
  157. origin: 时间原点,以us为单位。
  158. 返回值: 当前时刻相对于原点的的时间间隔。
  159. 修改记录:
  160. */
  161. uint32_t ustimer_get_duration(uint32_t origin)
  162. {
  163. return GetUsCounterValue()- origin;
  164. }
  165. #ifdef __LIGHT_DIFF_ACT_PRO__ // sunxi 20190904 光差保护
  166. // 80纳秒定时器,每80纳秒一个单位
  167. uint32_t timer80ns_get_duration(uint32_t origin)
  168. {
  169. //返回差值(根据C语言算法,会自动处理回绕问题)
  170. return MCF_REG32(MCF_DTIM_DTCN(CFG_DTIM_80NSTIMER)) - origin;
  171. }
  172. #endif // __LIGHT_DIFF_ACT_PRO__
  173. /******************************************************************************
  174. 函数名称: ustimer_delay_origin
  175. 函数版本: 01.01
  176. 创建作者: sunxi
  177. 创建日期: 2008-06-26
  178. 函数说明: 以us为单位的延时函数。最大延时值为10分钟和
  179. ustimer_delay函数不同的是ustimer_delay_origin函数的延时计算的时间
  180. 原点为origin,而不是函数被调用的时刻。当这个函数退出时,会确保延时
  181. 大于等于设定值。如果需要高精度的延时,调用这个函数时应先屏蔽中断。
  182. 参数说明:
  183. origin: 延时计算的时间原点,以us为单位,通常通过ustimer_get_origin函数获得。
  184. us: 延时us数。
  185. 返回值:
  186. 0: 成功
  187. 其它: 失败
  188. 修改记录:
  189. */
  190. int ustimer_delay_origin(uint32_t origin,uint32_t us)
  191. {
  192. //检查参数
  193. if(us > DTIM_DELAY_MAX_US)
  194. {
  195. return -1;
  196. }
  197. //循环等待
  198. while(GetUsCounterValue()- origin < us)
  199. ; //jack.liu 20200907 us计时暂时替换
  200. return 0;
  201. }
  202. /******************************************************************************
  203. 函数名称: ustimer_delay_origin2
  204. 函数版本: 01.01
  205. 创建作者: sunxi
  206. 创建日期: 2008-06-26
  207. 函数说明:
  208. 参数说明:
  209. origin: 延时计算的时间原点,以us为单位,通常通过ustimer_get_origin函数获得。
  210. us: 延时us数。
  211. 返回值:
  212. 0: 成功
  213. 其它: 失败
  214. 修改记录:
  215. */
  216. int ustimer_delay_origin2(uint32_t *us0,uint32_t us)
  217. {
  218. uint32_t us1;
  219. if(us0 == NULL)
  220. {
  221. return -1;
  222. }
  223. us1 = ustimer_get_origin();
  224. if(us1 - *us0 < us)
  225. {
  226. return 0;
  227. }
  228. *us0 = us1;
  229. return 1;
  230. }
  231. /******************************************************************************
  232. 函数名称: ustimer_delay
  233. 函数版本: 01.01
  234. 创建作者: sunxi
  235. 创建日期: 2008-06-26
  236. 函数说明: 以us为单位的延时函数。最大延时值为1小时(3600000000us)。
  237. 当这个函数退出时,会确保延时大于等于设定值。如果需要高精度的延时,
  238. 调用这个函数时应先屏蔽中断。
  239. 参数说明:
  240. us: 延时us数。
  241. 返回值:
  242. 0: 成功
  243. 其它: 失败
  244. 修改记录:
  245. */
  246. int ustimer_delay(uint32_t us)
  247. {
  248. uint32_t origin;
  249. //检查参数
  250. if(us > DTIM_DELAY_MAX_US)
  251. {
  252. return -1;
  253. }
  254. //得到原点
  255. origin = ustimer_get_origin();
  256. //开始延时
  257. ustimer_delay_origin(origin,us);
  258. return 0;
  259. }
  260. /*------------------------------ 测试函数 -------------------------------------
  261. */
  262. #ifdef DTIM_DEBUG
  263. #include "rt.h"
  264. int ustimer_test(void)
  265. {
  266. uint32_t us0,us1;
  267. rt_printf("\r\n");
  268. rt_printf("dtim_test start!\r\n");
  269. //测试函数ustimer_get_duration
  270. us0 = ustimer_get_origin();
  271. us1 = ustimer_get_duration(0xffffff00);
  272. rt_printf("ustimer_get_duration(us0=0x%lx,us1=0x%lx,diff=%lu)!\r\n",us0,us1,us1 - us0);
  273. //测试函数ustimer_delay_origin
  274. us0 = ustimer_get_origin();
  275. ustimer_delay_origin(0xffffff00,10000000);
  276. us1 = ustimer_get_origin();
  277. rt_printf("ustimer_delay_origin(us0=0x%lx,us1=0x%lx,diff=%lu)!\r\n",us0,us1,us1 - us0);
  278. //测试函数ustimer_delay
  279. us0 = ustimer_get_origin();
  280. ustimer_delay(10*USTIMER_SEC);
  281. us1 = ustimer_get_origin();
  282. rt_printf("ustimer_delay(us0=0x%lx,us1=0x%lx,diff=%lu)!\r\n",us0,us1,us1 - us0);
  283. rt_printf("dtim_test end!\r\n");
  284. rt_printf("\r\n");
  285. return 0;
  286. }
  287. #endif