EDA365电子论坛网
标题:
迅为-4418开发板-驱动-PWM输出实验
[打印本页]
作者:
孤久厌闹
时间:
2020-10-22 11:04
标题:
迅为-4418开发板-驱动-PWM输出实验
本文档介绍了在 iTOP-4418 开发板上用
PWM
控制蜂鸣器输出的测试历程,基于 QtE 系统。4418
MCU
共提供了 5 路 PWM 输出,其中一路未引出,所以共有 4 路可用的 PWM 输出。
, Y4 I* s% ~' S- J# h Q* d! r
注意:本文档中提供的例程,没有注册设备和驱动,只是在驱动入口和出口函数中进行了配置。如果用户需要生成设备节点,则需要自行添加剩余部分,这部分可以参考 GPIO 操作的文档。
3 M9 L* W. \+ U$ |
1 配置 IO
9 [( @) G% g% J k; x, y; x9 h2 V
打开底板
电路图
,搜索“beep”,可以看到 beep 的网络名为“MCU_ISO7816_CLK”,如下图所示。
6 \' H" s9 \4 Q+ Z3 ?
. |+ Z/ K% A' S* X4 J
在核心板原理图,搜索该关键词“MCU_ISO7816_CLK”,可见其对应 PWM2,如下图所示。
# J" I0 r& X- k7 h% k, B2 r* Q
# e ^+ q3 \& e( c! y/ Q+ K, e
所以,接下来我们便对 PWM2 进行操作。在下面的操作之前,我们需要配置内核,取消内核中 buzzer 的驱动,解除该驱动对蜂鸣器的占用,其目录如下图所示。
5 U9 l3 {, U, c. {
' r2 a4 @: l% M4 x- T: E
将该选项改为未选中状态,如下图所示。
& ^7 `( n/ W7 ~9 q8 X
3 h% k D, X/ F. y5 K/ j( R
接下来,编译烧写该内核镜像(boot.img)到开发板。再进行下面的操作即可。
1 v* ?6 W+ U/ S: K( M4 e% m8 i5 ]
2 编写驱动程序
/ r2 O( k. y' e6 A3 n
在 linux 内核中有一个规律,
Linux
内核开发者把通用的东西都总结出来,个性化的东西就留出接口,和 GPIO 驱动类似,PWM 驱动在内核中也提供了对应的接口函数,内核提供的接口函数声明在 include/linux/pwm.h 中。
: g* O" m8 L. E6 P) N, R: A
//申请一个 PWM 资源
: _% w0 J4 @1 Y# Z- L
struct pwm_device *pwm_request(int pwm_id, const char *label);
+ b- T$ ]+ }: s& S, P7 E
//释放一个 PWM 资源
2 G i; l9 J, i+ S0 m# K R/ z
void pwm_free(struct pwm_device *pwm);
6 V( }$ Z, R, O* t" B) \- W* U" w b
//配置 PWM
; c, U V. R f- r! \
int pwm_config(struct pwm_device *pwm, int duty_ns, int period_ns);
" g# q2 A/ u) s$ D1 S5 G; a- `
//使能 PWM,duty_ns 为高电平所用时间,period_ns 整个周期为所用时间,单位为纳秒。
: c% U: N$ G. u
int pwm_enable(struct pwm_device *pwm);
. d2 H& U* J6 ?) l* u. t4 k* q
//不使能 PWM
% M# p' y. G7 A8 ?7 \; J9 V1 R
void pwm_disable(struct pwm_device *pwm);
+ u8 R7 E- E! ^, V9 G
根据以上这些,我们便可以编写一个简单的 pwm 输出程序,来控制蜂鸣器的频率。创建
. e; |) N) B) C- G0 D. y
名称为 4418x_pwm.c 的文件,程序代码如下所示。
* t6 a2 {% p8 F6 y( E# X
#include
6 v; B2 [' z# M3 x" J& f F7 {
#include
, p0 O+ ^5 D+ K0 Y0 o
#include
7 Y/ s: i3 u6 @3 G1 Z; ~3 ^
#include
( r" l% w* u1 i! L% t# C: c/ T
#include
2 v" ^7 m' K5 U
#include
& c; C0 N/ N- @; z9 r |- U
#include
% X- y" P, L X; W: G n
#include
; J0 @; o/ M4 h3 Y$ f
#include
4 Q- \2 L' E4 Y0 [: K; b2 s' `
/*pwm for this buzzer*/
: l$ q% h: ^2 f& g6 b5 C7 J$ ~9 U
struct pwm_device *pwm = NULL;
% w( U: S5 Y7 L2 ~9 N0 G, ?
static int __init buzzer_init(void)
! X6 w. D6 b4 i( Q
{
, ]+ p( @; m" n. M6 N
int ret;
% S8 G k5 M" ]" ~
printk(" check buzzer init.\n");
' I' C0 D2 O) W1 o" Q
pwm = pwm_request(2, "buzzer");
$ ]4 u e. S6 b1 O+ z9 D
if ( pwm == NULL ) {
* N3 m7 j+ O4 p/ O F
printk("buzzer open error.\n");
, f- R6 Z2 d4 R) Y" V
}
, n1 _& W: E3 j/ x4 l+ }
//printk(KERN_EMERG "pwm_request %d ",pwm);
* T+ I# M- B4 ~& t
ret=pwm_config(pwm,100000,200000);//设置了 1000Hz 频率的声音
- @- T' q: U" s8 z
printk("pwm_config %d ",ret);
* \7 u# J! |# p y% @
printk("pwm_config %d ",ret);
6 Y$ L; O7 F9 b
ret=pwm_enable(pwm);
+ Q u' z+ V. I' c7 Y
printk("pwm_enable %d ",ret);
. c1 O# k, r0 `: x
printk(KERN_EMERG "done2. \n") ;
" i H; ?; ~$ ?, g( Y8 Q$ W5 @* D
return 0;
9 q& u1 B! W) I
}
2 |4 ]$ L3 t* U) j8 d2 e4 B
static void __exit buzzer_exit(void)
. M) r+ h$ W/ _; N
{
2 L0 u6 ~6 a4 |) ~
pwm_config(pwm,0,0); //关闭蜂鸣器输出
( y7 _ R" }& q6 s' }/ \" P
pwm_disable(pwm); // 关闭 pwm
( `. [% E) c# [7 Y) |. Z& L
pwm_free(pwm); // 释放 pwm 资源
& ^- `7 I; _# a) u
}
: b f6 M C, l% U5 N- L0 `
module_init(buzzer_init);
& @5 a( m: ]4 `7 d0 s( Q5 B' l
module_exit(buzzer_exit);
6 I% j& d, r! S9 K# `& A) ]1 e
MODULE_DESCRIPTION("pwm_buzzer driver");
/ `& p2 q8 M G R5 _8 a7 W0 `# c; W
MODULE_LICENSE("GPL");
# ~+ }" Q2 ]2 J6 t% Y
2.2 编写 Makefile
/ E3 m U! S& x9 E
接下来进行编写 Makefile 文件。
H/ Q' c) p* D
export ARCH=arm
: H t; H4 M+ q9 D9 R
obj-m += 4418x_pwm.o
( t$ ~; }2 d; I, E( N6 t' L
KDIR := /home/topeet/4418/4G/20170914/android/kernel
X& b; |4 i1 y$ A2 z* L; k
PWD = $(shell pwd)
- F$ Y5 Z1 N5 t% C
all:
Y( d! ~( o- t2 H [0 C2 |- l
make -C $(KDIR) M=$(PWD) modules
% n4 k8 s) Z9 ^, O
clean:
: N# m, B( F \$ J3 l( B
rm -rf *.o modules.order *.ko *mod.c Module.symvers
3 d7 z D# n2 n4 |7 a2 A
脚本中,export ARCH=arm 表示设置目标 CPU 类别为 arm,也就是编译的依赖内核和驱动模块目标 CPU 为
ARM
。
4 k2 t" t6 x9 ]* H! E: a% J$ C
obj-m += 4418x_pwm.o 表示编译的源文件为 4418x_pwm.c, 如果源文件名有变化,则需要修改成对应的文件名。
) W# D2 a+ c/ q+ c- ^/ i/ ]; C
KDIR 参数指向对应的内核源码目录。作者的内核源码是在/home/topeet/4418/4G/20170914/android/kernel 目录下,用户要根据自己的具体情况来修改。
0 L+ e2 L) m- p/ X j" E1 M
2.3 编译运行
: _0 ~& a! f0 ~6 S& x) G
首先设置环境变量,使其在编译时使用源码中的编译器。在源码目录中使用”cdkernel”进入 kernel 目录。然后使用命令“make menuconfig”打开内核缺省配置界面,如下图所示。
' f& s0 `7 v9 o+ @: @: f
0 j# r8 D8 n5 x3 a" a7 g6 s+ ]4 W
进入图中高亮的“General setup”,如下图所示。
F' [* u! E, z' ~: r* V" M2 P
) l( x( u) R7 R: ~9 y1 G; X
可以看到图中高亮的文本,描述了当前源码使用的编译器为“arm-eabi-”,我们回到源码文件夹,使用命令“find ./ -name arm-eabi-*”,可以得到源码中编译器所在路径,如下图所示。
1 e, [+ X, y, S
5 s; f6 O+ o5 `
这样,源码编译器的绝对路径为源码所在路径加上上图中红框的路径,在本文中为“/home/topeet/4418/4G/20170914/android/prebuilts/gcc/linux-x86/arm/arm-eabi-4.7/bin/”,因为笔者是用 root 登录的,所以打开文件“/root/.bashrc”在里面添加这样一条内容,如下图所示。
5 N$ e, w6 ?8 v1 _4 ^4 d" v
* p' ~$ ~" c! V6 `9 \3 P3 V1 O* K% j
接下来,我们便可以进行编译了。
3 K p* G, f, F
将 Makefile 与 C 程序放在
Ubuntu
系统的同一目录。如下图所示。
+ _1 L4 D# c7 N; `8 L L. I# o2 `
! e9 f t# V* i1 U! \- S% ~, I8 r- \
在当前目录输入“make”开始编译,生成内核模块文件“ 4418x_pwm.ko”,如下图所示。
, ^4 T7 Z3 E7 h: t
4 g y0 Z7 J8 X$ d6 n
将该内核模块文件拷贝到开发板,接下来在超级终端使用命令“insmod4418x_pwm.ko”加载该模块,如下图所示。
( X& A0 J, j. q4 D4 Z/ N5 a* {. F, A
( X7 v7 x0 C& Z; E6 R5 c; T
模块加载成功,同时蜂鸣器响起高频声音。然后使用命令“rmmod 4418x_pwm”卸载该驱动,如下图所示。
! F) u9 ?' c6 W; M& S- A' j
) v* {$ Q, l7 N( G& d6 I
此时,蜂鸣器停止播放高频声音,PWM 蜂鸣器测试例程到此结束。
. E J' ~8 z2 T: Y
& n" x+ |% t( J- d7 t& W& h( P
作者:
weqewq
时间:
2020-10-22 13:18
在驱动入口和出口函数中进行配置
欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/)
Powered by Discuz! X3.2