最近无聊将以前没做完的板子拿出来玩了一下,发现开发方面f1c200s和i.mx6ull还是有些细微的差别。话不多说,下面开始讲解如何让板子上的LED亮起来(从32点灯大师转行)。
我的led引脚是PD13且低电平有效。
okay,硬件确定好,接下来是修改设备树,我使用的是荔枝Pi的内核
打开内核目录,如下路径找到dts文件,ach/arm/boot/dts/suniv-f1c100s-licheepi-nano.dts,添加设备节点。这里我的绝对路径为 /home/wmp/linux/lc_core/Linux/arch/arm/boot/dts/suniv-f1c100s-licheepi-nano.dts
/ {
model = "Lichee Pi Nano";
compatible = "licheepi,licheepi-nano", "allwinner,suniv-f1c100s",
"allwinner,suniv";
led{
compatible = "wmp,led-PD13";
pinctrl-names = "default";
pinctrl-0 = <&led_pins>;
led-pin = <&pio 3 13 GPIO_ACTIVE_LOW>;
status = "okay";
};
.......
pinctrl-0后面再说,先说led-pin,其中描述了PD13的信息,3代表PD13中的D具体对应如下
A-0
B-1
C-2
D-3
E-4
其中13为IO号,也就是PD13中的13,如果是PD12则为12
GPIO_ACTIVE_LOW为低电平有效
其余的均根据实际定义
然后打开ach/arm/boot/dts/suniv.dtsi,在pio节点下添加自己的节点
pio: pinctrl@1c20800 {
compatible = "allwinner,suniv-pinctrl";
reg = <0x01c20800 0x400>;
interrupts = <38>, <39>, <40>;
clocks = <&ccu CLK_BUS_PIO>, <&osc24M>, <&osc32k>;
clock-names = "apb", "hosc", "losc";
gpio-controller;
interrupt-controller;
#interrupt-cells = <3>;
#gpio-cells = <3>;
spi0_pins_a: spi0-pins-pc {
//pins = "PC0", "PC1", "PC2", "PC3";
pins = "PD18", "PD19", "PD20", "PD21";
function = "spi0";
};
led_pins: led-pins{
pins = "PD13";
function = "gpio_out";
};
...
在dts文件的pinctrl-0便是引用该文件的led节点,这里function不能随意修改,如果要修改的话,需要到对应c文件添加自定义功能,具体这里不再赘述,修改完成后保存并重新编译设备树
我已经在内核的Makefile中添加了编译器信息,因此直接用如下指令编译
make dtbs
编译完成后将dtb文件保存到SD卡对应分区中
如此一来,设备树修改完成,接下来便是编写驱动代码
下面是具体驱动代码
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/jiffies.h>
#include <linux/timer.h>
#define MINOR 10 //次设备号
#define LED_BLINK_TIME 1000 //定时器中断出发时间 单位:ms
#define DEVICE_NAME "led" //设备名称
#define DTB_COMPATIABLE "wmp,led-PD13" //设备树led节点下的compatible属性
static int led_probe(struct platform_device * dev);
static int led_remove(struct platform_device * dev);
static void led_blink(struct timer_list *unused);
/*定义用户设备结构体*/
typedef struct{
struct device_node *nd;
int gpio_num;
struct timer_list timer;
}gpio_dev_t;
gpio_dev_t led = {0};
/*定义杂项设备结构体*/
struct miscdevice led_misc={
.minor = MINOR,
.name = DEVICE_NAME,
};
/*定义平台驱动匹配表*/
struct of_device_id led_table[]={
{.compatible = DTB_COMPATIABLE},
};
/*定义平台设备驱动结构体*/
struct platform_driver platform_led={
.driver={
.name = DEVICE_NAME,
.of_match_table = led_table,
},
.probe = led_probe,
.remove = led_remove,
};
/*probe函数*/
static int led_probe(struct platform_device * dev)
{
printk("led probe\r\n");
led.nd = dev->dev.of_node;//获取设备节点
led.gpio_num = of_get_named_gpio(led.nd,"led-pin",0);//获取gpio号
gpio_request(led.gpio_num,"led-pin");//请求gpio资源
gpio_direction_output(led.gpio_num,1);//设置gpio为输出
timer_setup(&led.timer, led_blink, 0);//初始化定时器
led.timer.expires = jiffies_64+msecs_to_jiffies(LED_BLINK_TIME);//设置超时时间
add_timer(&led.timer);//向内核添加定时器并开始计时
misc_register(&led_misc);//注册杂项设备
return 0;
}
/*remove函数*/
static int led_remove(struct platform_device * dev)
{
printk("led remove\r\n");
del_timer(&led.timer);//向内核注销定时器
gpio_set_value(led.gpio_num,1);//关灯
gpio_free(led.gpio_num);//释放gpio
misc_deregister(&led_misc);//注销杂项设备
return 0;
}
/*模块初始化函数*/
static int __init led_init(void)
{
printk("module init\r\n");
return platform_driver_register(&platform_led);
}
/*模块退出出函数*/
static void __exit led_exit(void)
{
printk("module exit\r\n");
platform_driver_unregister(&platform_led);
}
/*定时器超时函数*/
static void led_blink(struct timer_list *unused)
{
static unsigned char i;
if((++i)%2==1)
{
printk("led on!\r\n");
gpio_set_value(led.gpio_num,0);
}else{
printk("led off!\r\n");
gpio_set_value(led.gpio_num,1);
i=0;
}
led.timer.expires = jiffies_64+msecs_to_jiffies(LED_BLINK_TIME);//更新定时器超时时间
add_timer(&led.timer);//启动定时器
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("wmp");
根据自己的需求修改
接下来编译模块
make
将生成的文件保存到SD卡对应分区如下目录 /lib/modules/4.15.0-rc8-licheepi-nano+/
这一步还没完,还需要在内核当中复制两个依赖文件到上述目录下用于加载模块
接下来便可以使用模块
depmod生成加载模块的依赖文件
modprobe led 加载模块
出现了led闪烁的打印信息说明模块加载成功!!!
如果实在不放心可以使用lsmod查看模块加载情况
使用ls /dev/ 查看设备是否挂载
这下确信模块加载成功,使用rmmod led即可删除该设备。