一、PWM原理
1.有源蜂鳴器和無源蜂鳴器的概念
- 有源蜂鳴器高電平就響,無源蜂鳴器需要PWM波才響。
2.PWM脈沖波
- PWM = 定時器 + 定時器中斷(重載) + IO輸出(翻轉)
3.分析原理圖
- GPIO-GPD0_0
- XpwmTOUT0定時器0,同上面IO口
4.pwm定時器上的資源
- 5個32位定時器
- 定時器會產生內部中斷
- 定時器0,1,2,3可以通過編程實現PWM,定時器4有內部計時而沒有輸出
- 定時器都有各自對應的分頻區
- TCNTBn--,TCNTBn=TCMPBn
5.分頻器 圖形24-2
XpwmTOUT0 = PRESCALER0 + MUX + TCMPB0 + TCNTB0
6.例子分析
- 開啟自動重載
- 設置TCNTBn和TCMPBn寄存器
- 手動設置
- 設置自動翻轉,更新TCNTBn和TCMPBn寄存器
- 再次設置TCNTBn和TCMPBn寄存器(雙緩沖再次更新)
- 定時器開啟
- TCNTBn--,TCNTBn=TCMPBn,翻轉
- TCNTn=0,產生中斷
- 自動重載
- TCNTBn--,TCNTBn=TCMPBn,翻轉
- TCNTn=0,產生中斷
- 自動重載,產生中斷。然后關閉自動重載
- TCNTBn--,TCNTBn=TCMPBn,翻轉
- TCNTn=0,關閉自動重載,不再產生中斷
- 自動重載關閉,停止。
7.簡單用法
- GPIO-GPD0_0設置為PWM輸出GPD0CON[0] = 0x02
- TCFG0 預分頻(1-255)
- TCFG1分頻(1,2,4,8,16)
- 設置占空比:TCMPB0 和 TCNTB0 (TCMPB0<TCNTB0)
- 設置自動重載,開啟定時器,自動翻轉等。TCON 寄存器
二、pwm的ioremap
1.配置步驟
- GPD0_0設置為pwm輸出GPD0CON[0]=0x02
- TCFG0預分頻(1-255)
- TCFG1分頻(1.2.4.8.16)
- 設置占空比:TCMPB0和TCNTB0(TCMPB0<TCNTB0)
- 設置自動重載,開啟定時器等
- TCON寄存器
2.寫代碼
beep驅動

#include <linux/init.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/miscdevice.h> #include <linux/fs.h> #include <linux/gpio.h> #include <plat/gpio-cfg.h> #include <mach/gpio.h> #include <mach/gpio-exynos4.h> #include <asm/io.h> #define DRIVER_NAME "PWM" #define DEVICE_NAME "PWM" MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("TOPEET"); struct pwm_addr{ 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; //sotre virtual address and physical address volatile unsigned long virt_addr, virt_addr_gpio, phys_addr, phys_addr_gpio; volatile unsigned long *GPD0CON, *GPD0PUD; static void addr_init(void) { phys_addr = 0x139D0000; //(PWM Base Address) virt_addr = (unsigned long)ioremap(phys_addr, 0x48); //maybe 0x32 not enough PWM = (struct pwm_addr*)(virt_addr + 0x00); phys_addr_gpio = 0x11400000+0xA0; //GPD0 virt_addr_gpio = (unsigned long)ioremap(phys_addr_gpio, 0x24); GPD0CON = (unsigned long*)(virt_addr_gpio + 0x00); GPD0PUD = (unsigned long*)(virt_addr_gpio + 0x00A8 - 0x00A0); } static void PWM_Init(void) { addr_init(); /* config gpio */ *GPD0CON &= ~(0xf); *GPD0CON |= 0x2; //TOUT_0 *GPD0PUD &= ~(0x03); //disable pull-up/pull-down //prescaler0 0-254 + 1 (*PWM).TCFG0 = (((*PWM).TCFG0&(~(0xff)))|(0xf9)); //prescaler1 1.2.4.8.16 (*PWM).TCFG1 = ((*PWM).TCFG1&(~(0xf)))|(0x2); //set duty cycle (*PWM).TCMPB0 = 50; (*PWM).TCNTB0 = 100; //set auto-reload,timer on (*PWM).TCON = ((*PWM).TCON & (~(0xf))) | (0x1) | (0x2); } static void beep_on(void) { (*PWM).TCON = ((*PWM).TCON & (~(0xf)))|(0x1)|(0x8); } static void beep_off(void) { (*PWM).TCON = ((*PWM).TCON & (~(0xf)))|(0x0); //After timer stop,GPIO = 0; *GPD0CON = (*GPD0CON & (~(0xf)))|(0x0); } static int iTop4412_PWM_init(void) { PWM_Init(); beep_on(); return 0; } static void iTop4412_PWM_exit(void) { beep_off(); } module_init(iTop4412_PWM_init); module_exit(iTop4412_PWM_exit);
測試結果:
[root@iTOP-4412]# insmod pwm.ko [root@iTOP-4412]# rmmod pwm
加載后蜂鳴器開啟,不過頻率不對
總結:根據邏輯框圖中的寄存器名字,在PDF中搜索然后依次配置它。找到一個后,可以往下翻。類似的可能會在一起