如何在Linux系统中直接 *** 作GPIO

如何在Linux系统中直接 *** 作GPIO,第1张

方法/步骤

1

安装SD Linux系统

如图所示,先后将Arduino Software 1.5.3 (Arduino IDE)和SD-Card Linux Image下载到本机,Arduino IDE在后面查找GPIO与Arduino IO 之间的映射关系时需要用到。

如图所示,将SDCard1.0.4.tar.bz2解压后出现一个“image-full-galileo”的文件夹。

在MicroSD使用前需先将其以Fat32进行格式化,然后将“image-full-galileo”文件夹下地所有文件直接拷贝到microSD卡的根目录下。

进入Galileo

将MicroSD插到Galileo中,在路由器页面的已连接设备列表中会看到设备名称为“clanton”有线连接设备,找到其IP地址,然后中

Terminal(Unix和Linux,Windows可用Putty)中通过ssh进入Galileo,“ssh

[email protected]”。

有意思的是,这个在MicroSD中运行的Linux系统开启了ssh服务,并且root账号没有设置密码,可以直接进入。如上图所示,d出一对话框后输入 “yes”回车即可进入Galileo,出现下图中的 “root@clanton”说明这一步成功完成了

到这里,可能会有疑问了,Galileo板载也是有一个 *** 作系统的,microSD卡中也有一个Linux,如何保证现在进入的就是microSD卡中的系

统呢?在Terminal中输入“cat/proc/version”即可查看Linux系统版本,显示为“3.8.7-yocto-standard”,这就是前面下载的为Galileo定制的Linux *** 作系统,Yocto。

找到那个属于你的GPIO

下面就要开始这篇文章中的核心部分,也是最难的一部。找Linux GPIO 与 Arduino IO之间的映射关系!

如右图所示,在“/sys/class/gpio/”中有多大60多个GPIO,如何找出右侧GPIO与左侧Arduino IDE中对应的IO呢。

首先将0-13IO口全部设为“INPUT”输入模式

