0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

学技术|SemiDrive X9H GPIO 驱动学习篇

大大通 2023-01-13 10:42 次阅读

一、概述

SemiDrive X9H 拥有不同的 domain 域,例如 AP,Safety,Secure 等等。对于 GPIO 资源,不同 domain 之间 gpio 控制器是不同的,本次主要是使用的 AP 使用的是 gpio4 控制器。除了GPIO 控制器在不同 domain 之间不同以外,pin 也是有各自不同的 domain 的,但是当它作为 gpio 使用时,可以通过设置挂靠到对应域下的 gpio 控制器上来在对应 domain 下使用。具体 pin 的 gpio 控制器的设置是通过 PC 工具 SDConfigTool 来进行。

本文主要是讲述将 pin 作为 GPIO 使用,之后编写字符设备驱动,测试。

二、适用环境

硬件:SemiDrive SD003_X9H REF_A03 DEMO Board

软件:X9 PTG3.9

三、设备树匹配

1、复用管脚为 GPIO

路径:

/buildsystem/yocto/source/linux/arch/arm64/boot/dts/semidrive/x9_high_ref_native_serdes_nobt.dts

在上面 dts 文件的 &pinctrl 的 sdx9-evk 中添加管脚复用,主要是将 GPIO_C1 管脚复用成 GPIO。

pinctrl_gpio_learning: gpiogrp_learning {

kunlun,pins = <

X9_PINCTRL_GPIO_C1__GPIO_MUX2_IO1_1 0x00

>;

};

2、配置一个新节点

路径:

/buildsystem/yocto/source/linux/arch/arm64/boot/dts/semidrive/x9_high_ref_native_serdes_nobt.dts

在上面 dts 文件里面的根节点 / 下新建一个节点,添加属性,获取 gpio 编号。

gpio_learning {

#address-cells = <1>;

#size-cells = <1>;

compatible = "gpioled_learning";

pinctrl-0 = <&pinctrl_gpio_learning>;

gpio = <&port4b 17 GPIO_ACTIVE_HIGH>;

status = "okay";

};

四、驱动编写

1、模块出/入口函数

其中 module_init 是驱动入口函数,主要进行 platform 平台驱动注册,module_exit 是驱动出口函数,主要是进行 platform 平台驱动注销;

其中 MODULE_LICENSE 主要是声明模块许可证,一般为 GPL。

/*设备入口函数*/

static int __init gpio_learning_init(void)

{

return platform_driver_register(&gpio_learning_driver);

}

/*设备出口函数*/

static void __exit gpio_learning_exit(void)

{

platform_driver_unregister(&gpio_learning_driver);

}

/*指定上面的入口和出口函数*/

module_init(gpio_learning_init);

module_exit(gpio_learning_exit);

MODULE_LICENSE("GPL"); //LICENSE 采用 GPL 协议

2、platform 平台驱动结构体

主要是通过 match 函数和对应的设备树里面节点匹配,只要 compatible 属性匹配成功即可,匹配成功就执行 probe 函数。

/*匹配列表*/

static const struct of_device_id gpio_learning_of_match[] = {

{ .compatible = "gpioled_learning" },

{ /*sentinel*/}

};

/*

* platform 平台驱动结构体

*/

static struct platform_driver gpio_learning_driver ={

.driver = {

.name = "gpio_learning_device",

.of_match_table = gpio_learning_of_match,

},

.probe = gpio_learning_probe,

.remove = gpio_learning_remove,

};

3、probe 函数

主要是注册字符设备,通过获取设备树的节点,获取 gpio 属性,从而获得 gpio编号,之后请求使用该 gpio,设置 gpio 模式。

/*

* platform 驱动的 probe 函数

* 驱动与设备匹配成功以后此函数就会执行

*/

static int gpio_learning_probe(struct platform_device *dev)

