test_hwtimer.c 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. /*
  2. * Copyright (c) 2022-2024, Xiaohua Semiconductor Co., Ltd.
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2024-12-30 CDT first version
  9. */
  10. /*
  11. * 程序清单:这是一个 hwtimer 设备使用例程
  12. * 例程导出了 hwtimer_sample 命令到控制终端
  13. * 命令调用格式:hwtimer_sample hwtimer_sample [option1] [option2] [option3]
  14. * option1: [tmra_1/2/3..] 定时器单元
  15. * option2: [oneshot/period] 定时模式
  16. * option3: 超时时间,单位毫秒
  17. * eg:hwtimer_sample tmra_1 period 1000
  18. * 程序功能:每隔一秒打印一次定时器运行时间值,在定时器超时回调函数中打印总tick值
  19. * 可以使用逻辑分析进一步查看测试管脚PA0定时时间是否准确
  20. */
  21. #include <rtthread.h>
  22. #include <rtdevice.h>
  23. #include <stdlib.h>
  24. #include <board.h>
  25. #ifdef BSP_USING_HWTIMER
  26. /* IO用于定时时间测试 */
  27. #define TIMEOUT_TEST_PIN GET_PIN(A, 0)
  28. static rt_uint32_t tick;
  29. static rt_bool_t cb_run = RT_FALSE;
  30. static void _hwtimer_cmd_print_usage(void)
  31. {
  32. rt_kprintf("hwtimer_sample [option1] [option2] [option3]\n");
  33. rt_kprintf(" option1: [tmra_1/2/3..] tmra uint\n");
  34. rt_kprintf(" option2: [oneshot/period] timing mode set\n");
  35. rt_kprintf(" option3: timeout unit:ms\n");
  36. rt_kprintf(" e.g. MSH >hwtimer_sample tmra_1 period 1000\n");
  37. }
  38. /* 定时器超时回调函数 */
  39. static rt_err_t timeout_cb(rt_device_t dev, rt_size_t size)
  40. {
  41. static rt_uint8_t pin_cnt = 0;
  42. rt_pin_write(TIMEOUT_TEST_PIN, ++pin_cnt % 2); /* 电平取反 */
  43. /* 打印出的tick值由于printf原因可能有误差,可以查看测试IO来精确确认时间 */
  44. rt_kprintf("callback successful! ticks = %d \n", rt_tick_get() - tick);
  45. tick = rt_tick_get();
  46. cb_run = RT_TRUE;
  47. return 0;
  48. }
  49. static int hwtimer_sample(int argc, char *argv[])
  50. {
  51. rt_uint8_t i;
  52. rt_err_t ret = RT_EOK;
  53. rt_hwtimerval_t timeout_s; /* 定时器超时值 */
  54. rt_hwtimer_mode_t mode = HWTIMER_MODE_ONESHOT; /* 定时器模式 */
  55. rt_device_t hw_dev = RT_NULL; /* 定时器设备句柄 */
  56. rt_hwtimer_t *hwtimer;
  57. float t;
  58. rt_uint8_t loop_cnt; /* 循环打印次数 */
  59. rt_hwtimerval_t overflow_tv; /* 定时器超时值 */
  60. rt_uint32_t timer_out_s;
  61. if ((argc != 4) || (rt_strcmp("oneshot", argv[2]) && rt_strcmp("period", argv[2])))
  62. {
  63. _hwtimer_cmd_print_usage();
  64. return -RT_ERROR;
  65. }
  66. /* 查找定时器设备 */
  67. hw_dev = rt_device_find(argv[1]);
  68. if (hw_dev == RT_NULL)
  69. {
  70. rt_kprintf("hwtimer sample run failed! can't find %s device!\n", argv[1]);
  71. return -RT_ERROR;
  72. }
  73. else
  74. {
  75. hwtimer = (rt_hwtimer_t *)hw_dev;
  76. }
  77. /* 以读写方式打开设备 */
  78. ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
  79. if (ret != RT_EOK)
  80. {
  81. rt_kprintf("open %s device failed!\n", argv[1]);
  82. return ret;
  83. }
  84. /* 设置模式 */
  85. if (0 == rt_strcmp(argv[2], "oneshot"))
  86. {
  87. mode = HWTIMER_MODE_ONESHOT;
  88. loop_cnt = 1;
  89. }
  90. else if (0 == rt_strcmp(argv[2], "period"))
  91. {
  92. mode = HWTIMER_MODE_PERIOD;
  93. loop_cnt = 5;
  94. }
  95. rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
  96. /* 设置超时回调函数 */
  97. rt_device_set_rx_indicate(hw_dev, timeout_cb);
  98. /* 设置定时器超时并启动定时器 */
  99. timeout_s.sec = atoi(argv[3]) / 1000U; /* 秒 */
  100. timeout_s.usec = (atoi(argv[3]) % 1000U) * 1000U; /* 微秒 */
  101. if (rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s)) != sizeof(timeout_s))
  102. {
  103. rt_kprintf("set timeout value failed\n");
  104. return -RT_ERROR;
  105. }
  106. tick = rt_tick_get();
  107. rt_kprintf("set timeout (%d) ms successful\n", atoi(argv[3]));
  108. /* 设置测试管脚为输出模式 */
  109. rt_pin_mode(TIMEOUT_TEST_PIN, PIN_MODE_OUTPUT);
  110. /* oneshot模式cb函数执行一次,period模式cb函数执行5次,且每秒打印一次运行时间 */
  111. timer_out_s = (atoi(argv[3]) / 1000U) > 1 ? (atoi(argv[3]) / 1000U) : 1;
  112. for (i = 0; i < (timer_out_s * loop_cnt); i++)
  113. {
  114. /* 延时1000ms */
  115. rt_thread_mdelay(1000);
  116. /* 读取定时器当前值 */
  117. if (mode == HWTIMER_MODE_PERIOD)
  118. {
  119. rt_device_read(hw_dev, 0, &timeout_s, sizeof(timeout_s));
  120. }
  121. else if (mode == HWTIMER_MODE_ONESHOT)
  122. {
  123. rt_device_read(hw_dev, 0, &timeout_s, sizeof(timeout_s));
  124. t = hwtimer->overflow * hwtimer->period_sec;
  125. overflow_tv.sec = (rt_int32_t)t;
  126. overflow_tv.usec = (rt_int32_t)((t - overflow_tv.sec) * 1000000);
  127. timeout_s.sec = overflow_tv.sec + (timeout_s.usec + overflow_tv.usec) / 1000000;
  128. timeout_s.usec = (timeout_s.usec + overflow_tv.usec) % 1000000;
  129. }
  130. rt_kprintf("Read: Sec = %d, Usec = %d\n", timeout_s.sec, timeout_s.usec);
  131. }
  132. /* 确保oneshot模式cb函数执行一次后才关闭定时器 */
  133. while (cb_run == RT_FALSE);
  134. cb_run = RT_FALSE;
  135. /* close */
  136. rt_device_close(hw_dev);
  137. return ret;
  138. }
  139. /* 导出到 msh 命令列表中 */
  140. MSH_CMD_EXPORT(hwtimer_sample, hwtimer sample: devname [oneshot | period] timeout);
  141. #endif