标签:
尝试用2440的TOUT0和TOUT1输出PWM驱动两个电机,电机的硬件驱动电路是使用L298N。#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.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 <linux/clk.h> #include <linux/cdev.h> #include <linux/device.h> #include <linux/miscdevice.h> #define DEVICE_NAME "pwm" //设备名 #define IOCTL_SET_PWM_DUTY 1 #define IOCTL_PWM_STOP 2 /* 定义信号量 lock用于互斥,因此,改驱动程序只能同时有一个进程使用 */ static struct semaphore lock; static void pwm_set_duty(unsigned long duty) { unsigned long tcon; unsigned long tcnt0,tcmp0; unsigned long tcfg1; unsigned long tcfg0; tcfg0 = __raw_readl(S3C2410_TCFG0); tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK; tcfg0 |= (50 - 1); tcfg1 = __raw_readl(S3C2410_TCFG1); tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK; tcfg1 |= S3C2410_TCFG1_MUX0_DIV16; __raw_writel(tcfg0, S3C2410_TCFG0); __raw_writel(tcfg1, S3C2410_TCFG1); tcnt0 = 1000;//设置PWM频率 tcmp0 = duty;//设置PWM占空比 __raw_writel(tcnt0, S3C2410_TCNTB(0)); __raw_writel(tcmp0, S3C2410_TCMPB(0)); tcon = __raw_readl(S3C2410_TCON); tcon |= 0xf; //设置输出电平反转,start pwm output __raw_writel(tcon, S3C2410_TCON); tcon &= ~2; /* clear manual update bit */ __raw_writel(tcon, S3C2410_TCON); } static void pwm_stop(void) { unsigned long tcon; tcon = __raw_readl(S3C2410_TCON); tcon &= ~(1<<3);//Turn off the auto reload bit __raw_writel(tcon, S3C2410_TCON); // } static int my_pwm_open(struct inode *inode, struct file *file) { if (!down_trylock(&lock))//不会导致进程休眠 { s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_TOUT0); return 0; } else return -EBUSY; } static int my_pwm_close(struct inode *inode, struct file *file) { pwm_stop(); s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPIO_INPUT); up(&lock); return 0; } static int my_pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { switch (cmd) { case IOCTL_SET_PWM_DUTY: if (arg == 0) return -EINVAL; pwm_set_duty(arg); break; case IOCTL_PWM_STOP: pwm_stop(); break; default: printk(KERN_INFO"cmd error!\n"); break; } return 0; } static struct file_operations dev_fops = { .owner = THIS_MODULE, .open = my_pwm_open, .release = my_pwm_close, .ioctl = my_pwm_ioctl, }; //混杂设备驱动 static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, }; static int __init dev_init(void) { int ret; init_MUTEX(&lock); /* 初始化一个互斥锁 */ ret = misc_register(&misc); printk (DEVICE_NAME"\tinitialized\n"); return ret; } static void __exit dev_exit(void) { misc_deregister(&misc); } module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("CLBIAO"); MODULE_DESCRIPTION("S3C2440 Pwm Driver");(2)测试app程序:
#include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #define IOCTL_SET_PWM_DUTY 1 #define IOCTL_PWM_STOP 2 int main(int argc, char **argv) { int fd,i; unsigned long duty; fd = open("/dev/pwm",O_RDWR); for(i=0;i<4;i++) { ioctl(fd,IOCTL_SET_PWM_DUTY,duty);//duty=80% duty += 100; sleep(3); } close(fd); exit(0); }实验现象是:
#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> #include <linux/miscdevice.h> #define DEVICE_NAME "pwm" #define IOCTL_CONFIG_PWM0 1 #define IOCTL_CONFIG_PWM1 2 #define IOCTL_PWM0_STOP 3 #define IOCTL_PWM1_STOP 4 #define TIMER0 5 #define TIMER1 6 #define AUTO_RELOAD_ON 7 #define AUTO_RELOAD_OFF 8 #define INVER_ON 9 #define INVER_OFF (10) static struct semaphore lock; static void set_input_clock(void) { unsigned int tcfg0,tcfg1; tcfg0 = __raw_readl(S3C2410_TCFG0); tcfg1 = __raw_readl(S3C2410_TCFG1); tcfg0 &= ~S3C2410_TCFG_PRESCALER0_MASK; tcfg0 |= (50- 1); tcfg1 &= ~S3C2410_TCFG1_MUX0_MASK; tcfg1 |= S3C2410_TCFG1_MUX0_DIV16; __raw_writel(tcfg0, S3C2410_TCFG0); __raw_writel(tcfg1, S3C2410_TCFG1); } static void set_pwm_duty(int select,unsigned int duty) { unsigned int tcon; tcon = __raw_readl(S3C2410_TCON); switch(select) { case TIMER0: __raw_writel(1000, S3C2410_TCNTB(0)); __raw_writel(duty, S3C2410_TCMPB(0)); break; case TIMER1: __raw_writel(1000, S3C2410_TCNTB(1)); __raw_writel(duty, S3C2410_TCMPB(1)); break; } } static void auto_reload_on_off(int select,int status) { unsigned int tcon; tcon = __raw_readl(S3C2410_TCON); switch(select) { case TIMER0: if(status==7) { tcon |= (1<<3); __raw_writel(tcon,S3C2410_TCON); mdelay(1); } else if(status==8) { tcon &= ~(1<<3); __raw_writel(tcon,S3C2410_TCON); mdelay(1); } break; case TIMER1: if(status==7) { tcon |= (1<<11); __raw_writel(tcon,S3C2410_TCON); mdelay(1); } else if(status==8) { tcon &= ~(1<<11); __raw_writel(tcon,S3C2410_TCON); mdelay(1); } break; } } static void start_pwm_out(int select) { unsigned int tcon; tcon = __raw_readl(S3C2410_TCON); switch(select) { case TIMER0: tcon |= 1; __raw_writel(tcon, S3C2410_TCON); break; case TIMER1: tcon |= (1<<8); __raw_writel(tcon, S3C2410_TCON); break; } } static void stop_pwm_out(int select) { unsigned int tcon; tcon = __raw_readl(S3C2410_TCON); switch(select) { case TIMER0: auto_reload_on_off(TIMER0,AUTO_RELOAD_OFF); mdelay(5); tcon &= ~(1<<0); __raw_writel(tcon,S3C2410_TCON); break; case TIMER1: auto_reload_on_off(TIMER1,AUTO_RELOAD_OFF); mdelay(1); tcon &= ~(1<<8); __raw_writel(tcon,S3C2410_TCON); break; } } static void manual_update_tcont_tcmp(int select) { unsigned int tcon; tcon = __raw_readl(S3C2410_TCON); switch(select) { case TIMER0: tcon |= (1<<1);//Update TCNTB0 & TCMPB0 __raw_writel(tcon, S3C2410_TCON); break; case TIMER1: tcon |= (1<<9);//Update TCNTB1 & TCMPB1 __raw_writel(tcon, S3C2410_TCON); break; } } static void clear_manual_bit(int select) { unsigned int tcon; tcon = __raw_readl(S3C2410_TCON); switch(select) { case TIMER0: tcon &= ~(1<<1); __raw_writel(tcon, S3C2410_TCON); break; case TIMER1: tcon &= ~(1<<9); __raw_writel(tcon, S3C2410_TCON); break; } } static void output_inverte_on_off(int status) { unsigned long tcon; switch(status) { case INVER_ON: tcon = __raw_readl(S3C2410_TCON); tcon |= ((1<<2)|(1<<10)); __raw_writel(tcon, S3C2410_TCON); break; case INVER_OFF: tcon = __raw_readl(S3C2410_TCON); tcon &= ~((1<<2)|(1<<10)); __raw_writel(tcon, S3C2410_TCON); break; } } static void print_tcon(int status) { unsigned int tcon; tcon = __raw_readl(S3C2410_TCON); switch(status) { case 0: printk(KERN_INFO"beford set tcon:tcon=%d\n",tcon); break; case 1: printk(KERN_INFO" after set tcon:tcon=%d\n",tcon); break; } } static int s3c2440_pwm_open(struct inode *inode, struct file *file) { if (!down_trylock(&lock)) { s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPB0_TOUT0);//靠外边的一个TOUT0 s3c2410_gpio_cfgpin(S3C2410_GPB1, S3C2410_GPB1_TOUT1);// s3c2410_gpio_setpin(S3C2410_GPB6,1); output_inverte_on_off(INVER_ON); stop_pwm_out(TIMER0); stop_pwm_out(TIMER1); set_input_clock(); return 0; } else { printk(KERN_INFO"/dev/pwm opened!\n"); return -EBUSY; } } static int s3c2440_pwm_close(struct inode *inode, struct file *file) { auto_reload_on_off(TIMER0,AUTO_RELOAD_OFF); auto_reload_on_off(TIMER1,AUTO_RELOAD_OFF); stop_pwm_out(TIMER0); stop_pwm_out(TIMER1); output_inverte_on_off(INVER_OFF); s3c2410_gpio_cfgpin(S3C2410_GPB0, S3C2410_GPIO_INPUT); s3c2410_gpio_cfgpin(S3C2410_GPB1, S3C2410_GPIO_INPUT); s3c2410_gpio_setpin(S3C2410_GPB6,0); up(&lock); return 0; } static void config_pwm0(unsigned long duty) { stop_pwm_out(TIMER0); set_pwm_duty(TIMER0,duty); manual_update_tcont_tcmp(TIMER0); auto_reload_on_off(TIMER0,AUTO_RELOAD_ON); start_pwm_out(TIMER0); clear_manual_bit(TIMER0); } static void config_pwm1(unsigned long duty) { stop_pwm_out(TIMER1); set_pwm_duty(TIMER1,duty); manual_update_tcont_tcmp(TIMER1); auto_reload_on_off(TIMER1,AUTO_RELOAD_ON); start_pwm_out(TIMER1); clear_manual_bit(TIMER1); } static int s3c2440_pwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { switch (cmd) { case IOCTL_CONFIG_PWM0: printk(KERN_INFO"config timer0:\n"); print_tcon(0); config_pwm0(arg); print_tcon(1); break; case IOCTL_CONFIG_PWM1: printk(KERN_INFO"config timer1:\n"); print_tcon(0); config_pwm1(arg); print_tcon(1); break; case IOCTL_PWM0_STOP: printk(KERN_INFO"stop timer0:\n"); print_tcon(0); stop_pwm_out(TIMER0); print_tcon(1); break; case IOCTL_PWM1_STOP: printk(KERN_INFO"stop timer1:\n"); print_tcon(0); stop_pwm_out(TIMER1); print_tcon(1); break; default: printk(KERN_INFO"ioctl cmd error!\n"); break; } return 0; } static struct file_operations dev_fops = { .owner = THIS_MODULE, .open = s3c2440_pwm_open, .release = s3c2440_pwm_close, .ioctl = s3c2440_pwm_ioctl, }; static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_fops, }; static int __init dev_init(void) { int ret; init_MUTEX(&lock); /* 初始化一个互斥锁 */ ret = misc_register(&misc); printk (DEVICE_NAME"\tinitialized\n"); return ret; } static void __exit dev_exit(void) { misc_deregister(&misc); } module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("CLBIAO"); MODULE_DESCRIPTION("S3C2440 Pwm Driver");测试APP:
#include <stdlib.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <string.h> #define IOCTL_CONFIG_PWM0 1 #define IOCTL_CONFIG_PWM1 2 #define IOCTL_PWM0_STOP 3 #define IOCTL_PWM1_STOP 4 int main(int argc, char **argv) { int fd; fd = open("/dev/pwm",O_RDWR); sleep(12); ioctl(fd,IOCTL_CONFIG_PWM0,900); ioctl(fd,IOCTL_CONFIG_PWM1,100); sleep(6); ioctl(fd,IOCTL_CONFIG_PWM0,700); ioctl(fd,IOCTL_CONFIG_PWM1,300); sleep(6); ioctl(fd,IOCTL_PWM0_STOP); ioctl(fd,IOCTL_PWM1_STOP); sleep(6); ioctl(fd,IOCTL_CONFIG_PWM0,500); ioctl(fd,IOCTL_CONFIG_PWM1,500); sleep(6); close(fd); exit(0); }感想:s3c2440芯片手册上并没有说到两路timer同时输出时应该注意哪些方面,我想这就是这次调试过程中遇到最蛋疼的问题了,只能靠自己通过实验现象一点一点去摸索,醉了醉了.............
标签:
原文地址:http://blog.csdn.net/clb1609158506/article/details/45829389