遵循我们上次的步骤,
1.将c/src/lib/libbsp/arm/csb337复制为 c/src/lib/libbsp/arm/at9260;
at9260 │ aclocal.m4 │ bsp_specs │ ChangeLog │ configure │ configure.ac │ Makefile.am │ Makefile.in │ preinstall.am │ README │ times │ ├─autom4te.cache │ output.0 │ output.1 │ requests │ traces.0 │ traces.1 │ ├─console │ uarts.c │ ├─include │ bsp.h │ bspopts.h.in │ tm27.h │ ├─network │ network.c │ ├─start │ start.S │ └─startup bspclean.c bspstart.c linkcmds memmap.c
2.将c/src/lib/libcpu/arm/at91rm9200复制为c/src/lib/libcpu/arm/at91sam9260;at91sam9260 ├─clock │ clock.c │ ├─dbgu │ dbgu.c │ ├─include │ at91sam9260.h │ bits.h │ ├─irq │ bsp_irq_asm.S │ bsp_irq_init.c │ irq.c │ irq.h │ ├─memcpy │ memcpy.S │ ├─pmc │ pmc.c │ └─timer timer.c
连载2说了,关于start.S的修改。今天说说时钟驱动的修改。
时钟是RTEMS的心脏,RTEMS的内核需要这个时钟生成系统节拍。
RTEMS 时钟节拍的时间单位是 微秒(microseconds)。
AT9260有专门为操作系统节拍准备的 PIT 时钟,刚好符合这个应用。
为了代码撰写方便,可以从ATMEL官方网站上下载相关的软件包,软件包里有AT91sam9260的相关寄存器的定义,
相关宏的定义,便于我们开发代码。
RTEMS 的时钟驱动 因为和系统高度相关,虽然遵循一般RTEMS的驱动架构,但只有一个初始化函数,其他都为空函数,另外就是遵循了RTEMS对中断的架构。故时钟驱动更加简单。
与时钟驱动相关的文件有:
c/src/lib/libcpu/arm/at91sam9260/clock/clock.c
c/src/lib/libbsp/shared/clockdrv_shell.c
我们修改的地方是clock.c
首先是clock中断的打开与关闭,相对简单,不贴代码了。
static void clock_isr_on(const rtems_irq_connect_data *unused);
static void clock_isr_off(const rtems_irq_connect_data *unused);
static int clock_isr_is_on(const rtems_irq_connect_data *irq);
另外一个是时钟中断的ISR程序。
这个isr代码在 clockdrv_shell.c中,所以,要提前声明一下。
接着是时钟中断的相关数据。
rtems_isr Clock_isr(rtems_vector_number vector); /* Replace the first value with the clock's interrupt name. */ rtems_irq_connect_data clock_isr_data = {AT91C_ID_SYS, (rtems_irq_hdl)Clock_isr, clock_isr_on, clock_isr_off, clock_isr_is_on, 3, /* unused for ARM cpus */ 0 }; /* unused for ARM cpus */
定义安装时钟中断的宏。
#define Clock_driver_support_install_isr( _new, _old ) / BSP_install_rtems_irq_handler(&clock_isr_data)
这个是初始化时钟的硬件代码。
特别注意的是,由于使用微秒做单位,乘法很可能溢出,所以采用了64位做强制类型转换。
具体看代码。
void Clock_driver_support_initialize_hardware(void) { uint32_t st_str; int mck; /* the system timer is driven from MCK */ mck = at91sam9260_get_mck() / 16; /*rtems_configuration_get_microseconds_per_tick()乘 mck 也许会溢出,所以需要使用 uint64_t 类型*/ st_pimr_reload = ((((uint64_t)rtems_configuration_get_microseconds_per_tick() * (uint64_t)mck) + (1000000/2))/ 1000000); /* read the status to clear the int */ st_str = AT91C_BASE_PITC->PITC_PIVR; /* set priority */ AT91C_BASE_AIC->AIC_SMR[AT91C_ID_SYS] = AT91C_AIC_SRCTYPE_INT_LEVEL_SENSITIVE | AT91C_AIC_PRIOR_HIGHEST; /* set the timer value */ /* Enable the PIT with the correct compare value */ AT91C_BASE_PITC->PITC_PIMR = AT91C_PITC_PITIEN | AT91C_PITC_PITEN | st_pimr_reload; }
定义 Clock_driver_support_at_tick这个宏,由于时钟中断的服务程序是由系统提供的高度抽象的一个函数。
有些处理器要求在中断中可能要清理一下时钟中断或者别的与硬件相关的操作。这些不可能由高度抽象的代码去完成。
所以,系统定义了这个宏,主要完成每次中断以后与硬件高度相关的操作。例如清除时钟中断。
#define Clock_driver_support_at_tick() / do { / uint32_t st_str; / / AT91C_BASE_AIC->AIC_IVR = 0;/ /* read the status to clear the int */ / st_str = AT91C_BASE_PITC->PITC_PIVR; / /* clear system interrupt *// AT91C_BASE_AIC->AIC_ICCR = 1 << AT91C_ID_SYS;/ } while (0) void Clock_driver_support_shutdown_hardware( void ) { BSP_remove_rtems_irq_handler(&clock_isr_data); }
到这里,时钟驱动撰写完成。