EDA365电子论坛网

标题: 迅为-4418开发板-驱动-PWM输出实验 [打印本页]

作者: 孤久厌闹    时间: 2020-10-22 11:04
标题: 迅为-4418开发板-驱动-PWM输出实验
本文档介绍了在 iTOP-4418 开发板上用 PWM 控制蜂鸣器输出的测试历程,基于 QtE 系统。4418MCU 共提供了 5 路 PWM 输出,其中一路未引出,所以共有 4 路可用的 PWM 输出。
, Y4 I* s% ~' S- J# h  Q* d! r注意:本文档中提供的例程,没有注册设备和驱动,只是在驱动入口和出口函数中进行了配置。如果用户需要生成设备节点,则需要自行添加剩余部分,这部分可以参考 GPIO 操作的文档。3 M9 L* W. \+ U$ |
1 配置 IO9 [( @) 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. uint 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#include6 v; B2 [' z# M3 x" J& f  F7 {
#include
, p0 O+ ^5 D+ K0 Y0 o#include7 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 Ustruct 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 Nint 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  Fprintk("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 ~& tret=pwm_config(pwm,100000,200000);//设置了 1000Hz 频率的声音
- @- T' q: U" s8 zprintk("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 `: xprintk(KERN_EMERG "done2. \n") ;
" i  H; ?; ~$ ?, g( Y8 Q$ W5 @* Dreturn 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' }/ \" Ppwm_disable(pwm); // 关闭 pwm
( `. [% E) c# [7 Y) |. Z& Lpwm_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' lmodule_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% Y2.2 编写 Makefile
/ E3 m  U! S& x9 E接下来进行编写 Makefile 文件。  H/ Q' c) p* D
export ARCH=arm
: H  t; H4 M+ q9 D9 Robj-m += 4418x_pwm.o
( t$ ~; }2 d; I, E( N6 t' LKDIR := /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 ^, Oclean:
: N# m, B( F  \$ J3 l( Brm -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$ Cobj-m += 4418x_pwm.o 表示编译的源文件为 4418x_pwm.c, 如果源文件名有变化,则需要修改成对应的文件名。
) W# D2 a+ c/ q+ c- ^/ i/ ]; CKDIR 参数指向对应的内核源码目录。作者的内核源码是在/home/topeet/4418/4G/20170914/android/kernel 目录下,用户要根据自己的具体情况来修改。
0 L+ e2 L) m- p/ X  j" E1 M2.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: t4 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