学这个pwm真是非常曲则,首先是看s3c2440的datasheet,全英文的,而且还有硬件的时序图(很多是硬件的工作原理,和软件控制不相关)。看了很久加上网上看了资料才把这个pwm弄通。当然,其中牵扯到了几个知识,基本都弄通了。后面会通过blog一一列出来。
第一个知识点:I/O映射和内存映射所牵扯到的知识点,包括统一编址和独立编址,以及linux下怎么对这两种方式编程,以及这两种方式下怎么访问外设。
第二个知识点:映射到内存哪里?怎么映射?所以就涉及到linux内核的内存分布问题,顺便也分析了几个内核内存分配函数的区别。
这里对几个涉及到的知识点不展开来分析,后面会详细讲解下。这里只对pwm的工作原理和驱动分析下。
我最开始有写个简单的峰鸣器驱动,不能调频率的: s3c2440 杂项驱动实现蜂鸣器 里面用杂项设备驱动使峰鸣器工作,当然里面都是调用了s3c2440下提供的读写函数。这个对移植来说不是很好,我这篇blog是用通用的函数从底层一步步使pwm工作的。
首先是说下mini2440,我用的开发板是mini2440的,也就是s3c2440处理器。最开始我还不知道s3c2440是一款cpu,我在linux源码的 arch/arm平台中找到了s3c2440,然后我才找资料了解了下s3c2440处理器。其中主要的是了解s3c2440的I/O编址,s3c2440是统一编址其实就是内存映射了。
s3c2440提供了__raw_readl() 等函数来读写I/O,我在s3c2440系统自带的管脚宏和函数 blog也分析过这些函数的源码(好像有点乱),我这里不用s3c2440提供的系统I/O操作函数,自己映射地址,用通用的ioread()系列函数来操作端口;
首先是pwm的工作原理,这个可以看下我转载的一篇blog,简明扼要的讲清楚了pwm的工作原理: pwm的工作原理;当然也可以看看芯片的datasheet,总之看懂了就感觉很容易了。下面直接上代码:
regAddr.h代码
#ifndef __REG_ADDR_H__
#define __REG_ADDR_H_
/*
#define GPBCON ((volatile unsigned long*)0x56000010)
#define GPBDAT ((volatile unsigned long*)0x56000014)
#define TCFG0 ((volatile unsigned long *)0x51000000)
#define TCFG1 ((volatile unsigned long *)0x51000004)
#define TCON ((volatile unsigned long *)0x51000008)
#define TCNTB0 ((volatile unsigned long *)0x5100000c)
#define TCMPB0 ((volatile unsigned long *)0x51000010)
#define TCNTO0 ((volatile unsigned long *)0x51000014)
*/
#define GPBCON ((unsigned long)0x56000010)
#define GPBDAT ((unsigned long)0x56000014)
#define TCFG0 ((unsigned long)0x51000000)
#define TCFG1 ((unsigned long)0x51000004)
#define TCON ((unsigned long)0x51000008)
#define TCNTB0 ((unsigned long)0x5100000c)
#define TC