1.实验原理
打开扩展板原理图对照扩展板可以看到扩展板有
1
个振动马达
M1
,如下图:
![](https://i-blog.csdnimg.cn/blog_migrate/7b1de58093bc5eb843f6a05e586fbfd9.png)
由上图可见可通过 TIM16_CH1 电平改变控制电路的通断从而驱动线性马达。
查看原理图可知
TIM16_CH1
对应
PF6
,查看芯片手册可知
PF6
可以作为
PWM TIMER16 的通道 1
使用,本文实现如何通过
PWM
驱动振动马达:
![](https://i-blog.csdnimg.cn/blog_migrate/0e65c7f5c0918127c0fa8ef2addc19c1.png)
2.实验步骤
1) 导入交叉编译工具链
linux@ubuntu:$ source /opt/st/stm32mp1/3.1-openstlinux-5.4-dunfell-mp1-20-06-24/environm ent-setup-cortexa7t2hf-neon-vfpv4-ostl-linux-gnueabi
2) 内核配置
内核中为振动马达提供了标准的驱动,只要在内核中配置对应选项即可,驱动路径为:
drivers/input/misc/pwm- vibra.c
执行
make menuconfig
配置内核对应选项
linux@ubuntu:$ make menuconfigDevice Drivers --->Input device support --->[*] Miscellaneous devices ---><*> PWM vibrator support
3) 修改设备树
参考
linux
内核文档:
Documentation/devicetree/bindings/pwm/pwm-stm32.txtDocumentation/devicetree/bindings/input/pwm-vibrator.txt
修改设备树文件:
arch/arm/boot/dts/stm32mp157a-fsmp1a-extended.dts
由于
timers16
在
stm32mp151.dtsi
中已完成定义,这里需要在原有基础添加与硬件对应的 相关信息,在文件 stm32mp157a-fsmp1a-extended.dts
末尾继承并添加
timers16
相关内容:
&timers16 { /* spare dmas for other usage */ /delete-property/dmas; /delete-property/dma-names; status = "okay"; pwm16: pwm { pinctrl-0 = <&pwm16_pins_a>; pinctrl-1 = <&pwm16_sleep_pins_a>; pinctrl-names = "default", "sleep"; #pwm-cells = <2>; status = "okay"; }; timer@16 { status = "disabled"; }; };
仿照设备树对于
pwm
管脚的配置添加
timers16 pwm
输出管脚配置,在
stm32mp157a-fsmp1a-extended.dts 文件
pinctrl
节点中添加
pwm16
管脚信息,红色字体内容为添加内容:
&pinctrl {……pwm16_pins_a: pwm16-0 {pins {pinmux = <STM32_PINMUX('F', 6, AF1)>; /* TIM16_CH1 */bias-pull-down;drive-push-pull;slew-rate = <0>;};};pwm16_sleep_pins_a: pwm16-sleep-0 {pins {pinmux = <STM32_PINMUX('F', 6, ANALOG)>; /* TIM16_CH1 */};};};
最后在根节点下添加振动马达驱动对应节点:
vibrator {compatible = "pwm-vibrator";pwms = <&pwm16 0 4000000>;pwm-names = "enable";direction-duty-cycle-ns = <10000000>;};
4) 重新编译内核和设备树文件
linux@ubuntu:$ make -j4 uImage dtbs LOADADDR=0xC2000040
5) 更新系统内核和设备树
6) 测试
系统启动后可以查看目录
/dev/input
root@fsmp1a:~# ls /dev/input/by-path event0 event1 event2
如果系统中有多个
input
设备,这里可能会有很对
eventx
,确定哪个
event
文件是我们的 设备文件,可以通过查看/dev/input/by-path 或查看
dmesg
系统启动信息确认:
查看
by-path
目录下文件
root@fsmp1a:~# ls /dev/input/by-path/ -ltotal 0lrwxrwxrwx 1 root root 9 May 30 08:43 platform-40013000.i2c-event -> ../event2lrwxrwxrwx 1 root root 9 Jun 30 07:40 platform-beeper-event -> ../event0lrwxrwxrwx 1 root root 9 Jun 30 07:40 platform-vibrator-event -> ../event1
由显示信息可以确认
event1
是振动马达的设备文件
编写测试程序测试:
pwm-vibrator.c
#include <stdio.h> #include <fcntl.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <linux/input.h> #include <sys/ioctl.h> int main(const int argc, const char **argv) { int fd; if (argc != 2) { printf("usage: %s <device-file>\n", argv[0]); return 1; } fd = open(argv[1], O_RDWR); if (fd < 0) { printf("Error opening file '%s': %s\n", argv[1], strerror(errno)); return 1; } int num_effects; if (ioctl(fd, EVIOCGEFFECTS, &num_effects) < 0) { printf("Error getting number of effects playable at the same time: %s\n", strerror(errno)); return 1; } printf("%d effects playable at the same time\n", num_effects); struct ff_effect effect; effect.type = FF_RUMBLE, effect.id = -1, effect.u.rumble.strong_magnitude = 0xFFFF; //调节振动强度 effect.u.rumble.weak_magnitude = 0; effect.replay.length = 3000; //调节振动时长 ms effect.replay.delay = 0; if (ioctl(fd, EVIOCSFF, &effect) < 0) { printf("Error creating new effect: %s\n", strerror(errno)); return 1; } printf("New effect ID: %d\n", effect.id); struct input_event play = { .type = EV_FF, .code = effect.id, .value = 1 }; if (write(fd, (const void*) &play, sizeof(play)) < 0) { printf("Error writing effect to file: %s\n", strerror(errno)); return 1; } printf("Wrote effect\n"); sleep(3); return 0; }
交叉编译测试程序并将编译好的测试程序下载到板子上,执行程序如下:
root@fsmp1a:~# ./vibrator_test /dev/input/event116 effects playable at the same timeNew effect ID: 0Wrote effect
这时可以听到振动马达振动的声音。