{

printk("led driver and device was matched!\r\n");

/* 1、设置设备号 */

if (gpiodev.major) { //如果定义了主设备号

gpiodev.devid = MKDEV(gpiodev.major, 0);//次设备号号默认 0,构建设备号

register_chrdev_region(gpiodev.devid, GPIODEV_CNT,GPIODEV_NAME);//注册设备号

} else {

alloc_chrdev_region(&gpiodev.devid, 0, GPIODEV_CNT,GPIODEV_NAME);//动态申请设备号

gpiodev.major = MAJOR(gpiodev.devid);//获取主设备号

}

/* 2、注册设备 */

cdev_init(&gpiodev.cdev,&gpio_learning_fops);

cdev_add(&gpiodev.cdev, gpiodev.devid, GPIODEV_CNT);

/* 3、创建类 */

gpiodev.class = class_create(THIS_MODULE, GPIODEV_NAME);

if (IS_ERR(gpiodev.class)) {

return PTR_ERR(gpiodev.class);

}

/* 4、创建设备 */

gpiodev.device = device_create(gpiodev.class, NULL, gpiodev.devid,NULL, GPIODEV_NAME);

if (IS_ERR(gpiodev.device)) {

return PTR_ERR(gpiodev.device);

}

/* 5、初始化 IO */

gpiodev.node = of_find_node_by_path("/gpio_learning");

if (gpiodev.node == NULL){

printk("gpio_learning node nost find!\r\n");

return -EINVAL;

}

gpiodev.led0 = of_get_named_gpio(gpiodev.node, "gpio", 0);/*获取要使用的 GPIO 编号 */

if (gpiodev.led0 < 0) {

printk("can't get gpio\r\n");

return -EINVAL;

}

printk("led0 = %d\r\n",gpiodev.led0);

int ret = gpio_request(gpiodev.led0, "led0");/*申请gpio管脚 */

if(ret == 0)

{

printk("gpio_request success\r\n");

}

else

{

printk("gpio_request fail\r\n");

return -1;

}

ret = gpio_direction_output(gpiodev.led0, 1); /*设置为输出,默认高电平 */

if(ret == 0)

{

printk("gpio_direction_output success\r\n");

}

else

{

printk("gpio_direction_output fail\r\n");

return -1;

}

return 0;

}

4、设备函数操作结构体

主要是一个 open 和 write 的函数。

/*

* 设备操作函数结构体

*/

static struct file_operations gpio_learning_fops = {

.owner = THIS_MODULE,

.open = gpio_learning_open,

.write = gpio_learning_write,

};

5、设备操作 open 和 write函数

主要 open 函数是将 private_data 指向设备结构体。

主要 write 函数是接受用户层传来的数据,之后根据数据设置 gpio 操作。

#define GPIODEV_CNT 1 /* 设备号长度 */

#define GPIODEV_NAME "gpio_learning" /* 设备名字 */

#define GPIOOFF 0

#define GPIOON 1

//设备结构体

struct gpiodev_dev{

dev_t devid; /* 设备号 */

struct cdev cdev; /* cdev */

struct class *class; /* 类 */

struct device *device; /* 设备 */

int major; /* 主设备号 */

struct device_node *node; /* 设备节点 */

int led0; /* LED 灯 GPIO 标号 */

};

struct gpiodev_dev gpiodev;

/*

* @description : LED 打开/关闭

* @param - sta : LEDON(0) 打开 LED,LEDOFF(1) 关闭 LED

* @return : 无

*/

void led0_switch(u8 sta)

{

if (sta == GPIOON )

{

gpio_set_value(gpiodev.led0, 1);

printk("gpio_set_value = 1!\r\n");

}

else if (sta == GPIOOFF)

{

gpio_set_value(gpiodev.led0, 0);

printk("gpio_set_value = 0!\r\n");

}

return 0;

}

/*

* @description : 打开设备

* @param – inode : 传递给驱动的 inode

* @param - filp : 设备文件,file 结构体有个叫做 private_data 的成员变量

* 一般在 open 的时候将 private_data 指向设备结构体。

* @return : 0 成功;其他 失败

*/

