Linux 驱动基础知识:LED 驱动

2023-11-26 1303阅读

上一篇文章我们分享了字符设备驱动框架:Linux驱动基础知识:hello驱动。学习STM32,我们从点灯开始。在学习Linux驱动的时候,我们自然也点着灯来玩。我们尽力从这些基本套路中提炼出知识,认真挖掘,为以后更复杂的知识打下坚实的基础。回顾hello驱动,我们根据实际需要对其进行字符串写入和字符串读取操作。当然这里我们要根据实际情况来思考我们的LED驱动器。在嵌入Linux操作系统的时候,我们自然要想到写1/0的想法。我们的LED程序自然会写入0/1数据来点亮和关闭LED。上面分享了一个与硬件无关的LED驱动实验,主要是为了理清LED驱动的大致思路。这时候我们就需要编写Linux系统下的LED驱动程序。

前言

上一篇文章我们分享了字符设备驱动框架:Linux驱动基础知识:hello驱动。 当时我们就分享了hello司机。 学习STM32,我们从点灯开始。 在学习Linux驱动的时候,我们自然也点着灯来玩​​。 我们尽力从这些基本套路中提炼出知识,认真挖掘,为以后更复杂的知识打下坚实的基础。

独立于硬件的 LED 驱动器

回顾hello驱动,我们根据实际需要对其进行字符串写入和字符串读取操作。 当然这里我们要根据实际情况来思考我们的LED驱动器。 STM32点亮时一般输出低电平亮,输出高电平关灯。 在嵌入Linux操作系统的时候,我们自然要想到写1/0的想法。 类比我们上一篇文章中的 hello 程序:

c语言代码arm实现点灯的程序段_arm点亮led灯c语言_编程点亮led灯代码

我们的LED程序自然会写入0/1数据来点亮和关闭LED。 这里我们做了一个实验室硬件无关的 LED 实验:我们的驱动程序在收到应用程序发送的 0 时打印 LED on,并在收到 1 时打印 LED off。模仿上一篇文章中的 hello 程序,硬件无关的 LED 程序(核心部分)我们修改如下:

LED应用:

编程点亮led灯代码_c语言代码arm实现点灯的程序段_arm点亮led灯c语言

LED驱动器:

arm点亮led灯c语言_编程点亮led灯代码_c语言代码arm实现点灯的程序段

c语言代码arm实现点灯的程序段_arm点亮led灯c语言_编程点亮led灯代码

加载 LED 驱动模块并运行应用程序:

c语言代码arm实现点灯的程序段_arm点亮led灯c语言_编程点亮led灯代码

硬件相关的LED驱动器

上面分享了一个与硬件无关的LED驱动实验,主要是为了理清LED驱动的大致思路。 这里我们添加硬件相关的操作来构建硬件相关的LED驱动器。

我们在进行STM32裸机编程时,配置一些外设,实际上就是操作一些地址的过程。 这些外设地址可以在芯片手册中看到:

编程点亮led灯代码_c语言代码arm实现点灯的程序段_arm点亮led灯c语言

这是地址映射图。 这里的图仅列出了外设的边界地址。 每个外设都有很多寄存器。 这些寄存器的地址是通过外设基地址偏移得到的。 同样,对于NXP的IMX6ULL芯片,也有类似这样的地址:

编程点亮led灯代码_arm点亮led灯c语言_c语言代码arm实现点灯的程序段

这时候我们就需要编写Linux系统下的LED驱动程序。 当涉及到硬件操作时,操作的并不是这些地址(物理地址),而是操作系统提供的地址(虚拟地址)。 操作系统根据物理地址为我们生成一个虚拟地址。 我们的LED驱动器通过间接控制物理地址来控制这个地址。 至于这两个地址是如何连接的,我们暂时不详细阐述原理。 从功能上看,内核为我们提供了ioremap函数,可以将物理地址映射到虚拟地址。 该函数在内核文件arch/arm/include/asm/io.h中:

Linux 驱动基础知识:LED 驱动

void __iomem *ioremap(resource_size_t res_cookie, size_t size);

