[原创].关于编写Nios II的延时函数的一点心得
平台
硬件:nios/f 100MHz
内容
0 一点说明
本文仅讨论所述平台的一点心得,若其他等级的nios或优化,请自行研究。
1 usleep()有多准
参考[笔记].怎样使用Nios II中的timestamp_timer?.[Nios II][SOPC Builder],我们做以下实验:
代码1 本文所用测试代码模板
#include <stdio.h> // printf() #include <unistd.h> // usleep() #include "system.h" // 系统 #include "my_types.h" // 数据类型 #include "sys/alt_timestamp.h" // timestamp int main() { u32 t0, t1, t2; vu32 i; alt_timestamp_start(); // 开启时间戳服务 t0 = alt_timestamp(); // 测量时间戳t0 usleep(1000); t1 = alt_timestamp(); // 测量时间戳1 for(i=0; i<1000; i++); t2 = alt_timestamp(); // 测量时间戳1 printf("时间戳(t1-t0) = %ld \n", (t1-t0)); printf("时间戳(t2-t1) = %ld \n", (t2-t1)); printf("\n"); printf("系统时钟频率是 %ld Hz\n", alt_timestamp_freq()); return 0; }
其中第14行和第16行的内容是下面讨论的重点
usleep(1000);
for(i=0; i<100; i++);
众所周知,usleep()是Nios II HAL自带的us级的延时函数,那么它究竟有多准。
(1)修改第14行为:
usleep(1*1000*1000);
编译运行的结果如图1.1 所示,usleep(1*1000*1000)共占用99,568,957个tick。那么1s有多少tick呢,正如显示的时钟频率一样,1s可分为100,000,000个tick。也就是说usleep(1*1000*1000)实际延时为99,568,957/100M=0.99568957 s。这个时间已经相当准了,和1s差距不大。
图1.1 usleep(1*1000*1000)的结果
(2)修改第14行为:
usleep(1*1000);
编译运行的结果如图1.2所示。这一次是100,843/100M=1.008ms,也不错。
图1.2 usleep(1*1000)的结果
(3)修改第14行为:
usleep(100);
编译运行的结果如图1.3所示。这一次是11,743/100M=117.43us,误差开始显现了。
图1.3 usleep(100) 的结果
(4)修改第14行为:
usleep(10);
编译运行的结果如图1.4所示。这一次是1,511/100M=15.11us,误差不是一点点。
图1.4 usleep(10)的结果
(5)修改第14行为:
usleep(1);
编译运行的结果如图1.5所示。这一次是620/100M=6.2us,已经相当离谱了。
图1.4 usleep(1)的结果
小结一下:usleep()在ms级别及以上的延时的确很准,但是us级别就有点捉襟见肘了。
2 想要延时1us怎么办?
(1)修改第16行为:
for(i=0; i<100; i++);
编译运行的结果如图2.1所示,亦即延时1,197/100M=11.97us。
图2.1 for(100)的结果
(2)修改第16行为:
for(i=0; i<10; i++);
编译运行的结果如图2.2所示,亦即延时207/100M=2.07us。
图2.2 for(10)的结果
(3)修改第16行为:
for(i=0; i<1; i++);
编译运行的结果如图2.2所示,亦即延时106/100M=1.06us。
图2.3 for(1)的结果
小结:for(1)可以很第实现延时1us的任务。
需要注意的地方
观察第9行,此处i被申明为vu32(volatile unsigned long)类型,倘若改为u32(unsigned long)类型的话。那么无论i值为多少,都会被gcc优化掉的。
4 小结
timestamp可以有效地协助我们编写小时间段的延时代码。
推荐阅读
1. chactor.Nios II处理器性能测试
2. mubo814.Nios II IDE中编程的延时子程序的问题及解决