static int gpio_learning_open(struct inode *inode,struct file *filp)

{

filp->private_data = &gpiodev; /* 设置私有数据 */

return 0;

}

static ssize_t gpio_learning_write(struct file *filp,const char __user *buf,size_t cnt,loff_t *offt)

{

int retvalue;

unsigned char databuf[2];

unsigned char ledstat;

retvalue = copy_from_user(databuf, buf, cnt);

if(retvalue < 0) {

printk("kernel write failed!\r\n");

return -EFAULT;

}

printk("retvalue = %d\r\n",retvalue);

ledstat = databuf[0];

if (ledstat == GPIOON) {

printk("ledstat = 1\r\n");

led0_switch(GPIOON);

} else if (ledstat == GPIOOFF) {

printk("ledstat = 0\r\n");

led0_switch(GPIOOFF);

}

return 0;

}

五、Kernel 配置

1、Makefile 文件

obj-$(CONFIG_GPIO_LEARNING) += gpio_learning.o

2、Kconfig 文件

config GPIO_LEARNING

tristate "GPIO learning block support"

default m

help

This is enable gpio learning test

3、引用

在自己编写文件的上一级目录 Makefile 和 Kconfig 添加对应引用,并在对应 deconfig 配置。

Makefile 文件引用

obj-$(CONFIG_GPIO_LEARNING) += gpio_learning/

Kconfig 文件引用

source "drivers/gpio_learning/Kconfig"

deconfig 文件配置

路径:

/buildsystem/yocto/source/linux/arch/arm64/configs/x9_ref_linux_defconfig

等于 m 表示编译成 ko 文件,等于 y 表示编译进内核。

CONFIG_GPIO_LEARNING=m

六、APP 测试

主要是传入三个参数,一个是运行的 app,一个是对应的 /dev/xxx,一个是对 gpio 的操作(1/0),通过 /dev/xxx 打开对应驱动文件,通过 write 发送对应的操作。

#include "stdio.h"

#include "unistd.h"

#include "sys/types.h"

#include "sys/stat.h"

#include "fcntl.h"

#include "stdlib.h"

#include "string.h"

int main(int argc, char *argv[])

{

int fd, retvalue;

char *filename;

unsigned char databuf[2];

if(argc != 3){ //传入三个参数:运行的app /dev/xxx 操作

printf("Error Usage!\r\n");

return -1;

}

filename = argv[1];

/* 打开 /dev/xxx 驱动文件 */

fd = open(filename, O_RDWR);

if(fd < 0){

printf("file %s open failed!\r\n", argv[1]);

return -1;

}

databuf[0] = atoi(argv[2]); /* 要执行的操作:打开或关闭 */

retvalue = write(fd, databuf, sizeof(databuf));

if(retvalue < 0){

printf("LED Control Failed!\r\n");

close(fd);

return -1;

}

retvalue = close(fd); /* 关闭文件 */

if(retvalue < 0){

printf("file %s close failed!\r\n", argv[1]);

return -1;

}

return 0;

}

以上完成了 SemiDrive X9H GPIO 功能的实现。

接下来将会更新更多关于 SemiDrive X9H 的开发博文,如有相关技术问题,可在评论区留言。

七、参考文档

《 SemiDrive_9_Series_GPIO使用手册_Rev01.00.pdf 》

《 X9H处理器数据手册_Rev04.00.pdf 》

《 SD003_X9H_REF_A03_SCH.pdf 》

《 X9_Processor_TRM_Rev00.07.pdf 》

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 控制器
    +关注

    关注

    112

    文章

    16308

    浏览量

    177784
  • 驱动
    +关注

    关注

    12

    文章

    1837

    浏览量

    85253
  • GPIO
    +关注

    关注

    16

    文章

    1204

    浏览量

    52045
