• «
  • 1
  • 2
  • »
  • Pages: 1/2     Go
主题 : tiny6410定时器1模拟输出PWM波 复制链接 | 浏览器收藏 | 打印
级别: 新手上路
UID: 5386
精华: 0
发帖: 33
金钱: 165 两
威望: 33 点
贡献值: 0 点
综合积分: 66 分
注册时间: 2009-04-21
最后登录: 2011-09-26
楼主  发表于: 2011-09-18 15:46

 tiny6410定时器1模拟输出PWM波

  我的开发板是TINY6410,现在做项目需要用到两路PWM波,但是开发板上两个PWM口都被占用了,所以想到用定时器来控制IO口,模拟实现PWM输出的功能。
   我是参考http://blog.csdn.net/gfocean/article/details/6245927这篇博客里的内容改动的。根据博客中的这篇文章,可以输出PWM波,但是在该博文中,在初始化部分即启动了定时器中断,所以在TINY6410一启动后,就输出了PWM波,这不是我想要的,所以根据这篇文章进行了修改,在ioctl函数中启动定时器,但是修改后,就不能输出PWM了。小弟新手,希望大侠能帮忙看看,不胜感激!代码如下:

#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 <asm/irq.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <asm/uaccess.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>

#include <mach/map.h>
#include <asm/ioctl.h>

#include <plat/gpio-cfg.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>

#include <mach/gpio-bank-c.h>   //IOPWM:GPC4

#include <linux/ioctl.h>
#include <linux/timer.h>
#include <linux/irq.h>
#define DEVICE_NAME "iopwm"
#define iopwm_irq IRQ_TIMER1

static struct semaphore lock1;

struct cdev *iopwm_cdev;
unsigned int counter=0;
unsigned int f=0;
//unsigned int pwm[]={110,55};
//unsigned int pwm=100;
//unsigned int duty=50;
unsigned long tmp;
static irqreturn_t iopwm_interrupt(int irq , void *dev_id)
{
if(irq !=IRQ_TIMER1){
printk("bad irq % d in timer0 /n", irq);
return -1;
}
// printk("good irq % d in timer0 /n", irq);

counter++;
if(counter ==1)
{
tmp = readl(S3C64XX_GPCDAT);
tmp |= (0x10);
writel(tmp, S3C64XX_GPCDAT);
}
if(counter ==2)
{
tmp = readl(S3C64XX_GPCDAT);
tmp &= ~(0x10);
writel(tmp, S3C64XX_GPCDAT);
counter=0;
}

return IRQ_RETVAL(IRQ_HANDLED);
}


void iopwm_timerinit(int freq)
{

unsigned long tcfg0,tcfg1,cstat;
struct clk *clk_p;
unsigned long pclk,tcnt;
//unsigned long freq=20000;

{
unsigned temp;
temp = readl(S3C64XX_GPCPUD);
temp = (temp & ~(0x3<<8))|(0x2<<8); //设置GPC4为上拉输出
writel(temp, S3C64XX_GPCPUD);

temp = readl(S3C64XX_GPCCON);
temp = (temp & ~(0xf<<16))|(0x1<<16); //23:20 0001
writel(temp, S3C64XX_GPCCON);

temp = readl(S3C64XX_GPCDAT);
temp |= (0x10);
writel(temp, S3C64XX_GPCDAT);
}

//tcon = __raw_readl(S3C_TCON);
tcfg1 = __raw_readl(S3C_TCFG1);
tcfg0 = __raw_readl(S3C_TCFG0);

//prescaler = 50
tcfg0 &= ~S3C_TCFG_PRESCALER0_MASK;
tcfg0 |= (50 - 1);

//mux = 1/16
tcfg1 &= ~S3C_TCFG1_MUX1_MASK;
tcfg1 |= S3C_TCFG1_MUX1_DIV16;

__raw_writel(tcfg1, S3C_TCFG1);
__raw_writel(tcfg0, S3C_TCFG0);


clk_p = clk_get(NULL, "pclk");
pclk = clk_get_rate(clk_p);
tcnt = (pclk/50/16)/freq;
printk("TCNT is %ld/n",tcnt);
__raw_writel(tcnt, S3C_TCNTB(1));
__raw_writel(0, S3C_TCMPB(1));

//¶šÊ±Æ÷1ÖжÏÊ&sup1;ÄÜ
cstat = __raw_readl(S3C_TINT_CSTAT);
//cstat &=~S3C_TINT_CSTAT_T0INTEN;
cstat |=0x2;
__raw_writel(cstat,S3C_TINT_CSTAT);
printk("init iopwm success!\n");
}

