ARM_Linux NOTE_5
Vine Farer
2016.08.12
4、Timer定时中断
1)基本的定时(计时)中断
配置定时器中断,需要额外设置
TINT_CSTAT
寄存器以
Timer 2
为例Timer 2 interrupt enable
置一,使能Timer 2
Timer 2 interrupt status
置一,清除中断状态Timer 2
中断模式初始化(code)void init_timer2(int ms) { //-------------------Timer2----------------------// //----------- 39 71 ¨C TIMER2-----------------// PWM.TCFG0 = (PWM.TCFG0 & (~(0xff << 8))) | (99 << 8); // 100M / 100 = 1MHz PWM.TCFG1 = (PWM.TCFG1 & (~(0xf << 8))) | (0b0000 << 8); // 1M / 1 = 1MHz PWM.TCNTB2 = 1000000;// 1M / 1M 获得一秒的周期,初值自减到0,无需设置占空比 PWM.TCON = (PWM.TCON & (~(0xf << 12))) | (0b1010 << 12); PWM.TCON = (PWM.TCON & (~(0xf << 12))) | (0b1001 << 12); //依旧循环自动装载,保证每1s减到0能触发一次中断 PWM.TINT_CSTAT |= (1 << 2); //Timer 2 中断使能 fun_p[71] = timer2_int;//装载定时器中断处理函数 //------------------GIC中断设置------------------// ICDISER.ICDISER2 |= (1 << 7); ICDIPTR.ICDIPTR17 = (ICDIPTR.ICDIPTR17 & (~(0xff << 24))) | (1 << 24); ICDDCR = 1; CPU0.ICCICR = 1; }
作定时器中断时,只须设置
PWM.TCNTB2
初值,确定一个计时的长度,自减到0触发中断即可。无需设置占空比Timer 2
中断处理代码(code)void (*fun_p[160])(void); void do_irq(void) //Timer定时中断也属IRQ,依旧调用do_irq() { int irq_number; irq_number = CPU0.ICCIAR & 0x3ff; printf("irq:%d\n", irq_number); (*fun_p[irq_number])(); CPU0.ICCEOIR = (CPU0.ICCEOIR & ~0x3ff) | irq_number; //CPU0.ICC关闭对57号中断源的响应 } void timer2_int(void) { printf("timer2\n"); //每1s触发一次中断,打印信息 PWM.TINT_CSTAT = (PWM.TINT_CSTAT & (~(0b11111 << 5))) | (1 << 7); ICDICPR.ICDICPR2 = (1 << 7); }
定时器中断也属
IRQ
,一样进入do_irq()
处理,再调用timer2_int()
2)用Timer 2
中断处理按键消抖
按键的外部中断初始化函数(code)
void init_key() { /*gpx1_1 >> xeint_9 >> eint[9] >> 25 57 ¨C EINT[9]*/ GPX1.CON = (GPX1.CON & (~(0xf << 4))) | (0xf << 4);//配置GPIO端口为接收中断状态 //配置中断源相关寄存器 EXT_INT41_CON = (EXT_INT41_CON & (~(0xf << 4))) | (0x2 << 4); EXT_INT41_FLTCON0 |= (1 << 15); EXT_INT41_FLTCON0 &= ~(1 << 14); EXT_INT41_MASK &= ~(1 << 1); fun_p[57] = key2_int; //日常GIC中断控制器设置 ICDISER.ICDISER1 |= (1 << 25); //打开57号中断控制 ICDIPTR.ICDIPTR14 = (ICDIPTR.ICDIPTR14 & (~(0xff << 8))) | (0b00000001 << 8); //对应57号中断,选择CPU0处理 ICDDCR = 1; //开中断混合器,等待外设中断触发 CPU0.ICCICR = 1; //使能中断信号发送给CPU0 }
main()
中须添加init_key();
,然后死循环等待中断触发Timer 2
初始化函数(计时消抖)void init_timer2(int ms) { //-----------------Timer2--------------------// PWM.TCFG0 = (PWM.TCFG0 & (~(0xff << 8))) | (99 << 8); // 100M / 100 = 1MHz PWM.TCFG1 = (PWM.TCFG1 & (~(0xf << 8))) | (0b0000 << 8); // 1M / 1 = 1MHz PWM.TCNTB2 = 1000 * ms; //可传参设置定时量 PWM.TCON = (PWM.TCON & (~(0xf << 12))) | (0b1010 << 12); PWM.TCON = (PWM.TCON & (~(0xf << 12))) | (0b0001 << 12); //必须关闭自动装载,按键触发中断后,只须一轮计时 PWM.TINT_CSTAT |= (1 << 2); fun_p[71] = timer2_int; /* 39 71 ¨C TIMER2*/ ICDISER.ICDISER2 |= (1 << 7); ICDIPTR.ICDIPTR17 = (ICDIPTR.ICDIPTR17 & (~(0xff << 24))) | (0b00000001 << 24); ICDDCR = 1; CPU0.ICCICR = 1; }
中断处理函数
void (*fun_p[160])(void);//函数指针数组,存放各个中断源处理函数 void do_irq(void) { int irq_number; irq_number = CPU0.ICCIAR & 0x3ff; printf("irq:%d\n", irq_number); (*fun_p[irq_number])(); CPU0.ICCEOIR = (CPU0.ICCEOIR & ~0x3ff) | irq_number; //CPU0.ICC关闭对71号中断源的响应 } void key2_interrupt(void) { init_timer2(20); EXT_INT41_PEND = (1 << 1); //清除中断源 ICDICPR.ICDICPR1 = (1 << 25); //清除ICD对中断响应 } void timer2_interrupt(void) { printf("timer2\n"); if (0 == (GPX1.DAT & (1 << 1))) printf(">>>>>>>>>>>key2\n"); PWM.TINT_CSTAT = (PWM.TINT_CSTAT & (~(0b11111 << 5))) | (1 << 7);//清除中断状态 ICDICPR.ICDICPR2 = (1 << 7); //清除ICD对中断响应 }
程序执行过程中,按键按下触发 57 号外部中断,进入
do_irq()
后调用按键中断处理函数key2_interrupt()
;
key2_interrupt()
中初始化了Timer 2
定时中断,开始计时,并且按键中断响应结束;
等待 n ms后触发Timer 2
定时中断,再次进入do_irq()
调用timer2_interrupt()
,打印信息。
5、Watchdog Timer
Watchdog Timer
定时喂狗,使整个硬件重启两级分频器,
WTDAT
和WTCNT
、复位信号生成器WTCON
:Watchdog timer control register
WTDAT
:Watchdog Timer Data
WTCNT
:Watchdog Timer Counter
WTCLRINT
:Watchdog timer interrupt clear register
定时重启 code
int i = 10000; /*led5 GPX3_5*/ GPF3.CON = (GPF3.CON & (~(0xf << 20))) | (0x1 << 20); //两级分配系数:255、128,最后为3khz WDT.WTCON = (WDT.WTCON & (~(0xff << 0))) | (0xff39 << 0); WDT.WTCNT = 6000;//计数从6000开始减,结束时过去2秒 //正常情况下,看门狗计数减不到0循环就结束了,不会触发喂狗 //但最后i = 10000,延时很长可以等到喂狗触发,硬件重启 while (1) { WDT.WTCNT = 6000; GPF3.DAT ^= (1 << 5); mydelay_ms(500); GPF3.DAT ^= (1 << 5); mydelay_ms(500); GPF3.DAT ^= (1 << 5); mydelay_ms(i); }
Watchdog Timer
定时器中断一般来说不会用此定时器中断
6、RTC实时时钟
基本功能
自带
Alarm Function
和Tick Time Interrupt
Supports BCD Number
支持BCD码格式的年月日时间Supports Leap Year Generator
支持闰年发生器Supports Independent Power Pin (RTCVDD)
Supports millisecond tick time interrupt for RTOS kernel time tick.
RTC实时时钟的时间显示
用BCD码配置初始时间信息,启动RTC时间开始走
int main(void) { int sec,min,hour,week,day,mon,year; RTCCON = (RTCCON & (~(0xff << 0))) | (0b0001 << 0); //you can change the BCD time count setting开启时间设置功能 RTC.BCDSEC = 0x48; RTC.BCDMIN = 0x59; RTC.BCDHOUR = 0x04; RTC.BCDWEEK = 0x3; RTC.BCDDAY = 0x22; RTC.BCDMON = 0x10; RTC.BCDYEAR = 0x016; RTCCON = RTCCON & (~(0xff << 0));//关闭时间设置功能 while(1) { printf("%x-%x-%x week:%x %x:%x:%x\n", RTC.BCDYEAR,RTC.BCDMON,RTC.BCDDAY,RTC.BCDWEEK, RTC.BCDHOUR,RTC.BCDMIN,RTC.BCDSEC); } return 0; // mov pc,lr bx lr }
RTC定时闹钟
本质是定时中断的闹钟系统
void do_irq(void) { int irq_number; irq_number = CPU0.ICCIAR & 0x3ff; printf("irq:%d\n", irq_number); (*fun_p[irq_number])(); CPU0.ICCEOIR = (CPU0.ICCEOIR & ~0x3ff) | irq_number; } void alarm_int(void) { printf("alarm\n"); RTCINTP = (1 << 1); ICDICPR.ICDICPR2 = (1 << 12); } int main(void) { int i = 500; //依旧重设初始时间线 RTCCON |= 1; RTC.BCDYEAR = 0x016;//(0 << 8)|(1 << 4)|(6 << 0); RTC.BCDMON = 0x08; RTC.BCDDAY = 0X31; RTC.BCDWEEK = 0X7; RTC.BCDHOUR = 0X23; RTC.BCDMIN = 0X59; RTC.BCDSEC = 0X55; RTCCON &= ~1; RTCALM.SEC = 0x2;//每分钟的第二秒触发中断 RTCALM.ALM |= (1 << 6) | (1 << 0); // 44 76 RTC_ALARM fun_p[76] = alarm_int; ICDISER.ICDISER2 |= (1 << 12); ICDIPTR.ICDIPTR19 = (ICDIPTR.ICDIPTR19 & (~(0xff << 0))) | (0b00000001 << 0); ICDDCR = 1; CPU0.ICCICR = 1; while(1){ printf("2%03x-%02x-%02x week:%x %02x:%02x:%02x\n", RTC.BCDYEAR,RTC.BCDMON,RTC.BCDDAY, RTC.BCDWEEK,RTC.BCDHOUR,RTC.BCDMIN,RTC.BCDSEC); mydelay_ms(500); } return 0; // mov pc,lr bx lr }
7、ADC模数转换器
KEY Features of ADC for motor control
Resolution: 10-bit / 12-bit (optional)
Differential Nonlinearity Error: ± 2.0 LSB (Max.)
Integral Nonlinearity Error: ± 4.0 LSB (Max.)
Top Offset Error : 0 ~ + 55 LSB
Bottom Offset Error : 0 ~ - 55 LSB
Maximum Conversion Rate: 1 MSPS
Low Power Consumption
Power Supply Voltage: 1.8V (Typ.), 1.0V (Typ., Digital I/O Interface)
Analog Input Range: 0 ~ 1.8V
samsung / david.pang at 14:21,2012.05.07寄存器
ADCCON
:ADC Control Register
ADCDLY
:ADC Start or Interval Delay Register
ADCDAT
:ADC Conversion Data Register
CLRINTADC
:Clear ADC Interrupt
ADCMUX
:Specifies the Analog input channel selection
ADC采集可调电阻的电压值code
int main(void) { int value; ADCCON = (ADCCON & (~(0xf << 0))); ADCCON = (ADCCON & (~(0xff << 6)))| (99 << 6); ADCCON |= (1 << 14); ADCCON |= (1 << 16); ADCMUX = 0b0011; while(1) { ADCCON |= 1; printf("---\n"); if((ADCCON & (1 << 15)) != 0){ value = ADCDAT & 0xfff; printf(">>>>>>> value: %d\n",value); } mydelay_ms(500); } return 0; // mov pc,lr bx lr }
特别的,ADC有两种开启方式。
在ADCCON
寄存器中ENABLE_START
=1 ,
A/D conversion starts and this bit is automatically cleared after the start-up.
所以每次采样都需要使能一次READ_START
读启动,必须只读位ECFLG
= 1才可启动,
所以设置读启动后,要先象征性读一次ECFLG
才可启动采样