试验意图:通过运用MPLL进步体系时钟,发动守时器发生中止来点亮LED灯,发动Watchdog守时器,假如程序跑飞,凭借Watchdog从头运转程序,借此把握S3C2410的时钟办理、PWM及看门狗守时器。
试验环境及阐明:恒颐S3C2410开发板H2410。
实 验思路:开发板上电发动后,主动将NandFlash开端的4K数据仿制到SRAM中,然后跳转到0地址开端履行。然后来设置MPLL来改动FCLK、 HCLK、PCLK的值,初始化存储操控器来运用SDRAM。初始化LED灯管脚、守时中止操控器和看门狗,使能守时中止操控器和看门狗。之后进入 main函数死循环等候中止的发生,每隔设定的时刻触发守时中止,调用守时中止处理函数点亮/平息LED灯。若程序跑飞,触发看门狗重启。
常识把握:体系时钟、PWM守时器和Watchdog守时器
一、体系时钟:S3C2410的时钟操控逻辑为整个芯片供给了三种时钟。
★FCLK 用于CPU核;HCLK用于AHB总线上设备—CPU核、存储器操控器、中止操控器、LCD操控器、DMA和USB主机模块;PCLK用于APB总线 上设备—Watchdog、IIS、I2C、PWM守时器、MMC接口、ADC、UART、GPIO、RTC和SPI。
★AHB(Advanced High performance Bus)—首要用于高性能模块间的衔接;APB(Advanced Peripheral Bus)—首要用于低带宽的周边外设之间的衔接。
★ 开发板时钟频率为12MHz,首要是为了下降电磁搅扰和板间布线要求,需求通过PLL进步体系时钟。S3C2410包含MPLL(用于FCLK、 HCLK、PLCK)和UPLL(用于USB设备),他们的设置办法相似。开发板上电→FCLK=Fin(外部输入时钟)→设置MPLL相关寄存器→等候 (Lock Time:长短由寄存器LOCKTIME设定)→MPLL输出安稳,CPU作业在新的时钟FCLK下。
★设置MPLL需求设置下面几个重要寄存器:
●LOCKTIME寄存器(LOCK TIME COUNT)用于设置lock time的长度,初始值0x00FFFFFF。
●MPLLCON(Main PLL Control)寄存器用于设置FCLK与Fin的倍数,初始值0x0005C080。
●CLKDIVN(CLOCK DIVIDER CONTROL)寄存器用于设置FCLK、HCLK、PCLK三者的份额。
二、PWM(pulse width modulation)守时器
★S3C2410共有5个16位的守时器,其间守时器0、1、2、3有PWM功用,因为它们都有一个输出引脚,能够通过守时器来操控引脚周期性的高、低电平改动;守时器4木有输出引脚就不有PWM功用了。
★PLCK 是守时部件的时钟源,先通过2个8位预分频器(守时器0、1共用第一个守时器,2、3、4共用第二个),输出进入第二级分频(输出2/4/8/16分频或 者外部时钟TCLK0/TCLK1)。这两次预分频都是通过设置TCFG0寄存器完结的。每个守时器作业在哪种频率下能够通过TCFG1寄存器来挑选的。
★守时器的运用首要触及以下寄存器:
●TCFG0寄存器:位[7:0],位[15:8]别离用于操控预分频器0,1;它们的值为0~255。通过分频器出来的时钟频率:PLCK/(TCFG0[7:0]+1或TCFG0[15:8]+1)。
'700')this.width='700';if(this.offsetHeight>'700')this.height='700';" src="http://www.arm79.com/attachment/Mon_1005/94_67_154d167be4af4a1.jpg" onclick="if(this.width>=700) window.open('http://www.arm79.com/attachment/Mon_1005/94_67_154d167be4af4a1.jpg');" border="0" width="700">
●TCFG1寄存器:设定相应守时器为通过分频器出来的时钟频率的几分频。守时器作业频率= PLCK/(TCFG0[7:0]或TCFG0[15:8]+1)/几分频。
●TCNTBn/TCMPBn寄存器:这两个寄存器都只用到位[15:0]。TCNTBn中保存守时器的初始计数值,TCMPBn中保存比较值。它们的在发动守时器时,被传到守时器内部寄存器TCNTn,TCMPn中。
●TCNTOn寄存器:n为0~4,内部寄存器TCNTn在其作业时钟下不断减1计数,能够通过读取TCNTOn寄存器得知其值。
●TCON寄存器:它的功用如下:第一次发动守时器时,手动将TCNTBn/TCMPBn寄存器的值装入内部寄存器TCNTn,TCMPn中;发动,中止守时器;决议在守时器计数抵达0时是否主动装入初值;决议守时器的管脚TOUTn的输出电平是否回转。
三、Watchdog守时器:其运用和PWM守时器很类此。
★PLCK 先通过8位预分频器后再被分红4种频率(16/32/64/128分频)。运用看门狗守时器的一个最首要意图当然是让它给你看门了。程序正常履行时,有必要 不断从头设置WTCNT寄存器使其不为0,这样能够确保体系不被重启,称为“喂狗”;程序溃散时不能准时“喂狗”,则计数值抵达0后体系重启,使得程序可 以从头正常运转。
★Watchdog存在的含义:敞开Watchdog之后程序有必要守时向其反应信息,这看似费事又耗资源,其实是很重要的行为, 是程序向硬件传递本身运转状况的一种办法。假如程序运转杰出则它应该能够在规则的时刻距离内向Watchdog反应信息,借此来阐明程序运转正常;若程序 因为某个不妥的操作而进入死循环等,则无法向Watchdog反应信息,Watchdog将发生记时超时,然后引起硬件重起。假如没有Watchdog, 程序死掉就死掉了,只能等候用户自己发现去吧。
★相关寄存器:
●WTCON寄存器:用于设置预分频系数,挑选作业频率,决议是否使能中止,是否启用WATDOG功用等。
●WTDAT寄存器:用以决议Watchdog守时器的超时周期,值主动写入WTCNT。
●WTCNT寄存器:在发动WATDOG守时器前,有必要往这个寄存器写入初始计数值,发动守时器后,它做减1操作,当计数器值到达0时,假如中止被使能的话,就宣布中止,假如Watchdog功用被使能的话就宣布复位信号,装载WTDAT寄存器的值并从头计数。
要害代码解析:
★head.S头文件来初始化,设置中止形式、体系形式的栈,设置好中止处理函数
.text
.global _start
_start:
@中止向量表处理函数,只给出复位和一般中止形式的处理函数,其它反常未运用
b Reset
……
@0x18: 中止形式的向量地址
b HandleIRQ
@0x1c: 快中止形式的向量地址
HandleFIQ:
b HandleFIQ
Reset: @复位处理
bl disable_watch_dog @关门喂狗
ldr sp,=0x4096 @clock初始化栈地址
bl clock_init @设置MPLL,改动FCLK、HCLK、PCLK
bl mem_control_setup @设置存储操控器以运用SDRAM
bl copy_steppingstone_to_sdram @仿制代码到SDRAM中
ldr pc, =on_sdram @跳到SDRAM中持续履行
on_sdram:
msr cpsr_c, #0xd2 @进入中止形式
ldr sp, =0x32000000 @设置中止形式栈指针
msr cpsr_c, #0xdf @进入体系形式
ldr sp, =0x34000000 @设置体系形式栈指针
bl init_led @初始化LED
bl init_timer0 @初始化守时器0
bl enable_timer0 @使能守时器0
bl init_watchdog @初始化Watchdog
bl enable_watchdog @使能Watchdog
msr cpsr_c, #0x5f @设置I-bit=0,开IRQ中止
ldr lr, =halt_loop @设置回来地址
ldr pc, =main @调用main函数
halt_loop:
b halt_loop
★init.c文件完成时钟、GPIO、中止及守时的初始化,首要代码:
/*
* 时钟初始化
*/
#define S3C2410_MPLL_200MHZ ((0x5c<<12)|(0x04<<4)|(0x00))
void init_clock(void)
{
CLKDIVN = 0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
/* 假如HDIVN非0,CPU的总线形式应该从"fast bus mode"变为"asynchronous bus mode"*/
__asm__(
"mrc p15, 0, r1, c1, c0, 0\n" /* 读出操控寄存器 */
"orr r1, r1, #0xc0000000\n" /* 设置为"asynchronous bus mode" */
"mcr p15, 0, r1, c1, c0, 0\n" /* 写入操控寄存器 */
);
MPLLCON = S3C2410_MPLL_200MHZ; /* FCLK=200MHz,HCLK=100MHz,PCLK=50MHz */
}
/*
* 守时器0初始化
*/
void init_timer0(void)
{
TCFG0 = 99; // 预分频器0 = 99
TCFG1 = 0x03; // 挑选16分频
TCNTB0 = 31250; // 0.5秒钟触发一次中止
TCON |= (1<<1); // 手动更新
TCON = 0x09; // 主动加载,清“手动更新”位,发动守时器0
}
/*
* 守时器0中止使能
*/
void enable_timer0(void)
{
INTMSK &= (~(1<<10)); // 守时器0中止使能
}
/*
* Watchdog初始化
*/
void init_watchdog(void)
{
//Prescaler Value = 99;Division_factor = 16(Clock Select=16);Interrupt Generation = 0(不发生中止);Reset = 1(敞开Reset Signal)
WTCON = 0x6381;
//设置寄存器WTDAT的值为0x8000,时刻一定要大于Timer0的时刻
WTDAT = 0x8000;
}
/*
* Watchdog使能
*/
void enable_watchdog(void)
{
WTCON|=1<<5;
}
★interrupt.c文件完成中止的处理,首要代码:
/*
* 守时器0中止处理函数
*/
void Timer0_Handle(void)
{
//喂狗
WTCNT=0x8000;
//每次中止令4个LED改动状况
if(INTOFFSET == 10)
GPFDAT = ~(GPFDAT & (0xf << 4));
//清中止
SRCPND = 1 << INTOFFSET;
INTPND = INTPND;
}