I am trying to write a bare metal code to program PL111 LCD controller. I am using QEMU emulator set up for Realview ARM Cortex-A8. I earlier managed to print characters on the linux terminal window using QEMU's "-serial stdio" option.
I have gone through PL111 document and I can't figure out one thing. I set up PL111 controller's LCDUPBASE tovcontain the address of the frame buffer in memory. But can I simply write ascii values to the frame buffer and the LCD controller would pick my frame buffer and display the corresponding characters on the screen or do I need to perform some kind of conversion on ascii values( as per an already existing standard which I am not aware of) before writing them to the frame buffer?
In case of the former being true, is this conversion handled by the controller itself as per some conversion table in controller hardware? What about stuff such as background colour? The PL111 document doesn't say anything about this. This hurdle also made me think about the role of a GPU, if I were having a GPU as well, where would it fit it in this scheme and what exactly would be its role?
Are there any good resources, documents or books that can help to understand these concepts better. Pardon me if my questions sound stupid. I don't have much experience of embedded/peripheral programming, I am basically trying to learn/get acquainted with ARMv7 architecure and i thought it would be nice and interesting if I could get to print my assembly programming prints on the QEMU console rather than linux console. (using "-serial stdio" option)
I'd really appreciate it if people here can help me with this. Thanks
/* boot.s */
.section .data
.section .bss
.section .text
.globl _start
_start:
/*** Interrupt Vector Table 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 */
/*** Interrupt Vector Table End******/
_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 initialization code */
.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]
Code snippet for filling the frame buffer that actually turned the whole screen white. I took a randomly large value 10000 when simply using i=800 and j=600x4 didn't work
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;
}
}
}
I called this function from assembly after initialization code. Frame buffer start address is 0x00000000