S5PV210的定时器

时间:2024-04-02 18:33:16


一、PWM定时器

S5PV210有5个PWM定时器,其中0、1、2、3各自对应一个外部GPIO,可以通过这些对应的GPIO产生PWM波形信号输出。5个PWM定时器的时钟源为PCLK_PSYS,Timer0和Timer1共同使用一个预分频器、Timer2、3、4共同使用一个预分频器;每个timer有一个专用的独立的分频器;预分频器和分频器构成了2级分频系统,将PCLK_PSYS两级分频后生成的时钟供给Timer模块作为时钟周期。

S5PV210提供电平翻转器和死区生成器。电平翻转器在电路上的实质就是一个电平取反的部件,在编程上反映为一个寄存器位。写0就关闭输出电平反转,写1就开启输出电平反转。开启后和开启前输出电平刚好高低反转。

PWM有一个应用就是用在功率电路中用来对交流电压进行整流。整流时2路整流分别在正电平和负电平时导通工作,不能同时导通(同时导通会直接短路,瞬间的同时导通都会导致电路烧毁)。大功率的开关电源、逆变器等设备广泛使用了整流技术。特别是逆变器,用SoC的GPIO输出的PWM波形来分别驱动2路整流的IGBT。PWM波形用来做整理时要求不能同时高或低,因为会短路。但是实际电路是不理想的,不可能同时上升/下降沿,所以比较安全的做法是留死区。   

关于PWM输出的几个寄存器:

设置引脚输出

  S5PV210的定时器

设置预分频

 S5PV210的定时器

TCFG1寄存器,设置分频

 S5PV210的定时器

TCON寄存器,设置重装载

 S5PV210的定时器

TCNTB和TCMPB,设置周期和占空比

 S5PV210的定时器

S5PV210的定时器


#define GPD0CON(0xE02000A0)

#define TCFG0(0xE2500000)

#define TCFG1(0xE2500004)

#define CON(0xE2500008)

#define TCNTB2(0xE2500024)

#define TCMPB2(0xE2500028)

 

#define rGPD0CON(*(volatile unsigned int *)GPD0CON)

#define rTCFG0(*(volatile unsigned int *)TCFG0)

#define rTCFG1(*(volatile unsigned int *)TCFG1)

#define rCON(*(volatile unsigned int *)CON)

#define rTCNTB2(*(volatile unsigned int *)TCNTB2)

#define rTCMPB2(*(volatile unsigned int *)TCMPB2)

 

void timer2_pwm_init(void) {

rGPD0CON &= ~(0xf<<8);

rGPD0CON |= (2<<8);      //GPD0_2引脚配置为XpwmTOUT_2

rTCFG0 &= ~(0xff<<8);

rTCFG0 |= (65<<8); // prescaler1 = 65, 预分频后频率为1MHz

rTCFG1 &= ~(0x0f<<8);

   /*  MUX2设置为1/2,分频后时钟周期为500KHz,对应的时钟周期是2us  */

rTCFG1 |= (1<<8);

rCON |= (1<<15); // 使能auto-reload,反复定时才能发出PWM波形

//rTCNTB2 = 250;    // 0.5ms/2us = 500us/2us = 250

//rTCMPB2 = 125;    // duty = 50%

rTCNTB2 = 100;

rTCMPB2 = 99;

// 第一次需要手工将TCNTB中的值刷新到TCNT中去,以后就可以auto-reload

rCON |= (1<<13); // 打开自动刷新功能

rCON &= ~(1<<13); // 关闭自动刷新功能

rCON |= (1<<12); } // timer2定时器。要先把其他都设置好才能开定时器

 

二、看门狗定时中断

 S5PV210的定时器

 

WTCON寄存器

 S5PV210的定时器

 

void wdt_init_interrupt(void)

{

// 第一步,设置好预分频器和分频器,得到时钟周期是128us

rWTCON &= ~(0xff<<8);

rWTCON |= (65<<8);   // 1MHz

rWTCON &= ~(3<<3);

rWTCON |= (3<<3);  // 1/128 MHz, T = 128u

// 第二步,设置中断和复位信号的使能或禁止

rWTCON |= (1<<2); // enable wdt interrupt

rWTCON &= ~(1<<0); // disable wdt reset

// 第三步,设置定时时间

  rWTDAT = 1000; // 定时0.128s

rWTCNT = 1000; // 定时0.128s

 

/* 其实WTDAT中的值不会自动刷到WTCNT中去,如果不显式设置WTCON中的值,

      它的值就是,默认值,然后以这个默认值开始计数,所以这个时间比较久。设置了

      WTCNTWTDAT一样的值,则第一次的定时值就和后面的一样了   */

// 第四步,先把所有寄存器都设置好之后,开看门狗

rWTCON |= (1<<5); // enable wdt

}

 

三、RTC

设置年份

 S5PV210的定时器

设置月

 S5PV210的定时器

设置日期

 S5PV210的定时器

设置小时

 S5PV210的定时器

设置分

 S5PV210的定时器

S5PV210的定时器

 

struct rtc_time  {

unsigned int year;

unsigned int month;

unsigned int date; // 几号

unsigned int hour;

unsigned int minute;

unsigned int second;

unsigned int day; // 星期几

};

// 函数功能:把十进制num转成bcd码,

static unsigned int num_2_bcd(unsigned int num)

{

return (((num / 10)<<4) | (num % 10));

}

 

// 函数功能:把bcdbcd转成十进制,譬如把0x56转成56

static unsigned int bcd_2_num(unsigned int bcd)

{

return (((bcd & 0xf0)>>4)*10 + (bcd & (0x0f)));

}

 

void rtc_set_time(const struct rtc_time *p)

{

// 第一步,打开RTC读写开关

rRTCCON |= (1<<0);

// 第二步,写RTC时间寄存器

rBCDYEAR = num_2_bcd(p->year - 2000);

rBCDMON = num_2_bcd(p->month);

rBCDDATE = num_2_bcd(p->date);

rBCDHOUR = num_2_bcd(p->hour);

rBCDMIN = num_2_bcd(p->minute);

rBCDSEC = num_2_bcd(p->second);

rBCDDAY = num_2_bcd(p->day);

// 最后一步,关上RTC的读写开关

rRTCCON &= ~(1<<0);

}

 

void rtc_get_time(struct rtc_time *p)

{

// 第一步,打开RTC读写开关

rRTCCON |= (1<<0);

// 第二步,读RTC时间寄存器

p->year = bcd_2_num(rBCDYEAR) + 2000;

p->month = bcd_2_num(rBCDMON);

p->date = bcd_2_num(rBCDDATE);

p->hour = bcd_2_num(rBCDHOUR);

p->minute = bcd_2_num(rBCDMIN);

p->second = bcd_2_num(rBCDSEC);

p->day = bcd_2_num(rBCDDAY);

// 最后一步,关上RTC的读写开关

rRTCCON &= ~(1<<0);

}

 

void rtc_set_alarm(void)

{

rALMSEC = num_2_bcd(23);

rRTCALM |= 1<<0;

rRTCALM |= 1<<6;

}