s3c2440 ARM9 裸机驱动第三篇—定时器
来源:互联网 发布:淘宝在哪里交保证金 编辑:程序博客网 时间:2024/05/26 12:06
定时器这篇是比较艰辛的,过程中出现了很多小问题,有些解决了,有些还是没有完全弄明白,这些问题主要集中在汇编部分的程序。
此部分主要是通过定时器中断的方式实现LED灯的闪烁。
一、硬件部分:
1.LED部分:参见之前的文章
2.定时器:
定时器的频率:Timer input clock Frequency = PCLK / {prescaler value+1} / {divider value}
{prescaler value} = 0~255
{divider value} = 2, 4, 8, 16
其中PCLK如果配置了MPLL就是50M,prescaler value配置TCFG0得到,divider value配置TCFG1得到。
TCFG0和TCFG1这两个寄存器为配置寄存器,涉及配置定时器的频率和PWM死区时间和通道,DMA请求通道。
TCON为控制寄存器,这里涉及到定时器的工作模式,和使能和失能,值得注意的是NOTE的那句话,The bit has to be cleared at next writing.
3.中断寄存器:
SRCPND中断源挂起寄存器,产生中断则对应位会置1,在中断服务函数中清除此位
INTMOD中断模式寄存器,用于设置对应中断源事件的处理方式,是FIQ(快中断)还是IRQ
INTMSK中断屏蔽寄存器,屏蔽或者打开对应的中断。默认屏蔽。
PRIORITY中断优先级寄存器
INTRND中断挂起寄存器,在中断服务函数中清除SRCPND寄存器后清除此寄存器。
INTOFFSET中断偏移寄存器,在IRQ模式下起作用,根据其值,指示中断源。
二、软件部分:
1.start.s启动的汇编代码:
此部分直接改的韦东山老师的代码。
@******************************************************************************@ File:head.S@ 功能:初始化,设置中断模式、管理模式的栈,设置好中断处理函数@****************************************************************************** .extern main.text .global _start _start:@****************************************************************************** @ 异常向量,本程序中,除Reset和HandleIRQ外,其它异常都没有使用@****************************************************************************** b Reset@ 0x04: 未定义指令中止模式的向量地址HandleUndef: b HandleUndef @ 0x08: 管理模式的向量地址,通过SWI指令进入此模式HandleSWI: b HandleSWI@ 0x0c: 指令预取终止导致的异常的向量地址HandlePrefetchAbort: b HandlePrefetchAbort@ 0x10: 数据访问终止导致的异常的向量地址HandleDataAbort: b HandleDataAbort@ 0x14: 保留HandleNotUsed: b HandleNotUsed@ 0x18: 中断模式的向量地址 b HandleIRQ@ 0x1c: 快中断模式的向量地址HandleFIQ: b HandleFIQ Reset: ldr sp, =4096 @ 设置栈指针,以下都是C函数,调用前需要设好栈 bl disable_watch_dog @ 关闭WATCHDOG,否则CPU会不断重启@ldr pc, =disable_watch_dog msr cpsr_c, #0xd2 @ 进入中断模式 ldr sp, =3072 @ 设置中断模式栈指针 msr cpsr_c, #0xd3 @ 进入管理模式 ldr sp, =4096 @ 设置管理模式栈指针, @ 其实复位之后,CPU就处于管理模式, @ 前面的“ldr sp, =4096”完成同样的功能,此句可省略@ bl init_led @ 初始化LED的GPIO管脚@ bl init_irq @ 调用中断初始化函数,在init.c中 msr cpsr_c, #0x53 @ 设置I-bit=0,开IRQ中断 ldr lr, =halt_loop @ 设置返回地址 ldr pc, =main @ 调用main函数halt_loop: b halt_loopHandleIRQ: sub lr, lr, #4 @ 计算返回地址 stmdb sp!, { r0-r12,lr } @ 保存使用到的寄存器 @ 注意,此时的sp是中断模式的sp @ 初始值是上面设置的3072 ldr lr, =int_return @ 设置调用ISR即EINT_Handle函数后的返回地址 ldr pc, =timer0_Handle @ 调用中断服务函数,在timer.c中int_return: ldmia sp!, { r0-r12,pc }^ @ 中断返回, ^表示将spsr的值复制到cpsr
2.timer.c文件
#defineGPFCON(*(volatile unsigned long *)0x56000050)#defineGPFDAT(*(volatile unsigned long *)0x56000054)#define WTCON (*(volatile unsigned long *)0x53000000)//CLK#defineMPLLCON(*(volatile unsigned long *)0x4C000004)#defineCLKDIVN(*(volatile unsigned long *)0x4C000014)#defineCAMDIVN(*(volatile unsigned long *)0x4C000018)//TIME#defineTCFGO(*(volatile unsigned long *)0x51000000)//预分频#defineTCFG1(*(volatile unsigned long *)0x51000004)//分频#defineTCON(*(volatile unsigned long *)0x51000008)//控制寄存器#defineTCNTB0(*(volatile unsigned long *)0x5100000C)//计数寄存器//IRQ#defineSRCPND(*(volatile unsigned long *)0X4A000000)//中断源挂起#defineINTMOD(*(volatile unsigned long *)0X4A000004)//中断模式#defineINTMSK(*(volatile unsigned long *)0X4A000008)//中断屏蔽#defineINTPND(*(volatile unsigned long *)0X4A000010)//中断挂起#definePRITY(*(volatile unsigned long *)0X4A00000C)//中断优先级void clk_init(void);void timer0_init(unsigned char prescalers,unsigned int count);int main(int argv, char *argc){int i;GPFCON&=0x00ff;GPFCON|=0x5500;GPFDAT=0x0;clk_init();timer0_init(100,40000);GPFDAT=0xf0;while(1){}return 0;}void clk_init(void){//LOCKTIME默认值CLKDIVN=0x03;//MCLK:HCLK:PCLK=1:2:4//CAMDIVN默认值__asm__(//如果 HDIVN 不为 0,CPU 总线模式应该使用以下指令使其从"MRC p15, 0, r0, c1, c0, 0\n"//快总线模式改变为异步总线模式(S3C2440不支持同步总线模式)。"ORR r1, r1, #0xc0000000\n""MCR p15, 0, r0, c1, c0, 0\n");MPLLCON=((0x5c<<12)|(0x01<<4)|0x02);//MCLK=200M//MPLLCON=(0x5c<<12)|(1<<4)|2;}/**prescalers=0-255*中断频率=50/16/prescalers/count*/void timer0_init(unsigned char prescalers,unsigned int count){TCFGO=prescalers;//50M/prescalersTCFG1=0x3;//50M/prescalers/16TCNTB0=count;//计数值TCON |=1<<1;TCON |=1<<3;//自动重装载TCON &=~(1<<1);/*配置中断*/SRCPND |= (1<<10);//清除源挂起INTPND |= (1<<10);//清除中断挂起INTMOD &= ~(1<<10);//设置中断模式为IRQ模式INTMSK &= ~(1<<10);//使能定时器中断/*启动定时器*/TCON |= (1<<0);//启动定时器0}void timer0_Handle(){SRCPND |= (1<<10);//清除源挂起INTPND |= (1<<10);//清除中断挂起GPFDAT= ~GPFDAT;timer0_irq = 1;}void disable_watch_dog(void){ WTCON = 0; // 关闭WATCHDOG很简单,往这个寄存器写0即可}3.MakefileCC=arm-linux-gccLD=arm-linux-ldtimer.bin:timer.o start.o$(LD) -Ttext 0x0000000 -g start.o timer.o -o timer_elfarm-linux-objcopy -O binary -S timer_elf timer.binarm-linux-objdump -D -m arm timer_elf > timer.distimer.o:timer.c$(CC) -c -g -o timer.o timer.cstart.o:start.s$(CC) -c -g -o start.o start.sclean:rm -f timer.bin led_elf timer.dis start.o
- s3c2440 ARM9 裸机驱动第三篇—定时器
- s3c2440 ARM9 裸机驱动第二篇—2440系统时钟
- s3c2440 ARM9 裸机驱动第一篇-GPIO驱动(汇编)
- s3c2440 ARM9 裸机驱动第一篇-GPIO驱动(C)
- ARM9 mini2451裸机学习——LCD驱动学习 2
- ARM9 mini2451裸机学习——RTC驱动设置
- S3C2440裸机驱动--启动代码
- S3C2440裸机驱动--PWM基础
- S3C2440裸机驱动--PWM应用
- S3C2440裸机驱动--MMU基础
- S3C2440之IIC裸机驱动
- ARM9(S3C2440)时钟与定时器
- ARM9(S3C2440)时钟与定时器
- ARM9(S3C2440)时钟与定时器
- S3C2440裸机实验之timer(定时器)
- arm9+linux s3c2440 触摸屏驱动移植
- 定时器中断---那些年我们一起玩mini2440(arm9)裸机
- S3C2440裸机实验(7)----LCD驱动
- 表单json字符串生成
- BCC(Borland C++ Compiler)编译 ISAPI 扩展或者用MinGW也行
- 基础练习 闰年判断
- python pandas 查看数据的前五行
- The Elements of Computing Systems阅读笔记(5)
- s3c2440 ARM9 裸机驱动第三篇—定时器
- React ES6与ES5写法的区别
- SpringBoot依赖及其作用
- ubuntu修改系统/文件夹语言(中文/英文互转)
- 通过java反射机制操作对象的属性方法
- url编解码
- 2017年11月04日作业
- C++中产生1~100的随机数
- windows下安装linux双系统绕坑指南