时钟脉冲:脉冲信号是一个按一定电压幅度,一定时间间隔连续发出的脉冲信号,脉冲信号之间的时间间隔称为周期。
时钟频率:在单位时间(如1秒)内产生的时钟脉冲个数。
频率的其相应的单位有:Hz(赫)、kHz(千赫)、MHz(兆赫)、GHz(吉赫);其中1GHz=1000MHz,1MHz=1000kHz.1kHz=1000Hz。
s3c2440有外部晶振XTIPLL和外部时钟频率EXTCLK.并有两个PLL(锁相环):MPLL和UPLL.
UPLL:USB设备专用
- UCLK:USB设备的时钟频率
MPLL:用于CPU和其他外围设备,MPLL会产生3个部分的时钟频率:FCLK、HCLK、PCLK
- FCLK:用于CPU核
- HCLK:用于高速总线设备
- PCLK:用于低速总线设备
下图为PLL设置流程图:
LOCKTIME寄存器设置Lock Time所需的时间
MPLLCON寄存器设置FCLK和Fin(时钟源频率)的倍数
通过MPLLCON寄存器设置MDIV、PDIV、SDIV三个值得到FCLK与Fin的倍率
FCLK和Fin的计算公式:
MPLL(FCLK)= (2*m*Fin)/(p*2^s)
m=MDIV+8 p=PDIV+2 s=SDIV
CLKDIVN寄存器设置FCLK、HCLK、PCLK三者的比例
定时器输出时钟频率=PCLK/{prescaler value+ 1}/{divider value}
{prescaler value+ 1} = 0 ~ 255
prescaler value=TCFG0
{divider value} = 2 , 4 , 8 , 16
divider value=TCFG1
TCON:设置装载定时器计数值,并启动定时器.
定时器内部控制逻辑的工作流程:
①初始化或者获取PCLK值。
②程序初始,设置TCMPBn、TCNTBn这两个寄存器,它们表示定时器n的比较值、初始计数值。
③随之设置TCON寄存器启动定时器n,这时,TCMPBn、TCNTBn的值将被装入其内部寄存器TCMPn、TCNTn中。在定时器n的工作频率下,TCNTn开始减一计数,其值可以通过读取TCNTOn寄存器得知。
④当TCNTn的值等于TCMPn的值时,定时器n的输出管脚TOUTn反转;TCNTn继续减一计数。
⑤当TCNTn的值到达0时,其输出管脚TOUTn再次反转,并触发定时器n的中断。
⑥当TCNTn的值到达0时,如果在TCON寄存器中将定时器n设为“自动加载”,则TCMPB0和TCNTB0寄存器的值被自动装入TCMP0和TCNT0寄存器中,下一个计数流程开始。
定时器n的输出管脚TOUTn初始状态为高电平,以后在TCNTn的值等于TCMPn的值、TCNTn的值等于0时反转。
下图为详细的工作流程图:
最后通过例子结合芯片手册的定时器设置章节理解:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 | #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/poll.h> #include <linux/interrupt.h> #include <linux/gpio.h> #include <asm/irq.h> #include <asm/io.h> #include <asm/uaccess.h> #include <mach/regs-gpio.h> #include <mach/hardware.h> #include <plat/regs-timer.h> #include <mach/regs-irq.h> #include <asm/mach/time.h> #include <linux/clk.h> #include <linux/cdev.h> #include <linux/device.h> #define DEVICE_NAME "motor" #define Age_Life 10 #define Back_Life 110 #define Car_Stop 00 static struct cdev *motor_cdev; static dev_t devno; static struct semaphore lock; static void Motor_Ferg(unsigned long freq,unsigned int direction) { unsigned long tcon; unsigned long tcnt; unsigned long tcfg1; unsigned long tcfg0; struct clk *clk_p; unsigned long pclk; /*设置GPH10为OUTPUT模式*/ s3c2410_gpio_cfgpin(S3C2410_GPH(10),S3C2410_GPIO_OUTPUT); /*设置GPH10的转向,由direction控制方向*/ s3c2410_gpio_setpin(S3C2410_GPH(10),direction); /*设置GPB1为定时器1模式*/ s3c2410_gpio_cfgpin(S3C2410_GPB(1),S3C2410_GPB1_TOUT1); /*读取TCON、TCFG1、TCFG0三个寄存器的值*/ tcon = __raw_readl(S3C2410_TCON); tcfg1 = __raw_readl(S3C2410_TCFG1); tcfg0 = __raw_readl(S3C2410_TCFG0); /*定时器0和1的预分频值的掩码*/ tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK; /*设置预分频率为50赫兹*/ tcfg0 |= (50-1); /*定时器定1分频值的掩码*/ tcfg1 &= ~S3C2410_TCFG1_MUX1_MASK; /*设置定时器1为16分频*/ tcfg1 |= S3C2410_TCFG1_MUX1_DIV16; /*将设置好的分频值写入寄存器TCFG0和TCFG1当中*/ __raw_writel(tcfg1, S3C2410_TCFG1); __raw_writel(tcfg0, S3C2410_TCFG0); /*获取PCLK值*/ clk_p = clk_get(NULL,"pclk"); pclk = clk_get_rate(clk_p); /*得到定时器的输入时钟,进而设置PWM的调制频率*/ tcnt = (pclk/50/16)/freq; /*设置TCNTB1和TCMPB1的值并写入寄存器*/ __raw_writel(tcnt, S3C2410_TCNTB(1)); __raw_writel(tcnt/2, S3C2410_TCMPB(1)); /*设置定时器1启动,装载TCNTB1和TCMPB1并自动重载模式*/ tcon &= ~0xff0; tcon |= 0xb00; /*写入寄存器TCON*/ __raw_writel(tcon,S3C2410_TCON); /*设置TCNTB1和TCMPB1的值手动更新并写入寄存器*/ tcon &= ~0x600; __raw_writel(tcon,S3C2410_TCON); } /*停止运作函数*/ static void Motor_Stop(void) { s3c2410_gpio_cfgpin(S3C2410_GPB(1),S3C2410_GPIO_OUTPUT); s3c2410_gpio_setpin(S3C2410_GPB(1),0); s3c2410_gpio_cfgpin(S3C2410_GPH(10),S3C2410_GPIO_OUTPUT ); s3c2410_gpio_setpin(S3C2410_GPH(10),0); } /*控制函数*/ static long motor_ioctl( struct file *file, unsigned int cmd, unsigned long arg) { unsigned int direction; switch(cmd){ case Age_Life: direction=1; Motor_Ferg(arg,direction); break; case Back_Life: direction=0; Motor_Ferg(arg,direction); break; case Car_Stop: Motor_Stop(); break; } return 0; } /*打开函数*/ static int motor_open(struct inode *inode,struct file *file) { if(!down_trylock(&lock)) return 0; else return -EBUSY; } /*关闭函数*/ static int motor_release(struct inode *inode,struct file *file) { Motor_Stop(); up(&lock); return 0; } /*设置各函数*/ static struct file_operations motor_fops= { .owner = THIS_MODULE, .unlocked_ioctl = motor_ioctl, .release = motor_release, .open = motor_open, }; /*注册驱动函数*/ static int __init motor_init(void) { int ret,err; int major,minor; major=200; minor=0; sema_init(&lock,1); ret=register_chrdev_region(major,2,DEVICE_NAME); if(ret<0) return ret; devno=MKDEV(major,minor); motor_cdev=cdev_alloc(); cdev_init(motor_cdev,&motor_fops); err=cdev_add(motor_cdev,devno,2); if(err) { unregister_chrdev_region(devno,2); return -EFAULT; } printk(DEVICE_NAME "\tinitialized!\n"); return ret; } /*注销驱动函数*/ static void __exit motor_exit(void) { cdev_del(motor_cdev); unregister_chrdev_region(devno,2); printk(DEVICE_NAME "\tunloaded\n"); } module_init(motor_init); module_exit(motor_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Yayi"); |