收藏 人收藏

    评论

    相关推荐

    SOC GPIO操作

    支持4种中断从下面的表中需要注意到:中断使能有两个位bit0和bit1,所以GPIO的两个 中断是分别控制的。在gpio.h中已经有宏定义 #define
    的头像 发表于 11-01 11:06 131次阅读

    使用LP875230C-Q1 和 LP87565V-Q1 的 Semidrive X9H 电源设计

    电子发烧友网站提供《使用LP875230C-Q1 和 LP87565V-Q1 的 Semidrive X9H 电源设计.pdf》资料免费下载
    发表于 09-12 11:08 0次下载
    使用LP875230C-Q1 和 LP87565V-Q1 的 <b class='flag-5'>Semidrive</b> <b class='flag-5'>X9H</b> 电源设计

    Semidrive X9P/X9U 电源设计

    电子发烧友网站提供《Semidrive X9P/X9U 电源设计.pdf》资料免费下载
    发表于 09-11 10:21 0次下载
    <b class='flag-5'>Semidrive</b> <b class='flag-5'>X9</b>P/<b class='flag-5'>X9</b>U 电源设计

    SemiDrive X9 AI 开发环境搭建

    SemiDrivex9AI开发环境搭建分开发机端,开发板端。主要的工具是SDNN,它是一个基于开源编译器框架TVM的端到端的AI编译器框架,Semidrive对TVM编译器框架做了适配,主要特性如下
    的头像 发表于 08-03 08:27 381次阅读
    <b class='flag-5'>SemiDrive</b> <b class='flag-5'>X9</b> AI 开发环境搭建

    MGMF444L1H9M-MINAS A6BL (EtherCAT) 系列 技术资料 -基本功能规格- 松下

    电子发烧友网为你提供Panasonic(Panasonic)MGMF444L1H9M-MINAS A6BL (EtherCAT) 系列 技术资料 -基本功能规格-相关产品参数、数据手册,更有
    发表于 05-27 18:42
    MGMF444L1<b class='flag-5'>H9</b>M-MINAS A6BL (EtherCAT) 系列 <b class='flag-5'>技术</b>资料 -基本功能规格<b class='flag-5'>篇</b>- 松下

    MGMF444L1H9M-MINAS A6BL (EtherCAT) 系列 技术资料 -EtherCAT 通信规格- 松下

    电子发烧友网为你提供Panasonic(Panasonic)MGMF444L1H9M-MINAS A6BL (EtherCAT) 系列 技术资料 -EtherCAT 通信规格-相关产品参数、数据
    发表于 05-27 18:42
    MGMF444L1<b class='flag-5'>H9</b>M-MINAS A6BL (EtherCAT) 系列 <b class='flag-5'>技术</b>资料 -EtherCAT 通信规格<b class='flag-5'>篇</b>- 松下

    MGMF444L1H9M-MINAS A6NL系列 (RTEX) 技术资料 -基本功能规格- 松下

    电子发烧友网为你提供Panasonic(Panasonic)MGMF444L1H9M-MINAS A6NL系列 (RTEX) 技术资料 -基本功能规格-相关产品参数、数据手册,更有
    发表于 05-27 18:39
    MGMF444L1<b class='flag-5'>H9</b>M-MINAS A6NL系列 (RTEX) <b class='flag-5'>技术</b>资料 -基本功能规格<b class='flag-5'>篇</b>- 松下

    MGMF444A1H9M-MINAS A6B 系列 (EtherCAT) 技术资料 -EtherCAT 通信规格- 松下

    电子发烧友网为你提供Panasonic(Panasonic)MGMF444A1H9M-MINAS A6B 系列 (EtherCAT) 技术资料 -EtherCAT 通信规格-相关产品参数、数据
    发表于 05-22 19:14
    MGMF444A1<b class='flag-5'>H9</b>M-MINAS A6B 系列 (EtherCAT)  <b class='flag-5'>技术</b>资料 -EtherCAT 通信规格<b class='flag-5'>篇</b>- 松下

    MGMF294L1H9M-MINAS A6BL (EtherCAT) 系列 技术资料 -基本功能规格- 松下

    电子发烧友网为你提供Panasonic(Panasonic)MGMF294L1H9M-MINAS A6BL (EtherCAT) 系列 技术资料 -基本功能规格-相关产品参数、数据手册,更有
    发表于 05-08 18:43
    MGMF294L1<b class='flag-5'>H9</b>M-MINAS A6BL (EtherCAT) 系列 <b class='flag-5'>技术</b>资料 -基本功能规格<b class='flag-5'>篇</b>- 松下

    MGMF294L1H9M-MINAS A6S 系列 技术资料 -Modbus通信规格・Block 动作功能- 松下

    电子发烧友网为你提供Panasonic(Panasonic)MGMF294L1H9M-MINAS A6S 系列 技术资料 -Modbus通信规格・Block 动作功能-相关产品参数、数据手册,更有
    发表于 05-08 18:33
    MGMF294L1<b class='flag-5'>H9</b>M-MINAS A6S 系列 <b class='flag-5'>技术</b>资料 -Modbus通信规格・Block 动作功能<b class='flag-5'>篇</b>- 松下

    MGMF294A1H9M-MINAS A6BN 系列 技术资料 -基本功能规格- 松下

    电子发烧友网为你提供Panasonic(Panasonic)MGMF294A1H9M-MINAS A6BN 系列 技术资料 -基本功能规格-相关产品参数、数据手册,更有
    发表于 05-03 19:23
    MGMF294A1<b class='flag-5'>H9</b>M-MINAS A6BN 系列 <b class='flag-5'>技术</b>资料 -基本功能规格<b class='flag-5'>篇</b>- 松下

    MGMF294A1H9M-MINAS A6BU 系列 技术资料 -基本功能规格- 松下

    电子发烧友网为你提供Panasonic(Panasonic)MGMF294A1H9M-MINAS A6BU 系列 技术资料 -基本功能规格-相关产品参数、数据手册,更有
    发表于 05-03 19:22
    MGMF294A1<b class='flag-5'>H9</b>M-MINAS A6BU 系列 <b class='flag-5'>技术</b>资料 -基本功能规格<b class='flag-5'>篇</b>- 松下

    MGMF294A1H9M-MINAS A6BU 系列 技术资料 -EtherCAT 通信规格- 松下

    电子发烧友网为你提供Panasonic(Panasonic)MGMF294A1H9M-MINAS A6BU 系列 技术资料 -EtherCAT 通信规格-相关产品参数、数据手册,更有
    发表于 05-03 19:22
    MGMF294A1<b class='flag-5'>H9</b>M-MINAS A6BU 系列 <b class='flag-5'>技术</b>资料 -EtherCAT 通信规格<b class='flag-5'>篇</b>- 松下

    MGMF294A1H9M-MINAS A6B 系列 (EtherCAT) 技术资料 -基本功能规格- 松下

    电子发烧友网为你提供Panasonic(Panasonic)MGMF294A1H9M-MINAS A6B 系列 (EtherCAT) 技术资料 -基本功能规格-相关产品参数、数据手册,更有
    发表于 05-03 19:19
    MGMF294A1<b class='flag-5'>H9</b>M-MINAS A6B 系列 (EtherCAT)  <b class='flag-5'>技术</b>资料 -基本功能规格<b class='flag-5'>篇</b>- 松下

    MGMF294A1H9M-MINAS A6NL系列 (RTEX) 技术资料 -RTEX通信规格- 松下

    电子发烧友网为你提供Panasonic(Panasonic)MGMF294A1H9M-MINAS A6NL系列 (RTEX) 技术资料 -RTEX通信规格-相关产品参数、数据手册,更有
    发表于 05-03 19:16
    MGMF294A1<b class='flag-5'>H9</b>M-MINAS A6NL系列 (RTEX) <b class='flag-5'>技术</b>资料 -RTEX通信规格<b class='flag-5'>篇</b>- 松下