ioremap函数对应的函数是:

void iounmap (volatile void __iomem *addr)

地址映射完成后,我们可以直接通过指针访问虚拟地址,如:

*GPIO5_DR &= ~(1 << 3);  /* GPIO5_IO03输出低电平 */
*GPIO5_DR |= (1 << 3);   /* GPIO5_IO03输出高电平 */

这里简单介绍一下i.MX 6ULL​​的GPIO。 对于 i.MX 6ULL​​,IO 端口(组)命令以数字形式给出。 GPIO5是第五组,所以GPIO5_IO03是第五组端口的第三个引脚。 在STM32中,使用大写字母来表示端口(组)。 例如PA3代表A口的第三个引脚。

i.MX 6ULL​​有5组GPIO(GPIO1~GPIO5),每组最多32个引脚:

GPIO1 有 32 个引脚: GPIO1_IO0~GPIO1_IO31;
GPIO2 有 22 个引脚: GPIO2_IO0~GPIO2_IO21;
GPIO3 有 29 个引脚: GPIO3_IO0~GPIO3_IO28;
GPIO4 有 29 个引脚: GPIO4_IO0~GPIO4_IO28;
GPIO5 有 12 个引脚: GPIO5_IO0~GPIO5_IO11;

地址映射完成后,我们不仅可以通过指针访问虚拟地址,还可以使用内核提供的一些读写函数:

/* 写操作函数 */
void writeb(u8 value, volatile void __iomem *addr);
void writew(u16 value, volatile void __iomem *addr);
void writel(u32 value, volatile void __iomem *addr);
/* 读操作函数 */
u8 readb(const volatile void __iomem *addr);
u16 readw(const volatile void __iomem *addr);
u32 readl(const volatile void __iomem *addr);

writeb、writew、writel这三个函数分别对应8bit、16bit、32bit写操作。 参数value为要写入的值,addr为要写入的地址。

readb、readw、readl这三个函数分别对应8bit、16bit、32bit的读操作。 参数addr是读写内存地址,返回值是读取的数据。

此时我们可以修改上一节中的led_init函数led_drv_write函数:

arm点亮led灯c语言_c语言代码arm实现点灯的程序段_编程点亮led灯代码

编程点亮led灯代码_arm点亮led灯c语言_c语言代码arm实现点灯的程序段

与STM32一样,i.MX 6ULL​​ GPIO外设也有很多寄存器:

c语言代码arm实现点灯的程序段_arm点亮led灯c语言_编程点亮led灯代码

上面我们只点亮了一盏灯,如果我们想点亮多盏灯怎么办? 然后你必须控制多个GPIO。 如果地址映射按照上面的方式写的话,代码会变得非常臃肿。 回想一下我们的 STM32,GPIO 外设通过结构体管理其寄存器:

编程点亮led灯代码_c语言代码arm实现点灯的程序段_arm点亮led灯c语言

这里的__IO是一个宏,代表C语言关键字volatile,是为了防止编译器优化我们的一些硬件操作从而得不到想要的结果。 例如:

arm点亮led灯c语言_c语言代码arm实现点灯的程序段_编程点亮led灯代码

/* 假设REG为寄存器的地址 */
uint32 *REG;
*REG = 0;  /* 点灯 */
*REG = 1;  /* 灭灯 */

此时,如果REG不修改为volatile,则点亮操作将被优化,仅进行熄灭操作。

这里,我们也可以模仿STM32,用一个结构体来管理i.MX 6ULL​​ GPIO寄存器,如:

struct GPIO_RegDef
{
  volatile unsigned int DR;
  volatile unsigned int GDIR;
  volatile unsigned int PSR;
  volatile unsigned int ICR1;
  volatile unsigned int ICR2;
  volatile unsigned int IMR;
  volatile unsigned int ISR;
  volatile unsigned int EDGE_SEL;
};

结构体中的成员按特定顺序排序:

arm点亮led灯c语言_c语言代码arm实现点灯的程序段_编程点亮led灯代码

因为这些寄存器是相对于GPIO外设的基地址有偏移的,例如:

