Linux 内核 auxdisplay 辅助显示子系统:ks0108 控制器与 cfag12864b LCD 驱动实战指南
Linux 内核 auxdisplay 辅助显示子系统ks0108 控制器与 cfag12864b LCD 驱动实战指南【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux本文围绕 Linux 内核Documentation/admin-guide/auxdisplay/目录下的官方文档展开系统讲解辅助显示auxdisplay子系统的工作原理从 ks0108 LCD 控制器的硬件特性、并行口接线到 cfag12864b LCD 的 framebuffer 暴露方式与用户态编程方法并结合当前仓库中的 Kconfig 选项、内核驱动源码与官方示例程序给出从内核配置、接线到用户态点屏的完整可复现路径。1. 辅助显示子系统总览它解决什么问题“辅助显示”Auxiliary Display指主显示器之外的小尺寸显示设备比如并口打印机并行口上挂接的字符/点阵 LCD。这类设备不是内存映射memory-mapped外设内核必须用软件驱动逐字节驱动它因此被单独归入drivers/auxdisplay/子系统统一管理。当前仓库中的文档入口是 auxdisplay/index.rst它把该子系统的文档组织为一个索引页下辖两个子文档ks0108.rstSamsung KS0108 LCD 控制器驱动文档cfag12864b.rstCrystalfontz 12864b 系列 LCD 驱动文档。两者构成“控制器 具体屏”的两层结构ks0108 是可复用的 LCD 控制器驱动负责并行口协议cfag12864b 是基于该控制器的具体 LCD 板卡驱动负责把 framebuffer 数据按页分发到两块控制器。这个分层关系在源码中一一对应控制器驱动ks0108.c板卡驱动cfag12864b.cframebuffer 层cfag12864bfb.c官方用户态示例samples/auxdisplay/cfag12864b-example.c整个子系统通过 Kconfig 菜单AUXDISPLAYAuxiliary display support统一开关位于 drivers/auxdisplay/Kconfig。2. ks0108 控制器设备特性与内存模型ks0108 文档ks0108.rst声明该驱动支持 Samsung KS0108 LCD 控制器License 为 GPLv2。其设备信息表如下这是理解后续所有驱动行为的硬件基础属性值制造商Samsung设备名称KS0108 LCD Controller设备代码ks0108类型LCD 控制器Liquid Crystal Display Controller宽度 / 高度64 × 64 像素颜色2 色黑白 B/N页数Pages8 页每页地址数64 个每个地址的数据量1 字节显存总量8 × 64 × 1 512 字节由此得到 KS0108 的核心内存模型控制器管理一块 64×64 的位图组织为8 个“页”page每页 64 个字节地址每个地址 1 字节代表该页垂直方向 8 个像素每 bit 一个像素。单块控制器的总容量为 512 字节。要寻址任意像素需要先选中“页”再选中页内“列地址”这与文档中“Addresses: 64 each page / Data size: 1 byte each address”的描述一致。文档还说明了接线能力该驱动支持数据并行端口data parallel port接线。官方文档特别提醒如果你不是在自研 LCD 硬件应当查看具体屏的接线文档并直接举了 cfag12864b 的例子——这也解释了为什么文档目录里两个文件并列存在。3. 内核配置Kconfig 选项、默认值与模块参数3.1 配置项一览drivers/auxdisplay/Kconfig 中 ks0108 / cfag12864b 相关的配置项及其含义如下配置项类型默认值依赖 / 说明AUXDISPLAYmenuconfig总开关—Auxiliary display support关闭则整个子菜单不出现KS0108tristateY/M/N—KS0108 LCD Controllerdepends on PARPORT_PC选 M 时模块名为ks0108。注意它只是控制器还需要上层具体的 LCD 驱动KS0108_PORThex0x378LCD 所连并行口地址。第一并行口标准地址 0x378第二 0x278第三 0x3BCKS0108_DELAYint2每次写并行口控制线之间的延时微秒。若 LCD 出现随机丢写应调大CFAG12864Btristate—CFAG12864B LCDdepends on X86、depends on FB、depends on KS0108select FB_SYSMEM_HELPERS选 M 时产生两个模块cfag12864b与cfag12864bfbCFAG12864B_RATEint20刷新率Hz几个使用要点来自 Kconfig help 文本值得逐条注意KS0108_PORT 的确认方法如果不确定并行口地址先加载parport模块再执行dmesg或cat /proc/ioports即可看到系统上存在几个并行口及各自地址“通常你只需要 0x378”。编译为模块后仍可用模块参数覆盖KS0108_PORT和KS0108_DELAY的 help 均注明若编译为 M可在 insmod 时通过模块参数覆盖默认值。这与源码一致——ks0108.c 中用module_param()注册了两个运行时参数初值分别取自CONFIG_KS0108_PORT与CONFIG_KS0108_DELAYstatic unsigned int ks0108_port CONFIG_KS0108_PORT; module_param(ks0108_port, uint, 0444); MODULE_PARM_DESC(ks0108_port, Parallel port where the LCD is connected); static unsigned int ks0108_delay CONFIG_KS0108_DELAY; module_param(ks0108_delay, uint, 0444); MODULE_PARM_DESC(ks0108_delay, Delay between each control writing (microseconds));因此实际加载时可写成insmod ks0108.ko ks0108_port0x378 ks0108_delay5这类形式参数名、类型与权限0444均由源码确认。CFAG12864B_RATE 的风险警告由于 LCD 不是内存映射设备驱动必须用软件搬运数据help 文本明确提示设得过高可能让系统变慢甚至“冻结计算机”如果 CPU 很慢或感觉系统被拖慢应调低该值。CFAG12864B 的平台限制help 文本写明它依赖 x86 架构与 framebuffer 支持该 LCD framebuffer 可以挂接虚拟控制台console且工作正常但不能挂接 Xorg 的 fbdev 驱动。3.2 推荐的配置组合要启用 cfag12864b 显示从源码结构看依赖链是CFAG12864B → KS0108 → PARPORT_PC且需要FB。在make menuconfig中对应的操作是Device Drivers → Character device support → Parallel port support勾选PARPORT_PC或加载现成的 parport 模块Device Drivers → Auxiliary display supportAUXDISPLAYyKS0108 LCD ControllerKS0108y或M并行口地址KS0108_PORT默认 0x378控制线写延时KS0108_DELAY默认 2usCFAG12864B LCDCFAG12864By或M刷新率CFAG12864B_RATE默认 20Hz4. ks0108 控制器驱动并行口协议与命令封装ks0108 文档只声明了设备特性具体的协议行为要读源码。ks0108.c 通过parportAPI 操作并行口并对外导出了一组“命令”函数供上层 LCD 驱动如 cfag12864b.c调用。4.1 两个最底层的原语void ks0108_writedata(unsigned char byte) { parport_write_data(ks0108_parport, byte); } void ks0108_writecontrol(unsigned char byte) { udelay(ks0108_delay); parport_write_control(ks0108_parport, byte ^ (bit(0) | bit(1) | bit(3))); }两个要点控制线位反相源码注释解释ks0108_writecontrol的位需要先对 bit(0)、bit(1)、bit(3) 取反^ (bit(0) | bit(1) | bit(3))因为并行口的硬件逻辑门本身会对这些信号做一次“非”运算。这是硬件层面的取反补偿调试时如果 Enable / RS / R/W 行为反直觉应首先想到这一点。ks0108_delay在这里生效每次写控制线前执行udelay(ks0108_delay)这正是 Kconfig 中KS0108_DELAY“Delay between each control writing (microseconds)”对应的运行时行为。出现随机丢写时调大该值即作用于此处。4.2 页/地址/显示状态命令与文档“8 页 × 64 地址 × 1 字节”内存模型直接对应的封装函数void ks0108_displaystate(unsigned char state) /* 开/关显示 */ { ks0108_writedata((state ? bit(0) : 0) | bit(1) | bit(2) | bit(3) | bit(4) | bit(5)); } void ks0108_startline(unsigned char startline) /* 设置起始扫描行0..63 */ { ks0108_writedata(min_t(unsigned char, startline, 63) | bit(6) | bit(7)); } void ks0108_address(unsigned char address) /* 设置页内列地址0..63 */ { ks0108_writedata(min_t(unsigned char, address, 63) | bit(6)); } void ks0108_page(unsigned char page) /* 设置页0..7 */ { ks0108_writedata(min_t(unsigned char, page, 7) | bit(3) | bit(4) | bit(5) | bit(7)); }以上为 ks0108.c 摘录。可以看到每个命令都是向数据口写一个“指令字节”用特定标志位的组合区分命令类型显示状态 / 起始行 / 列地址 / 页其余位携带参数。源码注释还特别说明了一个重要的并发约定这些导出的命令函数“不锁”dont lock——上层的顶层驱动应该负责加锁。因为逐字节加锁“又慢又没意义”上层应保证调用序列本身不会竞争。4.3 并发模型parport pardevice驱动通过parport_find_base(ks0108_port)按 Kconfig 里配置的基地址查找并行口再注册一个pardevice见 ks0108.c 中的ks0108_parport/ks0108_pardevice。这解释了 Kconfig help 中“依赖并行口支持Depends on Parallel Port support”的来由ks0108 复用内核并行口子系统不自己摸端口。5. cfag12864b双控制器、并行口接线与显存布局5.1 设备信息cfag12864b 文档cfag12864b.rst描述 Crystalfontz 12864b 系列 LCD属性值制造商Crystalfontz设备名称Crystalfontz 12864b LCD Series设备代码cfag12864b类型LCDLiquid Crystal Display宽度 / 高度128 × 64 像素颜色2 色黑白 B/N控制器ks0108控制器数量2 个每控制器页数8 页每页地址数64 个每地址数据量1 字节显存总量2 × 8 × 64 × 1 1024 字节 1 Kbyte关键结构是**“128×64 的屏 两块 64×64 的 KS0108 显存拼接”**每块控制器负责 64 列两块并排放出 128 列所以总容量正好是 1 Kbyte。文档给出厂商主页为 crystalfontz.com12864b 产品页。5.2 并行口接线官方文档原图文档强调 cfag12864b 系列没有官方接线图社区通用做法是接到并行口原文档给出的完整接线如下保持原样供硬件接线参考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 -从接线图可以读出几个硬件语义并行口Strobe接 LCD 的EnableSelect接Data/Instruction即 RS 信号Linepin 14与Initpin 16分别接Controller Select 1/2——这正是两块 KS0108 的选择线印证了“双控制器”结构Read/Write 固定接地只写不读、Reset 接 5V不复位背光 LED 由 5V 经 1K 可调电位器 P2、22 欧电阻 R 到 LED- 构成限流回路Vee 偏压由 10K 电位器 P1 分压提供——这是调节液晶对比度的典型接法。接线前提与 Kconfig 的depends on PARPORT_PC以及 help 文本中的cat /proc/ioports提示一致这块屏本质上就是一个“挂在并口上的软件显存”。5.3 板级驱动 cfag12864b.c 的角色板卡驱动 cfag12864b.c 位于两个驱动之间向下调用 ks0108 的命令函数把 1 Kbyte 的 framebuffer 缓冲区按“页 × 列”分发到两块控制器向上通过 platform device 与cfag12864bfb层交互并按CFAG12864B_RATE默认 20Hz周期性刷新。Kconfig 中“选 M 时会得到cfag12864b与cfag12864bfb两个模块”的说法与之对应板卡驱动与 framebuffer 驱动分开成模块。6. cfag12864bfbframebuffer 暴露方式/dev/fbX 从哪来文档“Userspace Programming”一节的结论——“cfag12864bfb 描述一个 framebuffer 设备/dev/fbX”——其实现见 cfag12864bfb.c固定屏幕参数cfag12864bfb_fixtype FB_TYPE_PACKED_PIXELSvisual FB_VISUAL_MONO101bpp 单色line_length CFAG12864B_WIDTH / 8128/8 16 字节每行可变屏幕参数cfag12864bfb_varxres 128、yres 64、bits_per_pixel 1RGB 分量各为{ 0, 1, 0 }1 位色深cfag12864bfb_probe()中info-flags FBINFO_VIRTFBinfo-screen_buffer cfag12864b_buffer、info-screen_size CFAG12864B_SIZE随后register_framebuffer(info)完成注册。也就是说 framebuffer 的显存就是内核里一块静态缓冲区cfag12864b_buffer大小CFAG12864B_SIZE 1024 字节FBINFO_VIRTFB表明它使用虚拟 framebuffer 模式用户态写入的数据先落到该缓冲区由cfag12864b板级驱动按刷新率搬运到硬件。这正好解释了文档中的那句关键提示你可以像普通文件一样使用 framebufferfopen、fwrite、fclose……但在下一次刷新时刻到来之前LCD 不会更新。Also, you can use the framebuffer as a file... Although the LCD wont get updated until the next refresh time arrives.mmap 路径同样有源码依据cfag12864bfb_mmap()通过virt_to_page(cfag12864b_buffer)vm_map_pages_zero()把这 1024 字节映射进用户进程地址空间见 cfag12864bfb.c因此文档才说“open mmap … 对大多数用途是最佳选项”。7. 用户态编程1 Kbyte 位图模型与官方完整示例7.1 位图模型文档明确framebuffer 大小为1024 字节 1 Kbyte每一位bit代表一个像素bit 为 1 时点亮为 0 时熄灭可用文件方式读写也可以 mmap推荐后者完整的用户态示例见samples/auxdisplay/cfag12864b-example.c。7.2 官方示例程序解读samples/auxdisplay/cfag12864b-example.c 是一个可直接编译运行的完整演示程序GPL-2.0其骨架如下初始化与退出——open mmap 1024 字节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); if (cfag12864b_mem MAP_FAILED) { close(cfag12864b_fd); return -2; } return 0; }位图地址计算——128×64 屏按 8 像素一字节打包#define CFAG12864B_ADDRESS(x, y) ((y) * CFAG12864B_WIDTH / \ CFAG12864B_BPB (x) / CFAG12864B_BPB) #define CFAG12864B_BIT(n) (((unsigned char) 1) (n))即像素 (x, y) 落在第y行的第x/8个字节中字节内位编号为x % 8。单像素操作——set / unset / isset / notstatic void cfag12864b_set(unsigned char x, unsigned char y) { if (CFAG12864B_CHECK(x, y)) cfag12864b_buffer[CFAG12864B_ADDRESS(x, y)] | CFAG12864B_BIT(x % CFAG12864B_BPB); } static void cfag12864b_unset(unsigned char x, unsigned char y) { if (CFAG12864B_CHECK(x, y)) cfag12864b_buffer[CFAG12864B_ADDRESS(x, y)] ~CFAG12864B_BIT(x % CFAG12864B_BPB); }边界检查由CFAG12864B_CHECK(x, y)宏完成源码中默认关闭#undef CFAG12864B_DOCHECK时恒为真性能优先也可整屏填充/清空cfag12864b_fill()全 0xFF、cfag12864b_clear()全 0或用cfag12864b_format(matrix)把一张 128×64 的 0/1 矩阵批量打包进位图。提交显示——注意“双缓冲 显式 blit”的模式所有绘图只改本地cfag12864b_buffer最后由cfag12864b_blit()一次性memcpy到 mmap 的内核帧缓冲static void cfag12864b_blit(void) { memcpy(cfag12864b_mem, cfag12864b_buffer, CFAG12864B_SIZE); }main 流程——程序依次演示 6 个例子每个例子 blit 后等待回车int main(int argc, char *argv[]) { ... if (argc ! 2) { printf( Syntax: %s fbdev\n Usually: /dev/fb0, /dev/fb1...\n, argv[0]); return -1; } if (cfag12864b_init(argv[1])) { printf(Cant init %s fbdev\n, argv[1]); return -2; } for (n 1; n EXAMPLES; n) { example(n); cfag12864b_blit(); while (getchar() ! \n); } cfag12864b_exit(); return 0; }6 个演示example()的 switch 分支分别是1) 隔点打点set 位画点阵2) 清屏3) 通过 128×64 矩阵 format 画横线4) 全屏填充5) 用 unset 位画竖线6) 全像素取反not。7.3 运行方式程序用法由源码中打印的 Syntax 提示确认第一个参数是 framebuffer 设备节点通常是/dev/fb0、/dev/fb1等。即在内核启用CFAG12864B并接线正确的前提下./cfag12864b-example /dev/fb0哪个/dev/fbX对应 cfag12864bfb 取决于系统中 framebuffer 的注册顺序可通过cat /sys/class/graphics/fbX/name查看其fix.id在源码中固定为cfag12864b见 cfag12864bfb.c。示例程序在 samples/auxdisplay/Makefile 中定义了构建规则可用内核 sample 构建流程make samples编译。8. 常见问题的定位路径结合文档与源码调试这类“并口 LCD 不亮/显示错乱”问题时可按以下顺序排查并行口地址是否找对cat /proc/ioports或dmesg确认必要时用模块参数ks0108_port0xXXX覆盖KconfigKS0108_PORThelp 文本推荐的排查手段。是否丢写提高ks0108_delayKconfig 默认 2 微秒Kconfig 原文提示“If your LCD seems to miss random writings, increment this”。刷新是否发生LCD 内容停在旧画面属于预期行为写入后等下一次刷新才上屏若刷新过慢检查CFAG12864B_RATE默认 20Hz同时注意调过高的风险Kconfig 原文警告可能拖慢甚至冻结系统。接线核对重点核对 Strobe→Enable、Select→Data/Instruction、Line/Init→Controller Select 1/2、R/W 接地、Reset 接 5V背光限流电阻22 欧 1K 电位器与 Vee 偏压10K 电位器。fb 节点对应关系FBINFO_VIRTFB语义决定了用户态写入的是内核缓冲区上屏由cfag12864b模块周期完成确认两个模块都加载lsmod | grep -E ks0108|cfag12864b。9. 小结文档层Documentation/admin-guide/auxdisplay/下三份文档index ks0108 cfag12864b构成了“控制器特性 → 设备特性与接线 → 用户态编程”的完整知识链驱动层ks0108.c用 parport API 封装并行口协议含控制线位反相与ks0108_delay节流cfag12864b.c把 1 Kbyte 帧缓冲分发到两块控制器并按 20Hz可配刷新cfag12864bfb.c以 1bpp MONO10 虚拟 framebuffer 的形式将其注册为/dev/fbX用户层官方示例 cfag12864b-example.c 展示了 open/mmap 初始化、按y*16 x/8计算位图地址、位级 set/unset/format 绘图与 blit 提交流程可作为二次开发的起点。适用前提与限制该方案面向x86 物理并口parport KS0108 系并行驱动 LCD的硬件组合LCD 由软件刷新刷新率设置需量力而行cfag12864b 的 framebuffer 可挂虚拟控制台但不可用于 Xorg fbdev。以上结论均可在当前仓库的Documentation/admin-guide/auxdisplay/、drivers/auxdisplay/与samples/auxdisplay/中逐一对照验证。【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →