| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368 |
- /******************************************************************************
- 版权所有:
- 文件名称: ustimer.c
- 文件版本: 01.01
- 创建作者: sunxi
- 创建日期: 2009-06-04
- 功能说明: US定时器模块驱动程序。
- 其它说明:
- 修改记录:
- */
- #include "bspconfig.h"
- #include "bsp.h"
- #include "rt.h"
- #include <semaphore.h>
- #include <signal.h>
- #include <time.h>
- #include <sys/prctl.h>
- #if CFG_BSP_DEBUG
- #define DTIM_DEBUG
- #endif
- #define DTIM_DELAY_MAX_US (10UL*60*USTIMER_SEC) //10分钟
- #ifdef __LIGHT_DIFF_ACT_PRO__ // sunxi 20190904 光差保护
- #define DTIM_CLOCK_12_5M (CFG_CPU_CLK/2/12500000) // 12.5M的频率,80纳秒一次计数
- #endif // __LIGHT_DIFF_ACT_PRO__
- void ustimer_isr(void);
- pthread_t UsTimerPthread;
- sem_t UsCounterSem;
- timer_t timerid;
- volatile unsigned int uscounter=0;
- static pthread_t thread_id = 0;
- static int exit_flag = 0;
- //返回us
- unsigned int GetUsCounterValue(void)
- {
- unsigned int us;
- us=uscounter*500; //定时器精度在500us
- return us;
- }
- #if 0
- void timer_thread(union sigval v)
- {
- static int cnt = 0;//sunxi for test
- uscounter++;
- if(++cnt >= 20)
- {
- cnt = 0;
- _led_run_err();//sunxi for test
- }
- }
- #endif
- static void *timer_thread(void *arg)
- {
- struct sched_param sch_par;
- sch_par.sched_priority = 11;
- pthread_setschedparam(pthread_self(), SCHED_RR, &sch_par); // 设置当前线程优先级
- prctl(PR_SET_NAME, "timer_thread");
- while(!exit_flag)
- {
- usleep(500);//定时器精度在500us
- uscounter++;
-
- }
- printf("timer_thread exit\r\n");
- pthread_exit(NULL);
- }
- /******************************************************************************
- 函数名称: dtim_init
- 函数版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-06-26
- 函数说明: dtim初始化。使用dtim0做为延时函数参考定时器。
- 参数说明: 无
- 返回值: 无
- 修改记录:
- */
- int ustimer_init(void)
- {
- #if 0
- //int ret;
- struct sigevent evp;
- struct itimerspec it;
- memset(&evp, 0, sizeof(struct sigevent)); //清零初始化
- evp.sigev_value.sival_int = 0x5A5A; //也是标识定时器的,这和timerid有什么区别?回调函数可以获得
- evp.sigev_notify = SIGEV_THREAD; //线程通知的方式,派驻新线程
- evp.sigev_notify_function = timer_thread; //线程函数地址
- if (timer_create(CLOCK_REALTIME, &evp, &timerid) == -1)
- {
- rt_printf("fail to timer_create\r\n");
- return -1;
- }
- it.it_interval.tv_sec = 0;
- it.it_interval.tv_nsec = 500000; //间隔500US //sunxi for test 20220411 暂时精度定为500us
- it.it_value.tv_sec = 1;
- it.it_value.tv_nsec = 0;
- if (timer_settime(timerid, 0, &it, NULL) == -1)
- {
- rt_printf("fail to timer_settime\r\n");
- return -1;
- }
- #ifdef __LIGHT_DIFF_ACT_PRO__ // sunxi 20190904 光差保护
- //设置DTIM扩展模式寄存器。
- MCF_REG08(MCF_DTIM_DTXMR(CFG_DTIM_80NSTIMER)) = 0;
- MCF_REG16(MCF_DTIM_DTMR(CFG_DTIM_80NSTIMER)) = (unsigned short)(0
- | MCF_DTIM_DTMR_RST //允许定时器
- | MCF_DTIM_DTMR_CLK_DIV1 //输入clock除1
- | MCF_DTIM_DTMR_PS(DTIM_CLOCK_12_5M - 1));//将定时器clock周期设为80ns。
- #endif // __LIGHT_DIFF_ACT_PRO__
- #endif
- //noted by sunxi: 经测试,这种RR线程比定时器还要准确。
- int ret;
- ret = pthread_create(&thread_id, NULL, timer_thread, NULL);
- if(ret)
- {
- printf("thread timer_thread fail ret=%d\r\n", ret);
- thread_id = 0;
- return ret;
- }
- return 0;
- }
- int ustimer_exit(void)
- {
- //timer_delete(timerid);
- exit_flag = 1;
- pthread_join(thread_id, NULL);
- return 0;
- }
- //us定时器函数
- /******************************************************************************
- 函数名称: ustimer_get_origin
- 函数版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-07-01
- 函数说明: 得到当前时刻定时器的值,用作ustimer_get_duration、
- ustimer_delay_origin函数的origin参数。
- 参数说明: 无
- 返回值: 当前时刻定时器的值。
- 修改记录:
- */
- uint32_t ustimer_get_origin(void)
- {
- return GetUsCounterValue();
- }
- #ifdef __LIGHT_DIFF_ACT_PRO__ // sunxi 20190904 光差保护
- // 8纳秒定时器,每8纳秒一个单位
- uint32_t timer80ns_get_origin(void)
- {
- return MCF_REG32(MCF_DTIM_DTCN(CFG_DTIM_80NSTIMER));
- }
- uint32_t timer80ns_get_duration(uint32_t origin);
- #endif // __LIGHT_DIFF_ACT_PRO__
- /******************************************************************************
- 函数名称: ustimer_get_duration
- 函数版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-06-26
- 函数说明: 得到当前时刻相对于指定时间原点的时间间隔,以us为单位。
- 参数说明:
- origin: 时间原点,以us为单位。
- 返回值: 当前时刻相对于原点的的时间间隔。
- 修改记录:
- */
- uint32_t ustimer_get_duration(uint32_t origin)
- {
- return GetUsCounterValue()- origin;
- }
- #ifdef __LIGHT_DIFF_ACT_PRO__ // sunxi 20190904 光差保护
- // 80纳秒定时器,每80纳秒一个单位
- uint32_t timer80ns_get_duration(uint32_t origin)
- {
- //返回差值(根据C语言算法,会自动处理回绕问题)
- return MCF_REG32(MCF_DTIM_DTCN(CFG_DTIM_80NSTIMER)) - origin;
- }
- #endif // __LIGHT_DIFF_ACT_PRO__
- /******************************************************************************
- 函数名称: ustimer_delay_origin
- 函数版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-06-26
- 函数说明: 以us为单位的延时函数。最大延时值为10分钟和
- ustimer_delay函数不同的是ustimer_delay_origin函数的延时计算的时间
- 原点为origin,而不是函数被调用的时刻。当这个函数退出时,会确保延时
- 大于等于设定值。如果需要高精度的延时,调用这个函数时应先屏蔽中断。
- 参数说明:
- origin: 延时计算的时间原点,以us为单位,通常通过ustimer_get_origin函数获得。
- us: 延时us数。
- 返回值:
- 0: 成功
- 其它: 失败
- 修改记录:
- */
- int ustimer_delay_origin(uint32_t origin,uint32_t us)
- {
- //检查参数
- if(us > DTIM_DELAY_MAX_US)
- {
- return -1;
- }
- //循环等待
- while(GetUsCounterValue()- origin < us)
- ; //jack.liu 20200907 us计时暂时替换
- return 0;
- }
- /******************************************************************************
- 函数名称: ustimer_delay_origin2
- 函数版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-06-26
- 函数说明:
- 参数说明:
- origin: 延时计算的时间原点,以us为单位,通常通过ustimer_get_origin函数获得。
- us: 延时us数。
- 返回值:
- 0: 成功
- 其它: 失败
- 修改记录:
- */
- int ustimer_delay_origin2(uint32_t *us0,uint32_t us)
- {
- uint32_t us1;
- if(us0 == NULL)
- {
- return -1;
- }
-
- us1 = ustimer_get_origin();
- if(us1 - *us0 < us)
- {
- return 0;
- }
-
- *us0 = us1;
- return 1;
- }
- /******************************************************************************
- 函数名称: ustimer_delay
- 函数版本: 01.01
- 创建作者: sunxi
- 创建日期: 2008-06-26
- 函数说明: 以us为单位的延时函数。最大延时值为1小时(3600000000us)。
- 当这个函数退出时,会确保延时大于等于设定值。如果需要高精度的延时,
- 调用这个函数时应先屏蔽中断。
- 参数说明:
- us: 延时us数。
- 返回值:
- 0: 成功
- 其它: 失败
- 修改记录:
- */
- int ustimer_delay(uint32_t us)
- {
- uint32_t origin;
-
- //检查参数
- if(us > DTIM_DELAY_MAX_US)
- {
- return -1;
- }
-
- //得到原点
- origin = ustimer_get_origin();
-
- //开始延时
- ustimer_delay_origin(origin,us);
-
- return 0;
- }
-
- /*------------------------------ 测试函数 -------------------------------------
- */
-
- #ifdef DTIM_DEBUG
- #include "rt.h"
- int ustimer_test(void)
- {
- uint32_t us0,us1;
-
- rt_printf("\r\n");
- rt_printf("dtim_test start!\r\n");
-
- //测试函数ustimer_get_duration
- us0 = ustimer_get_origin();
- us1 = ustimer_get_duration(0xffffff00);
- rt_printf("ustimer_get_duration(us0=0x%lx,us1=0x%lx,diff=%lu)!\r\n",us0,us1,us1 - us0);
-
- //测试函数ustimer_delay_origin
- us0 = ustimer_get_origin();
- ustimer_delay_origin(0xffffff00,10000000);
- us1 = ustimer_get_origin();
- rt_printf("ustimer_delay_origin(us0=0x%lx,us1=0x%lx,diff=%lu)!\r\n",us0,us1,us1 - us0);
-
- //测试函数ustimer_delay
- us0 = ustimer_get_origin();
- ustimer_delay(10*USTIMER_SEC);
- us1 = ustimer_get_origin();
-
- rt_printf("ustimer_delay(us0=0x%lx,us1=0x%lx,diff=%lu)!\r\n",us0,us1,us1 - us0);
-
- rt_printf("dtim_test end!\r\n");
- rt_printf("\r\n");
-
- return 0;
- }
- #endif
|