编程点亮led灯代码_c语言代码arm实现点灯的程序段_arm点亮led灯c语言

顺序不能打乱,否则无法正确访问相应的寄存器。 使用该结构体进行管理后,我们可以用类似下面的方式进行映射:

struct GPIO_RegDef *GPIO5 = ioremap(0x20AC000, sizeof(struct GPIO_RegDef));

然后就可以像STM32一样控制GPIO寄存器了,如:

GPIO5->DR &= ~(1 << 3);  /* GPIO5_IO03输出低电平 */
GPIO5->DR |= (1 << 3);   /* GPIO5_IO03输出高电平 */

硬件相关LED驱动(升级版)

上一节我们分享的LED驱动器是常规LED驱动器,只能应用于我们当前的开发版本,因此它是专用LED驱动器。 如果更换另一块板,连接到 LED 的 GPIO 引脚可能会有所不同。 我们将修改我们的驱动程序led_drv.c中与寄存器相关的操作。 有没有更好的方法而不修改我们的 led_drv.c 驱动程序?

如果led_drv.c不需要修改,那么这个led_drv.c驱动就是通用驱动。 详细内容请查看魏东山先生的《完整的嵌入式Linux应用开发手册,第二版》第五章第3至7节进一步学习。

我们简单总结一下如下:

编程点亮led灯代码_c语言代码arm实现点灯的程序段_arm点亮led灯c语言

由于篇幅问题,具体部分就不贴出来了。

在之前的笔记:C语言、嵌入式关键知识:中也提到过回调函数中通用和特殊的含义。 你可以理解并加深对这两个词的理解。

在这里我们学到了软件分层非常重要的思想和技术,不过就是点击几下而已。 未来的路还很长,需要我们不断学习、不断提高。

1. 典型的FPGA开发流程

(1)电路设计

(2) 设计输出

(3)功能模拟

(4)综合优化

(5) 综合后仿真

(6) 布局与接线

(7)时序仿真

(8)板级调试

(9)芯片编程与调试

Linux 驱动基础知识:LED 驱动

2、FPGA内部资源及其功能有哪些?

1)。 输入输出单元(IOB)

可编程输入/输出单元,简称I/O单元,是芯片与外部电路的接口,完成不同电气特性下输入/输出信号的驱动和匹配要求。

2)。 可编程逻辑块 (CLB)

FPGA的基本可编程逻辑单元由查找表和寄存器组成。 查找表完成纯组合逻辑功能。 FPGA内部寄存器可以配置为触发器或锁存器。 Altera的基本可编程单元LE配置为寄存器加查找表。

3)、底层嵌入功能单元(DLL)

嵌入式功能模块主要指DLL(Delay Locked Loop)、PLL(Phase Locked Loop)、DSP、CPU等软处理核(Soft Core)。

4)、丰富的接线资源(可编程接线矩阵)

布线资源连接FPGA内部的所有单元。 连接的长度和工艺决定了连接上信号的驱动能力和传输速度。 可以分为4个不同的类别。 第一类是全局布线资源,用于芯片内部的全局时钟和全局复位/设置的布线; 第二类是长期资源,用于完成芯片组之间的高速信号和第二全局时钟信号的布线; 第三种是长期资源。 第一类是短线资源,用于完成基本逻辑单元之间的逻辑互连和布线; 第四类是分布式布线资源,用于专有时钟、复位等控制信号线。

5)、嵌入式块RAM(BRAM)

RAM可配置为单端口RAM、双端口RAM、内容地址存储器(CAM)、FIFO等常见存储结构。 Block RAM 由一定数量的固定大小的存储块组成。 使用BRAM不占用额外的逻辑资源,速度快。

6)、嵌入式专用硬核

嵌入式专用硬核是相对于底层嵌入式软核而言的。 指FPGA具有强大处理能力的硬核(***),相当于ASIC电路。 为了提高FPGA性能,芯片制造商在芯片内部集成了一些专用的硬核。

3.查找表LUT原理

