用QEMU进行嵌入式Linux开发

前言:

嵌入式linux的学习一定离不开一块linux开发板,但在一些情况下,我们手边可能没有一块linux开发板实物,那么使用QEMU去模拟一块linux开发板同样能够满足我们的一些学习、实验需求。

本文适用于:

  • 没有单板的嵌入式linux初学者
  • 有单板但是不想用想靠模拟去做一些实验的嵌入式linux开发者
  • 过了好几年忘掉关于qemu单板操纵的作者本人 -.-

1、环境搭建&&资料获取

韦东山老师的百问网中有关于"百问网im6ull-qemu"开发板的简介,说明了qemu的简介、这块开发板的一些资源介绍、快速使用等等各个介绍。

里面有一整个ubuntu的镜像,里面有搭建好的关于"百问网im6ull-qemu"开发板的一切

根据文档完成Ubuntu的镜像下载,使用虚拟机打开之后,那么恭喜你!你现在拥有了一块名字叫做"百问网im6ull-qemu"的开发板。

2、快速上手

一些文件介绍:

100ask_imx6ull-qemu:linux启动需要的:根文件系统源码(buildroot2019.02)、内核源码(linux-4.9.88)、qemu源码(qemu)编译工具链(ToolChain)。如果我们想改一些内核的东西需要在这里哈。

ubuntu-18.04_imx6ul_qemu_system:开发板启动所需的文件都在这里啦!使用sh脚本即可

bash 复制代码
$ ./qemu-imx6ull-gui.sh  // 启动后,登录名是root,无需密码
或
$ ./qemu-imx6ull-gui_test.sh  // 使用测试版的QEMU,启动后登录名是root,无需密码

启动之后我们要先挂载一下nfs:里面要有一些库文件,且这也是我们通过mnt文件完成Ubuntu系统中的文件到开发板的传递的重要方式,

bash 复制代码
mount -t nfs -o nolock,vers=3  10.0.2.2:/home/boook/nfs_rootfs

now,我们可以进行一些学习和开发了!

3、按键点灯

这里我想开发一个通过按钮点灯的功能(花式点灯,舍我其谁!)。

3.1 轮询方式

开发板中自带的代码就是以这种方式实现的,通过不断查询按键设备节点的状态,检测有变化时去设置led灯的状态。

3.2中断方式

3.1中的实现并不是终端实现,而是一种轮询,这会造成资源的浪费,因此我这里想探究一下终端的实现方式。

如何改进为真正的中断方式

3.2 方案1:修改用户空间程序(使用poll/select)

没试过,只是搜到有这种方案

3.3 方案2:改进内核驱动

首先看下memory map:i.MX 6ULL Applications Processor Reference Manual

看下设备树文件:给gpio1起了个gpio0的别名,有点意思...

再看下设备节点的定义,

cpp 复制代码
soc {
        #address-cells = <1>;
        #size-cells = <1>;
        compatible = "simple-bus";
        interrupt-parent = <&gpc>;
        ranges;
省略...
aips1: aips-bus@02000000 {
            compatible = "fsl,aips-bus", "simple-bus";
            #address-cells = <1>;
            #size-cells = <1>;
            reg = <0x02000000 0x100000>;
            ranges;
省略...
            gpio1: gpio@0209c000 {
                compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
                reg = <0x0209c000 0x4000>;
                interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
                         <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-controller;
                #interrupt-cells = <2>;
            };

            gpio2: gpio@020a0000 {
                compatible = "fsl,imx6ul-gpio", "fsl,imx35-gpio";
                reg = <0x020a0000 0x4000>;
                interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
                         <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
                gpio-controller;
                #gpio-cells = <2>;
                interrupt-controller;
                #interrupt-cells = <2>;
            };

看下芯片手册,发现其实gpio1有两种中断形式,66、67为15个引脚共用一个中断号,只关注66、67吧。

注意:在编写驱动时,我们不需要关心具体的中断父节点设置,只需要从设备树中获取中断号即可。设备树中的interrupt-parent属性由内核在解析设备树时使用,用于构建中断映射。

① 修改设备节点

需要为案件增加终中断属性:

② 驱动编写

伪代码如下:

cpp 复制代码
// 1. 在probe函数中获取资源
static int button_probe(struct platform_device *pdev)
{
    // 获取GPIO和中断
    int gpio = of_get_gpio(np, 0);
    int irq = gpio_to_irq(gpio);  // 获取GPIO的Linux中断号
    
    // 注册中断处理函数
    request_irq(irq, button_isr, IRQF_TRIGGER_FALLING, "button1", NULL);
    
    return 0;
}

// 2. 中断处理函数
static irqreturn_t button_isr(int irq, void *dev_id)
{
    // 处理按键中断
    // 1. 读取GPIO值确认状态
    // 2. 消抖处理
    // 3. 执行相应操作(如控制LED)
    return IRQ_HANDLED;
}
③ 如果有多个引脚(例如GPIO1_IO02、GPIO1_IO03、GPIO1_IO04)使用同一个中断号(即GPIO1的组合中断66或67)注册中断,如何处理。

不需要用同一个中断号注册多个中断,内核GPIO子系统已经帮你处理好了!

gpio_to_irq或有一个映射

注:补充说明

GPC寄存器的描述如下所示:

设备树中gpio的中断父节点是gpc(General Power Controller):

gpc的中段父节点是intc再来看下中断节点:

相关推荐
潜创微科技9 小时前
4K 转 MIPI 硬核方案|ITE IT6616 HDMI1.4 转 MIPI CSI/DSI 转换芯片解析
嵌入式硬件·音视频
bukeyiwanshui10 小时前
20260417 DNS实验
linux
代码中介商10 小时前
Linux 帮助手册与用户管理完全指南
linux·运维·服务器
三佛科技-1341638421210 小时前
FT32F103系列与APM32F103,STM32F103之间的对比,能否替换?
单片机·嵌入式硬件·物联网·智能家居·pcb工艺
李永奉11 小时前
杰理可视化SDK开发-蓝牙的可发现可连接和回连
单片机·嵌入式硬件·物联网·语音识别
weixin_4491736512 小时前
Linux -- 项目中查找日志的常用Linux命令
linux·运维·服务器
振浩微433射频芯片13 小时前
标签界的“千里眼”:VRT5312,150cm超远读写距离,重新定义RFID新可能!
科技·单片机·嵌入式硬件·物联网
想唱rap13 小时前
C++智能指针
linux·jvm·数据结构·c++·mysql·ubuntu·bash
andylauren13 小时前
论单点接地的重要性——从MP3模块噪声问题看接地设计的关键
嵌入式硬件
Strugglingler13 小时前
基于whiptail开发shell导航工具
linux·shell·ui设计·whiptail