|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本文档介绍了在 iTOP-4418 开发板上用 PWM 控制蜂鸣器输出的测试历程,基于 QtE 系统。4418mcu 共提供了 5 路 PWM 输出,其中一路未引出,所以共有 4 路可用的 PWM 输出。
V+ U2 G3 g' `8 |注意:本文档中提供的例程,没有注册设备和驱动,只是在驱动入口和出口函数中进行了配置。如果用户需要生成设备节点,则需要自行添加剩余部分,这部分可以参考 GPIO 操作的文档。( E1 y! G) ]& c) ~3 P8 ?
1 配置 IO
9 g' M; g! Y! Y/ c% g) R打开底板电路图,搜索“beep”,可以看到 beep 的网络名为“MCU_ISO7816_CLK”,如下图所示。
0 N& Z7 Q1 s4 l0 j6 e5 @) n![]()
( a2 P+ q* d: j# i( T在核心板原理图,搜索该关键词“MCU_ISO7816_CLK”,可见其对应 PWM2,如下图所示。9 y" H2 e# A+ q4 A6 F
; _7 j: [5 S6 K$ Z. |
所以,接下来我们便对 PWM2 进行操作。在下面的操作之前,我们需要配置内核,取消内核中 buzzer 的驱动,解除该驱动对蜂鸣器的占用,其目录如下图所示。, Z9 h) t( R5 d& J# P/ k9 f
; T& F7 T# w$ _. f/ A s
将该选项改为未选中状态,如下图所示。$ G" q) }' ? _" Q3 I* e1 p- T
![]()
/ ~0 z j. K5 z接下来,编译烧写该内核镜像(boot.img)到开发板。再进行下面的操作即可。/ P1 x t- l) d
2 编写驱动程序
8 o7 s. }6 Y& Y: d# U在 linux 内核中有一个规律,Linux 内核开发者把通用的东西都总结出来,个性化的东西就留出接口,和 GPIO 驱动类似,PWM 驱动在内核中也提供了对应的接口函数,内核提供的接口函数声明在 include/linux/pwm.h 中。6 Q F) a5 d% r
//申请一个 PWM 资源* Q- N( t& b% Y; Q
struct pwm_device *pwm_request(int pwm_id, const char *label);0 P( S/ K( J! G
//释放一个 PWM 资源3 g/ V8 O7 \5 L- G+ M2 h7 O# E
void pwm_free(struct pwm_device *pwm);1 k# z; t. i& `
//配置 PWM5 g& T) l# U( E$ j. L2 ?! W
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);4 |5 l r+ N% c7 q/ W
//使能 PWM,duty_ns 为高电平所用时间,period_ns 整个周期为所用时间,单位为纳秒。2 K6 k# J% k! ~+ |- I
int pwm_enable(struct pwm_device *pwm);2 b4 V' H# h8 f% U
//不使能 PWM
5 q0 G- M0 G) n1 f# I3 p3 {/ ^! u, Svoid pwm_disable(struct pwm_device *pwm);, K( S5 U' E& C2 F
根据以上这些,我们便可以编写一个简单的 pwm 输出程序,来控制蜂鸣器的频率。创建
! W! f7 G2 O4 j W名称为 4418x_pwm.c 的文件,程序代码如下所示。$ i4 F7 g1 Z. r0 q: H6 b# L
#include
& r/ G' F/ }3 L) g1 @#include
! e- [9 \3 h" t4 q* O9 `#include
/ w# B0 [& A# L# A6 A% T2 f' `. M#include2 m9 G. x5 W* e( P7 Y
#include
% f2 O( K3 M" P#include3 a/ l3 C0 }# R; z( N4 q, G
#include) a: B$ a; H& q% C2 g
#include+ V. }* y9 N6 {: u% A
#include
0 K: p& i+ o5 e( [# b/*pwm for this buzzer*/0 V* z$ [9 [$ {& d2 A
struct pwm_device *pwm = NULL;9 q0 d9 D0 p) \6 e
static int __init buzzer_init(void)
1 z" t, H1 ~; C7 j( M9 F{
0 W% A/ Y/ U" @% ~3 Y* K7 tint ret;
~, E9 C" Y% h( i3 ]& tprintk(" check buzzer init.\n");% L! ?; \4 l v* A, o
pwm = pwm_request(2, "buzzer");7 M* u7 S- c' S, I1 g4 c; l6 U4 V3 U
if ( pwm == NULL ) {
5 K# \1 \, x2 O9 Xprintk("buzzer open error.\n");, |' g- {3 E6 h; G) B
}4 _/ ?7 m' O9 y7 Y; p; s9 Y
//printk(KERN_EMERG "pwm_request %d ",pwm);
7 z# g4 B6 ~" q) B8 n. _0 |( @' q$ Mret=pwm_config(pwm,100000,200000);//设置了 1000Hz 频率的声音
& K! m. v* o( C, l+ e+ T7 sprintk("pwm_config %d ",ret);
* X/ M- [) S5 ]' [printk("pwm_config %d ",ret);
$ i% Y8 z. @9 `5 _- L, E. H+ xret=pwm_enable(pwm);
$ D" m6 {8 p7 U, e( e& dprintk("pwm_enable %d ",ret);' U1 \+ g F B6 Z/ _3 r) C" I
printk(KERN_EMERG "done2. \n") ;# b- i# ?- F0 A
return 0;6 M4 i% }* |+ `
}
6 ]3 [5 U+ B6 s/ W% ]. |0 Kstatic void __exit buzzer_exit(void)7 L3 r6 C; O8 r0 q/ h- Z
{* r% n, |9 E3 ?! y- K" |1 a3 |3 f* ?
pwm_config(pwm,0,0); //关闭蜂鸣器输出
" S1 j) h+ b% P. c5 J, Vpwm_disable(pwm); // 关闭 pwm" C0 R" @" g* ]2 h7 p0 d( {; Y
pwm_free(pwm); // 释放 pwm 资源/ E4 y0 m J+ G4 t' |; X
}
2 Y! A# X+ w8 T6 M7 nmodule_init(buzzer_init);/ i$ x) D1 t# \4 a8 k# @
module_exit(buzzer_exit);+ b; ]- g; _, e# @4 @& t
MODULE_DESCRIPTION("pwm_buzzer driver");& s6 C* t% A, p- i& m: `6 D8 j
MODULE_LICENSE("GPL");
2 {8 `5 F4 j0 ~! A2.2 编写 Makefile2 T7 F8 I" j5 ?- J2 I$ Q9 G
接下来进行编写 Makefile 文件。
) @$ K! M2 a1 v/ `4 \export ARCH=ARM: |$ C7 G4 l' v2 i" N; J/ W
obj-m += 4418x_pwm.o! x; @0 f, _. h$ A
KDIR := /home/topeet/4418/4G/20170914/android/kernel
1 A/ e3 O# O# A% S. K O/ x7 HPWD = $(shell pwd)
+ i3 m5 o" F/ Nall:
( `: {) E' Z, f( N* cmake -C $(KDIR) M=$(PWD) modules
2 v7 w. e% f/ `( L7 fclean:
( G4 l2 Q2 }1 G J% M; hrm -RF *.o modules.order *.ko *mod.c Module.symvers
& X/ _3 [5 K! s& t. ]+ ?* z! H( D脚本中,export ARCH=arm 表示设置目标 CPU 类别为 arm,也就是编译的依赖内核和驱动模块目标 CPU 为 ARM。3 l. m% V4 ~$ L* ?7 C
obj-m += 4418x_pwm.o 表示编译的源文件为 4418x_pwm.c, 如果源文件名有变化,则需要修改成对应的文件名。9 w% ]7 |. S( j1 P
KDIR 参数指向对应的内核源码目录。作者的内核源码是在/home/topeet/4418/4G/20170914/android/kernel 目录下,用户要根据自己的具体情况来修改。
5 Q `/ g% C0 e) }2.3 编译运行9 q0 O2 V; x4 i& S" q
首先设置环境变量,使其在编译时使用源码中的编译器。在源码目录中使用”cdkernel”进入 kernel 目录。然后使用命令“make menuconfig”打开内核缺省配置界面,如下图所示。
# r* X W8 S- }# J- d- q( o" k: e( e ; o, }! Q" I% ^+ \( |+ y. ^
进入图中高亮的“General setup”,如下图所示。) h P9 G d. T3 s4 H9 z" y
9 k( L+ F6 r$ o
可以看到图中高亮的文本,描述了当前源码使用的编译器为“arm-eabi-”,我们回到源码文件夹,使用命令“find ./ -name arm-eabi-*”,可以得到源码中编译器所在路径,如下图所示。8 r7 R7 ~, H$ {& [) h( ?
![]()
( k& {/ t& ^) H) @4 p这样,源码编译器的绝对路径为源码所在路径加上上图中红框的路径,在本文中为“/home/topeet/4418/4G/20170914/android/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7/bin/”,因为笔者是用 root 登录的,所以打开文件“/root/.bashrc”在里面添加这样一条内容,如下图所示。
% Q8 s4 p. D) w) O8 X; T/ ^![]()
/ o' K4 f* K5 D' G接下来,我们便可以进行编译了。, Y' Y5 k# h: P
将 Makefile 与 C 程序放在 Ubuntu 系统的同一目录。如下图所示。
9 ~* V2 E; R0 W7 o7 l% Y2 u![]()
$ _+ o8 V8 f, E4 S在当前目录输入“make”开始编译,生成内核模块文件“ 4418x_pwm.ko”,如下图所示。8 p* e/ j! R2 n' o2 [" H
![]()
$ k# G$ \+ o. P# C% n! p将该内核模块文件拷贝到开发板,接下来在超级终端使用命令“insmod4418x_pwm.ko”加载该模块,如下图所示。' l1 V+ D$ G, e+ x: f
a( H5 @+ x6 j' |& s4 {: \$ D
模块加载成功,同时蜂鸣器响起高频声音。然后使用命令“rmmod 4418x_pwm”卸载该驱动,如下图所示。
9 r3 G" Z) N( j6 `' d3 \2 B9 l: D: l ' p) R% J4 g: A
此时,蜂鸣器停止播放高频声音,PWM 蜂鸣器测试例程到此结束。
1 i2 c0 [0 z! n2 q8 n o![]()
6 _0 y2 u& G! |9 b$ d, H |
|