查找表(称为 LUT)本质上是 RAM。 目前,4输入LUT主要用于FPGA中,因此每个LUT可以被视为具有4位地址线的16x1 RAM。 多于 4 输入的逻辑可以使用多个 LUT 来实现。

原理:当用户通过原理图或HDL语言描述一个逻辑电路时,CPLD/FPGA开发软件会自动计算该逻辑电路所有可能的结果,并将结果提前写入RAM中。 每输入一个信号进行逻辑运算,就相当于输入一个地址进行查表,找出该地址对应的内容,然后输出。 LUT 可以配置为内部存储器,即分布式RAM。

4. FPGA芯片中有哪些内存资源?

FPGA芯片中有两种存储资源:一种称为Block ram,另一种是由LUT配置的内部存储器(即分布式RAM)。 Block ram由一定数量的固定大小的存储块组成。 使用Block RAM不占用额外的逻辑资源,速度快。 但所使用的时钟消耗的块 RAM 资源是其大小的整数倍。

FPGA 中可以综合实现为 RAM/ROM/CAM 的三种资源:BLOCK RAM、查找表和 FF 触发器。

(1)生成ram等存储单元时,应优先考虑block ram资源; 这样做的原因有两个:第一:使用Block RAM等资源可以节省更多的底层可编程单元,如FF、4_LUT等。 使用block_ram可以说是不白用的体现,最大化设备性能,节省成本; 第二:Block RAM是可配置的硬件结构,其可靠性和速度比用LUT和寄存器构建的存储器要好。 有优点。

(2)了解FPGA的硬件结构,合理利用Block RAM资源;

(3) 分析Block RAM容量,高效利用Block RAM资源

(4)分布式RAM资源(distribute RAM)

5、选择FPGA时需要考虑哪些因素?

Linux 驱动基础知识:LED 驱动

6.FPGA和CPLD有什么区别?

可编程逻辑器件

FPGA

内部结构

基于产品条款

基于查找表

程序存储

内部EEPROM/闪存

SRAM、外部EEPROM

资源类型

丰富的资源组合

丰富的计时资源

一体化

低的

高的

使用场合

完整的控制逻辑

完成更复杂的算法

速度

慢的

Linux 驱动基础知识:LED 驱动

快的

其他资源

PLL、RAM 和乘法器

保密

可以加密

一般不能保密

7.FPGA和ASIC有什么区别?

FPGA,即现场可编程门阵列,是在PAL、GAL、CPLD等可编程器件的基础上进一步发展起来的产品。 它作为专用集成电路(ASIC)领域的半定制电路出现,不仅解决了定制电路的缺点,而且克服了原有可编程器件中门数有限的缺点。 它是当今数字系统设计的主要硬件平台。 其主要特点是完全由用户通过软件进行配置和编程,完成特定的功能,并且可以反复擦除和写入。 修改升级时,无需额外更换PCB电路板。 只需在计算机上修改和更新程序,将硬件设计工作转变为软件开发工作,缩短系统设计周期,提高实施灵活性,降低成本。 。

ASIC(专用集成电路)是为特定目的而设计的集成电路。 是指针对特定用户要求和特定电子系统的需要而设计和制造的集成电路。 ASIC的特点是面向特定用户的需求。 ASIC分为全定制和半定制。 最大的特点是专用、量身定制,所以执行速度更快。 一句话简介:这是一款市面上买不到的芯片。 Fruit的A系列处理器是典型的ASIC。

FPGA

专用集成电路

速度

慢的

快的

尺寸

实现相同的功能规模需要大量

实现相同的功能需要更小的

能量消耗

高功耗

低功耗

花费

便宜的

昂贵的

位置

小规模

规模大

8. FPGA、CPLD和ASIC有什么区别?

Linux 驱动基础知识:LED 驱动

9. 以下关于 FPGA 和 ASIC 的描述哪一项是正确的:(ABD)

A. FPGA开发周期比较短。 B.在相同的工艺下,ASIC可以运行更快的时钟。

C. FPGA更注重面积要求。 D、ASIC量产成本相对较低

10、根据FPGA和CPLD的特点,它们分别适用于哪些场合? (C)

