iTop-4412的Linux驱动之PWM的完整整理笔记及分析,不会让你失望的

写这篇文章之前呢,我算了一下,我已经欠下了13片文章,我的妈呀,泪奔啊!!!不过呢我后边一定会都补回来,尽快吧。还有就是我发现讯为在后期的一些视频里讲解的不是太详细,可能这个就是师傅领进门修行在个人,设计到一些原理呢,就告诉我们照着这个程序弄,但是具体的没有说太明白,比如这篇文章要讲的PWM,这部分设计到CPU内部时钟以及是如何利用定时器和定时中断请求来实现的,没有细说,我在看完这个视频后脑海中框架基本为零,就知道照着提供的代码写就完了,但是往往在后期自己做一些东西的时候还是需要去了解到底这个东西是什么原理,我们要怎么去利用它。讯为的老师可能也是认为嵌入式行业不光有三星的芯片,还有其它厂家的芯片,如果说的太细,可能对人产生一个固有印象,影响我们后边对其它芯片的研发;以上纯属个人见解,有什么问题可以评论。下面就进入主题:
首先呢说一下PWM是什么;其实PWM是一种脉冲宽度调制是一种模拟控制方式,说白了就是输出脉宽和占空比可调的方波;再多了就不说了,大家可以上百度搜一下,写的都很详细。比如说脉宽时间,占空比是怎么一会儿事儿,大家还是要了解一下;
一:iTop4412产生PWM的思路
我看了讯为的视频教程,对这部分进行优化完整一下;其实这部分的视频还算完整,适合大家初学,简单的实现PWM就可以了,如果说要再深入的话,那就是“调制”。所谓“调制”就是设置想要的脉宽和占空比的PWM输出,这就需要大家去看ITop4412芯片的手册,了解时钟的频率;
先看一下iTop4412 SCP的手册,关于PWM那一章,应该是在第14章:
首先呢要了解一下这部分的作用机理,我自己画了一个简图,供大家参考,如果有问题可以评论,我再修改:
在这里插入图片描述
看了上边这个图,应该就能理解它的原理了。这里要提的是为什么高电平时80T呢,应为在第二次加载的时候需要一个T的时间,所以总共80T,上边的值只是一个例子;下面分为三个部分去写:
㈠定时器+定时器中断(重载)+GPIO翻转实现PWM
为了实现PWM的输出需要以上3个部分来配合;具体需要设置定时器预分频、分频、开启定时器、手动设置一次定时器重载、自动定时器重载设置、配置IO(IO的初始化)等:
首先要对定时器以及用到的输出IO进行初始化,初始化定时器主要是设置预分频、分频、占空比(也就是上图中的TCNTBn和TCMPBn)、手动加载和开启定时器;初始化IO主要是对IO的输入输出状态进行设置,用到的寄存器有GPD0CON(配置寄存器)、GPD0PUD(上下拉设置寄存器)、GPD0DAT(输入输出缓冲寄存器);
㈡用的寄存器最好自己看看手册,这里就不从手册粘贴复制了,主要是把原理,还有思路搞清楚。然后看看代码就一目了然了;这里还有一个需要做的事儿是编译内核前把make menuconfig中的相应项取消编译进内核,具体是看下图:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
㈢用到一些头文件:

#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/gpio-bank.h>
#include <mach/regs-gpio.h>
#include <asm/io.h>
#include <linux/regulator/consumer.h>
//#include "gps.h"
#include <linux/delay.h>

二:ioremap的方式输出PWM程序:

#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/gpio-bank.h>
#include <mach/regs-gpio.h>
#include <asm/io.h>
#include <linux/regulator/consumer.h>
//#include "gps.h"
#include <linux/delay.h>

/*声明是开源的,没有内核版本限制*/
MODULE_LICENSE("Dual BSD/GPL");
/*声明作者*/
MODULE_AUTHOR("iTOPEET_dz");

/*定时器所有寄存器的结构体*/
struct {  
    unsigned int    TCFG0;  
    unsigned int    TCFG1;  
    unsigned int    TCON;  
    unsigned int    TCNTB0;  
    unsigned int    TCMPB0;  
    unsigned int    TCNTO0;  
    unsigned int    TCNTB1;  
    unsigned int    TCMPB1;  
    unsigned int    TCNTO1;  
    unsigned int    TCNTB2;  
    unsigned int    TCMPB2;  
    unsigned int    TCNTO2;  
    unsigned int    TCNTB3;  
    unsigned int    TCMPB3;  
    unsigned int    TCNTO3;  
    unsigned int    TCNTB4;  
    unsigned int    TCNTO4;  
    unsigned int    TINT_CSTAT;  
}*PWM;

