一、前言
在上一节我们移植了nes游戏,但是没有手柄不能操作,这只能看不能玩着实无趣。 在家里翻出来了小时候玩的游戏机的手柄,这里移植过来玩。
二、FC手柄介绍
先看一下手柄原型 感觉还挺不错的,哈哈
图片中可以看出,小霸王游戏机的手柄接口从外形上类似我们常说的DB9接口,但是其引脚定义与引脚功能与DB9接口差别较大。
游戏中是高电平有效
三、硬件连接
从上面我们可以知道驱动这个FC手柄需要3个IO,我从自己的开发板选取3个IO进行连接。 选取的是这三个IO。 手柄连接是通过一个DB9的公头,然后用洞洞板连接的。
STM32连接图: linux连接图:
四、修改设备树
在sun8i-v3s-licheepi-zero-dock.dts中添加
pio节点下添加:
uart1_pins_a: uart1_pins_a@0 {
pins = "PE21", "PE22";
function = "gpio_out";
};
data_pins: data_pins@0 {
pins = "PB5";
function = "gpio_in";
bias-pull-up;
};
根节点下添加:
handle{
compatible = "luatao-handle";
#address-cells = <1>;
#size-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&data_pins &uart1_pins_a>;
load_gpios = <&pio 4 22 GPIO_ACTIVE_LOW>;
clk_gpios = <&pio 4 21 GPIO_ACTIVE_LOW>;
data_gpios = <&pio 1 5 GPIO_ACTIVE_HIGH>;
status = "okay";
};
五、编写驱动程序
移植的led的驱动,好多描述没改(懒得改,凑合用吧) handle.c
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#define GPIOLED_CNT 1
#define GPIOLED_NAME "joypad"
struct gpioled_dev{
dev_t devid;
struct cdev cdev;
struct class *class;
struct device *device;
int major;
int minor;
struct device_node *nd;
int data_gpio;
int clk_gpio;
int load_gpio;
};
struct gpioled_dev gpioled;
ssize_t Handle_Get_Data(void)
{
int i;
ssize_t Data=0;
gpio_set_value(gpioled.load_gpio, 1);
udelay(2);
gpio_set_value(gpioled.load_gpio, 0);
for(i=0;i<8;i++)
{
udelay(2);
if(!gpio_get_value(gpioled.data_gpio))
{
Data |= 1<<i;
}
gpio_set_value(gpioled.clk_gpio, 1);
udelay(2);
gpio_set_value(gpioled.clk_gpio, 0);
}
gpio_set_value(gpioled.clk_gpio, 0);
gpio_set_value(gpioled.load_gpio, 0);
return Data;
}
static int led_open(struct inode *inode, struct file *filp)
{
filp->private_data = &gpioled;
printk("handle open!\r\n");
return 0;
}
static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
ssize_t val = 0;
val = Handle_Get_Data() & 0x000000ff;
if(val != 255)
printk("%d\r\n", val);
return val;
return 0;
}
static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
return 0;
}
static int led_release(struct inode *inode, struct file *filp)
{
return 0;
}
static struct file_operations gpioled_fops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_release,
};
static int __init led_init(void)
{
int ret;
gpioled.nd = of_find_node_by_path("/handle");
if(gpioled.nd == NULL){
printk("handle node no find!\r\n");
return -EINVAL;
}
gpioled.data_gpio = of_get_named_gpio(gpioled.nd, "data_gpios", 0);
if(gpioled.data_gpio < 0 ){
printk("can't get data-gpio\r\n");
return -EINVAL;
}
gpioled.clk_gpio = of_get_named_gpio(gpioled.nd, "clk_gpios", 0);
if(gpioled.clk_gpio < 0 ){
printk("can't get clk-gpio\r\n");
return -EINVAL;
}
gpioled.load_gpio = of_get_named_gpio(gpioled.nd, "load_gpios", 0);
if(gpioled.load_gpio < 0 ){
printk("can't get load-gpio\r\n");
return -EINVAL;
}
printk("data-gpio num = %d \r\n", gpioled.data_gpio);
printk("clk-gpio num = %d \r\n", gpioled.clk_gpio);
printk("load-gpio num = %d \r\n", gpioled.load_gpio);
ret = gpio_direction_output(gpioled.clk_gpio, 0);
if(ret < 0){
printk("can't set clk_gpio!\r\n");
}
ret = gpio_direction_output(gpioled.load_gpio, 0);
if(ret < 0){
printk("can't set load_gpio!\r\n");
}
ret = gpio_direction_input(gpioled.data_gpio);
if(ret < 0){
printk("can't set data_gpio!\r\n");
}
if(gpioled.major){
gpioled.devid = MKDEV(gpioled.major, 0 );
register_chrdev_region(gpioled.devid, GPIOLED_CNT, GPIOLED_NAME);
}else{
alloc_chrdev_region(&gpioled.devid,0,GPIOLED_CNT, GPIOLED_NAME );
gpioled.major = MAJOR(gpioled.devid);
gpioled.minor = MINOR(gpioled.devid);
}
printk("gpioled major = %d,minor = %d\r\n",gpioled.major, gpioled.minor);
gpioled.cdev.owner = THIS_MODULE;
cdev_init(&gpioled.cdev, &gpioled_fops);
cdev_add(&gpioled.cdev, gpioled.devid, GPIOLED_CNT );
gpioled.class = class_create(THIS_MODULE, GPIOLED_NAME);
if(IS_ERR(gpioled.class)){
return PTR_ERR(gpioled.class);
}
gpioled.device = device_create(gpioled.class, NULL, gpioled.devid, NULL, GPIOLED_NAME);
if(IS_ERR(gpioled.device)){
return PTR_ERR(gpioled.device);
}
return 0;
}
static void __exit led_exit(void)
{
cdev_del(&gpioled.cdev);
unregister_chrdev_region(gpioled.devid, GPIOLED_CNT );
device_destroy(gpioled.class, gpioled.devid);
class_destroy(gpioled.class);
printk("handle drive unregsister ok !\r\n");
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("luatao");
六、运行
加载驱动: 将编译的handle.ko放到开发板运行 然后运行游戏: 按下对应的按键会出来对应的值。
这里不得不说一下 这个游戏的识别默认是高电平有效,也就是说,值为1,2,4,8,16,32,64,128
这个我一直弄成低电平有效了,搞了半天就是没反应,不然的话,很快就完事了。
参考链接: https://blog.csdn.net/weixin_43182682/article/details/105449248 https://blog.csdn.net/weixin_43182682/article/details/105769236 nes按键
|