我正在尝试编写裸机代码来编程 PL111 LCD 控制器。我正在使用为 Realview ARM Cortex-A8 设置的 QEMU 模拟器。我之前设法使用 QEMU 的“-serial stdio”选项在 linux 终端窗口上打印字符。
我已经浏览了 PL111 文档,但我无法弄清楚一件事。我设置了 PL111 控制器的 LCDUPBASE 来包含内存中帧缓冲区的地址。但是我可以简单地将 ascii 值写入帧缓冲区,LCD 控制器会选择我的帧缓冲区并在屏幕上显示相应的字符,还是我需要对 ascii 值执行某种转换(根据我已经存在的标准)我不知道)在将它们写入帧缓冲区之前?
如果前者是真的,这种转换是由控制器本身根据控制器硬件中的一些转换表处理的吗?诸如背景颜色之类的东西呢?PL111 文件没有说明这一点。这个障碍也让我想到了 GPU 的作用,如果我也有一个 GPU,它在这个方案中的位置是什么,它的作用到底是什么?
是否有任何好的资源、文档或书籍可以帮助更好地理解这些概念。如果我的问题听起来很愚蠢,请原谅我。我没有太多嵌入式/外围编程经验,我基本上是在尝试学习/熟悉 ARMv7 架构,我认为如果我可以在 QEMU 控制台上打印我的汇编编程打印而不是linux控制台。(使用“-serial stdio”选项)
如果这里的人可以帮助我,我将非常感激。谢谢
/* boot.s */
.section .data
.section .bss
.section .text
.globl _start
_开始:
/ * **中断向量表开始* * /
b _RESET_HANDLER /* Reset Handler */
b _UNDEF_HANDLER /* Undef Instruction Handler */
b _SWI_HANDLER /* Software Interrupt Handler */
b _PREFETCHABORT_HANDLER /* Prefect Abort Handler */
b _DATAABORT_HANDLER /* Data Abort Handler */
b _IRQ_HANDLER /* IRQ Handler */
b _FIQ_HANDLER /* FIQ Handler */
/ * ** 中断向量表结束* * **** /
_FIQ_HANDLER:
b . /* Not implemented yet, so go in infinite loop */
_IRQ_HANDLER:
b . /* _isr_irq /* jump to interrupt service routine */
_DATAABORT_HANDLER:
b . /* Not implemented yet, so go in infinite loop */
_PREFETCHABORT_HANDLER:
b . /* Not implemented yet, so go in infinite loop */
_SWI_HANDLER:
b . /* Not implemented yet, so go in infinite loop */
_UNDEF_HANDLER:
b . /* Not implemented yet, so go in infinite loop */
_RESET_HANDLER:
b _initialize_cpu
cpuinitialize.s =>
.section .data
.section .bss
.section .text
.globl _initialize_cpu
_initialize_cpu:
/* LCD 初始化代码 */
.include "ColourLCDPL111.s"
.set SYS_OSC4, 0x1000001C /* Mapped register for OSCCLK4*/
.set SYS_LOCK, 0x10000020 /* reference clock CLCDCLK for PL111*/
movw r0, #:lower16:SYS_LOCK /* Unlocking the register*/
movt r0, #:upper16:SYS_LOCK
movw r1, #0xA05F
str r1, [r0]
movw r2, #:lower16:SYS_OSC4 /* Setting the CLCDCLK frequency 36MHz*/
movt r2, #:upper16:SYS_OSC4
movw r1, #0x2CAC
str r1, [r2]
str r1, [r0] /* Locking the register again*/
movw r0, #:lower16:LCDTiming0_ADDR
movt r0, #:upper16:LCDTiming0_ADDR
movw r1, #:lower16:0x1313A4C4 /* PPL = 49 ; HSW = 3 TODO:change*/
movt r1, #:upper16:0x1313A4C4 /* HBP = 5 ; HFP = 5 */
str r1, [r0]
movw r0, #:lower16:LCDTiming1_ADDR
movt r0, #:upper16:LCDTiming1_ADDR
movw r1, #:lower16:0x0505F657 /* LPP = 600 ; VSW = 2 TODO:change*/
movt r1, #:upper16:0x0505F657 /* VBP = 2 ; VFP = 2 */
str r1, [r0]
movw r0, #:lower16:LCDTiming2_ADDR
movt r0, #:upper16:LCDTiming2_ADDR
movw r1, #:lower16:0x071F1800 /* CPL[25:16] = 799 ; BCD[26] = 1 (PCD Bypassed) */
movt r1, #:upper16:0x071F1800 /* PCD = ignored */
str r1, [r0]
movw r0, #:lower16:LCDUPBASE_ADDR /* Setting up frame buffer address to 0x00000000*/
movt r0, #:upper16:LCDUPBASE_ADDR
mov r1, #0x0
str r1, [r0]
movw r0, #:lower16:LCDControl_ADDR
movt r0, #:upper16:LCDControl_ADDR
movw r1, #0x082B /* Setting up TFT 24Bit Mode */
str r1, [r0]
movw r0, #:lower16:LCDIMSC_ADDR /* LCD interrupts: Disabled for now */
movt r0, #:upper16:LCDIMSC_ADDR
mov r1, #0x00000000
str r1, [r0]
mov r0, #40 /* lets try to print 'A' at frame buffer + 40 */
mov r1, #65
str r1, [r0]
用于填充实际上使整个屏幕变白的帧缓冲区的代码片段。当仅使用 i=800 和 j=600x4 不起作用时,我随机取了一个大值 10000
void PopulateFrameBuffer(void)
{
unsigned int i,j;
unsigned char *ptr = (unsigned char *)0x0;
for(i=0; i<800;i++)
{
for (j=0;j<(600*10000);j++)
{
*ptr++=0xFF;
}
}
}
我在初始化代码后从程序集中调用了这个函数。帧缓冲区起始地址为 0x00000000