一、前言
搭建好环境后,先做一项 BSP 开发最基础的调试,通过 GPIO 驱动配置以及编写字符设备驱动来实现 Hi3559V200 引脚电平变化,
下面使用按键作输入,LED作输出,通过按键控制 LED 的亮灭这种方式能直观地展示电平变化的结果。使用的硬件平台是 Hi3559V200DMEB VER.A,
使用的 SDK 版本是 Hi3559V200_MobileCam_SDK_V1.0.1.5。
二、硬件原理图
2.1 Hi3559V200 平台 GPIO 介绍
Hi3559V200 平台一共有 12 组 GPIO,每组有 8 个 IO 口,即一共有 96 个 IO 口,通过管脚复用可以把具有 IO 功能的管脚复用为 GPIO 功能,
然后通过设置寄存器的值设置 GPIO 的输入输出模式,并写入输出的值或读取输入的值。
2.2 确认用作输出的 GPIO
查看原理图可以发现板上的 WIFI_LED,即 D9 是连接到 SoC 的 GPIO5_1,因此可以选用 GPIO5_1 来验证 GPIO 的输出。
图 2.1 GPIO5_1 作输出
2.3 确认用作输入的 GPIO
查看原理图可以发现板上的 GPIO0_0 和 GPIO10_3 分别连接着两个按键,因此可以用来做 GPIO 输入管脚。
图 2.2 GPIO0_0 作输入
图 2.3 GPIO10_3 作输入
三、 硬件资源申请及分配
3.1 修改 hi3559v200-demb.dts
选用连接到 LED 的 GPIO5_1 作为输出,选用连接到 key 的 GPIO0_0 和 GPIO10_3 作为输入控制 LED 的亮灭。海思平台可以通过 DTS 文件对
硬件设备资源进行申请及分配,DTS 文件所在目录为 osdrv\opensource\kernel\linux-4.9.y\arch\arm\boot\dts,文件名是 hi3559v200-demb.dts。
只需在该文件内把第 0、5、10 组 GPIO 的状态设置为 “ok”即可:
图3.1 申请硬件资源分配
注:完成此步骤后需要重新编译 kernel 并更新到板端。
四、 管脚复用
4.1 查询管脚复用寄存器
在 《Hi3559V200_PINOUT_CN.xlsx》 中查询以上三个管脚的控制寄存器地址:
图 4.1 查询管脚复用寄存器
4.2 配置管脚复用
接下来需要把以上的三个引脚复用成 GPIO,海思提供了一个表格工具对引脚复用进行初始化配置,表格工具位于 osdrv\tools\pc\uboot_tools,
对于 Hi3559V200DMEB 板,适用 Hi3559V200-DMEB_6L_T-DDR3_1800M_512MB_16bitx2-A7_900M-SYSBUS_300M.xlsm 表格,
只需按照上面的例子把刚才查到的寄存器名称、地址、要写入的数据填进去即可:
图 4.2 配置管脚复用
注:添加复用后要重新编译 u-boot 并更新到板端。
五、 编写 GPIO 设备驱动
5.1 编写驱动代码 gpio_driver.c
① 以下为驱动代码框架:
static int __init gpio_control_init(void)
{
printk(KERN_ALERT "Driver init\r\n");
/*注册一个新的字符设备,返回主设备号*/
majorNumber = register_chrdev(0,DEVICE_NAME,&file_oprts);
if(majorNumber < 0 )
{
printk(KERN_ALERT "Register failed!!\r\n");
return majorNumber;
}
printk(KERN_ALERT "Registe success,major number is %d\r\n",majorNumber);
/*以CLASS_NAME创建一个class结构,这个动作将会在/sys/class目录创建一个名为CLASS_NAME的目录*/
gpio_control_class = class_create(THIS_MODULE,CLASS_NAME);
if(IS_ERR(gpio_control_class))
{
unregister_chrdev(majorNumber,DEVICE_NAME);
return PTR_ERR(gpio_control_class);
}
/*以DEVICE_NAME为名,参考/sys/class/CLASS_NAME在/dev目录下创建一个设备:/dev/DEVICE_NAME*/
gpio_control_device = device_create(gpio_control_class,NULL,MKDEV(majorNumber,0),NULL,DEVICE_NAME);
if(IS_ERR(gpio_control_device))
{
class_destroy(gpio_control_class);
unregister_chrdev(majorNumber,DEVICE_NAME);
return PTR_ERR(gpio_control_device);
}
printk(KERN_ALERT "gpio_control device init success!!\r\n");
return 0;
}
② 使用中断检测按键是否按下,检测到按下后设置 LED 的电平:
static irqreturn_t key0_irq_handle(int irq, void *dev_id)
{
printk(KERN_INFO "Enter irq!!\n");
if(0 == led_status)
{
gpio_set_value(LED_PIN, 1);
led_status = 1;
}
else
{
gpio_set_value(LED_PIN, 0);
led_status = 0;
}
return (irqreturn_t)IRQ_HANDLED;
}
static void gpio_config(void)
{
int ret = 0;
if(!gpio_is_valid(LED_PIN) || !gpio_is_valid(KEY0_PIN) || !gpio_is_valid(KEY1_PIN))
{
printk(KERN_ALERT "Error wrong gpio number\n");
return ;
}
gpio_request(LED_PIN, "LED");
gpio_direction_output(LED_PIN, 1);
gpio_set_value(LED_PIN, 1);
gpio_request(KEY0_PIN, "KEY0");
gpio_direction_input(KEY0_PIN);
gpio_request(KEY1_PIN, "KEY1");
gpio_direction_input(KEY1_PIN);
key0_irq_num = gpio_to_irq(KEY0_PIN);
printk(KERN_INFO "NUM = %d",key0_irq_num);
ret = request_irq(key0_irq_num,
(irq_handler_t)key0_irq_handle,
IRQF_TRIGGER_RISING,
"KEY0",
NULL);
printk(KERN_INFO "GPIO_TEST: The interrupt request result is: %d\n", ret);
led_status = 1;
}
5.2 编写应用程序c,应用程序只需要打开字符设备就可以了。
int main(int argc,char *argv[])
{
int fd = open("/dev/gpio_control_demo", O_RDWR);
if(fd < 0)
{
perror("Open file failed!!!\r\n");
return -1;
}
while(1)
{
}
close(fd);
return 0;
}
六、 验证过程
6.1 把驱动文件编译成 ko 模块后拷贝到板端,安装模块,运行应用程序:
图 6.1 启动应用程序
6.2 按下 S2 和 S3 按键即可控制 D9 的亮灭
图 6.2 LED 灯亮
图 6.3 LED 灯灭
至此,已经可以利用 GPIO 设备驱动成功控制 GPIO 的输入和输出。
参考资料:
【1】《外围设备驱动操作指南.doc》
【2】《Hi3559V200_PINOUT_CN.xlsx》
【3】《HI3559V200DMEB_VER_A_SCH.pdf》
评论