voidsetup(){//putyoursetupcodehere,torunonce:

pinMode(0,INPUT)pinMode(1,INPUT)pinMode(2,INPUT)pinMode(3,INPUT)

pinMode(4,INPUT)pinMode(5,INPUT)pinMode(6,INPUT)pinMode(7,INPUT)

pinMode(8,INPUT)pinMode(9,INPUT)pinMode(10,INPUT)

pinMode(11,INPUT)pinMode(12,INPUT)pinMode(13,INPUT)} voidloop(){

//putyourmaincodehere,torunrepeatedly: }

如图所示,左侧"pinMode(13,OUTPUT)"将13引脚变为输出模式,右侧gpio7变成out模式,因此gpio7对应的就是Arduino IO 13(pin13)

按照这种方法依次找出Arduino IO与GPIO之间如下的对应关系

GPIODigitalI/Ogpio11pin0

gpio12pin1 gpio13pin2 gpio14pin3 gpio6pin4 gpio0pin5 gpio1pin6

gpio38pin7 gpio40pin8 gpio4pin9 gpio10pin10 gpio5pin11 gpio15pin12

gpio7pin13

下面就需要来对上面找到的gpio对应关系进行验证了。“echo "out"

>/sys/class/gpio/gpio*/direction”为将gpio变为输出模式,“echo "1"

>/sys/class/gpio/gpio*/value”为将gpio输出高电平。然后就有了下面这段python程序,这段程序依次将

pin13,pin12,pin11,pin10四个引脚的LED点亮然后关闭,但由于python程序的执行效率问题,应该所有LED同时点亮有了延时

成为流水灯,如下图所示效果。这段程序在Linux系统的任意文件夹内均可。

importos,timewhileTrue:os.system('echo"out">/sys/class/gpio/gpio7/direction')

os.system('echo"1">/sys/class/gpio/gpio7/value')

os.system('echo"out">/sys/class/gpio/gpio15/direction')

os.system('echo"1">/sys/class/gpio/gpio15/value')

os.system('echo"out">/sys/class/gpio/gpio5/direction')

os.system('echo"1">/sys/class/gpio/gpio5/value')

os.system('echo"out">/sys/class/gpio/gpio10/direction')

os.system('echo"1">/sys/class/gpio/gpio10/value') time.sleep(0.2)

os.system('echo"0">/sys/class/gpio/gpio5/value')

os.system('echo"0">/sys/class/gpio/gpio15/value')

os.system('echo"0">/sys/class/gpio/gpio7/value')

os.system('echo"0">/sys/class/gpio/gpio10/value') time.sleep(0.2)

首先第一步,需要把想要观测的信号标记出来,即mark_debug,有两种mark_debug的方法,我用verilog写了一个简单的流水灯程序,只有几行代码,如下:

module main(

inputclk,

inputrst,

output reg [7:0] led

)

(*mark_debug = "true"*)reg [23:0] counter

always @(posedge clk) begin

if(rst) begin

counter <= 0

led <= 8'b00000001

end

else counter <= counter + 1

if (counter == 24'hffffff)

led <= {led[6:0],led[7]}

end

endmodule

例如,要观察counter信号的波形,那么在第7行定义reg型信号counter时,前面加上(*mark_debug=“true”*),这样就把counter信号标记了出来。如果用vhdl语言实现的话,这句话用该这样写:

signal counter : std_logic_vector (23 downto 0)

attribute mark_debug: string

attribute mark_debug of counter : signal is "true"

另外添加xdc约束文件,内容如下:

set_property PACKAGE_PIN Y9 [get_ports clk]

set_property PACKAGE_PIN T18 [get_ports rst]

set_property IOSTANDARD LVCMOS33 [get_ports clk]

set_property IOSTANDARD LVCMOS18 [get_ports rst]

set_property PACKAGE_PIN T22 [get_ports {led[0]}]

set_property PACKAGE_PIN T21 [get_ports {led[1]}]

set_property PACKAGE_PIN U22 [get_ports {led[2]}]

set_property PACKAGE_PIN U21 [get_ports {led[3]}]

set_property PACKAGE_PIN V22 [get_ports {led[4]}]

set_property PACKAGE_PIN W22 [get_ports {led[5]}]

set_property PACKAGE_PIN U19 [get_ports {led[6]}]

set_property PACKAGE_PIN U14 [get_ports {led[7]}]

set_property IOSTANDARD LVCMOS33 [get_ports {led[0]}]

set_property IOSTANDARD LVCMOS33 [get_ports {led[1]}]

set_property IOSTANDARD LVCMOS33 [get_ports {led[2]}]

set_property IOSTANDARD LVCMOS33 [get_ports {led[3]}]

set_property IOSTANDARD LVCMOS33 [get_ports {led[4]}]

set_property IOSTANDARD LVCMOS33 [get_ports {led[5]}]

set_property IOSTANDARD LVCMOS33 [get_ports {led[6]}]

set_property IOSTANDARD LVCMOS33 [get_ports {led[7]}]

之后run synthesis综合,之后open synthesized design,在左上角选择debug layout,在debug窗口中netlist看到counter信号前面有一个绿色的小蜘蛛,表示counter信号被标记出来了。

这其实是一种比较繁琐的方法,更为方便的方法是,直接综合工程,在之后打开综合设计,在netlist中直接选中想要查看的信号,右键选择mark debug,即可将信号标记出来。

但是采用第一种方式的好处是,如果工程比较复杂的话,一些信号可能会被综合优化掉,加上模块层层实例化,在netlist中可能找不到要观测的信号,这时在代码里面mark_debug,依旧可以将该信号引出来。

接着第二步就是插入调试内核了,在Vivado界面下方,找到Unassigned Debug Nets,右键选择 set up debug,在接下来的对话框中列出了counter信号的lk domain是CLK_IBUG_BUFG,其trig和data项都打了对勾,表示counter信号既作为触发信号也作为数据信号。

代码:

#include&ltlinux/module.h&gt

#include&ltlinux/kernel.h&gt

#include&ltasm/io.h&gt

#include&ltlinux/miscdevice.h&gt

#include&ltlinux/fs.h&gt

#include&ltasm/uaccess.h&gt

//流水灯代码

#define GPM4CON 0x110002e0

#define GPM4DAT 0x110002e4

static unsigned long*ledcon=NULL

static unsigned long*leddat=NULL

//自定义write文件 *** 作(不自定义的话,内核有默认的一套文件 *** 作函数)

static ssize_t test_write(struct file*filp,const char __user*buff,size_t count,loff_t*offset)

{

int value=0

int ret=0

ret=copy_from_user(&value,buff,4)

//底层驱动只定义基本 *** 作动作,不定义功能

if(value==1)

{

*leddat|=0x0f

*leddat&=0xfe

}

if(value==2)

{

*leddat|=0x0f

*leddat&=0xfd

}

if(value==3)

{

*leddat|=0x0f

*leddat&=0xfb

}

if(value==4)

{

*leddat|=0x0f

*leddat&=0xf7

}

return 0

}

//文件 *** 作结构体初始化

static struct file_operations g_tfops={

.owner=THIS_MODULE,

.write=test_write,

}

//杂设备信息结构体初始化

static struct miscdevice g_tmisc={

.minor=MISC_DYNAMIC_MINOR,

.name="test_led",

.fops=&g_tfops,

}

//驱动入口函数杂设备初始化

static int __init test_misc_init(void)

{

//IO地址空间映射到内核的虚拟地址空间

ledcon=ioremap(GPM4CON,4)

leddat=ioremap(GPM4DAT,4)

//初始化led

*ledcon&=0xffff0000

*ledcon|=0x00001111

*leddat|=0x0f

//杂设备注册函数

misc_register(&g_tmisc)

return 0

}

//驱动出口函数

static void __exit test_misc_exit(void)

{

//释放地址映射

iounmap(ledcon)

iounmap(leddat)

}

//指定模块的出入口函数

module_init(test_misc_init)

module_exit(test_misc_exit)

MODULE_LICENSE("GPL")

扩展资料:

include用法:

#include命令预处理命令的一种,预处理命令可以将别的源代码内容插入到所指定的位置;可以标识出只有在特定条件下才会被编译的某一段程序代码;可以定义类似标识符功能的宏,在编译时,预处理器会用别的文本取代该宏。

插入头文件的内容

#include命令告诉预处理器将指定头文件的内容插入到预处理器命令的相应位置。有两种方式可以指定插入头文件:

1、#include&lt文件名&gt

2、#include"文件名"

如果需要包含标准库头文件或者实现版本所提供的头文件,应该使用第一种格式。如下例所示:

#include&ltmath.h&gt//一些数学函数的原型,以及相关的类型和宏

如果需要包含针对程序所开发的源文件,则应该使用第二种格式。

采用#include命令所插入的文件,通常文件扩展名是.h,文件包括函数原型、宏定义和类型定义。只要使用#include命令,这些定义就可被任何源文件使用。如下例所示:

#include"myproject.h"//用在当前项目中的函数原型、类型定义和宏

你可以在#include命令中使用宏。如果使用宏,该宏的取代结果必须确保生成正确的#include命令。例1展示了这样的#include命令。

【例1】在#include命令中的宏

#ifdef _DEBUG_

#define MY_HEADER"myProject_dbg.h"

#else

#define MY_HEADER"myProject.h"

#endif

#include MY_HEADER

当上述程序代码进入预处理时,如果_DEBUG_宏已被定义,那么预处理器会插入myProject_dbg.h的内容;如果还没定义,则插入myProject.h的内容。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12201559.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-21
下一篇 2023-05-21

发表评论

登录后才能评论

评论列表(0条)

保存