/****************************************************************************** 版权所有: 文件名称: ustimer.c 文件版本: 01.01 创建作者: sunxi 创建日期: 2009-06-04 功能说明: US定时器模块驱动程序。 其它说明: 修改记录: */ #include "bspconfig.h" #include "bsp.h" #include "rt.h" #include #include #include #include #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