[OK210開發(fā)板體驗]功能篇(5)Linux字符驅(qū)動之PWM蜂鳴器驅(qū)動
[OK210開發(fā)板體驗]入門篇(2):板載資源
[OK210開發(fā)板體驗]入門篇(3):開發(fā)環(huán)境(軟件安裝,開發(fā)環(huán)境,燒寫系統(tǒng))
[OK210開發(fā)板體驗]入門篇(4):編程入門(NFS登錄,驅(qū)動入門)
[OK210開發(fā)板體驗]功能篇(1):Linux字符驅(qū)動之Led
[OK210開發(fā)板體驗]功能篇(2):Linux字符驅(qū)動之Key按鍵
[OK210開發(fā)板體驗]功能篇(3):Linux Input子系統(tǒng)之Key按鍵
[OK210開發(fā)板體驗]功能篇(4):Linux字符驅(qū)動之DS18B20
今天是功能篇的第五篇:Linux字符驅(qū)動之PWM蜂鳴器,本節(jié)主要分3部分:硬件分析,軟件基礎(chǔ),驅(qū)動編程。
一、硬件分析
在[OK210開發(fā)板體驗]的第二篇:板載資源中,簡單分析了蜂鳴器的功能和作用。其實對蜂鳴器的操作,主要是通過S5PV210的PWM來實現(xiàn)的,因為在OK210上,連接的是一個無源蜂鳴器,必須通過外部的驅(qū)動信號,才能控制其的“鳴叫”。
首先從OK210的底板原理圖中可知,OK210開發(fā)板上的DS18B20連接通過一個三極管組成的放大電路連接到了核心板的XpwmTOUT[0]引腳上,如下圖所示:
所以,我們要對蜂鳴器進(jìn)行操作,就是通過對XpwmTOUT[0]引腳的設(shè)置,即將其設(shè)置為TOUT_0功能,通過配置PWM的波形來實現(xiàn)蜂鳴器的鳴叫。
二、軟件基礎(chǔ)
如上所述,無源蜂鳴器沒有自帶震蕩電路,必須外部提供2-5Khz左右的方波,才能驅(qū)動其發(fā)聲,而要想產(chǎn)生方波,就會用到S5PV210的PWM模塊。
S5PV210共有5個32bit的PWM定時器,其中定時器0、1、2、3有PWM功能,定時器4沒有輸出引腳。這些定時器都可產(chǎn)生中斷。每個定時器可選擇輸入時鐘為PCLK或SCLK_PWM。對PWM的操作,主要通過幾個寄存器來完成,操作步驟如下:
1、設(shè)置TCFG0寄存器:配置定時器的一級分頻值
2、設(shè)置TCFG1寄存器:配置定時器的二級分頻值
3、設(shè)置TCNTBn寄存器:遞減計數(shù)器緩沖寄存器
4、設(shè)置TCMPBn寄存器:比較緩沖寄存器
5、設(shè)置TCON寄存器:
(1)手動更新on(執(zhí)行后,CPU會把TCNTBn的值加載到遞減計數(shù)器中)
(2)手動更新off、自動重載、啟動定時器
不過在Linux內(nèi)核中,三星公司和飛凌公司已經(jīng)為我們配置好了對這些PWM模塊的使用,具體參見源碼目錄下 arch/arm/plat-s3c/的pwm.c文件,在驅(qū)動編程中,主要使用pwm_config()、pwm_enable()、pwm_disable(pwm4buzzer)這三個函數(shù)。另外,也可參見另一篇博文【S5PV210 PWM】。
三 驅(qū)動編程
有圖有真相,按照如下運行后,即可聽到“鳴叫”。
- 
					#include <linux/module.h>
 - 
					#include <linux/kernel.h>
 - 
					#include <linux/init.h>
 - 
					#include <linux/platform_device.h>
 - 
					#include <linux/fb.h>
 - 
					#include <linux/backlight.h>
 - 
					#include <linux/err.h>
 - 
					#include <linux/pwm.h>
 - 
					#include <linux/slab.h>
 - 
					#include <linux/miscdevice.h>
 - 
					#include <linux/delay.h>
 - 
					#include <mach/gpio.h>
 - 
					#include <mach/regs-gpio.h>
 - 
					#include <plat/gpio-cfg.h>
 - 
					
 - 
					#define DEVICE_NAME                                "pwm"
 - 
					#define PWM_IOCTL_SET_FREQ                1
 - 
					#define PWM_IOCTL_STOP                        0
 - 
					#define NS_IN_1HZ                                (1000000000UL)
 - 
					#define BUZZER_PWM_ID                        0
 - 
					#define BUZZER_PMW_GPIO                        S5PV210_GPD0(0)
 - 
					
 - 
					static struct pwm_device *pwm4buzzer;
 - 
					static struct semaphore lock;
 - 
					
 - 
					static void pwm_set_freq(unsigned long freq) {
 - 
					        int period_ns = NS_IN_1HZ / freq;
 - 
					        pwm_config(pwm4buzzer, period_ns / 2, period_ns);
 - 
					        pwm_enable(pwm4buzzer);
 - 
					}
 - 
					
 - 
					static void pwm_stop(void) {
 - 
					        pwm_config(pwm4buzzer, 0, NS_IN_1HZ / 100);
 - 
					        pwm_disable(pwm4buzzer);
 - 
					}
 - 
					
 - 
					
 - 
					static int my_pwm_open(struct inode *inode, struct file *file) {
 - 
					 , ; &, nbsp;     if (!down_trylock(&lock))
 - 
					                return 0;
 - 
					        else
 - 
					                return -EBUSY;
 - 
					}
 - 
					
 - 
					static int my_pwm_close(struct inode *inode, struct file *file) {
 - 
					        up(&lock);
 - 
					        return 0;
 - 
					}
 - 
					
 - 
					static long my_pwm_ioctl(struct file *filep, unsigned int cmd,
 - 
					                unsigned long arg)
 - 
					{
 - 
					        switch (cmd) {
 - 
					                case PWM_IOCTL_SET_FREQ:
 - 
					                        if (arg == 0)
 - 
					                                return -EINVAL;
 - 
					                        pwm_set_freq(arg);
 - 
					                        break;
 - 
					
 - 
					                case PWM_IOCTL_STOP:
 - 
					                default:
 - 
					                        pwm_stop();
 - 
					                        break;
 - 
					        }
 - 
					
 - 
					        return 0;
 - 
					}
 - 
					
 - 
					
 - 
					static struct file_operations my_pwm_ops = {
 - 
					        .owner                        = THIS_MODULE,
 - 
					        .open                        = my_pwm_open,
 - 
					        .release                = my_pwm_close,
 - 
					        .unlocked_ioctl        = my_pwm_ioctl,
 - 
					};
 - 
					
 - 
					static struct miscdevice my_misc_dev = {
 - 
					        .minor = MISC_DYNAMIC_MINOR,
 - 
					        .name = DEVICE_NAME,
 - 
					        .fops = &my_pwm_ops,
 - 
					};
 - 
					
 - 
					static int __init my_pwm_dev_init(void) {
 - 
					        int ret;
 - 
					    printk(DEVICE_NAME " my_pwm_dev_init\n");
 - 
					        ret = gpio_request(BUZZER_PMW_GPIO, DEVICE_NAME);
 - 
					        if (ret) {
 - 
					                printk("request GPIO %d for pwm failed\n", BUZZER_PMW_GPIO);
 - 
					                return ret;
 - 
					        }
 - 
					
 - 
					        gpio_set_value(BUZZER_PMW_GPIO, 0);
 - 
					        s3c_gpio_cfgpin(BUZZER_PMW_GPIO, S3C_GPIO_OUTPUT);
 - 
					        pwm4buzzer = pwm_request(BUZZER_PWM_ID, DEVICE_NAME);
 - 
					        if (IS_ERR(pwm4buzzer)) {
 - 
					                printk("request pwm %d for %s failed\n", BUZZER_PWM_ID, DEVICE_NAME);
 - 
					                return -ENODEV;
 - 
					        }
 - 
					
 - 
					        pwm_stop();
 - 
					        s3c_gpio_cfgpin(BUZZER_PMW_GPIO, S3C_GPIO_SFN(2));
 - 
					        gpio_free(BUZZER_PMW_GPIO);
 - 
					        init_MUTEX(&lock);
 - 
					        ret = misc_register(&my_misc_dev);
 - 
					        return ret;
 - 
					}
 - 
					
 - 
					static void __exit my_pwm_dev_exit(void) {
 - 
					    printk(DEVICE_NAME " my_pwm_dev_exit\n");
 - 
					        pwm_stop();
 - 
					        misc_deregister(&my_misc_dev);
 - 
					}
 - 
					
 - 
					module_init(my_pwm_dev_init);
 - 
					module_exit(my_pwm_dev_exit);
 - 
					
 - 
					MODULE_LICENSE("GPL");
 - 
					MODULE_AUTHOR("gjianw217@163.com");
 - MODULE_DESCRIPTION("PWM Driver");
 
