|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
本文档介绍了在 iTOP-4418 开发板上用 PWM 控制蜂鸣器输出的测试历程,基于 QtE 系统。4418mcu 共提供了 5 路 PWM 输出,其中一路未引出,所以共有 4 路可用的 PWM 输出。
4 M/ {: C2 y- r. Z3 B A& t注意:本文档中提供的例程,没有注册设备和驱动,只是在驱动入口和出口函数中进行了配置。如果用户需要生成设备节点,则需要自行添加剩余部分,这部分可以参考 GPIO 操作的文档。 O0 ^. K9 _) y& q3 S! C8 G7 v7 L
1 配置 IO& G4 G0 ^- h' ]! `- L) c# t
打开底板电路图,搜索“beep”,可以看到 beep 的网络名为“MCU_ISO7816_CLK”,如下图所示。
( r) H7 T& J! n4 e, b& L" F0 U H" z5 V! k; L( g! D; Y
在核心板原理图,搜索该关键词“MCU_ISO7816_CLK”,可见其对应 PWM2,如下图所示。
3 L8 ? G; P2 @+ ~5 n / S4 |3 D+ v; k* t. Q
所以,接下来我们便对 PWM2 进行操作。在下面的操作之前,我们需要配置内核,取消内核中 buzzer 的驱动,解除该驱动对蜂鸣器的占用,其目录如下图所示。
' q0 r8 f; O e6 V + \ K. w, q, T6 g
将该选项改为未选中状态,如下图所示。 C4 |! P$ | j
" s9 R5 s+ @2 k& q. y: V' }7 j
接下来,编译烧写该内核镜像(boot.img)到开发板。再进行下面的操作即可。! @* ~# L; R1 R; {7 K9 s5 L
2 编写驱动程序" x. _' Q) z- v1 y) G
在 linux 内核中有一个规律,Linux 内核开发者把通用的东西都总结出来,个性化的东西就留出接口,和 GPIO 驱动类似,PWM 驱动在内核中也提供了对应的接口函数,内核提供的接口函数声明在 include/linux/pwm.h 中。2 O ]' q5 M6 U( z: o, [
//申请一个 PWM 资源
7 P6 ~! K% H+ |7 z0 Sstruct pwm_device *pwm_request(int pwm_id, const char *label);3 R1 q9 V! D/ z) L. q
//释放一个 PWM 资源# m6 s* c4 _9 I; m# M4 ?7 l* {
void pwm_free(struct pwm_device *pwm);+ ^2 Z8 P. l5 c1 l: @/ q, N) k
//配置 PWM3 h( Z! {+ l* P/ c! w5 c
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);+ e. H3 Z! R* I D. x7 h/ n) T
//使能 PWM,duty_ns 为高电平所用时间,period_ns 整个周期为所用时间,单位为纳秒。4 x2 a" O: E6 k/ K4 Y# F
int pwm_enable(struct pwm_device *pwm);
, @% S8 }4 m" l+ c1 S//不使能 PWM
; ^' M! l$ ^" l+ x a* d2 I! Lvoid pwm_disable(struct pwm_device *pwm);0 l+ R; w: R' K* _& P: d1 w
根据以上这些,我们便可以编写一个简单的 pwm 输出程序,来控制蜂鸣器的频率。创建
: ?. n: g$ @& K2 _名称为 4418x_pwm.c 的文件,程序代码如下所示。2 p% @4 c& t2 [7 l( \
#include3 L4 m, Y2 F0 @, f
#include7 Q% `- U4 s# [2 r2 Y- g* }( D
#include( c. h3 m0 r+ x4 Y4 }) [
#include
- ^+ O1 T' [" s1 p#include- J& O' y; L$ W& y, V
#include
3 s& ]# ?( ?) s5 [+ K. ~0 ?#include; A2 V! b8 C. c- a: F# S* Z
#include: J; Q1 i# F; Z. i$ `) {
#include
" c m: v. G/ v/*pwm for this buzzer*/5 W y; m2 a9 x: T- z! |# N& V
struct pwm_device *pwm = NULL;5 }- ?0 f' \+ V" A* C* q1 f
static int __init buzzer_init(void)
; F* w3 z2 @# l{
; q1 `$ y- u3 E# a& hint ret;
( P3 F$ b! J x' R' ^6 \0 `2 D/ \printk(" check buzzer init.\n");
2 s( V& {" L; f# r4 r2 Mpwm = pwm_request(2, "buzzer");
% i+ H7 B1 f" M4 Y! [: @if ( pwm == NULL ) {
$ J. N# Z" c& zprintk("buzzer open error.\n");
" g# d! i6 _& m}. q Y2 J4 H" U+ s/ \
//printk(KERN_EMERG "pwm_request %d ",pwm);1 _, O/ m) C) ?+ S$ ]& Z2 \' Q
ret=pwm_config(pwm,100000,200000);//设置了 1000Hz 频率的声音
+ V A! R' E$ u3 E- q5 j& qprintk("pwm_config %d ",ret);; H( Q9 e% d# g8 n8 O% ~5 X
printk("pwm_config %d ",ret);: j! }- v. U% `
ret=pwm_enable(pwm);
' X( t: C) _! [9 ~/ k0 N' kprintk("pwm_enable %d ",ret);
$ F. h4 w9 P- [8 c. V$ }printk(KERN_EMERG "done2. \n") ;
& ]# | \3 K( |. I' L. ^: |return 0;
( d; n) Z2 g% a% e}5 Z. C" p: O5 A" L X
static void __exit buzzer_exit(void) b" @* L' ^6 [' Y) L4 n
{9 |/ h# X! T! ?3 y/ z# F! W
pwm_config(pwm,0,0); //关闭蜂鸣器输出+ {" L' q/ S4 w7 v+ i5 H3 t: w
pwm_disable(pwm); // 关闭 pwm0 r- v$ d* l% ]; U; j: _
pwm_free(pwm); // 释放 pwm 资源4 y6 L. R. M5 Q( I" ~( w
}8 }8 Y8 z$ s; ~$ H4 C9 y
module_init(buzzer_init);# f% g. w7 N- I8 ]8 @& P$ z
module_exit(buzzer_exit);
2 y9 r( y v, ^% VMODULE_DESCRIPTION("pwm_buzzer driver");
* f3 k# O# f3 c+ z6 a4 n+ e6 v6 eMODULE_LICENSE("GPL");4 z& L( l* E R' N9 O
2.2 编写 Makefile
, [6 a4 s I% l接下来进行编写 Makefile 文件。
. b) q! l) {9 Vexport ARCH=ARM
8 |. D) c$ b% Oobj-m += 4418x_pwm.o2 F m$ P$ [6 S- F
KDIR := /home/topeet/4418/4G/20170914/android/kernel; e1 @/ V8 j, l- D: D# c3 [* M
PWD = $(shell pwd)
: Z/ ^0 A5 y+ S7 M3 Qall:! z+ i( [2 z% I- i$ a2 [% Y
make -C $(KDIR) M=$(PWD) modules Y% W7 _5 t8 K
clean:
% m, ?; l( `9 t ^rm -RF *.o modules.order *.ko *mod.c Module.symvers
+ [& w7 O! n6 E5 m脚本中,export ARCH=arm 表示设置目标 CPU 类别为 arm,也就是编译的依赖内核和驱动模块目标 CPU 为 ARM。. M$ t# d6 U% R8 J f8 u$ v o: |
obj-m += 4418x_pwm.o 表示编译的源文件为 4418x_pwm.c, 如果源文件名有变化,则需要修改成对应的文件名。
1 x M' F/ z, h2 x8 CKDIR 参数指向对应的内核源码目录。作者的内核源码是在/home/topeet/4418/4G/20170914/android/kernel 目录下,用户要根据自己的具体情况来修改。5 H2 _1 ?6 \0 g$ {1 t m5 f
2.3 编译运行7 \& ]9 ^5 [# S1 A; I) a3 s
首先设置环境变量,使其在编译时使用源码中的编译器。在源码目录中使用”cdkernel”进入 kernel 目录。然后使用命令“make menuconfig”打开内核缺省配置界面,如下图所示。
& D8 i: t; y% G$ e7 k ' g4 L/ v" i8 K2 a; Q- V
进入图中高亮的“General setup”,如下图所示。6 N- b- ~* z0 H3 t* P1 y) _
![]()
7 g( m8 i8 v! \9 u可以看到图中高亮的文本,描述了当前源码使用的编译器为“arm-eabi-”,我们回到源码文件夹,使用命令“find ./ -name arm-eabi-*”,可以得到源码中编译器所在路径,如下图所示。/ J6 a% a$ H# p% J# f: ]
![]()
9 b7 b8 o3 f0 X这样,源码编译器的绝对路径为源码所在路径加上上图中红框的路径,在本文中为“/home/topeet/4418/4G/20170914/android/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7/bin/”,因为笔者是用 root 登录的,所以打开文件“/root/.bashrc”在里面添加这样一条内容,如下图所示。
8 a! n5 b/ @! w3 o* B- U% l; G " |! K+ @- {5 o! H
接下来,我们便可以进行编译了。
% G" l2 _- |& Q5 i将 Makefile 与 C 程序放在 Ubuntu 系统的同一目录。如下图所示。
% m7 R: t5 G. F8 o& `$ t' _![]()
" y3 ]( {1 r1 o$ Q. |0 [. T1 p' D在当前目录输入“make”开始编译,生成内核模块文件“ 4418x_pwm.ko”,如下图所示。+ y. G; V3 E L- v( U8 Q4 z
![]()
- \. O3 ^; D" M8 |& T* g" I将该内核模块文件拷贝到开发板,接下来在超级终端使用命令“insmod4418x_pwm.ko”加载该模块,如下图所示。; @% r! K8 a. V% n5 S' M- t! Z8 J& i
4 ]2 F/ L* o8 _8 X7 w* y
模块加载成功,同时蜂鸣器响起高频声音。然后使用命令“rmmod 4418x_pwm”卸载该驱动,如下图所示。
. z1 ^0 w9 }" b8 x0 A, K9 \![]()
! C. Q* \* k$ l此时,蜂鸣器停止播放高频声音,PWM 蜂鸣器测试例程到此结束。
/ c6 f& m$ `- q+ n( r 0 g6 S" x# _& i
|
|