GPIO之MIO的使用#
Bank0: 32-bit bank controlling MIO pins[31:0] Bank1: 22-bit bank controlling MIO pins[53:32]
除 Bank1 之外的 Bank 都具有 32bit, Bank1 只具有 22bit 是因为总共只有 54 个 MIO,其中 32bit 的 Bank0控制了 MIO[031],剩下的 MIO[3153]就由 22bit 的 Bank1 控制。 Bank2 和 Bank3 用于控制扩展的 MIO 即EMIO,也就是说总共可以有 32+32=64 个 EMIO。
PS-MIO:
Bank0:MIO[31:0] GPIO PIN 脚号: MIO31~MIO0
Bank1:MIO[53:32] GPIO PIN 脚号: MIO53~MIO32
PS-EMIO:
Bank2:EMIO[ 0:31] 可以分配到任意的 FPGA IO
Bank3:EMIO[32:63] 可以分配到任意的 FPGA IO
查看硬件原理图以及数据手册#
搜索AXU4EVB-E_UG.pdf发现目标led连接在开发板PS端的MIO40引脚上。 在xilinx 官网搜索ug1087就可以找到。搜索关键词MIO,找到GPIO Module。
GPIO 寄存器的基地址为0xFF0A0000,控制GPIO我们需要三步:使能、设置方向、控制输出。MIO40在GPIO BANK1中。对应找到使能寄存器OEN_1:0xFF0A0248、方向寄存器DIRM_1:0xFF0A0244、控制寄存器DATA_1:0xFF0A0044。
led-ps 源码#
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/ide.h>
#include <linux/types.h>
#define GPIO_BASE 0x00FF0A0000
#define GPIO_BASE_LEN 0x300
static unsigned int *gpio_addr_vir = 0;
#define GPIO_OEN1 (unsigned int *)(0x248 + (unsigned long)gpio_addr_vir)
#define GPIO_DIRM1 (unsigned int *)(0x244 + (unsigned long)gpio_addr_vir)
#define GPIO_DATA1 (unsigned int *)(0x044 + (unsigned long)gpio_addr_vir)
#define CHAR_DEV_MAJOR 200
#define CHAR_DEV_NAME "led_dev"
static int char_dev_open(struct inode *inode_p, struct file *file_p)
{
printk(KERN_ERR "char dev open\n");
return 0;
}
static int char_dev_release(struct inode *inode_p, struct file *file_p)
{
printk("char dev release\n");
return 0;
}
static ssize_t char_dev_write(struct file *file_p, const char __user *buf, size_t len, loff_t *loff_t_p)
{
int ret = 0;
char lc_buf = 0;
ret = copy_from_user(&lc_buf, buf, len);
if (ret != 0)
{
printk("copy_from_user failed\n");
return -1;
}
if (len != 1)
{
printk("len err\n");
return -2;
}
if (1 == lc_buf)
{
*GPIO_DATA1 |= 0x00004000;
}
else if (0 == lc_buf)
{
*GPIO_DATA1 &= 0xFFFFBFFF;
}
else
{
printk("data err\n");
}
return 0;
}
static struct file_operations char_dev_opt = {
.owner = THIS_MODULE,
.open = char_dev_open,
.write = char_dev_write,
.release = char_dev_release,
};
static int __init char_drv_init(void)
{
int ret = 0;
ret = register_chrdev(CHAR_DEV_MAJOR, CHAR_DEV_NAME, &char_dev_opt);
if (ret < 0)
{
}
else
{
gpio_addr_vir = ioremap_wc(GPIO_BASE, GPIO_BASE_LEN);
*GPIO_DIRM1 |= 0x00004000;
*GPIO_OEN1 |= 0x00004000;
}
return ret;
}
static void __exit char_drv_exit(void)
{
iounmap(gpio_addr_vir);
unregister_chrdev(CHAR_DEV_MAJOR, CHAR_DEV_NAME);
}
module_init(char_drv_init);
module_exit(char_drv_exit);
MODULE_AUTHOR("Alinx");
MODULE_ALIAS("gpio_led");
MODULE_DESCRIPTION("GPIO LED driver");
MODULE_VERSION("v1.0");
MODULE_LICENSE("GPL");
使用petalinux编译#
进入工作目录(/peta/peta_prj/linuxPsBase/petalinux
)启动docker
docker run -ti -v "$PWD":"$PWD" -w "$PWD" --rm -u petalinux docker_petalinux2:2020.1 $@
输入下面的命令添加新的驱动:
petalinux-create -t modules --name ps-led --enable
/peta/peta_prj/linuxPsBase/petalinux/project-spec/meta-user/recipes-modules
,下面有了名为 ps-led 的文件夹,再进入petalinux工程中目录/peta/peta_prj/linuxPsBase/petalinux/project-spec/meta-user/recipes-modules/ps-led/files
,目录下名为 ps-led.c 的文件就是 petalinux 帮我们新建的驱动文件。
使用 makefile单独编译驱动#
修改c文件第一行添加一个语法错误用于寻找KERNELDIR
/peta/peta_prj/linuxPsBase/petalinux/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts
创建Makefile
modname:=ps-led
obj-m:=$(modname).o
PWD :=$(shell pwd)
MAKE :=make
KERNELDIR = /peta/peta_prj/linuxPsBase/petalinux/build/tmp/work-shared/zynqmp-generic/kernel-build-artifacts
CROSS_COMPILE=aarch64-linux-gnu-ARCH=arm64
all:
$(MAKE) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) -C $(KERNELDIR) M=$(PWD) modules
clean:
rm -rf $(modname).ko *.o *mod* \.*cmd *odule* .tmp_versions
.PHONY: all clean
将其和c放置在同一文件夹时使用make即可编译
首次编译需要安装 gcc-aarch64-linux-gnu
sudo apt-get install gcc-aarch64-linux-gnu