- 
					#include <stdio.h>
 - 
					#include <unistd.h>
 - 
					#include <stdlib.h>
 - 
					#include <sys/types.h>
 - 
					#include <sys/stat.h>
 - 
					#include <sys/ioctl.h>
 - 
					#include <fcntl.h>
 - 
					#define PWM_IOCTL_SET_FREQ 1
 - 
					#define PWM_IOCTL_STOP 0
 - 
					
 - 
					int main(int argc ,char* argv[])
 - 
					{
 - 
					   int m_fd=0;//
 - 
					   m_fd = open("/dev/pwm", O_RDONLY);
 - 
					   int freq=1000;
 - 
					   if(argc>1)
 - 
					   freq=atoi(argv[1]);
 - 
					   printf("%d \t\t",freq);
 - 
					   ioctl(m_fd, PWM_IOCTL_STOP);
 - 
					   ioctl(m_fd, PWM_IOCTL_SET_FREQ,freq);
 - 
					   getchar();
 - 
					   ioctl(m_fd, PWM_IOCTL_STOP);
 - 
					   close(m_fd);
 - 
					   return 0;
 - }
 
- 
					#pwm Makefile
 - 
					ARCH=arm
 - 
					CROSS_COMPILE=/home/ok210/arm-2009q3/bin/arm-none-linux-gnueabi-
 - 
					APP_COMPILE=/home/ok210/arm-2009q3/bin/arm-none-linux-gnueabi-
 - 
					#obj-m := app-drv.o
 - 
					obj-m := pwm-drv.o
 - 
					#KDIR := /path/to/kernel/linux/
 - 
					KDIR := /home/ok210/android-kernel-samsung-dev/
 - 
					PWD := $(shell pwd)
 - 
					default:
 - 
					        make -C $(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules
 - 
					app:pwm-app.c
 - 
					        $(APP_COMPILE)gcc -o app pwm-app.c
 - 
					clean:
 - 
					        $(MAKE) -C $(KDIR) M=$(PWD) clean
 
相關(guān)產(chǎn)品 >
- 
                
OKMX6UL-C開發(fā)板
飛凌嵌入式專注imx6系列imx6ul開發(fā)板、飛思卡爾imx6ul核心板等ARM嵌入式核心控制系統(tǒng)研發(fā)、設(shè)計和生產(chǎn),i.mx6UL系列產(chǎn)品現(xiàn)已暢銷全國,作為恩智浦imx6ul,imx6ul開發(fā)板,i.mx6提供者,飛凌嵌入式提供基于iMX6 iMX6UL解決方案定制。
了解詳情
 - 
                
OKMX6ULL-C開發(fā)板
40*29mm,雙網(wǎng)雙CAN,8路串口| i.MX6ULL開發(fā)板是基于NXP i.MX6ULL設(shè)計開發(fā)的的一款Linux開發(fā)板 ,主頻800MHz,體積小,其核心板僅40*29mm,采用板對板連接器,適應(yīng)場景豐富。 了解詳情
 