A、CPLD适合时序逻辑电路,FPGA适合组合逻辑电路。

B、CPLD适合逻辑较大的设计,FPGA适合逻辑较小的设计。

C、CPLD适合组合逻辑的设计,FPGA适合时序逻辑的设计。

D、CPLD适合逻辑规模较小的设计,FPGA适合逻辑规模较大的设计。

11、FPGA通过(查找表)实现组合逻辑,CPLD通过(乘积项)实现组合逻辑。

12、FPGA中,可以综合实现为RAM的资源包括(ABD)

A. BLOCK RAM B. 查找表 C. 可编程输入和输出单元 (IOB) D. FF 触发器

13.什么是IP核? 有哪些类别?

IP核(Intellectual Property core),即知识产权核。

IP核是具有特定电路功能的硬件描述语言程序。 这种程序通常独立于集成电路工艺,可以移植到不同的半导体工艺中来生产集成电路芯片。 由于IP核将数字电路中一些常用但相对复杂的功能块设计成可修改参数的模块,FPGA设计者可以通过调用相关IP核来完成所需的逻辑功能,从而节省大量的开发时间。 。 调用IP核可以避免重复工作,大大减轻设计人员的负担。 因此,IP核的使用必然成为未来FPGA设计的发展趋势。

根据IP核的硬件描述级实现方案,可分为软核、硬核和实体核三类。

Soft IP Core:在EDA设计领域,软核是指综合前的寄存器传输级(RTL)模型; 具体在FPGA设计中,是指电路的硬件语言描述,包括逻辑描述、网表和帮助文档等。软核只经过功能仿真,需要综合和布局布线后才能使用。 其优点是高度灵活性和可移植性,允许用户自行配置; 其缺点是模块的可预测性较低,后续设计可能出现错误,存在一定的设计风险。 软核是应用最广泛的IP核形式。

Firm IP Core:Firm IP Core是指EDA设计领域中带有布局信息的网表; 具体在FPGA设计中,可以看作是一个有布局规划的软核,通常有RTL代码和相应的具体流程。 网表以混合形式提供。 将RTL描述与特定的标准单元库相结合进行全面优化设计,形成门级网表,然后可以通过布局布线工具使用。 与软磁芯相比,实心磁芯的设计灵活性稍差,但其可靠性却大大提高。 目前,实心核也是IP核的主流形式之一。

Hard IP Core:在EDA设计领域,硬核是指经过验证的设计布局; 具体在FPGA设计中,是指布局和工艺已经固定并经过前端和后端验证的设计,设计者无法修改。 不能修改的原因有两个:一是系统设计对各个模块都有严格的时序要求,不允许打乱现有的物理布局; 其次,保护知识产权的要求不允许设计者对其进行任何更改。 IP硬核无法修改,难以复用。 因此只能用于某些特定的应用场合,使用范围较窄。

14. IP核和硬件原语有什么区别?

硬件原语是相对低级的并且可以在逻辑单元上操作。 它们集成在软件中,不需要调用IP核的复杂过程。 可以直接在代码中调用它们。 当然,功能还是比较简单的。 IP核的功能很多,调用时需要设置很多参数。

15. IP核在EDA技术和开发中发挥着非常重要的作用。 IP分为软IP、实体IP和硬IP。 下面描述的IP核中,对硬IP的正确描述是(A)

A. 没有其他选项

B、提供硬件语言描述如VHDL语言来描述功能块,但不涉及实现功能块的具体电路。

C.提供设计的最终产品——掩模

D、以网表文件的形式提交给用户,完成综合功能块

16. IP核中的功能块使用HDL硬件描述语言进行描述。 不涉及具体电路实现功能块的IP核是(A)

A 软 IP B 固定 IP C 硬 IP D 所有对

17. FPGA组成的数字系统中为什么要配备PROM或E2PROM?

数字电路与逻辑设计编码器_数字电路与系统设计 可编程逻辑器件_数字逻辑电路设计软件

断电后数据丢失。 每次上电时,必须从PROM或E2PROM中检索程序来运行。

