ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Linux 内核 cfag12864b LCD 驱动实战指南:Crystalfontz 12864b 显示屏的硬件接线与 Framebuffer 编程

Linux 内核 cfag12864b LCD 驱动实战指南:Crystalfontz 12864b 显示屏的硬件接线与 Framebuffer 编程 Linux 内核 cfag12864b LCD 驱动实战指南Crystalfontz 12864b 显示屏的硬件接线与 Framebuffer 编程【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux本文以 Linux 内核官方文档 cfag12864b.rst 为核心讲解 Crystalfontz 12864b 系列 128×64 双色字符/图形点阵 LCD 在内核中的完整支持体系设备规格、与并行口的接线方案、Kconfig/模块参数配置以及基于/dev/fbX的 userspace framebuffer 编程。读完后你可以独立完成该 LCD 的内核驱动配置、硬件连接并使用仓库自带的示例程序 cfag12864b-example.c 直接驱动屏幕。1. 驱动架构三层模块分工cfag12864b LCD 的内核支持由三个紧密配合的模块构成均位于 drivers/auxdisplay/ 目录下模块源文件职责ks0108ks0108.c底层控制器驱动直接操作并行口实现 KS0108 芯片的数据/控制写入与 6 条基本命令cfag12864bcfag12864b.c设备驱动管理双控制器选通信号、维护 1K 帧缓冲并周期性刷新cfag12864bfbcfag12864bfb.cframebuffer 封装向上注册/dev/fbX设备节点支持 write 与 mmap 两种访问方式三者的依赖链条在源码中写得很明确cfag12864b.c 开头注释Depends: ks0108而 cfag12864bfb.c 注释Depends: cfag12864b模块初始化时cfag12864b_init()会先检查ks0108_isinited()cfag12864bfb_init()又会先检查cfag12864b_isinited()不满足依赖即报错退出。因此加载顺序必须是ks0108 → cfag12864b → cfag12864bfb。文档头部信息LicenseGPLv2作者 Miguel Ojeda ojedakernel.org日期 2006-10-27与上述源文件中的MODULE_AUTHOR/MODULE_LICENSE声明一致可据此确认文档描述的对象就是仓库中这套代码。2. 设备信息规格参数全表原文档第 2 节给出的设备规格如下这些数值与内核头文件 include/linux/cfag12864b.h 中的宏定义一一对应属性值源码对应厂商Crystalfontz—设备型号Crystalfontz 12864b LCD Seriescfag12864bCFAG12864B_NAME类型LCD 点阵屏128 × 64 像素黑白 2 色CFAG12864B_WIDTH (128)/CFAG12864B_HEIGHT (64)控制器KS0108共 2 片CFAG12864B_CONTROLLERS (2)分页每控制器 8 页CFAG12864B_PAGES (8)地址每页 64 个地址每地址 1 字节CFAG12864B_ADDRESSES (64)显存总量2 × 8 × 64 × 1 1024 字节 1 KbyteCFAG12864B_SIZE由上述三项相乘得出值得注意的一个架构细节KS0108 的显存布局是按控制器分半屏的2 片控制器各驱动 128×32 的半屏8 页 × 64 列 × 1 字节/列 512 字节/半屏。这与后文刷新函数中i * CFAG12864B_ADDRESSES / 8的寻址偏移直接相关见第 5 节。3. 硬件接线并行口直连方案原文档说明 cfag12864b 系列没有官方标准接线社区普遍采用并行口LPT直连方案。完整接线图如下继承自原文档第 3 节Parallel Port cfag12864b Name Pin# Pin# Name Strobe ( 1)------------------------------(17) Enable Data 0 ( 2)------------------------------( 4) Data 0 Data 1 ( 3)------------------------------( 5) Data 1 Data 2 ( 4)------------------------------( 6) Data 2 Data 3 ( 5)------------------------------( 7) Data 3 Data 4 ( 6)------------------------------( 8) Data 4 Data 5 ( 7)------------------------------( 9) Data 5 Data 6 ( 8)------------------------------(10) Data 6 Data 7 ( 9)------------------------------(11) Data 7 (10) [5v]---( 1) Vdd (11) [GND]---( 2) Ground (12) [5v]---(14) Reset (13) [GND]---(15) Read / Write Line (14)------------------------------(13) Controller Select 1 (15) Init (16)------------------------------(12) Controller Select 2 Select (17)------------------------------(16) Data / Instruction Ground (18)---[GND] [5v]---(19) LED Ground (19)---[GND] Ground (20)---[GND] E A Values: Ground (21)---[GND] [GND]---[P1]---(18) Vee - R Resistor 22 ohm Ground (22)---[GND] | - P1 Preset 10 Kohm Ground (23)---[GND] ---- S ------( 3) V0 - P2 Preset 1 Kohm Ground (24)---[GND] | | Ground (25)---[GND] [GND]---[P2]---[R]---(20) LED -接线要点解读数据总线并口 Data 0~7 直连 LCD 的 Data 0~7一次并行写入 1 字节。控制信号映射并口 Strobe→Enable、Line→CS1第一片控制器、Init→CS2第二片控制器、Select→Data/Instruction。这四个信号全部走并口控制端口与 cfag12864b.c 中定义的控制位完全对应CFAG12864B_BIT_E (0)、CFAG12864B_BIT_CS2 (1)、CFAG12864B_BIT_CS1 (2)、CFAG12864B_BIT_DI (3)。CS1/CS2 低电平有效注意并口的 Line/Init 是高电平有效的通用信号而 KS0108 片选是低电平有效。源码 cfag12864b.c 中cfag12864b_setcontrollers()对first/second参数做了取反处理if (first) cfag12864b_cs1(0)印证了这一电气特性。常电平线Vdd/Reset/LED 接 5VGND、R/W只写模式接电源地Vee对比度经 10K 电位器 P1 分压接地LED 背光经 1K 电位器 P2 加 22Ω 限流电阻 R 后接 LED−。只写不读R/W 直接接地意味着该接口只支持主机向屏幕写数据驱动中也确实没有任何读操作。3.1 底层并行口驱动 ks0108ks0108.c 通过module_parport_driver注册为标准并行口设备只认领地址与ks0108_port参数匹配的端口认领后独占该端口PARPORT_DEV_EXCL。它导出 6 条 KS0108 命令函数供上层调用ks0108_writedata、ks0108_writecontrol、ks0108_displaystate开/关显示、ks0108_startline、ks0108_address、ks0108_page每条命令的编码如页地址命令page | bit(3) | bit(4) | bit(5) | bit(7)、地址命令address | bit(6)均按 KS0108 芯片手册实现。两个与接线相关的实现细节值得注意控制位反相ks0108_writecontrol()中写入前会执行byte ^ (bit(0) | bit(1) | bit(3))源码注释说明这是因为并口硬件电路用非门反相了 Strobe/Init/Select 三根控制线驱动层必须再反相一次才能与接线图中的逻辑一致。命令时序每次控制写入前执行udelay(ks0108_delay)为 KS0108 提供命令建立时间。4. 内核配置与模块参数4.1 Kconfig 依赖关系在 drivers/auxdisplay/Kconfig 中三个配置项形成链式依赖config KS0108 tristate KS0108 LCD Controller depends on PARPORT_PC config CFAG12864B tristate CFAG12864B LCD depends on X86 depends on FB depends on KS0108 select FB_SYSMEM_HELPERS适用前提与限制源自 Kconfig help 文本平台限定x86且依赖framebufferFB支持KS0108进一步依赖PARPORT_PC并行口支持没有并行口的现代主机需转接或改用其他显示方案该 LCD 的 framebuffer可以挂接内核 console但不能接入 Xorg 的 fbdev 驱动。4.2 参数与默认值参数位置默认值说明ks0108_portks0108.c编译期CONFIG_KS0108_PORT0x378LCD 所接并行口基址第二并口为 0x278第三为 0x3BC。可用dmesg或cat /proc/ioports查看实际地址ks0108_delayks0108.c2每次控制写之间的延迟微秒。若屏幕偶发丢字/花屏应调大cfag12864b_ratecfag12864b.cCONFIG_CFAG12864B_RATE20刷新率Hz。LCD 非内存映射设备刷新全靠软件搬运Kconfig 明确警告调太高可能拖慢甚至卡死系统CPU 较慢时应调低三个参数均可在编译时通过 Kconfig 设定模块方式选 M生成ks0108.ko、cfag12864b.ko、cfag12864bfb.ko加载时也可用模块参数覆盖例如modprobe ks0108 ks0108_port0x378 ks0108_delay2 modprobe cfag12864b cfag12864b_rate20 modprobe cfag12864bfb5. 刷新机制buffer/cache 双缓冲与软件搬运这套驱动的显示模型决定了 userspace 编程方式原文档第 4 节直到下一次刷新到来 LCD 才会更新正是由此而来。核心机制在 cfag12864b.c 中共享帧缓冲cfag12864b_buffer是一个 1 KiB128×64÷8的全零页get_zeroed_page分配且有BUILD_BUG_ON(PAGE_SIZE CFAG12864B_SIZE)保证整页容纳通过EXPORT_SYMBOL_GPL导出framebuffer 驱动直接将其设为screen_buffer。延迟刷新任务cfag12864b_enable()启动单线程工作队列上的延迟工作每HZ / cfag12864b_rate即每 1/rate 秒执行一次cfag12864b_update()并自动重新排队。脏检查cfag12864b_update()先用memcmp比较cfag12864b_cache与cfag12864b_buffer内容无变化则完全跳过写入避免对屏幕的无谓刷屏有变化才执行整屏搬运并memcpy更新 cache。位重排搬运搬运并非简单write——KS0108 的 GDDRAM 以页为单位每页 8 行高、64 列宽驱动需要把线性 framebuffer行优先、每行 16 字节转成控制器需要的字节流。三层循环对每个控制器i、每页j、每地址k逐位重组for (i 0; i CFAG12864B_CONTROLLERS; i) { cfag12864b_controller(i); cfag12864b_nop(); for (j 0; j CFAG12864B_PAGES; j) { cfag12864b_page(j); cfag12864b_nop(); cfag12864b_address(0); cfag12864b_nop(); for (k 0; k CFAG12864B_ADDRESSES; k) { for (c 0, b 0; b 8; b) if (cfag12864b_buffer [i * CFAG12864B_ADDRESSES / 8 k / 8 (j * 8 b) * CFAG12864B_WIDTH / 8] bit(k % 8)) c | bit(b); cfag12864b_writebyte(c); } } }索引式i * CFAG12864B_ADDRESSES / 8 k / 8 (j*8b) * 16的含义是i项选上下半屏每半屏 512 字节、k/8项在页内按 8 列一字节偏移、(j*8b)项定位第 j 页第 b 行对应 framebuffer 中第 16×(j*8b) 字节行最后取k%8位合成该地址要写入的字节。每条命令后插入cfag12864b_nop()发送 startline0 空操作为控制器留出时序余量。互斥保护cfag12864b_enable/disable用互斥量保护updating状态保证刷新器只被启动一次cfag12864bfb初始化时若cfag12864b_enable()返回非 0刷新器已占用即报错退出模块卸载时cfag12864bfb_exit()再调用cfag12864b_disable()停止刷新。6. Userspace 编程framebuffer 设备详解6.1 设备模型与像素语义原文档第 4 节指出cfag12864bfb注册一个 framebuffer 设备/dev/fbX大小为 1024 字节每一位对应一个像素位为高该像素点亮为低则熄灭。源码 cfag12864bfb.c 中fb_fix_screeninfo/fb_var_screeninfo的静态定义与之完全吻合static const struct fb_fix_screeninfo cfag12864bfb_fix { .id cfag12864b, .type FB_TYPE_PACKED_PIXELS, .visual FB_VISUAL_MONO10, /* 1 bit/pixel 单色 */ .line_length CFAG12864B_WIDTH / 8, /* 16 字节/行 */ .accel FB_ACCEL_NONE, }; static const struct fb_var_screeninfo cfag12864bfb_var { .xres CFAG12864B_WIDTH, /* 128 */ .yres CFAG12864B_HEIGHT, /* 64 */ .bits_per_pixel 1, ... };即单色MONO10 视觉、每像素 1 bit、每行 16 字节、无虚拟屏外扩、无硬件加速——1024 字节恰好铺满 128×64。6.2 两种访问方式file I/O 与 mmap原文档给出两种用法方式一当普通文件用——fopen/fwrite/fclose。fb_ops中启用了__FB_DEFAULT_SYSMEM_OPS_RDWRframebuffer 内存是系统内存FBINFO_VIRTFB标志普通 read/write 直接落在cfag12864b_buffer上。写入后屏幕不会立即变化须等待下一个刷新周期默认 1/20 秒。方式二mmap 映射——原文档认为这是对大多数用途最佳的方式。对应实现static int cfag12864bfb_mmap(struct fb_info *info, struct vm_area_struct *vma) { struct page *pages virt_to_page(cfag12864b_buffer); vma-vm_page_prot pgprot_decrypted(vma-vm_page_prot); return vm_map_pages_zero(vma, pages, 1); }mmap 直接把承载帧缓冲的那个物理页映射进用户地址空间用户态修改后同样等待软件刷新周期送达屏幕。由于刷新器做脏检查未改动的内容不会重复刷屏。6.3 官方示例程序 samples/auxdisplay/cfag12864b-example.c原文档结尾指向 samples/auxdisplay/cfag12864b-example.c这是一个真实可用的、带用法示例的 userspace 完整程序由 samples/auxdisplay/Makefile 的userprogs-always-y无条件构建。其结构值得逐段学习像素寻址宏——与 framebuffer 布局一致地址 行 × 16 列/8位掩码 列%8#define CFAG12864B_ADDRESS(x, y) ((y) * CFAG12864B_WIDTH / \ CFAG12864B_BPB (x) / CFAG12864B_BPB) #define CFAG12864B_BIT(n) (((unsigned char) 1) (n))设备初始化open mmap与第 6.2 节的内核侧实现精确对应static int cfag12864b_init(char *path) { cfag12864b_fd open(path, O_RDWR); if (cfag12864b_fd -1) return -1; cfag12864b_mem mmap(0, CFAG12864B_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, cfag12864b_fd, 0); ... }位操作 APIcfag12864b_set/unset/isset/not(x, y)单点操作、cfag12864b_fill/clear()整屏点亮/熄灭、cfag12864b_format(matrix)把 128×64 的逻辑 0/1 矩阵按每 8 像素打包 1 字节转成 framebuffer 格式。所有像素写入目标是用户态的cfag12864b_buffer副本最后由cfag12864b_blit()一次性memcpy到 mmap 的内核帧缓冲static void cfag12864b_blit(void) { memcpy(cfag12864b_mem, cfag12864b_buffer, CFAG12864B_SIZE); }六个演示画面程序按 1~6 依次展示——①每隔 2 像素点一个点set 画点阵②清屏③用 128×64 矩阵格式化画出横条④全屏点亮⑤用 unset 画竖线⑥对全像素取反做负片。每个画面blit后暂停等待回车。编译与运行make -C samples/auxdisplay ./samples/auxdisplay/cfag12864b-example /dev/fb1 # 或先确认 /dev/fbX 中哪一个对应 cfag12864bfix.id 为 cfag12864b再传入设备节点命令行参数即 framebuffer 设备路径程序打印Usually: /dev/fb0, /dev/fb1...通常先加载三个驱动模块再根据ls /dev/fb*与cat /sys/class/graphics/fb*/...或dmesg中cfag12864bfb frame buffer device提示确定节点号。7. 小结从接线到点亮的完整路径硬件按第 3 节接线图将 LCD 接到并口Strobe/Line/Init/Select 分别承担 Enable/CS1/CS2/DIVee 电位器调对比度LED 回路经 1K22Ω 限流内核PARPORT_PCy、KS0108端口 0x378、延迟 2µs、CFAG12864B刷新 20Hz framebuffer 支持x86 平台可挂 console加载ks0108 → cfag12864b → cfag12864bfb 依序加载满足源码中的初始化依赖检查使用userspace 对/dev/fbX做 openmmap128×64/81024 字节1 bit 1 像素按行优先、8 像素/字节布局绘制后 memcpy 写入等待 ≤1/rate 秒刷新周期内核侧经脏检查后由工作队列逐控制器、逐页、逐地址搬运至 KS0108 GDDRAM 点亮屏幕。整套实现规模极小两个驱动文件加一个 framebuffer 封装共约 450 行却完整覆盖了并行口时序控制—双控制器选通—GDDRAM 页式寻址—软件双缓冲刷新—标准 fbdev 用户接口这条复古字符屏驱动的全链路是研究 Linux framebuffer 体系与 auxdisplay 子系统的理想切入点。【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表