0

PL111LCDコントローラーをプログラムするためのベアメタルコードを書き込もうとしています。RealviewARMCortex-A8用にセットアップされたQEMUエミュレーターを使用しています。以前、QEMUの「-serialstdio」オプションを使用して、Linuxターミナルウィンドウに文字を印刷することができました。

PL111ドキュメントを確認しましたが、1つわかりません。PL111コントローラーのLCDUPBASEをセットアップして、フレームバッファーのアドレスをメモリに格納します。しかし、単純にASCII値をフレームバッファーに書き込むと、LCDコントローラーがフレームバッファーを選択して対応する文字を画面に表示しますか、それともASCII値に対して何らかの変換を実行する必要がありますか(既存の標準に従って)フレームバッファに書き込む前に)を認識していませんか?

前者が当てはまる場合、この変換は、コントローラーハードウェアの変換テーブルに従ってコントローラー自体によって処理されますか?背景色などはどうですか?PL111文書はこれについて何も述べていません。このハードルにより、GPUの役割についても考えるようになりました。もし、GPUも持っていたとしたら、それはこのスキームのどこに当てはまり、その役割は正確には何でしょうか。

これらの概念をよりよく理解するのに役立つ優れたリソース、ドキュメント、または本はありますか。私の質問がばかげているように聞こえたら、私を許してください。私は組み込み/周辺機器プログラミングの経験があまりありません。基本的にARMv7アーキテクチャを学び、理解しようとしています。アセンブリプログラミングプリントをQEMUコンソールではなく、QEMUコンソールで印刷できれば素晴らしいと思いました。 Linuxコンソール。(「-serialstdio」オプションを使用)

ここの人たちが私を助けてくれたら本当にありがたいです。ありがとう

/* 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です

4

1 に答える 1

2

これは本当の答えではなく、コメントのようなものですが、コメント ボックスで使用できるスペースとフォーマットは限られています。

このナレッジ ベースの記事によると、PL111 はピクセル マップ モードのみをサポートします。つまり、各ピクセルのオンとオフを切り替える必要があります。そのため、24 ビットのトゥルー カラーを選択した場合、フレーム バッファからの 24 ビットが各ピクセルの色を制御するために使用されます。赤は 8 ビット、緑は 8 ビット、青は 8 ビットです。これらのビットがどのように編成されているかは誰にもわかりません。例えば:

  • 連続した 3 バイトのシーケンスを使用する場合があります。
  • または、連続した 4 バイトのシーケンスを使用しているが、最上位バイトを使用していない可能性があります。
  • または、ビットマップをプレーンに編成することもできます。たとえば、すべての赤の値の後にすべての緑の値が続き、その後にすべての青の値が続きます。
  • 極端なオプションとして、最大 24 のプレーンを持つことができるため、すべてのピクセルの最初のビットが最初に来て、次にすべてのピクセルの 2 番目のビットが続きます。

私の推測では、最初のオプションが使用されているものです (1 ピクセルあたり 24 連続ビット)。これは、フレーム バッファの最初の 6 バイトに 0xFF を入れることでテストできます。これにより、一番上の行の左側の 2 ピクセルが白に変わります。最初の白と 2 番目のピクセルがシアンに変わる場合、最上位バイトを無視してピクセルあたり 32 ビットがあることがわかります (バイトはリトル エンディアンです)。最初の 6 ピクセルが赤または別の色に変わる場合は、フレーム バッファーがプレーンに編成されています。

実際のキャラクターを出現させるには、考えられる各キャラクターのビット マップが必要であり、それらをフレーム バッファーにブリットする必要があります。これはソフトウェアで行うことができますが、何らかのハードウェア サポートが利用可能である必要があります。

編集

では、フレーム バッファに文字を入れる方法を設定しましょう。私の ARM アセンブリ スキルは素晴らしいものではないので、C を使用します。また、これは完全にテストされていないか、コンパイルされています

8 x 8 文字が 8 ピクセルをバイトにパックされ、24 ビットのカラー フレーム バッファがあるとします。

 #define PIXEL_WIDTH 3   // width in bytes of a pixel
 #define CHAR_WIDTH  8
 #define CHAR_HEIGHT 8

 #define RED_BYTE    2   // Index of the RGB components in the pixel in the framebuffer (little endian)
 #define GREEN_BYTE  1
 #define BLUE_BYTE   0

 struct FrameBufferDescriptor
 {
     uint8_t* start;           // Address of first byte in the buffer
     size_t rasterLineWidth;   // width in bytes of each line of pixels in the display.
 };

/*
 *  Draw a character at the (x, y) coordinates (0, 0) is top left.
 *  frameBuffer: describes position and width of the frame buffer
 *  x, y: coordinates of top left corner of the character
 *  characterMap: monochrome bitmap of 1 x 8 x 8 character.  Pixel packed 8 per byte.  
 *                If a bit is set, it means foreground colour, if cleared, it means 
 *                background colour
 *  foreground, background: RGB colours for foreground and background.
 */
void drawCharacter(struct FramBufferDescriptor* frameBuffer, size_t x, size_t y, uint8_t* characterMap, uint32_t foreground, uint32_t background)
{
    // first where to start drawing in the frame buffer
    uint8_t* destination =  frameBuffer->start + (y * rasterLineWidth) + (x * PIXEL_WIDTH);
    // char is 8 x 8
    for (int row = 0 ; row < CHAR_HEIGHT ; ++row)  // iterate for each row
    {
        for (pixel = 0 ; pixel < CHAR_WIDTH ; ++pixel)   // iterate for each picxel on the row
        {
            // determine the coloutr of this pixel
            uint32_t colour = background;
            if ((characterMap[row] & (1 << (CHAR_WIDTH - pixel - 1))) != 0) // Most sig bit will be on the left
            {
                colour = foreground;
            }
            // Put the RGB values in the framebuffer
            destination[pixel * PIXEL_WIDTH + RED_BYTE] = colour >> (RED_BYTE * 8);
            destination[pixel * PIXEL_WIDTH + GREEN_BYTE] = colour >> (GREEN_BYTE * 8);
            destination[pixel * PIXEL_WIDTH + BLUE_BYTE] = colour >> (BLUE_BYTE * 8);
        }
        destination += frameBuffer->rasterLineWidth;  // Go to next line of the frame buffer
    }
}
于 2012-04-12T10:17:33.807 に答える