在SMDK210.C中添加如下beeper_device 結構體
static struct platform_device beeper_device = {
.name = 'pwm_buzzer',
.id = 1,
.dev = {
.parent = &s3c_device_timer[1].dev, //PWM1是定時器1
.platform_data= 0,
},
};
然后在smdkv210_devices中添加該結構體
static struct platform_device *smdkv210_devices[] __initdata = {
&s3c_device_fb,
&s3c_device_adc,
&s3c_device_cfcon,
&s3c_device_hsmmc0,
&s3c_device_hsmmc1,
&s3c_device_hsmmc2,
&s3c_device_hsmmc3,
&s3c_device_i2c0,
&s3c_device_i2c1,
&s3c_device_i2c2,
&s3c_device_timer[1], //add
&beeper_device, //add
}
一、硬件分析
對蜂鳴器的操作,主要是通過S5PV210的PWM來實現的,因為在OK210上,連接的是一個無源蜂鳴器,必須通過外部的驅動信號,才能控制其的“鳴叫”。
首先從OK210的底板原理圖中可知,OK210開發板上的蜂鳴器連接通過一個三極管組成的放大電路連接到了核心板的XpwmTOUT[1]引腳上,如下圖所示:
而XpwmTOUT[1]引腳由S5PV210用戶手冊,可知,該引腳位于GPD0[1]引腳上,默認為GPI,即當作通用輸入端口使用,如下圖所示:
但的第一功能名為TOUT_0,繼續查閱,可知,該功能可作為PWM輸出使用,如下所示,
所以,我們要對蜂鳴器進行操作,就是通過對XpwmTOUT[1]引腳的設置,即將其設置為TOUT_0功能,通過配置PWM的波形來實現蜂鳴器的鳴叫。
二、軟件基礎
如上所述,無源蜂鳴器沒有自帶震蕩電路,必須外部提供2-5Khz左右的方波,才能驅動其發聲,而要想產生方波,就會用到S5PV210的PWM模塊。
S5PV210共有5個32bit的PWM定時器,其中定時器0、1、2、3有PWM功能,定時器4沒有輸出引腳。這些定時器都可產生中斷。每個定時器可選擇輸入時鐘為PCLK或SCLK_PWM。對PWM的操作,主要通過幾個寄存器來完成,操作步驟如下:
1、設置TCFG0寄存器:配置定時器的一級分頻值
2、設置TCFG1寄存器:配置定時器的二級分頻值
3、設置TCNTBn寄存器:遞減計數器緩沖寄存器
4、設置TCMPBn寄存器:比較緩沖寄存器
5、設置TCON寄存器:
(1)手動更新on(執行后,CPU會把TCNTBn的值加載到遞減計數器中)
(2)手動更新off、自動重載、啟動定時器
不過在Linux內核中,三星公司和飛凌公司已經為我們配置好了對這些PWM模塊的使用,具體參見源碼目錄下 arch/arm/plat-s3c/的pwm.c文件,在驅動編程中,主要使用pwm_config()、pwm_enable()、pwm_disable(pwm4buzzer)這三個函數。另外,也可參見另一篇博文【S5PV210 PWM】。
三 驅動編程
有圖有真相,按照如下運行后,即可聽到“鳴叫”。
1 驅動程序
#include #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEVICE_NAME 'pwm_buzzer' #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) { 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_initn'); ret = gpio_request(BUZZER_PMW_GPIO, DEVICE_NAME); if (ret) { printk('request GPIO %d for pwm failedn', 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 failedn', 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_exitn'); 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'); 2 應用程序 #include #include #include #include #include #include #include #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 tt',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; } 3 Makefile文件 #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
上一篇:S5PV210之UBOOT-2011.06啟動過程解析
下一篇:MPlayer在ARM上的移植(S5PV210開發板)
推薦閱讀最新更新時間:2025-06-08 12:35

設計資源 培訓 開發板 精華推薦
- AM1DR-2403SH30Z 3.3V 1 瓦 DC-DC 轉換器的典型應用
- 使用 Analog Devices 的 LTC3728LIGN 的參考設計
- 用于開/關控制應用的 AM2G-4818SZ 18V 2 瓦 DC-DC 轉換器的典型應用
- ToubanPCB
- 使用 Infineon Technologies AG 的 TDA 16846-2 的參考設計
- ADA4610-2ARZ-R7 正峰值檢波器運算放大器的典型應用電路
- LT6656ACS6-2.5、2.5V 精密電流和升壓電壓基準的典型應用
- 使用 Omron 的 S8VS-09024BS 的參考設計
- 使用具有 PowerPath 和 2A 輸入限制的 LTC4162EUFD-L41 9V 至 35V、2 節、3.2A 充電器的典型應用
- VL53L0X測距模塊