18. FPGA的下载方式有哪些?

1)主动串行模式(AS)

2)主动并行模式(AP)

3)被动串行模式(PS)

4)JTAG方法

19. FPGA固件编程方案有哪些?

第一种方法是使用专用AS接口直接对配置芯片进行编程。 这种方式需要电路板上有独立的AS接口,占用PCB面积较大,使用不方便。

第二种方法是通过JTAG接口通过FPGA芯片间接对配置芯片进行编程。

20. JTAG链接加载信号信号线不包括(C)

A.tck B.tms C.tdelay D.tdi

21. FPGA在对FLASH进行编程时可以使用三种不同的文件类型。 以下哪一项是不正确的? (B) 值得怀疑

A. mcs B.prm C.bin D.hex

22、EDA工具中,能将硬件描述语言转换为硬件电路的重要工具是(B)

A. 模拟器 B. 合成器 C. 适配器 D. 下载器

23.你知道哪些可编程逻辑器件?

PAL、PLA、GAL、CPLD、FPGA

24. FPGA常用的级别标准包括(ABCD)

A.LVTTL B.LVCOMS C.LVDS D.ECL

25. XILINX常用FPGA系列支持以下哪些级别标准? (阿布德)

A、TTL B、CMOS C、SSTL D、LVDS

26、TTL电平输入高电平为Vh(A)

A、2.4 B、3.5 C、2 D、1.5 分析:VH=2.4v、VL=0.4V

27.你知道哪些常见的逻辑层次?

常用逻辑电平:TTL、CMOS、LVTTL、LVCMOS、ECL(发射极耦合逻辑)、

PECL(伪/正发射极耦合逻辑)、LVDS(低压差分信号)、

GTL(Gunning 收发器逻辑)、BTL(背板收发器逻辑)、ETL(增强型

收发器逻辑)、GTLP(Gunning 收发器逻辑 Plus); RS232、RS422、RS485(12V、

5V、3.3V);

还有一个答案:常见逻辑电平:12V、5V、3.3V。

28.以下步骤属于FPGA编译(BCE)

A. 功能模拟 B. 综合 C. 布线 D. 烧录 E. 布局

29、verilog语法指定的以下I/O端口类型是(ACD)

A. 输入端口 B. 差分信号端口 C. 双向端口 D. 输出端口

30.什么是逻辑综合?

它实现了在设计电路的功能、速度和面积的约束下,行为层次描述转化为指定技术序列单元的连接。

31.请解释一下xilinx的FPGA专用术语DCM

DCM:提供完整的时钟发生器供片上和片外使用。 DCM采用全数字延迟技术,可以高精度控制时钟相位和频率; 采用完整的数字反馈系统; 并且可以动态补偿由温度和电压偏移引起的时钟相位和频率偏差。

32. xilinx 是否推荐高电平复位?

因为在xilinx器件中,触发器的复位端是高电平有效,不能改变。 如果您的复位信号为低电平有效,则必须添加一个额外的反相器。

33. Xilinx RAM可以实例化很多类型,比如什么? (阿布德)

A. 简单双端口 RAM B. 单端口 RAM C. 三端口 RAM D. 真正的双端口 RAM

34、使用相同的仿真平台和相同的编译环境来模拟相同的RTL代码。 下列模拟耗时最长的是(A)

A. 时序仿真 B. 功能仿真 C. 逻辑仿真 D. 预仿真

35. 下面是关于芯片中GPIO的说明。 错误的是:(A)

A、GPIO一般只有0状态和1状态,没有高阻状态。

B.GPIO引脚一般都是多功能复用的

C、GPIO作为输出接口时具有锁存功能

D、GPIO作为输入接口时具有缓冲功能

36、为什么需要IO电路?

三大功能:电平转换、增强驱动、ESD保护。

37. ESD电路的概念和作用是什么?

概念:ESD,Elecro Static Discharge,即静电放电。

作用:保护CMOS电路中的栅极氧化层(SiO2)不被击穿。

38.FPGA系列是什么意思?

Linux 驱动基础知识:LED 驱动

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]