|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本文档介绍了在 iTOP-4418 开发板上用 PWM 控制蜂鸣器输出的测试历程,基于 QtE 系统。4418mcu 共提供了 5 路 PWM 输出,其中一路未引出,所以共有 4 路可用的 PWM 输出。/ r. E! d4 g* k6 Q5 M8 i3 {' ~
注意:本文档中提供的例程,没有注册设备和驱动,只是在驱动入口和出口函数中进行了配置。如果用户需要生成设备节点,则需要自行添加剩余部分,这部分可以参考 GPIO 操作的文档。- g7 u2 E* y. m/ f: d
1 配置 IO8 Z, T8 o8 c! {) Z
打开底板电路图,搜索“beep”,可以看到 beep 的网络名为“MCU_ISO7816_CLK”,如下图所示。' V/ S9 Q; y: |! g# v! _
1 } u& R' ?: I% r
在核心板原理图,搜索该关键词“MCU_ISO7816_CLK”,可见其对应 PWM2,如下图所示。
2 X/ U% y" Z% U- O2 m) P- I! ?3 G2 C1 w( B![]()
- x, f: f/ Y% X, e$ b所以,接下来我们便对 PWM2 进行操作。在下面的操作之前,我们需要配置内核,取消内核中 buzzer 的驱动,解除该驱动对蜂鸣器的占用,其目录如下图所示。) ]% v1 R; n6 Z6 G* q' {* Y
. W0 S- K8 d$ |% C. \7 q
将该选项改为未选中状态,如下图所示。
$ \" q( L& u m& p' _3 } 2 M9 H# R+ l" O! ^
接下来,编译烧写该内核镜像(boot.img)到开发板。再进行下面的操作即可。
- j/ v$ v/ H1 F4 |; _( G2 编写驱动程序" S4 x2 s. V9 v f! @
在 linux 内核中有一个规律,Linux 内核开发者把通用的东西都总结出来,个性化的东西就留出接口,和 GPIO 驱动类似,PWM 驱动在内核中也提供了对应的接口函数,内核提供的接口函数声明在 include/linux/pwm.h 中。7 h0 {# [* b: j3 T/ K, a7 |3 z p8 D
//申请一个 PWM 资源! c& o6 x- e7 z& Q
struct pwm_device *pwm_request(int pwm_id, const char *label);
" F/ \7 y6 }1 `, y* s8 m//释放一个 PWM 资源
' v/ l( ?4 i' l B% A" gvoid pwm_free(struct pwm_device *pwm);+ i! h0 K! ~& Y
//配置 PWM$ z# g. {& H0 a: S
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
0 Q, C0 r; z, D! |+ H//使能 PWM,duty_ns 为高电平所用时间,period_ns 整个周期为所用时间,单位为纳秒。
; K: w2 K0 |6 W" |9 t+ {8 oint pwm_enable(struct pwm_device *pwm);
: Z& N1 Y; [0 F# B( d; I//不使能 PWM
7 h" ~; M+ z+ Q: l8 p4 vvoid pwm_disable(struct pwm_device *pwm);
" q, c4 k5 x6 o# v9 C6 ^( i根据以上这些,我们便可以编写一个简单的 pwm 输出程序,来控制蜂鸣器的频率。创建
& C8 c' ~# N* i5 r q) X名称为 4418x_pwm.c 的文件,程序代码如下所示。6 Y f5 E$ P6 N+ e ^
#include
v9 ]9 M! p; M#include7 v' j* P; C8 m7 S) ]" Y) _
#include
8 |) e' f) b; J/ ~0 b#include
9 w8 p7 R ~$ u, e0 E+ v#include: w$ W$ D8 y/ z
#include
. u _. U5 o; R' z' [7 ]/ ^#include
, I7 R' B* D5 q0 R#include
. D+ U3 B/ q5 y+ d# R( e#include
" G* K/ Z% Z; C! j7 A/*pwm for this buzzer*/" z9 v0 W( I% D. m% J, p4 i
struct pwm_device *pwm = NULL;
0 I' F( t* g6 Y+ b* o# L/ [7 ?0 Jstatic int __init buzzer_init(void)6 G( R; ~. D& O, O% C8 ?/ h
{. H4 n! ~/ Q( k( }; t; j
int ret;
6 ^9 ?2 u1 T- x. w/ u! P; @printk(" check buzzer init.\n");5 K. y& g# D8 H$ e* V V( }
pwm = pwm_request(2, "buzzer");
* z# l. d: g: f" M$ `0 ?: T$ Bif ( pwm == NULL ) {
G' m5 c3 B& P/ t2 \printk("buzzer open error.\n");6 B M0 y6 `& j5 o' U
}6 e/ [3 l( k Z
//printk(KERN_EMERG "pwm_request %d ",pwm);
; u' G, L5 f$ \" kret=pwm_config(pwm,100000,200000);//设置了 1000Hz 频率的声音 o0 ^; T1 O& e3 e
printk("pwm_config %d ",ret);' ?9 X5 C: A3 H4 X- U8 g: B
printk("pwm_config %d ",ret);+ f5 q. H1 k5 \% |6 D( q, y
ret=pwm_enable(pwm);
' C8 ` C' E9 |" [( [! U+ Fprintk("pwm_enable %d ",ret);" j9 l s( y2 h! C' p
printk(KERN_EMERG "done2. \n") ;3 o4 |3 t2 |7 b. c: P
return 0;3 a& K4 O. |! \* P
}
@( i% Y/ d |4 E. `2 Y! S. Ustatic void __exit buzzer_exit(void)! J. T/ | {5 C* L( [1 e
{6 G. Z1 |4 D9 ^3 O3 e
pwm_config(pwm,0,0); //关闭蜂鸣器输出+ w2 ~: _! Q& ]3 P" k
pwm_disable(pwm); // 关闭 pwm# {$ D1 t( s; }5 q: G
pwm_free(pwm); // 释放 pwm 资源
@; w" r$ j$ d$ b& f/ F0 z, i8 `5 s}
" \) L7 [/ G- l. h- Gmodule_init(buzzer_init);9 Z& y% G5 l, z9 g' B! i
module_exit(buzzer_exit);
' l: r0 o/ A4 H4 t' r' o( cMODULE_DESCRIPTION("pwm_buzzer driver");
$ N- i1 W3 H4 S# r8 L: [2 t1 CMODULE_LICENSE("GPL");- M4 H2 Y1 u1 l2 ]; a1 p+ }* C, ]
2.2 编写 Makefile1 j, H+ ?3 g/ i2 M4 ?3 ~) V7 q" o
接下来进行编写 Makefile 文件。6 R7 s4 S4 t6 j2 a; i. y& l. j
export ARCH=ARM
' M6 F0 Z! x' u; d9 Dobj-m += 4418x_pwm.o* w O1 I( k* z
KDIR := /home/topeet/4418/4G/20170914/android/kernel# _% I5 l+ ]: b2 U7 b* J' G8 x
PWD = $(shell pwd) P) R% l& g$ k( V# }' W o% E# R+ \/ `
all:8 M7 E) T: w$ X
make -C $(KDIR) M=$(PWD) modules
+ @1 d! O5 i8 x& }2 B1 U" C: Y& [clean:# F7 O; v) d/ J& Q! {) ?, f
rm -RF *.o modules.order *.ko *mod.c Module.symvers0 j8 G3 b/ E4 F. Q; u
脚本中,export ARCH=arm 表示设置目标 CPU 类别为 arm,也就是编译的依赖内核和驱动模块目标 CPU 为 ARM。2 J; R/ R: j5 o
obj-m += 4418x_pwm.o 表示编译的源文件为 4418x_pwm.c, 如果源文件名有变化,则需要修改成对应的文件名。3 u2 M3 C2 l- ^( o- T$ X
KDIR 参数指向对应的内核源码目录。作者的内核源码是在/home/topeet/4418/4G/20170914/android/kernel 目录下,用户要根据自己的具体情况来修改。' O. r2 e5 i8 q9 D& @5 _
2.3 编译运行
1 e% ^5 U2 }% g& e; X首先设置环境变量,使其在编译时使用源码中的编译器。在源码目录中使用”cdkernel”进入 kernel 目录。然后使用命令“make menuconfig”打开内核缺省配置界面,如下图所示。
0 v: a" Z5 B* y# _7 H![]()
) }( g" K0 }/ E- d2 z( p5 q! B进入图中高亮的“General setup”,如下图所示。
" P. M) q9 e& h' V. c& N- ? ' @* O( D4 H+ i# i- _
可以看到图中高亮的文本,描述了当前源码使用的编译器为“arm-eabi-”,我们回到源码文件夹,使用命令“find ./ -name arm-eabi-*”,可以得到源码中编译器所在路径,如下图所示。1 {! l: X* Y" Z9 F
; C+ H# q8 e: F/ E2 Y4 u. f2 r
这样,源码编译器的绝对路径为源码所在路径加上上图中红框的路径,在本文中为“/home/topeet/4418/4G/20170914/android/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7/bin/”,因为笔者是用 root 登录的,所以打开文件“/root/.bashrc”在里面添加这样一条内容,如下图所示。0 q% p0 V" `) E
+ u& O5 S! N6 T. U7 P$ a
接下来,我们便可以进行编译了。2 c \" t9 h; ^+ e3 y
将 Makefile 与 C 程序放在 Ubuntu 系统的同一目录。如下图所示。+ _7 q( }: `& W* a8 f& ]
![]()
+ _; s9 z* X' e3 {2 K在当前目录输入“make”开始编译,生成内核模块文件“ 4418x_pwm.ko”,如下图所示。6 K1 H( N1 B% ~# r
![]()
% f9 t" Q. q) `9 d+ W将该内核模块文件拷贝到开发板,接下来在超级终端使用命令“insmod4418x_pwm.ko”加载该模块,如下图所示。. J- @" `2 j. F/ Q1 b# F
![]()
7 }$ s$ _) b4 b7 J模块加载成功,同时蜂鸣器响起高频声音。然后使用命令“rmmod 4418x_pwm”卸载该驱动,如下图所示。, t2 `2 k/ s6 J, i5 r7 B
f6 Z% H9 W" `' v5 j3 ]
此时,蜂鸣器停止播放高频声音,PWM 蜂鸣器测试例程到此结束。
- {" K! K0 o( b1 ^) ^+ h G1 G7 o9 d% }![]()
, k7 v: B% ^1 D& E3 d2 F" }) x4 ` |
|