void start_timer(void)
{
    unsigned long tcon;
    tcon = __raw_readl(S3C_TCON);
    tcon &= ~0xf1<<4;
    tcon |= 0xb<<8; //disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, start timer 1
    __raw_writel(tcon, S3C_TCON);
    tcon &= ~0x2<<8; //clear manual update bit
    __raw_writel(tcon, S3C_TCON);
}
void stop_timer(void)
{
    unsigned long tcon;
    tcon = __raw_readl(S3C_TCON);
    tcon &= ~0xf1<<4;
    tcon |= 0xa<<8; //disable deadzone, auto-reload, inv-off, update TCNTB0&TCMPB0, stop timer 1
    __raw_writel(tcon, S3C_TCON);
}
static int iopwm_open(struct inode *inode, struct file *file)
{
    if (!down_trylock(&lock1))
        return 0;
    else
        return -EBUSY;
}

static int iopwm_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned int arg)
{

switch (cmd)
{
case 1:
    f=arg*2;
    iopwm_timerinit(f);
    stop_timer();
    break;
case 0:
    f=arg*2;
    iopwm_timerinit(f);
    start_timer();
    break;

default:
    return -EINVAL;
}
return 0;
}

static int iopwm_close(struct inode *inode,struct file *filp)
{
      free_irq(iopwm_irq,NULL);
    up(&lock1);
    return 0;
}

static struct file_operations iopwm_fops={
.owner=THIS_MODULE,
.open=iopwm_open,
.unlocked_ioctl=iopwm_ioctl,
.release=iopwm_close,
};

static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &iopwm_fops,
};

static int __init iopwm_init(void)
{
    int ret;
    init_MUTEX(&lock1);
    ret = misc_register(&misc);
    printk (DEVICE_NAME"\tinitialized\n");
    iopwm_timerinit(1000);
    stop_timer();
    ret=request_irq(iopwm_irq,iopwm_interrupt,IRQ_TYPE_LEVEL_HIGH, DEVICE_NAME, NULL);
    if(ret<0){
    printk("Register IOPWM failed!/n");
    return ret;
    }
        return ret;
}
static void __exit iopwm_exit(void)
{
    free_irq(iopwm_irq,NULL);
    misc_deregister(&misc);
}

