标签:linux内核 嵌入式 移植 延时delay udelay
申请CSDN博客认证专家通过,着实让我受宠若惊,自己还是有这份自知之明,与专家 大牛这些词汇还是有很长距离。这2个函数在实现上有着天壤之别。
msleep实现是基于调度,延时期间调用schedule_timeout产生调度,待时间到期后继续运行,该函数实现在kernel/timer.c中。
由于linux内核不是实时系统,因此涉及调度的msleep肯定不会精确。
今天不细说msleep,有时间再来分析它,今天重点来学习mdelay。mdelay ndelay都是基于udelay来实现的。在include/linux/delay.h中,如下:
#ifndef MAX_UDELAY_MS #define MAX_UDELAY_MS 5 #endif #ifndef mdelay #define mdelay(n) ( (__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : ({unsigned long __ms=(n); while (__ms--) udelay(1000);})) #endif #ifndef ndelay static inline void ndelay(unsigned long x) { udelay(DIV_ROUND_UP(x, 1000)); } #define ndelay(x) ndelay(x) #endif #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d))
ndelay实现可以看出非常不精确,经过计算调用udelay。因此ndelay最少也是延时1us。
所以接下来来看udelay实现。这里讨论基于ARM处理器架构的实现,udelay实现在arch/arm/include/asm/delay.h中。
#define MAX_UDELAY_MS 2 #define udelay(n) (__builtin_constant_p(n) ? ((n) > (MAX_UDELAY_MS * 1000) ? __bad_udelay() : __const_udelay((n) * ((2199023U*HZ)>>11))) : __udelay(n))
.LC0: .word loops_per_jiffy .LC1: .word (2199023*HZ)>>11 /* * r0 <= 2000 * lpj <= 0x01ffffff (max. 3355 bogomips) * HZ <= 1000 */ ENTRY(__udelay) ldr r2, .LC1 mul r0, r2, r0 ENTRY(__const_udelay) @ 0 <= r0 <= 0x7fffff06 mov r1, #-1 ldr r2, .LC0 ldr r2, [r2] @ max = 0x01ffffff add r0, r0, r1, lsr #32-14 mov r0, r0, lsr #14 @ max = 0x0001ffff add r2, r2, r1, lsr #32-10 mov r2, r2, lsr #10 @ max = 0x00007fff mul r0, r2, r0 @ max = 2^32-1 add r0, r0, r1, lsr #32-6 movs r0, r0, lsr #6 moveq pc, lr 上面这段汇编运算规则可以总结为下面这个计算公式,n为传入参数: loops = ( ( (n *((2199023*HZ)>>11)) >> 14 ) * (loops_per_jiffy >> 10) ) >> 6 /* * loops = r0 * HZ * loops_per_jiffy / 1000000 * * Oh, if only we had a cycle counter... */ @ Delay routine ENTRY(__delay) subs r0, r0, #1 bhi __delay mov pc, lr ENDPROC(__udelay) ENDPROC(__const_udelay) ENDPROC(__delay)
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:linux内核 嵌入式 移植 延时delay udelay
原文地址:http://blog.csdn.net/skyflying2012/article/details/46763779