ROC-RK3308-CC开发实例总结--PS2 Joystick摇杆模块
时间:2022-10-12 05:30:01
本帖最后由 Demon 于 2019-4-8 17:58 编辑
最近,我调试了一个有趣的传感器模块--PS2Joystick摇杆模块。下面和大家分享一下我的测试方法。下面只有个人意见。如果有缺点,请指出,非常感谢。
一、模块介绍
PS2双轴游戏摇杆模块采用了PS2.游戏手柄上的优质金属按钮摇杆电位器和模块集成电源指示灯可显示工作状态;坐标符清晰简洁,定位准确。
模块外观.png (94.31 KB, 下载次数: 24)
2019-4-8 15:51 上传
让我们先看看它的工作原理,这样我们就知道它发生了什么,这对我们使用它很有帮助。以下是模块的功能示意图:
功能示意图.png (100.63 KB, 下载次数: 22)
2019-4-8 15:53 上传
从上图可以看出,该模块配二路模拟输出和一路数字输出接口,输出值分别对应(X,Y)双轴偏移量,其类型为模拟量;另一数字表示用户是否在Z轴按下,其类型为数字开关量。通过控制器编程,传感器扩展板插接,完成具有创意性的互动作品或者游戏。
game.jpeg (34.75 KB, 下载次数: 25)
2019-4-8 16:07 上传
game1.jpeg (48.97 KB, 下载次数: 29)
2019-4-8 17:52 上传
二、代码简述
按照惯例,了解模块后,首先kernel/arch/arm64/boot/dts/rockchip/rk3308-firefly.dtsi将设备的节点信息添加到设备树中。
PS2_test@ff1e0000{
compatible = "ps2 joystick";
clocks = ;
lock-names = "saradc";
Z-axis = ;
io-channels = , ;
io-channel-names = "X-axis" , "Y-axis";
status = "okay";
};复制代码 使用代码ADC通道0与ADC还有一个通道2GPIO口。使用的ADC时钟为saradc。以下将编写驱动代码:首先是kernel/drivers/adc/创建相应的文件夹,添加Kconfig、Makefile、ps2.c其中。
static struct file_operations ps2_fops = {
.owner = THIS_MODULE,
.open= ps2_open,
.release = ps2_release,
.read= ps2_read,
};
static struct miscdevice ps2_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
.name= "PS2",
.fops= &ps2_fops,
};
static const struct of_device_id ps2_match[] = {
{ .compatible = "ps2 joystick" },
{},
};
static struct platform_driver ps2_driver = {
.probe = ps2_probe,
.remove = ps2_remove,
.driver = {
.owner = THIS_MODULE,
.name = "PS2 Game joystick module",
.of_match_table = ps2_match,
}
};
static int ps2_init(void)
{
adc_clock = clk_get(NULL, "saradc");
if(!adc_clock) {
return -ENOENT;
}
clk_enable(adc_clock);
platform_driver_register(&ps2_driver);
return misc_register(&ps2_miscdev);
}复制代码 这里就不赘述驱动框架了,驱动应用于初始化函数中的杂项设备和相关设备信息。以下将是probe分析函数:
static int ps2_probe(struct platform_device *pdev)
{
enum of_gpio_flags z_flag;
devs = pdev;
ps2 = kmalloc(sizeof(struct PS2), GFP_KERNEL);
if(!ps2){
printk("ps2 kmalloc memory err!!!\n");
return -ENODEV;
}
z_axis_gpio = of_get_named_gpio_flags(pdev->dev.of_node, "Z-axis", 0, &z_flag);
if(!gpio_is_valid(z_axis_gpio)) {
printk("z-axis is invalid!\n");
return -ENODEV;
}
gpio_direction_input(z_axis_gpio);
chan0 = iio_channel_get(&(pdev->dev), "X-axis");
if(IS_ERR(chan0)){
return -1;
}
chan2 = iio_channel_get(&(pdev->dev), "Y-axis");
if(IS_ERR(chan2)){
return -1;
}
return 0;
}复制代码 需要一提的是iio_channel_get()函数的功能是:获取 iio 通道描述。参数为:设备描述指针,通道描述指针。of_get_named_gpio_flags()功能为:获取GPIO信息。gpio_is_valid()功能为:判断GPIO是否合法。下面为ps2_read()函数:
ssize_t ps2_read(struct file *filp, char __user *buf, size_t size, loff_t *f_pos)
{
int ret;
char data[20] = {0};
ps2_get_value();
sprintf(data, "%d,%d,%d",ps2->x_axis,ps2->y_axis,ps2->z_axis);
ret = copy_to_user(buf, data, sizeof(data));
return ret;
}复制代码 在read()调用函数ps2_get_value()是获取所需值的函数。具体如下:
int ps2_get_value(void)
{
int ret;
ret = iio_read_channel_raw(chan0, &(ps2->x_axis));
if(ret < 0 || ret > 4) {
printk("read channel() erro!!!");
return ret;
}
ps2->x_axis = (STANDARD_VOL * ps2->x_axis) / CONVERSION_NUM;
ret = iio_read_channel_raw(chan2, &(ps2->y_axis));
if(ret < 0 || ret > 4){
printk("read channel() erro!!!");
return ret;
}
ps2->y_axis = (STANDARD_VOL * ps2->y_axis) / CONVERSION_NUM;
ps2->z_axis = gpio_get_value(z_axis_gpio);
return 0;
}复制代码 其中iio_read_channel_raw()函数的功能为:读取 chan 通道 AD 采集的原始数据。参数为:通道指针、数据存放指针。此处的STANDARD_VOL与CONVERSION_NUM分别表示标准电压、转换位数。关于ADC的使用方法,可以参照firefly官方wikADC使用
gpio_get_value()函数的功能为:获取GPIO的IO值。代码写到此处,驱动算是基本已经完成,对其进行编译,生成固件,烧入开发板。以下为应用层测试程序的编写:
int main(int argc, char argv[])
{
char data[20] = {0};
int fd,ret;
int ps2[3];
char tmp = ',';
char *flag[5] = {0};
fd = open("/dev/PS2", O_RDONLY);
if(fd < 0){
printf("open /dec/PS2 faild!!\n");
return -1;
}
while(1)
{
ret = read(fd, buff, sizeof(data));
if(ret < 0){
printf("read fd faild!!\n");
return -1;
}
flag = strtok(data, &tmp);
if(flag)
ps2[0] = atoi(flag);
flag = strtok(NULL, &tmp);
if(flag)
ps2[1] = atoi(flag);
flag = strtok(NULL, &tmp);
if(flag)
ps2[2] = atoi(flag);
printf("x: %d, y: %d, z:%d", ps2[0], ps2[1], ps2[2]);
bzero(data, 20);
sleep(1);
}
return 0;
}复制代码 测试程序较为简单,访问读取/dev/PS2数据即可。再使用strtok()函数分割data,得到每个轴的数据。完成之后,使用指定的交叉编译链进行编译,将可执行文件传输至开发板中。
三、效果展示
一切准备工作处理完成之后,即可执行程序,查看代码效果!!
效果.png (94.25 KB, 下载次数: 26)
2019-4-8 17:33 上传
(此文仅个人见解,若有不足之处,望指出,不胜感激)