module_init(iopwm_init);
module_exit(iopwm_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("gfpeak@gmail.com");
级别: 新手上路
UID: 5386
精华: 0
发帖: 33
金钱: 165 两
威望: 33 点
贡献值: 0 点
综合积分: 66 分
注册时间: 2009-04-21
最后登录: 2011-09-26
1楼  发表于: 2011-09-19 00:00
911gt3老大,mindee 斑竹,各位老大?麻烦帮忙看看啊
^很多问题的背后都是简单的原因......
级别: 荣誉会员
UID: 34780
精华: 0
发帖: 1219
金钱: 6230 两
威望: 1246 点
贡献值: 0 点
综合积分: 2438 分
注册时间: 2010-12-21
最后登录: 2017-09-18
2楼  发表于: 2011-09-19 12:43
你的ioctl可能根本没有被调用, ioctl命令不要用0/1/2这些, 你也可以加些打印确认一下是不是有被调用
级别: 新手上路
UID: 5386
精华: 0
发帖: 33
金钱: 165 两
威望: 33 点
贡献值: 0 点
综合积分: 66 分
注册时间: 2009-04-21
最后登录: 2011-09-26
3楼  发表于: 2011-09-20 16:06

 回 2楼(911gt3) 的帖子

问题解决了,IOCTL函数没执行,但是输出的PWM波抖动很厉害....不知道有什么办法避免或者减小类似抖动不?是不是定时器的问题?换个定时器可以不?好像定时器0和定时器1被用作蜂鸣器和一线触摸了。我输出频率只要在1000Hz左右就可以了
[ 此帖被风清扬csu在2011-09-20 20:48重新编辑 ]
级别: 侠客
UID: 54019
精华: 0
发帖: 76
金钱: 380 两
威望: 76 点
贡献值: 0 点
综合积分: 152 分
注册时间: 2011-08-22
最后登录: 2012-03-17
4楼  发表于: 2011-09-21 14:53
楼主 我也尝试使用这个定时器的中断
,但是irq中断的响应时间长短不好控制(因可能会有更高优先级中断发生)
中断频率高就会出问题

所以我希望能用FIQ来解决,这两天都在搜索有关FIQ的资料,但是没有能找到很多啊
有一个spi_s3c24xx.c
中有用到FIQ但是没看明白 如何才能在6410上将FIQ使用起来

也许我们可以探讨一下!!
QQ 853943935
级别: 侠客
UID: 54019
精华: 0
发帖: 76
金钱: 380 两
威望: 76 点
贡献值: 0 点
综合积分: 152 分
注册时间: 2011-08-22
最后登录: 2012-03-17
5楼  发表于: 2011-09-21 14:56
要么你在request_irq时 加上 IRQF_TIMER 试试

我现在需要产生一个4KHZ的中断  而且时间需要精确
用于检测外部信号
且不说时间是否精确了 ,现在经常导致中断被关闭没再打开
晕死。。。
[ 此帖被odanobunaga在2011-09-21 15:18重新编辑 ]
级别: 新手上路
UID: 5386
精华: 0
发帖: 33
金钱: 165 两
威望: 33 点
贡献值: 0 点
综合积分: 66 分
注册时间: 2009-04-21
最后登录: 2011-09-26
6楼  发表于: 2011-09-22 16:38

 回 5楼(odanobunaga) 的帖子

TINY6410还是做控制板好,如果要产生精确中断定时,还是得通过单片机实现,我就是通过定时器控制GPIO来产生PWM波,但产生的波形太不稳定,我现在考虑通过单片机的方式实现了。。。tiny6410做主机,单片机做从机。
级别: 侠客
UID: 54019
精华: 0
发帖: 76
金钱: 380 两
威望: 76 点
贡献值: 0 点
综合积分: 152 分
注册时间: 2011-08-22
最后登录: 2012-03-17
7楼  发表于: 2011-09-22 21:04
我很想使用FIQ实现,但苦于没有什么参考资料
如果使用FIQ,中断响应速度应当与裸奔无异

plat-s3c24xx下有一个fiq.c
但是我不太明白,其中set_fiq_handler将中断响应函数copy到0x1c
悲催啊 这个贴实现的是红外(6410+linux)
通过EINT中断,在信号迅速翻转的时候 中断频率应该也会有1K  
http://www.aiothome.net/read.php?tid-15097-fpage-0-toread--page-1.html
用的是IRQ 我就在想这样不是会很容易捕获不到么。。。
级别: 侠客
UID: 54019
精华: 0
发帖: 76
金钱: 380 两
威望: 76 点
贡献值: 0 点
综合积分: 152 分
注册时间: 2011-08-22
最后登录: 2012-03-17
8楼  发表于: 2011-09-22 23:18
楼主的PWM抖动大概有多大?
另外是否影响系统速度?
要是误差不大 我这个应用也可以用用。。。
级别: 新手上路
UID: 5386
精华: 0
发帖: 33
金钱: 165 两
威望: 33 点
贡献值: 0 点
综合积分: 66 分
注册时间: 2009-04-21
最后登录: 2011-09-26
9楼  发表于: 2011-09-23 15:37

 回 8楼(odanobunaga) 的帖子

1KHz的频率不算高,捕捉应该不成问题。在数字示波器上看,波形还可以,但是时常伴有抖动,对系统倒是几乎没影响。
  • «
  • 1
  • 2
  • »
  • Pages: 1/2     Go