cpu cycle counter gettimeofday 两种us级延时

us级延时可调用系统函数gettimeofday来实现,也可以用时钟计数器来实现
arm的要先使能用户态访问权限,v6 v7 v8都不一样 读取时钟计数器需先内核态使能,x86可以直接读
利用cpu时钟计数器可以ns级延时

以下代码

#include 
#include 
#include 
#define CPUFREQ 7e8 // 700M

typedef void (*Delay)(unsigned int);
Delay delay;

//arm11 reset cycle counter
void rstccnt()
{
        unsigned int tmp;
        asm volatile (  "mrc p15, 0, %0, c15, c12, 0 \n"
                        "orr %0,%0,%1 \n"
                        "mcr p15, 0, %0, c15, c12, 0 \n"
                        :"+r" (tmp) : "r"(0x4));
}

unsigned int readccnt()
{
        unsigned int tmp;
        asm volatile ("mrc p15, 0, %0, c15, c12, 1 \n":"=r" (tmp));
        return tmp;
}

void ccdelay(unsigned int cnt) //cycle counter delay
{
        //cnt = ((CPUFREQ>>6) * cnt) >> 3 ;// avoid overflow    
        unsigned long long ct = cnt;
        cnt = (CPUFREQ*ct)/1e6;
        unsigned int tmp;

         rstccnt();
         tmp = readccnt();
         while(tmp < cnt)
              tmp = readccnt();
}

void tmdelay(unsigned int cnt)
{
        struct timeval cur;
        gettimeofday(&cur, NULL);
        unsigned long long now = cur.tv_sec * 1e6 + cur.tv_usec;
        unsigned long long end = now + cnt;
        while(now < end){
                gettimeofday(&cur, NULL);
                now = cur.tv_sec * 1e6 + cur.tv_usec;
        }
}
int main()
{
        unsigned int t[50];
        delay = ccdelay;
        (*delay)(100);
        t[0] = readccnt()*1e6/CPUFREQ;
        delay = tmdelay;
        for(int i = 1; i < 20; i++){
                rstccnt();
                (*delay)(20*i);
                t[i] = readccnt()*1e6/CPUFREQ;
        }
        printf("tccnt 100  %u \n",t[0]);
        for(int i = 1; i < 20; i++)
                printf(" %u-%u \n",20*i,t[i]);
}

输出

tccnt 100  100 
 20-231 
 40-42 
 60-61 
 80-82 
 100-102 
 120-124 
 140-142 
 160-162 
 180-181 
 200-201 
 220-221 
 240-241 
 260-261 
 280-321 
 300-302 
 320-322 
 340-342 
 360-361 
 380-382

相差不大, gettimeofday只在初次延时较大。
bcm2835测试,其它需改写前面的汇编代码。

附 其它几个读取时钟计数器的汇编代码
arm64

 asm volatile("mrs %0, cntvct_el0" :"=r"(ct));

arm32 v7

asm volatile("mrc p15,0,%0, c9, c13, 0":"=r"(ct));

x86 64

 asm volatile("rdtsc ; shl $32, %%rdx ; or %%rdx, %0": "=a"(ct));

你可能感兴趣的:(嵌入式硬件,c语言,linux)