查看数据手册
使用的GPIO
原理图
核心板
可以看到使用了GPD0_0,需要用到GPD0CON(选择定时器),GPD0PUD(禁止上下拉)。
pwm定时器
4412(scp封装)有5个32位的定时器,其中0、1、2、3可以用来编程,其中0、1共用第一个8位预分频器,2、3、4共用第二个8位预分频器,都可输出2,4,8,16的频率。
设置定时器(占空比)
(1)需要用到TCMPBn(用于比较),TCNTBn(初值) 寄存器,设置好TCMPBn,TCNTBn的值后,TCON开启定时器。(其实只要记住TCNTBn>TCMPBn即可)。
(2)TCMPBn值传入TCMPn ,TCNTBn值会传入TCNTn。
(3)TCNTn开始做减1的操作,当TCNTn等于TCMPn,输出电平翻转,当TCNTn减为0,输出电平再次翻转,并触发定时器中断。
(4)若TCON开启了自动重载,那会重复(2),(3)操作,再次开启下一次计时操作。
代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <mach/gpio.h>
#include <plat/gpio-cfg.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <mach/regs-gpio.h>
#include <asm/io.h>
#include <linux/regulator/consumer.h>
#include <linux/delay.h>
struct PWM_union
{
unsigned int TCFG0;
unsigned int TCFG1;
unsigned int TCON;
unsigned int TCNTB0;
unsigned int TCMPB0; //TCMPB0 < TCNTB0
};
struct PWM_union *Pwm;
//gpio和pwm定时器虚拟地址和物理地址
volatile unsigned long virt_pwm_addr,virt_gpio_addr,phy_pwm_addr,phy_gpio_addr;
//gpio的寄存器
volatile unsigned long *GPD0CON,*GPD0PUD;
void addr_init(void)
{
printk(KERN_EMERG "addr init");
phy_pwm_addr=0x139D0000;
phy_gpio_addr=0x11400000;
virt_pwm_addr = (unsigned long)ioremap(phy_pwm_addr,0x32);
Pwm = (unsigned int*)(virt_pwm_addr+0x00);
virt_gpio_addr = (unsigned long)ioremap(phy_gpio_addr,0x10);
GPD0CON = (unsigned long*)(virt_gpio_addr+0x00A0);
GPD0PUD = (unsigned long*)(virt_gpio_addr+0x00A8);
}
void pwm_init(void)
{
addr_init();
*GPD0CON &= ~(0xf);
*GPD0CON |= 0x2; //定时器0 TOUT_0
*GPD0PUD &= ~(0xf); //不要上下拉
//预分频
Pwm->TCFG0 &= ~(0xff);
Pwm->TCFG0 |= 0xf9; //这个值是1到255即(0x01-0xff);
//分频
Pwm->TCFG1 &= ~(0xf);
Pwm->TCFG1 |= 0x2;
//占空比
Pwm->TCMPB0 = 50;
Pwm->TCNTB0 = 100;
//手动加载 开启定时器
Pwm->TCON &= ~(0xf);
//定时器
Pwm->TCON |= 0x1;
//手动加载
Pwm->TCON |= 0x2;
}
static void beep_on(void)
{
//开启自动加载
Pwm->TCON &= ~(0xf);
Pwm->TCON |= 0x1;
Pwm->TCON |= 0x8;
}
static void beep_off(void)
{
//关闭定时器
Pwm->TCON &= ~(0xf);
Pwm->TCON |= 0x0;
//gpio
*GPD0CON &= ~(0xf);
*GPD0CON |= 0x0;
}
static int BEEP_PWM_init(void)
{
printk(KERN_EMERG "BEEP_PWM_init\n");
pwm_init();
beep_on();
return 0;
}
static void BEEP_PWM_exit(void)
{
printk(KERN_EMERG "BEEP_PWM_exit\n");
beep_off();
}
module_init(BEEP_PWM_init);
module_exit(BEEP_PWM_exit);//初始化函数
MODULE_LICENSE("Dual_BSD/GPL"); //没有版本限制,什么版本都能运行
MODULE_AUTHOR("LIN"); //作者
本人也是新手有什么错误,请麻烦指出来。