RPI2 framebuffer not displaying fully


29 posts   Page 1 of 2   1, 2
by alexlanzano » Fri Mar 17, 2017 11:50 pm
Hey guys,

I'm having trouble getting my RPI2 to display across the screen. I initialize my frame buffer and attempt to set each pixel to white (0xFFFFFFFF) but when I do so it only displays the first few hundred rows being white. It's almost as if I'm running out of ram but I would think with 2gigs I would be alright. My resolution is 1920x1080 with a depth of 32. If anyone one could weigh in on this, that would be great.

Thanks
Posts: 12
Joined: Fri Mar 17, 2017 11:41 pm
by alexlanzano » Sat Mar 18, 2017 12:17 am
here's a snippit from main.c:
Code: Select all
   
    uint32_t *frame_buffer = frame_buffer_init(WIDTH, HEIGHT, DEPTH);
    uint32_t *buffer = (uint32_t *)(get_frame_buffer());
    uint32_t size = get_frame_buffer_size();
    init_screen_buffer(buffer, WIDTH, HEIGHT, DEPTH);
    for(int y = 0; y < HEIGHT; ++y){
        for(int x = 0; x < WIDTH; ++x){
            draw_pixel(x, y, color);
        }
    }

    /*                                                                                                 
    draw_rect(10, 10, 50, 50, 0xff0000ff);                                                             
                                                                                                       
    draw_char('A', 30, 30, 0xff0000ff);                                                                 
    */



    while(1){

    }



heres my frame_buffer.s:
Code: Select all
    .section    .data
    .align      12
    .global frame_buffer
frame_buffer:
    .int    1024    // width                                                                                                                                                                                       
    .int    768     // height                                                                                                                                                                                     
    .int    1024    // virtual width                                                                                                                                                                               
    .int    768     // virtual height                                                                                                                                                                             
    .int    0       // pitch                                                                                                                                                                                       
    .int    16      // depth                                                                                                                                                                                       
    .int    0       // x offset                                                                                                                                                                                   
    .int    0       // y offset                                                                                                                                                                                   
    .int    0       // address                                                                                                                                                                                     
    .int    0       // size                                                                                                                                                                                       


    .section .text
    .global frame_buffer_init