//用于存放虚拟地址和物理地址
//第一个为虚拟地址,第二个是物理地址
volatile unsigned long 	virt_addr_PWM,phys_addr_PWM,	//PWM的虚拟地址和物理地址
						virt_addr_GPIO,phys_addr_GPIO;	//GPIO的虚拟地址和物理地址
//用户存放三个寄存器的地址
volatile unsigned long *GPD0CON,*GPD0PUD,*GPD0DAT;

static void addr_init(void)
{
	/*初始化PWM*/
	phys_addr_PWM = 0x139D0000;
	//在内核中申请一个虚拟地址空间
	virt_addr_PWM = (unsigned long) ioremap(phys_addr_PWM,0x32);//物理地址映射到虚拟地址
	//指定需要操作的寄存器
	PWM = (unsigned long *) (virt_addr_PWM+0x00);
	
	/*初始化GPIO*/
	phys_addr_GPIO = 0x11400000+0xA0;
	//在内核中申请一个虚拟地址空间
	virt_addr_GPIO = (unsigned long) ioremap(phys_addr_GPIO,0x10);
	//指定需要操作的寄存器
	GPD0CON = (unsigned long *) (virt_addr_GPIO+0x00);
	GPD0PUD = (unsigned long *) (virt_addr_GPIO+0x08);
	GPD0DAT = (unsigned long *) (virt_addr_GPIO+0x04);//设置GPIO电平
}
/*定时器和GPIO初始化*/
static void pwm_init(void)
{
	addr_init();
	*GPD0CON = (*GPD0CON&(~(0xf)))|(0x2);//TOUT_0
	*GPD0PUD = *GPD0PUD&(~(0xf));//浮空
	
	//预分频1~254 + 1
	(*PWM).TCFG0 = ((*PWM).TCFG0&(~(0xff))) | (0xf9);//250分频
	//分频1、2、4、8、16
	(*PWM).TCFG1 = ((*PWM).TCFG1&(~(0xf))) | (0x8);//16分频
	//占空比、50%、脉宽和频率的话自己算一下
	(*PWM).TCMPB0 = 249999;
	(*PWM).TCNTB0 = 250000;
	//设置手动加载,开启定时器
	(*PWM).TCON = ((*PWM).TCON&(~(0xf))) | (0x3);
}
/*开始自动重载,开启定时器函数*/
static void beep_on(void)
{
	//开始自动重载,开启定时器
	(*PWM).TCON = ((*PWM).TCON&(~(0xf))) | (0x1) | (0x8);
}
/*功能初始化函数*/
static int iTop4412_PWM_init(void)
{
	pwm_init();//定时器和GPIO初始化
	beep_on();//开始自动重载,开启定时器
	return 0;
}
/*关闭定时器和GPIO重置*/
static void beep_off(void)
{
	//关闭定时器
	(*PWM).TCON = ((*PWM).TCON&(~(0xf)))|(0x0);
	//定时器结束后,输出的是高电平还是低电平
	*GPD0CON = (*GPD0CON&(~(0xf)))|(0x1);//OUTPUT
	*GPD0DAT = (*GPD0DAT&(~(0x1)))|(0x0);//拉低
}
/*功能卸载函数*/
static void iTop4412_PWM_exit(void)
{
	beep_off();//关闭定时器和GPIO重置

}
/*初始化函数*/
module_init(iTop4412_PWM_init);//iTop4412_PWM_init自己定义
/*卸载函数*/
module_exit(iTop4412_PWM_exit);//iTop4412_PWM_init自己定义

下一篇文章就是,查询的方式获取按键值,敬请关注!!

又到了这个环节,请欣赏我的鸡汤时刻!一GO我嘞GOGO!!!!
送给阅读过这篇文章的人:你要小心你的思想,因为它会变成你的语言;你要小心你的语言,因为它会变成你的行动;你要小心你的行动,因为它会变成你的习惯;你要小心你的习惯,因为它会成为你的命运;心态决定命运,思想决定你的出路!
下篇文章见。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值