时钟 中断 day54
七:时钟
一:两个锁相环(PLL)
一个提供给FCLK、HCLK和PCLK,另一个专用于USB模块(48MHz)。时钟控制逻辑可以不使用PLL来减慢时钟,并且可以由软件连接或断开各外设模块的时钟,以降低功耗
先配置HDIVN和PDIVN,因为如果先配置PMS的话,由于H,P没有配置比例,导致他们的频率没有限制,过高,下面的模块可能损坏
二:代码
#ifndef __CLK_H
#define __CLK_H#define CLKDIVN (*(volatile unsigned long *)0x4C000014UL)
#define MPLLCON (*(volatile unsigned long *)0x4C000004UL)
#define CAMDIVN (*(volatile unsigned long *)0x4C000018UL)
#define CLKCON (*(volatile unsigned long *)0x4C00000CUL)void clk_init(void);
void Delay_ms(unsigned int num);#endif#include"clk.h"void clk_init(void)
{MPLLCON=(127<<12) | (2<<4) | (1<<0); CLKDIVN &= (0x2 << 1)|(1 << 0);
}void clk_enable(unsigned char num)
{CLKCON |=(1<<num);
}void clk_disable(unsigned char num)
{CLKCON &=~(1<<num);
}
八:中断
一:基础概念
ARM没有中断嵌套,所以当低优先级中断在运行时,高优先级中断也要排队
这些挂起标志,中断处理后,还要手动清零,不然一直中断下去
先清源挂起标志,因为他是中断挂起标志的源头,
带次级源的源和其他源比较时,次级源也会参与比较
数字越小,优先级越高(仲裁源情况下)
这种情况就不是按顺序中断优先级
二:中断irq
(默认0-irq/1--fiq
)
#include <s3c2440.h> //不用再#define各种寄存器了
#include "irq.h"void eint8_init(void)
{//配置GPG0引脚功能为eint8GPGCON &= ~(0X3 << 0); //用K1,并且还要使能eint8GPGCON |= (0X2 <<0);//配置eint8下降沿触发,(外部中断寄存器)EXTINT1 &= ~(0X7 << 0);EXTINT1 |= (0X2 << 0);//使能eint8EINTMASK &= ~(1 << 8);//使能eint8_23INTMSK &= ~(1 << 5); }void deal_eint8_23(void)
{if(EINTPEND & (1 << 8)) //成立,eint8被触发{//EINT8被触发//EINT8的处理函数EINTPEND |= (1 << 8); //写1 清除}//else if(1 << 9)//else if(1 << ....)//else if(1 << 23)
}void c_deal_irq(void)
{// 判断哪个中断源触发中断斤并处理// 清中断标志unsigned int irq_num = INTOFFSET;switch(irq_num){case 5:deal_eint8_23();break;default:break;}SRCPND |= (1 << irq_num);//先清标志源//INTPND |= (1 << irq_num);INTPND = INTPND; //作用和上面一样,写1清0
}
preserve8area reset, code, readonlycode32entryb start ; resetnop ; undefb deal_swi ; swinop ; prefetch abortnop ; data abortnop ; reservedb deal_irq ; irqnop ; fiqdeal_irqsub lr, lr, #4stmfd sp!, {r4-r12, lr} ;保护现场import c_deal_irqbl c_deal_irqldmfd sp!, {r4-r12, pc}^ ;恢复现场deal_swistmfd sp!, {r4-r12, lr} ;保护现场sub r0, lr, #4ldr r1, [r0]bic r0, r1, #(0xff << 24)import c_deal_swibl c_deal_swi ldmfd sp!, {r4-r12, pc}^ ;带模式切换的恢复现场startldr sp, =0x40001000 ;初始化SVC模式的栈mrs r0, cpsrbic r0, r0, #(1 << 7) ;清I位msr cpsr_c, r0 ;设置使能IRQ,权限的问题,在svc(特权)下才有权限,普通用户没有权限mrs r0, cpsrbic r0, r0, #0x1forr r0, r0, #0x12 msr cpsr_c, r0 ;设置工作模式位irqldr sp, =0x40000C00 ;初始化irq模式的栈mrs r0, cpsrbic r0, r0, #0x1forr r0, r0, #0x10msr cpsr_c, r0 ;设置工作模式位userldr sp, =0x40000800 ;初始化user模式的栈;swi #5 ;软中断指令; 函数的调用规则; 前四个参数使用r0-r3传递,剩余参数使用栈传递; 返回值存放在r0中mov r0, #1mov r1, #2import main ;声明一个外部符号供本文件使用bl main ;带链接返回的跳转 自动保存返回地址到lr nop ;空转1个机器周期b startend
2.1SRCPND 和INTPND,EINTPEND(操作而不是动作)
源挂起寄存器(SRCPND)和中断挂起寄存器(INTPND),这些挂起寄存器表明一个中断请求是否为挂起
当INTPND寄存器的挂起位为置位,每当I标志或F标志被清除为O中断服务程序将开始,始。SRCPND和INTPND寄存器可以被读取和写入,因此服务程序必须首先通过写1到SRCPND寄存器的相应位来清除挂起状态并且通过相同方法来清除INTPND寄存器中挂起状态。
总结:写1 清 0,他不是对应的位变成1 ,而是写入对应位的1,进行这个操作,与它本身这个状态没有关系,他的逻辑要的是:向对应位写1,有这个操作,才能进行清0 这个动作
我们之前学的寄存器,是当这位为0/1,才能有这样的功能,要的是结果
而这个寄存器是写入1这个操作,不用管它本身是0/1,要的是过程
2.2INTOFFSET
中断偏移(INTOFFSET)寄存器是CPU处理,CPU才知道你进行的是什么样的中断,判断哪个中断需要被处理
2.3关于irq
栈的问题
deal_irqsub lr, lr, #4stmfd sp!, {r4-r12, lr} ;保护现场import c_deal_irqbl c_deal_irqldmfd sp!, {r4-r12, pc}^ ;恢复现场
所有工作模式的栈都是独立的,所以创建一个新函数,你也要重新初始化栈,且与其他栈独立
2.4程序员模型
标准 swi 已经写好,看图
deal_irqsub lr, lr, #4 ;程序员模型,图为标准stmfd sp!, {r4-r12, lr} ;保护现场import c_deal_irqbl c_deal_irqldmfd sp!, {r4-r12, pc}^ ;恢复现场