frame_buffer_init:
    width               .req    r0
    height              .req    r1
    depth               .req    r2
    frame_buffer_addr   .req    r4

    push    {r4, lr}
    ldr     frame_buffer_addr, =frame_buffer

    str     width, [r4, #0]
    str     height, [r4, #4]
    str     width, [r4, #8]
    str     height, [r4, #12]
    str     depth, [r4, #20]

    .unreq  width
    .unreq  height
    .unreq  depth

    mov     r0, #1
    mov     r1, frame_buffer_addr
    add     r1, #0xc0000000
    bl      mailbox_write

    mov     r0, #1
    bl      mailbox_read

    teq     r0, #0
    movne   r0, #0
    popne   {r4, pc}

    mov     r0, frame_buffer_addr
    pop     {r4, pc}
    .unreq  frame_buffer_addr
    .global get_frame_buffer
get_frame_buffer:

    push    {lr}
    ldr     r1, =frame_buffer
    ldr     r0, [r1, #32]
    and     r0, #0x3fffffff
    pop     {pc}

    .global get_frame_buffer_size
get_frame_buffer_size:

    push    {lr}
    ldr     r1, =frame_buffer
    ldr     r0, [r1, #36]
    pop     {pc}




And here is my mailbox.s:
Code: Select all
    .global get_mailbox_base
get_mailbox_base:
    ldr     r0, =0x3f00b880
    mov     pc, lr


    .global mailbox_write
mailbox_write:
    // void mailbox_write(uint8_t channel, uint32_t value)                                                                                                                                                         
    mailbox     .req    r0
    value       .req    r1
    channel     .req    r2
    status      .req    r3

    mov     channel, r0

    push    {lr}
    bl      get_mailbox_base

mailbox_full:
    ldr     status, [mailbox, #0x18]
    tst     status, #0x80000000
    bne     mailbox_full

    add     value, channel
    str     value, [mailbox, #0x20]

    .unreq  mailbox
    .unreq  channel
    .unreq  value
    .unreq  status

    pop     {pc}



    .global mailbox_read
mailbox_read:
    //  uint32_t mailbox_read(uint8_t channel)                                                                                                                                                                     
    mailbox     .req    r0
    channel     .req    r1
    status      .req    r2
    value       .req    r3

    mov     r1, r0
    push    {lr}
    bl      get_mailbox_base

loop1:

mailbox_empty:
    ldr     status, [mailbox, #0x18]
    tst     status, #0x40000000
    bne     mailbox_empty

    ldr     value, [mailbox, #0x0]
    and     r4, value, #0xf
    teq     r4, channel
    bne     loop1


    and     r0, value, #0xfffffff0

    .unreq  mailbox
    .unreq  channel
    .unreq  status
    .unreq  value

    pop     {pc}


Posts: 12
Joined: Fri Mar 17, 2017 11:41 pm
by LdB » Sat Mar 18, 2017 12:36 am
Your order is wrong

1.) Set the screen resolution (Tag: 0x00048003)
2.) Set the Virtual screen resolution to same (Tag: 0x00048004)
3.) Get framebuffer (Tag: 0x00040001)

1920x1080 x 4 bytes = 8,294,400 bytes ... 8Megabytes .. No gigabytes were harmed in the making of this calculation :-)

Your screen memory runs from Framebuffer to FrameBuffer + 0x007E9000

Sidenote:
add r1, #0xc0000000 ... NO dangerous if you mess up and have already adjusted
orr r1, #0xc0000000 ... YES safe always
Posts: 297
Joined: Wed Dec 07, 2016 2:29 pm
by alexlanzano » Sat Mar 18, 2017 7:32 pm
LdB wrote:Your order is wrong

1.) Set the screen resolution (Tag: 0x00048003)
2.) Set the Virtual screen resolution to same (Tag: 0x00048004)
3.) Get framebuffer (Tag: 0x00040001)

1920x1080 x 4 bytes = 8,294,400 bytes ... 8Megabytes .. No gigabytes were harmed in the making of this calculation :-)

Your screen memory runs from Framebuffer to FrameBuffer + 0x007E9000

Sidenote:
add r1, #0xc0000000 ... NO dangerous if you mess up and have already adjusted
orr r1, #0xc0000000 ... YES safe always


Thanks for the input! But I'm still confused on how my order is wrong. Aren't I just filling a buffer with the frame buffer info and then sending it to the videocore to then allocate everything?
Posts: 12
Joined: Fri Mar 17, 2017 11:41 pm
by LdB » Mon Mar 20, 2017 3:33 am
The frame buffer moves around depending on resolution you have to request the framebuffer AFTER you set the screen res. You need to note the word the framebuffer return uses which is an ALLOCATION.

So lets look at your code ..... First you first get the frame buffer (the code you use is)
Code: Select all
 uint32_t *frame_buffer = frame_buffer_init(WIDTH, HEIGHT, DEPTH);
uint32_t *buffer = (uint32_t *)(get_frame_buffer());

Then you set the screen resolution
Code: Select all
init_screen_buffer(buffer, WIDTH, HEIGHT, DEPTH);

You are doing step 3 then 1,2 ... AKA it is a different order surely you can see that.

So lets be more blunt ... you need to explicitly get the framebuffer after this line not before
>>>> init_screen_buffer(buffer, WIDTH, HEIGHT, DEPTH); <<<<
That line fires Tag: 0x00048003 (step 1) .. and its the order of the TAG commands that matters.

If you want the current resolution before that use Tag: 0x00040003 but don't get the framebuffer.

Do it in the right order and your 0x007E9000 byte buffer works as expected .. try it.

If you look at my articles ... I have no trouble drawing to whole screen and I promise you that is all I do.
https://www.codeproject.com/Articles/11 ... ated-Suppo
https://www.codeproject.com/Articles/11 ... he-Pi-part
Posts: 297
Joined: Wed Dec 07, 2016 2:29 pm
by Ultibo » Mon Mar 20, 2017 11:10 pm
Hi alexlanzano,

alexlanzano wrote:I initialize my frame buffer and attempt to set each pixel to white (0xFFFFFFFF) but when I do so it only displays the first few hundred rows being white.


I can't see anything wrong from the code you posted but I can clear up the confusion about the "wrong order"

You seem to be using the Mailbox framebuffer interface which only requires you to fill in a buffer and send it to the mailbox so you don't appear to be doing anything wrong when calling that. The other post is referring to the Mailbox property interface instead which requires a different sequence.

From your description (and the fact you get something on screen) I wonder if your draw_pixel() function is correctly calculating the location of each pixel, the basic algorithm should be something like this:

Code: Select all
 Pixel_Address = Framebuffer_Address + (Y * Framebuffer_Pitch) + (X * (Framebuffer_Depth div 8))

If you still have no luck maybe you could post a little bit more of the code to show the complete handling of the framebuffer.
Ultibo.org | Make the future
https://ultibo.org
User avatar
Posts: 83
Joined: Wed Sep 30, 2015 10:29 am
Location: Australia
by alexlanzano » Tue Mar 21, 2017 12:16 am
Yeah, it seems the problem was with the way I was accessing the pixels.
This is what I was doing:
Code: Select all
for(int y = 0; y < HEIGHT; ++y){
    for(int x = 0; x < WIDTH; ++x){
        frame_buffer[y+WIDTH + x] = color;
    }
}

So I changed it to what you suggested:
Code: Select all
for(int y = 0; y < HEIGHT; ++y){
    for(int x = 0; x < WIDTH; ++x){
        frame_buffer[(y * pitch) + (x * (DEPTH >> 3))] = color;
    }
}

Which does make it draw to the entire screen but now it's drawing vertical lines of the color i specified. They seem to be only one or two pixels apart...
Posts: 12
Joined: Fri Mar 17, 2017 11:41 pm
by Ultibo » Tue Mar 21, 2017 12:55 am
alexlanzano wrote:
Code: Select all
for(int y = 0; y < HEIGHT; ++y){
    for(int x = 0; x < WIDTH; ++x){

It might not make any difference (I'm not a C programmer) but wouldn't you normally do post increment (y++) instead of pre increment (++y) ?
Code: Select all
for(int y = 0; y < HEIGHT; y++){
    for(int x = 0; x < WIDTH; x++){
Ultibo.org | Make the future
https://ultibo.org
User avatar
Posts: 83
Joined: Wed Sep 30, 2015 10:29 am
Location: Australia
by alexlanzano » Tue Mar 21, 2017 1:32 am
Usually that would be correct. But in the case of the for loop in c it doesn't matter. I just changed it just to be safe and I'm still running into the same problem.
Posts: 12
Joined: Fri Mar 17, 2017 11:41 pm
by LdB » Tue Mar 21, 2017 3:16 am
alexlanzano wrote:[/code]
So I changed it to what you suggested:
Code: Select all
for(int y = 0; y < HEIGHT; ++y){
    for(int x = 0; x < WIDTH; ++x){
        frame_buffer[(y * pitch) + (x * (DEPTH >> 3))] = color;
    }
}

Pretty obvious why .. your framebuffer is a 32 bit array you don't need the (DEPTH >> 3) .. AKA 32 >> 8 = 4

Remember it depends on how you define FrameBuffer

uint8_t* FrameBuffer VS uint32_t* FrameBuffer

FrameBuffer[1] is the 1st byte in case 1 and byte 4 in case 2 with the same index.. C deals with the index multiply for you. I probably have a uint8_t array because I was supporting 16 and 24 bit modes as well.

If you defined 32 bit array and you use (DEPTH >> 3) it will write every 4th pixel

That bit of code does the following

In 16 bit colour it will multiply X by two
In 24 bit colour it will multiply X by three
In 32 bit colour it will multiply X by four

So it's a multiply you would use on an 8 bit array which I probably did because of the 16 & 24 bit colour modes. I was lazy and accessed them as bytes rather than go thru the whole preserve certain byte(s) in a 32 bit read, ORR in the pixel bits to the right place and write the whole 32 bits back again.
Last edited by LdB on Tue Mar 21, 2017 3:32 am, edited 1 time in total.
Posts: 297
Joined: Wed Dec 07, 2016 2:29 pm
by alexlanzano » Tue Mar 21, 2017 3:27 am
We seem to making some progress. I omitted the the (DEPTH >>3) and now it's showing horizontal lines. And I apologize for not knowing much about graphics. This is my first experience with this kind of thing.
Posts: 12
Joined: Fri Mar 17, 2017 11:41 pm
by LdB » Tue Mar 21, 2017 3:35 am
Excellent and try writing something like 0xFFFFFF00 rather than 0xFFFFFFFF and you should get a colour

Update: Silly me what you are saying is you have the same problem on the Y because your pitch is 4 times to large hence why you have lines. Divide your pitch from line to line by 4 .. pitch is in bytes and you have 32 bit array ... so this.

Code: Select all
pitch /= 4;    // divid by 4 for 32 bit array
 for(int y = 0; y < HEIGHT; ++y){
    for(int x = 0; x < WIDTH; ++x){
        frame_buffer[(y * pitch) + x ] = color;
    }
}
Posts: 297
Joined: Wed Dec 07, 2016 2:29 pm
by alexlanzano » Tue Mar 21, 2017 3:54 am
Man, this is frustrating... So I made those changes and it draws the pixels smoothly on the screen but it only fills roughly the top quarter of the screen.

Is there some sort of config that I'm missing?
Posts: 12
Joined: Fri Mar 17, 2017 11:41 pm
by LdB » Tue Mar 21, 2017 4:05 am
Don't get frustrated just do it slowly and analyze so i want you to draw just two lines cut and paste you code and manually set the X and Y values

Line 1 0,0 to 1920,0 set with colour 0xFFFF0000
Line 2 0,2, to 1920,2 set with colour 0xFFFFFF00

Do we get two coloured lines seperated by 1 pixel in the Y but going only half way across screen.

The quick code and all the display should be at very top of screen
Code: Select all
pitch /= 4;    // divid by 4 for 32 bit array
for(int x = 0; x < 1920; x++){
        frame_buffer[x ] = 0xFFFF0000;
 }
for(int x = 0; x < 1920; x++){
        frame_buffer[(2 * pitch) + x ] = 0xFFFFFF00;
}

Let me explain my concern ... you say the screen is 1920x1024 .. but is the virtual screen size correctly set at that
Posts: 297
Joined: Wed Dec 07, 2016 2:29 pm
by LdB » Tue Mar 21, 2017 4:21 am
Okay had another look at your assembler code and there is one quick thing I would like you to fix as it is wrong I am pretty sure
Code: Select all
    .section    .data
    .align      12      <===== PLEASE CHANGE THIS TO .align 16
    .global frame_buffer
frame_buffer:

Not sure where you got the 12 from but I am pretty sure it has to be align 16

And I really need to see the code for this call it isn't in your code above
Code: Select all
init_screen_buffer(buffer, WIDTH, HEIGHT, DEPTH);
Last edited by LdB on Tue Mar 21, 2017 4:33 am, edited 1 time in total.
Posts: 297
Joined: Wed Dec 07, 2016 2:29 pm
by alexlanzano » Tue Mar 21, 2017 4:28 am
Both lines make it across the screen but they aren't separated by one pixel. they seem right on top of each other.
When I try to display color to the entire screen it only fills the first few hundred rows with the color then stops abruptly.

And I got the align 12 from the baking pi tutorial. and I've tried changing that in the pasted to 16 but the complier complains say that the alignment is too large
Posts: 12
Joined: Fri Mar 17, 2017 11:41 pm
by LdB » Tue Mar 21, 2017 4:37 am
Hehe now I am getting got with the x4 thing
Yes it .align 4 or .balign 16 meaning byte align .. but .align 12 will be 48 bytes which is safe it has to be 16 or above

So can I see that code for the line above

oh and can I have 3 lines no gap
Code: Select all
pitch /= 4;    // divid by 4 for 32 bit array
for(int x = 0; x < 1920; x++){
        frame_buffer[x ] = 0xFFFF0000;
 }
for(int x = 0; x < 1920; x++){
        frame_buffer[pitch + x ] = 0xFF000FF;
 }
for(int x = 0; x < 1920; x++){
        frame_buffer[(2 * pitch) + x ] = 0xFFFFFF00;
}
Last edited by LdB on Tue Mar 21, 2017 4:41 am, edited 1 time in total.
Posts: 297
Joined: Wed Dec 07, 2016 2:29 pm
by alexlanzano » Tue Mar 21, 2017 4:41 am
Here's when I write to the entire screen
Code: Select all
for(int y = 0; y < HEIGHT; y++){
        for(int x = 0; x < WIDTH; x++){
            buffer[(y * pitch) + x ] = color;
        }
}


and here are the two lines
Code: Select all
int y = 0;                                                                                         
for(int x = 0; x < WIDTH; ++x)                                                                     
    buffer[(y * pitch) + x] = 0xffffff00;                                                           
                                                                                                       
y = 2;                                                                                             
for(int x = 0; x < WIDTH; ++x)                                                                     
    buffer[(y * pitch) + x] = 0xffff0000;
Posts: 12
Joined: Fri Mar 17, 2017 11:41 pm
by LdB » Tue Mar 21, 2017 4:43 am
See above put a line in what should be the gap and can I have that code as per request above

So
Code: Select all
int y = 0;                                                                                         
for(int x = 0; x < WIDTH; x++)                                                                     
    buffer[(y * pitch) + x] = 0xffffff00;                                                           
y = 1;                                                                                             
for(int x = 0; x < WIDTH; x++)                                                                     
    buffer[(y * pitch) + x] = 0xff0000ff;                                                                                                     
y = 2;                                                                                             
for(int x = 0; x < WIDTH; x++)                                                                     
    buffer[(y * pitch) + x] = 0xffff0000;
Last edited by LdB on Tue Mar 21, 2017 4:45 am, edited 1 time in total.
Posts: 297
Joined: Wed Dec 07, 2016 2:29 pm
by alexlanzano » Tue Mar 21, 2017 4:44 am
And WIDTH = 1920
and HEIGHT = 1080
Posts: 12
Joined: Fri Mar 17, 2017 11:41 pm
by LdB » Tue Mar 21, 2017 4:46 am
I really hate your pre-increment ++x can you get rid of it permanently it will put a random pixel somewhere.

You do know what ++x does right? Add to that you start the value at 0 so it's obvious what the first value of x output which will be some random place miles off screen.

Can we stick to x++ please :-)
Posts: 297
Joined: Wed Dec 07, 2016 2:29 pm
by alexlanzano » Tue Mar 21, 2017 4:54 am
Yeah, it increments the variable before it's used but in terms of a c for loop int i gets set to zero then it checks if it's less than WIDTH, then does the stuff within the for loop, then executes ++i. Supposedly ++i is less instructions than i++. that's why I use it.
it makes no difference either way.

but the above changes yield the same results as before.
Posts: 12
Joined: Fri Mar 17, 2017 11:41 pm
by LdB » Tue Mar 21, 2017 5:09 am
I know it wasn't the problem worst case it just draws a random pixel. So rare to use it in C it's a C++ thing I couldn't remember if it really pre-incremented the loop variable. It doesn't by the way you made me try it, it does nothing, produced output code was identical. The only difference is the number left in the register at the end of the loop. So it's perfectly safe I just find it ugly because it looks wrong to what I see all day .. so ignore me on that .. I am being OCD ... now about your indenting ... lol :-)

How did you go with 3 lines and can I have a look at that code for

init_screen_buffer(buffer, WIDTH, HEIGHT, DEPTH);

I want to confirm you are setting the virtual screen height in that call.

Update:
Forget all that I just checked I used int's and it doesn't roll. I was very bad and growled at myself :-)

I would say we have narrowed to Virtual Screen height not set if the 3 lines work, as everything seems to be as expected.
Posts: 297
Joined: Wed Dec 07, 2016 2:29 pm
by alexlanzano » Tue Mar 21, 2017 6:45 pm
I have a suspicion that the VideoCore isn't allocating enough memory. Right now I'll try to implement the mini-uart to check all that and post what I find. Thanks for all your help by the way.
Posts: 12
Joined: Fri Mar 17, 2017 11:41 pm
by LdB » Wed Mar 22, 2017 6:21 am
It can't not allocate enough memory .. it is the virtual screen port

I keep asking you for this routine .. it's not on your post
init_screen_buffer(buffer, WIDTH, HEIGHT, DEPTH);

The virtual screen sets how much of the screen you can see it's a clip if you like.
If you don't set it at least as big as you asked for the screen it clips.

Usually you set the screen resolution then set the virtual screen straight after to same size ... hence
I want to see
init_screen_buffer(buffer, WIDTH, HEIGHT, DEPTH);
Posts: 297
Joined: Wed Dec 07, 2016 2:29 pm