小白今天又踩坑,又有一个填坑的经验
源码:
首先介绍一下关键源码的说明,加红色说明是需要注意的地方
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include " gpio_control_app.h"
#include "errno.h"
//static unsigned char gpio_pin;//define GPIOs to be use
static int gpio_dev_fd = -1;;
int mcu_gpio_pin = 12;
int work_gpio_pin = 18;
void mcu_gpio_release(int signal_no)
{
ioctl(gpio_dev_fd, GPIO_CONTROL_SET_IN, GPIO_IOCTL_PRAM(mcu_gpio_pin, 0));
//信号量响应,将相应的IO口设置输入
ioctl(gpio_dev_fd, GPIO_CONTROL_FREE_GPIO, GPIO_IOCTL_PRAM(mcu_gpio_pin, 0));
//信号量响应,释放相应的IO口资源
exit(0);
}
void bsp_gpio_init(void)
{
gpio_dev_fd = open(GPIO_CONTROL_DEVICE_PATH, O_RDWR);//open gpio device
if (gpio_dev_fd < 0)
{
printf("###open %s ERROR###\n", GPIO_CONTROL_DEVICE_PATH);
}
else
{
printf("***open %s success***\n", GPIO_CONTROL_DEVICE_PATH);
}
}
int set_work_gpio(void)
{
int ret = 0;
if(gpio_dev_fd == -1)
{
return -1;
}
printf("work_gpio_pin:%d\n", work_gpio_pin);
ret =ioctl(gpio_dev_fd, GPIO_CONTROL_REQUEST_GPIO, GPIO_IOCTL_PRAM(work_gpio_pin, 0));
printf("%s\n",strerror(errno));
printf("set_gpio ret = %d\n",ret);
if (ret < 0)
{
printf("###request GPIO %d error###", work_gpio_pin);
return -1;
}
ret = ioctl(gpio_dev_fd, GPIO_CONTROL_SET_OUT, GPIO_IOCTL_PRAM(work_gpio_pin, 0));
if (ret < 0)
{
printf("###set GPIO %d output error###", work_gpio_pin);
return -1;
}
return 1;
}
int bsp_work_gpio_ctrl(int gpio_state)
{
if(gpio_dev_fd == -1)
{
return -1;
}
if(gpio_state == 0)
{
ioctl(gpio_dev_fd, GPIO_CONTROL_SET_VALUE, GPIO_IOCTL_PRAM(work_gpio_pin, 0));
printf("###set work_gpio low ###\r\n");
}
else
{
ioctl(gpio_dev_fd, GPIO_CONTROL_SET_VALUE, GPIO_IOCTL_PRAM(work_gpio_pin, 1));
printf("###set work_gpio high ###\r\n");
}
return 0;
}
int set_mcu_gpio(void)
{
int ret;
if(gpio_dev_fd == -1)
{
return -1;
}
printf("mcu_gpio_pin:%d\n", mcu_gpio_pin);
ret = ioctl(gpio_dev_fd, GPIO_CONTROL_REQUEST_GPIO, GPIO_IOCTL_PRAM(mcu_gpio_pin, 0));
printf("bsp_mcu_gpio_ctrl ret = %d\n",ret);
if (ret < 0)
{
printf("###request GPIO %d error###\n", mcu_gpio_pin);
return -1;
}
ret = ioctl(gpio_dev_fd, GPIO_CONTROL_SET_OUT, GPIO_IOCTL_PRAM(mcu_gpio_pin, 0));
if (ret < 0)
{
printf("###set GPIO %d output error###", mcu_gpio_pin);
return -1;
}
return 1;
}
int bsp_mcu_gpio_ctrl(void)
{
signal(SIGINT, mcu_gpio_release);//register terminal signa 注册相应的信号量
ioctl(gpio_dev_fd, GPIO_CONTROL_SET_VALUE, GPIO_IOCTL_PRAM(mcu_gpio_pin, 0));
printf("### mcu_gpio_pin high###\r\n");
return 0;
}
int main(int argc, char *argv[])
{
bsp_gpio_init();
set_work_gpio();
set_mcu_gpio();
bsp_mcu_gpio_ctrl();
while(1)
{
bsp_work_gpio_ctrl(1);
sleep(1);
bsp_work_gpio_ctrl(0);
sleep(1);
}
return 1;
}
代码中先通过GPIO_CONTROL_REQUEST_GPIO,取得了相应的gpio的资源,
在终端输入ctrl+c 释放相应的gpio的资源:
遇到的问题:
下次代码运行的时候,无法重新设置相应的IO口
调试方法:
在虚拟机中
步骤一
修改gpio_control_driver.c
进入相应的驱动目录:
~/lede_AR9331_zhuotk_source_32bit/package/kernel/gpio_control_driver/src$
打开gpio_control_driver.c
将GPIO_CONTROL_REQUEST_GPIO下的打印信息打开
make menuconfig 进行选择
重新进行make V=s编译
找到生成的.ko文件
~/lede_AR9331_zhuotk_source_32bit/build_dir/target-mips_24kc_musl/linux-ar71xx_generic/gpio_control_driver$
gpio_control_driver.ko为新生成的驱动
在开发板中
进入开发板的命令行终端:
首先卸载掉以前的驱动
原有的驱动程序加载模块在目录
root@AOTUO:/lib/modules/4.4.79#
输入命令行:rmmod gpio_control_driver.ko
将新生成的驱动传输到当前目录
输入命令行:insmod gpio_control_driver.ko
重新加入驱动模块
步骤三
在命令行终端运行相应的app程序,
发现错误信息打印,request GPIO 18 error
进入内核日志,查看打印信息
发现驱动中的打印GPIO_CONTROL_REQUEST_GPIO 返回值为-16
解决问题:
Linux中调用gpio_request申请一个GPIO时返回错误码-16,原因是前面已经用gpio_request对同一个GPIO做了申请操作。可以把前面的GPIO用gpio_free先释放再改作它用。
这是因为ctrl+c信号量那边只释放了一个IO口的资源,另一个没有进行释放。下次调用的时候会出现调用失败的情况
一般来说,一个GPIO只是分配给一个设备的,所以这个设备的驱动会请求这个GPIO。这样,在其他的设备也想请求这个GPIO的时候会返回失败。事实上,gpio_request只是给这个GPIO做一个标示,并没有什么实质的作用。操作GPIO是通过gpio_set_value、gpio_direction_output之类的函数去做的,即便没有request,一样可以设置GPIO的电平。
结束进程的时候,将相应的io口资源进行释放
后记:
一个实用的命令
find –iname 文件名 //查找
实用的快捷键
在命令行终端
Ctrl+shirt+n //多窗口
下面这一篇是关于led驱动的开发应用流程,可以作为参考