[翻译中] 树莓派Framebuffer

介绍

The aim of this page is to provide some documentation on BCM2835's frame buffer, as this is not publicly documented by Broadcom, and is necessary to write a basic OS for the Raspberry Pi. Most of this was worked out by reading the Linux source code (mostly drivers/video/bcm2708_fb.c and arch/arm/mach-bcm2708/) and experimentation. Note: At times I have used a different naming convention to that used by Broadcom's kernel source, partially because I used slightly different semantics where the kernel source is either unclear or seemed confusing. A working (more or less) example code for the frame buffer can be found here (note: this page includes corrections to the large comment in fb.c).

Basic procedure to get stuff on screen

The basic procedure to get a frame buffer is:

  1. Set up a structure with the frame buffer specification (resolution, etc)
  2. Tell the GPU about this structure by writing to the mailbox
  3. Wait by reading from the mailbox for the GPU to modify this structure
  4. Write to the frame buffer at the pointer we got in stage 3

注意

  • Only step 4 is required for subsequent writes to the frame buffer.
  • Currently, I do not know how to enable the HDMI output, so this will always operate the composite, and not the HDMI (there have been suggestions that this might be achieved using a combination of config.txt, parameters specified by the GPU, and appropriate resolution settings).
  • The two conditions for successfully acquiring a frame buffer are:
    • The 28 bits of data read from the mailbox is zero
    • The pointer in the structure is non-zero after the mailbox read
  • For some reason (that I haven't discovered yet), the code sometimes fails (not meeting one of the two criteria above) unless it is retried. Hence steps 1-3 of the basic procedure are tried in a loop until success.
  • Once we have the frame buffer, we can just write to it. The pixels (in 24 bit mode) are RGB ordered by y then x coordinate. The address of a subpixel is given by: y * pitch + x * 3 + rgb_channel, where rgb_channel is 0 for red, 1 for green, and 2 for blue.

Memory mapped registers

The bus address for the mailbox memory mapped registers is 0x7E00B880. This corresponds to an ARM physical address of 0x2000B880 (the address we use from the ARM processor, and hence here). We use three registers from the mail box:

  • MAIL0_READ
  • MAIL0_WRITE
  • MAIL0_STATUS

Partial Memory Map at Address 0x7E00B880

偏移 名称 说明
0x00 MAIL0_READ The read register for mailbox 0 at offset (the Linux source mentions something of "and the next 4 words", but I've found it sufficient to read only from this address)
0x10 MAIL0_PEAK Read from the mailbox without removing data from it.
0x14 MAIL0_SENDER Sender ID (bottom 2 bits only)
0x18 MAIL0_STATUS The status register for mailbox 0
0x1C MAIL0_CONFIG The configuration register for mailbox 0
0x20 MAIL0_WRITE The write register for mailbox 0 (this is actually the read register for mailbox 1).

MAIL0_READ格式

Bits 名称 说明
0-3 channel The mailbox channel number from which the data originated
4-31 data The 28 bits of data sent to the CPU

MAIL0_STATUS格式

Bits 名称 说明
0-29 N/A Not documented here. Unused?
30 MAIL_EMPTY Set if the mailbox is empty, and thus no more data is available to be read from it.
31 MAIL_FULL Set if the mailbox is full, and thus no more data can be written to it.

MAIL0_WRITE格式

Bits 名称 说明
0-3 channel The mailbox channel number to which the data is to be sent
4-31 data The 28 bits of data to be sent to the destination

信箱操作

Read/write operatitons on the mailbox consist of transfering data via a 32 bit register. 28 bits of this 32 bit register are the data to be sent to the receiver, while the lower 4 bits specify the channel (channel 1 is the frame buffer, but there are others).

Procedure to Send Via the Mailbox

  1. Wait for space in the mailbox
    1. Execute a memory barrier
    2. Read MAIL0_STATUS
    3. Goto step 1 if MAIL_FULL bit is set
  2. Write channel and data to MAIL0_WRITE
  3. Execute a memory barrier

Procedure to Receive Via the Mailbox

  1. Wait for the mailbox to be non-empty
    1. Execute a memory barrier
    2. Read MAIL0_STATUS
    3. Goto step 1 if MAIL_EMPTY bit is set
  2. Execute a memory barrier
  3. Read from MAIL0_READ
  4. Check the channel (lowest 4 bits) of the read value for the correct channel
  5. If the channel is not the one we wish to read from (i.e: 1), go to step 1
  6. Return the data (i.e: the read value >> 4)

信箱通道

通道号 说明
0 Power management interface
1 Framebuffer
2 Virtual UART
3 VCHIQ interface
4 LEDs interface
5 Buttons interface
6 Touch screen interface

注意

  • The read procedure will not work if we're interested in reading from more than one channel as it does not handle the reception of other channels' data
  • The address of the frame buffer structure must be at least a multiple of 16 (in order to be accurately transmitted in the 28 bits available in the mailbox). I used (1 << 22) as the address of this structure.

GPU Framebuffer结构格式

The structure expected by the GPU for initializing the frame buffer is as follows:

字节           名称 说明
0-3 width Width of the requested frame buffer. My code uses a value of 640 here.
4-7 height Height of the requested frame buffer. My code uses a value of 480 here.
8-11 virtual_width Virtual Width -- easiest thing to do is to set this to width. I'm not entirely certain what this does (perhaps rescales?).
12-15 virtual_height Virtual Height -- easiest thing to do is to set this to height. I'm not entirely certain what this does (perhaps rescales?).
16-19  pitch Number of bytes between each row of the frame buffer. This is set by the GPU; in my code, I set it to zero before passing the structure to the GPU.
20-23 depth The number of bits per pixel of the requested frame buffer. I have not managed to make this work with anything other than a value of 24, however the Linux source seems to use 16 bit?!
24-27 x_offset Offset in the x direction. The easiest thing to do is to set this to zero. I'm not entirely certain exactly what this does.
28-31 y_offset Offset in the y direction. The easiest thing to do is to set this to zero. I'm not entirely certain exactly what this does.
32-35 pointer The pointer to the frame buffer into which your code should write. This is set by the GPU. I set this to zero before passing the structure to the GPU.
36-39 size The size of the frame buffer. Set by the GPU. I set this to zero before passing the structure to the GPU.

Each of the 32-bit values should be little endian (i.e: that of the included ARM processor). Hence a simple C struct with a data type of uint32_t for each of these fields will suffice.

转载于:https://my.oschina.net/funnky/blog/141247

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值