RTEMS 的 AT91SAM9260 移植(6): 杂项函数

杂项函数在 BSP 中也是非常重要的。我为了图省事,全部都放置在了:c/src/lib/libcpu/arm/at91sam9260/pmc/pmc.c中。

主要是获取CPU当前的频率和系统主时钟的频率。

前几篇连载中,我们在串口和时钟驱动里都是用了获取主时钟频率的函数。

 

另外一个就是 udelay 函数。udelay函数原来是posix的标准函数,但是rtems并没有实现,

我们不可能用时钟节拍去做微秒级别的时间延时。

许多驱动程序必须要延迟一定的时间才能工作,这里我给出了一个简单的实现方式。

启动定时器1,采用计数方式,选择一个合适的时钟平率,我选择的是主时钟的 32 分之一,一个脉冲大约是300ns。然后

给定时器一个初值,测量一段空循环的时间。得出循环多少次正好是1微秒。

这是通过 calc_delay 来实现的。实际实现中,为了防止除法的精度不够,还做了一下微调。

我是在c/src/lib/libbsp/arm/at9260/startup/bspstart.c中的bsp_start_default函数中调用这个函数,bsp_start_default会在bootcard函数一开始就调用。不用担心定时器1会和别的驱动冲突。只调用calc_delay一次,不要再调用,就绝对不会冲突。

 

 

闲话少说,看pmc.c的全部代码:

/* * Atmel AT91sam9260 PMC functions * * Bacon xu */ #include <rtems.h> #include <bsp.h> #include <at91sam9260.h> uint32_t at91sam9260_get_mainclk(void) { return (BSP_MAIN_FREQ); } uint32_t at91sam9260_get_slck(void) { return (BSP_SLCK_FREQ); } uint32_t at91sam9260_get_cpuclk(void) { uint32_t mckr_css; uint32_t pll_mult; uint32_t pll_div; uint32_t pclk_div; uint32_t cpu_freq; mckr_css = (AT91C_BASE_PMC->PMC_MCKR) & AT91C_PMC_CSS; if (mckr_css == AT91C_PMC_CSS_SLOW_CLK) { return (BSP_SLCK_FREQ); } if (mckr_css == AT91C_PMC_CSS_MAIN_CLK) { return (BSP_MAIN_FREQ); } if (mckr_css == AT91C_PMC_CSS_PLLA_CLK) { pll_mult = ((AT91C_BASE_PMC->PMC_PLLAR & AT91C_CKGR_MULA) >> 16); pll_div = (AT91C_BASE_PMC->PMC_PLLAR & AT91C_CKGR_DIVA) >> 0; } else { pll_mult = ((AT91C_BASE_PMC->PMC_PLLBR & AT91C_CKGR_MULB) >> 16); pll_div = (AT91C_BASE_PMC->PMC_PLLBR & AT91C_CKGR_DIVB) >> 0; } if (pll_div == 0) { return (BSP_MAIN_FREQ); /* If the PLL mult is 0, then the PLL is disabled */ } /* Read the Master Clock divider */ pclk_div = (AT91C_BASE_PMC->PMC_MCKR >> 2) & 0x07; pclk_div = 1 << pclk_div; /* Convert 0-7 into 1, 2, 4, 8, 16, 32, or 64 */ if (pclk_div >= 128) { /* Divider pattern for 128 is reserved */ return (BSP_MAIN_FREQ); } cpu_freq = ((BSP_MAIN_FREQ / pll_div) / pclk_div) * (pll_mult + 1); return (cpu_freq); } uint32_t at91sam9260_get_mck(void) { uint32_t mclk_div; uint32_t cpu_freq; cpu_freq = at91sam9260_get_cpuclk(); mclk_div = (AT91C_BASE_PMC->PMC_MCKR >> 8) & 0x03; /* Read the Master Clock divider */ mclk_div = 1 << mclk_div; /* Convert 0-3 into 1, 2, 4 */ cpu_freq = cpu_freq / mclk_div; return (cpu_freq); } static unsigned int _gLoopsPerMicrosec = 0; #define TIMER_INT_VALUE 0xFFFFFFFFL #define INIT_DELAY_TIMES (1 << 10) static inline void __const_delay(unsigned int value) { for ( ; value > 0; value--) { __asm__ __volatile__ ("nop;/n"); } } #define START_TIMER() / do {/ AT91C_BASE_TC2->TC_CMR = AT91C_TC_CLKS_TIMER_DIV3_CLOCK | AT91C_TC_WAVE;/ AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS | AT91C_TC_SWTRG;/ AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKEN | AT91C_TC_SWTRG;/ } while (0) #define STOP_TIMER() / (AT91C_BASE_TC2->TC_CCR = AT91C_TC_CLKDIS) #define READ_TIMER(clock) / ((uint64_t) (32 * 1000000) * (AT91C_BASE_TC2->TC_CV) / clock) void calc_delay(void) { uint32_t time; uint32_t mck; mck = at91sam9260_get_mck(); AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC2; START_TIMER(); __const_delay(INIT_DELAY_TIMES); STOP_TIMER(); time = READ_TIMER(mck); _gLoopsPerMicrosec = INIT_DELAY_TIMES / time; while (1) { START_TIMER(); udelay(1000); STOP_TIMER(); time = READ_TIMER(mck); if (time < 1000) { _gLoopsPerMicrosec++; } else break; } AT91C_BASE_PMC->PMC_PCDR = 1 << AT91C_ID_TC2; } void udelay(unsigned int usecs) { unsigned int loops = usecs * _gLoopsPerMicrosec; __const_delay(loops); }

 

这里,杂项函数我们就搞定了。

你可能感兴趣的:(c,timer,css,div,delay,loops)