BrianW
Posts: 83
Joined: Sun Jul 29, 2012 9:03 pm

Bare metal framebuffer in C

Fri Sep 07, 2012 12:08 am

Hi,

Thought I'd share my work with the class. So far I've got a framebuffer up, using the newer tag mailbox approach, and some text on it.

https://github.com/brianwiddas/pi-baremetal

The character set I'm using for the text might amuse some people - it's the SAA5050 teletext characters (as seen in MODE 7 on a BBC Micro).

Hopefully the code is fairly self-explanatory and the README makes sense.

Thanks to all the usual suspects for their examples, and the people who wrote the various wikis and documents.

hermanhermitage
Posts: 65
Joined: Sat Jul 07, 2012 11:21 pm
Location: Zero Page

Re: Bare metal framebuffer in C

Fri Sep 07, 2012 12:44 am

BrianW wrote: The character set I'm using for the text might amuse some people - it's the SAA5050 teletext characters (as seen in MODE 7 on a BBC Micro).
Oh my! Sheer genius! I love it:)

BrianW
Posts: 83
Joined: Sun Jul 29, 2012 9:03 pm

Re: Bare metal framebuffer in C

Fri Sep 07, 2012 4:38 pm

hermanhermitage wrote: Oh my! Sheer genius! I love it:)
Thanks.

It now comes with added "working at screen resolutions other than 1280x720". That'll teach me not to test with other screen sizes...

SupremeSpod
Posts: 22
Joined: Thu Jan 05, 2012 12:19 pm

Re: Bare metal framebuffer in C

Sun Sep 09, 2012 11:26 am

Hi,

Just a quick question, is it possible to use your code to obtain a framebuffer from code that is running under raspbian rather than "bare metal"?

I ask because "All I want is a pointer to display memory, I don't want SDL and I don't want OPENGL, I just want to write to display memory."

Thanks in advance.

User avatar
jojopi
Posts: 3078
Joined: Tue Oct 11, 2011 8:38 pm

Re: Bare metal framebuffer in C

Sun Sep 09, 2012 12:19 pm

SupremeSpod wrote:Just a quick question, is it possible to use your code to obtain a framebuffer from code that is running under raspbian rather than "bare metal"?
In Linux you can use the generic framebuffer interface, which is portable across multiple platforms. In the link below, ignore the first nine steps and skip straight to the example program in step10. It works perfectly on a Pi (although it could do with including <stdlib.h> to remove the warning about exit()).

http://web.njit.edu/all_topics/Prog_Lan ... howto.html

SupremeSpod
Posts: 22
Joined: Thu Jan 05, 2012 12:19 pm

Re: Bare metal framebuffer in C

Sun Sep 09, 2012 12:53 pm

jojopi wrote:
SupremeSpod wrote:Just a quick question, is it possible to use your code to obtain a framebuffer from code that is running under raspbian rather than "bare metal"?
In Linux you can use the generic framebuffer interface, which is portable across multiple platforms. In the link below, ignore the first nine steps and skip straight to the example program in step10. It works perfectly on a Pi (although it could do with including <stdlib.h> to remove the warning about exit()).

http://web.njit.edu/all_topics/Prog_Lan ... howto.html
Many thanks for your help. If I could leave you positive rep I would :)

Emanuele Spa
Posts: 9
Joined: Mon Sep 10, 2012 10:08 pm

Re: Bare metal framebuffer in C

Mon Sep 10, 2012 10:27 pm

Hi,
I tried to build the source code, but I got this error message:

framebuffer.o: In function `fb_init':
framebuffer.c:(.text+0x918): undefined reference to `__aeabi_uidiv'
framebuffer.c:(.text+0x928): undefined reference to `__aeabi_uidiv'
make: *** [kernel.elf] Error 1


I didn't change any line of code except the make file because it didn't work:
"CC=arm-linux-gnueabihf-gcc" with "CC=arm-linux-gnueabihf-gcc-4.4"

Any idea?
Thank you for helping :D

tufty
Posts: 1456
Joined: Sun Sep 11, 2011 2:32 pm

Re: Bare metal framebuffer in C

Tue Sep 11, 2012 4:18 am

You need to link in the gcc arm intrinsics library - the code is using "/" somewhere, and as arm has no division opcode, you need a library implementing that.

Simon

User avatar
Chadderz
Posts: 64
Joined: Thu Aug 30, 2012 12:50 pm
Location: Cambridge, UK

Re: Bare metal framebuffer in C

Tue Sep 11, 2012 8:22 am

Yes the error is because ARM doesn't have a hardware level divide, so GCC compiles a division as a call to the function __aeabi_uidiv with the prototype:

Code: Select all

unsigned int __aeabi_uidiv(unsigned int numerator, unsigned int denominator);
If you prefer to do everything yourself you can implement this in C or assembly to be quick. There are a whole bunch of methods like this that you would need to implement, listed here: http://infocenter.arm.com/help/topic/co ... _rtabi.pdf.

BrianW
Posts: 83
Joined: Sun Jul 29, 2012 9:03 pm

Re: Bare metal framebuffer in C

Tue Sep 11, 2012 12:17 pm

Emanuele Spa wrote: "CC=arm-linux-gnueabihf-gcc" with "CC=arm-linux-gnueabihf-gcc-4.4"
Hi,

As others have said, there's a handful of divide operators in the code (the one you've hit divides the horizontal/vertical resolution by the size of a character cell) which ARM doesn't have, so it has use code generated by gcc. I've only tested it on gcc-4.6 (it's the compiler on the latest Raspbian image, and the cross-compiler on my x86 box), which seems able to put the code inline, whereas I presume gcc 4.4 is placing a function call and expecting to link against libgcc.a

I'll have a poke at it and get it working... there are a lot of functions in that ARM ABI Chadderz linked to; can't hope to avoid them all forever :)

Emanuele Spa
Posts: 9
Joined: Mon Sep 10, 2012 10:08 pm

Re: Bare metal framebuffer in C

Tue Sep 11, 2012 8:21 pm

I installed gcc-4.6-multilib-arm-linux-gnueabihf and now everything works. :D
Thank you all!

aclindsa
Posts: 1
Joined: Fri Sep 14, 2012 2:21 pm

Re: Bare metal framebuffer in C

Fri Sep 14, 2012 2:30 pm

For what it's worth, I've run into this same issue with other bare-metal code, and found that I have to add '-lgcc' to the end of the linking target in my Makefile (i.e. adding it to the end of line 41: https://github.com/brianwiddas/pi-barem ... kefile#L41). This gets the linker to link with the libgcc.a file others were mentioning. Note: not compile-tested, but I think it should work if you still want to use your original toolchain.

BrianW
Posts: 83
Joined: Sun Jul 29, 2012 9:03 pm

Re: Bare metal framebuffer in C

Fri Sep 14, 2012 3:56 pm

aclindsa wrote:For what it's worth, I've run into this same issue with other bare-metal code, and found that I have to add '-lgcc' to the end of the linking target in my Makefile (i.e. adding it to the end of line 41: https://github.com/brianwiddas/pi-barem ... kefile#L41). This gets the linker to link with the libgcc.a file others were mentioning. Note: not compile-tested, but I think it should work if you still want to use your original toolchain.
There's an additional wrinkle which has been bugging me for a couple of days - some cross-compilers, like the one I'm using, don't have a libgcc.a suitable for the ARM1176. Mine (arm-linux-gnueabihf 4.6 on Linux Mint 12) comes with a libgcc.a which contains Thumb2 instructions, so, for instance, a divide operation which calls __aeabi_uidiv ends up triggering an undefined instruction exception.

I can fix it by using libgcc.a from the Raspbian build (I have a makefile which checks to see if it's running on a Raspberry Pi, and, if not, asks you to provide libgcc.a from one, unless you tell it you're sure your libgcc is suitable). While it works, and the libgcc ABI is presumably fairly stable, it feels like a horrible approach to the problem.

LLVM and Clang are starting to look interesting, if only because I don't know enough about them to know why they won't work ;) It's impossible to ignore gcc, though.

geordish
Posts: 5
Joined: Thu May 31, 2012 8:21 pm

Re: Bare metal framebuffer in C

Thu Sep 20, 2012 7:40 pm

I cannot for the life of me get this working. It constantly fails with the error code "FBFAIL_GET_RESOLUTION"

I've ran the baking pi tutorials, and they all work just fine. To make the last one work, I have to set kernel_old=1 in the config.txt.

If I do this, and run your framebuffer, I get no output at all. It just sticks on the boot test screen. When its in this state, shorting out the two pins does nothing at all, so it looks like its crashed/hung. I've also tried booting without the HDMI cable inserted, plugging it in while its booting etc, but no dice!

I'm runing Linux Mint 13, and using the toolchain you suggested. I've also used this toolchain to compile the baking pi examples to ensure that its working as expected.

Any ideas?

--
Dave

User avatar
DexOS
Posts: 876
Joined: Wed May 16, 2012 6:32 pm
Contact: Website

Re: Bare metal framebuffer in C

Thu Sep 20, 2012 7:55 pm

geordish wrote:I cannot for the life of me get this working. It constantly fails with the error code "FBFAIL_GET_RESOLUTION"

I've ran the baking pi tutorials, and they all work just fine. To make the last one work, I have to set kernel_old=1 in the config.txt.

If I do this, and run your framebuffer, I get no output at all. It just sticks on the boot test screen. When its in this state, shorting out the two pins does nothing at all, so it looks like its crashed/hung. I've also tried booting without the HDMI cable inserted, plugging it in while its booting etc, but no dice!

I'm runing Linux Mint 13, and using the toolchain you suggested. I've also used this toolchain to compile the baking pi examples to ensure that its working as expected.

Any ideas?

--
Dave
Just in case try this:
http://www.raspberrypi.org/phpBB3/viewt ... 82#p178082
Batteries not included, Some assembly required.

geordish
Posts: 5
Joined: Thu May 31, 2012 8:21 pm

Re: Bare metal framebuffer in C

Thu Sep 20, 2012 7:56 pm

Well, after I posted, I remembered something I was going to try.

I updated the firmware files from the raspberry pi git repository, and tried again without kernel_old defined. Worked first time. I've spent a few hours trying to get that working!

Thanks for your work, I'm now going to borrow it to help me out in my project :)

--
Dave

BrianW
Posts: 83
Joined: Sun Jul 29, 2012 9:03 pm

Re: Bare metal framebuffer in C

Thu Sep 20, 2012 8:34 pm

geordish wrote:Well, after I posted, I remembered something I was going to try.

I updated the firmware files from the raspberry pi git repository, and tried again without kernel_old defined. Worked first time. I've spent a few hours trying to get that working!

Thanks for your work, I'm now going to borrow it to help me out in my project :)
Glad it's sorted. I was only ever using the recent firmware, so I've not tried it with the older versions - I know the tag mailbox way of doing things is newer, but I didn't know how recent the firmware had to be.

I'll make a note in the README to ensure the firmware is reasonably up-to-date.

The way it works at the moment: when the Pi boots, its framebuffer physical size and depth are set to the right values (eg, 1280x720 on my monitor, 16 bits/pixel), but the virtual size is set to 2x2. Because the virtual size is scaled to the physical size, you get 4 very big virtual pixels which blend together at the edges - coloured red, green, yellow and blue to make the rainbow image.

My code reads the physical screen size (hence the FBFAIL_GET_RESOLUTION if it can't read the physical screen size from the tag mailbox interface) and sets the virtual screen size to be the same. It also sets the physical screen size and the depth, even though doing so seems to be unnecessary (I experimented with various combinations of setting the physical size, virtual size and depth to see what was actually required).

I'm wondering a little whether this is the right approach, or if I should be reading the screen size from the ATAGS structure and using that.

rupertr
Posts: 11
Joined: Fri Sep 07, 2012 2:21 am

Re: Bare metal framebuffer in C

Fri Sep 21, 2012 7:27 am

I'm wondering a little whether this is the right approach, or if I should be reading the screen size from the ATAGS structure and using that.
I've setup my own code to do some mailbox probing.
Just thought I'd mention my config.txt has nothing in it other than comments, and the physical width/height is coming out as 656x416 upon probing. This matches the ATAGs. I also get a virtual width/height of 2x2. This is via composite btw.

Anyone know how to get the framebuffer pointer without allocating one? I think this 2x2 "virtual" buffer is actually a framebuffer, and the "physical" buffer is the video signal resolution. It makes sense to scale a 2x2 framebuffer up to the video signal to see a nice gradient. I want the framebuffer pointer to test this.

rupertr
Posts: 11
Joined: Fri Sep 07, 2012 2:21 am

Re: Bare metal framebuffer in C

Fri Sep 21, 2012 8:36 am

Looks like you allocate a buffer without changing any parameters, it'll give you the location of the frame buffer, but it will clear the buffer. Reusing that address without allocating the frame buffer is indeed the correct location for the buffer on startup, and that address is (for me atleast) 0x0d385000. This is running a 192/64mb memory split, where the vc mem starts at 0x0c000000. Giving us a frame buffer offset of 0x01385000 from the vc mem.
And at that location I found the four pixels (2x2) used to display the nice rainbow image. Huzzah.
This is probably of no interest to anyone but myself, oh well :)

I'd still like to know if there's a way to query where the location is via the mailbox, if it's possible?

Dasaan
Posts: 7
Joined: Mon Sep 24, 2012 6:34 pm

Re: Bare metal framebuffer in C

Sat Sep 29, 2012 9:40 pm

I've been following along with the Baking Pi lesson objectives (sort of) in C. I got OK01->Screen01 working (had to Frankenstein my code with some of the other C frame buffer examples).
After that I thought I'd make a simple ClearScreen function that turns all the pixels the same colour. I started off turning the pixels white and it seemed to kind of work with the following oddities:
- On first power up the framebuffer constantly failed to initialise.
- Subsequent power ups showed a white screen with a small line of coloured pixels near the top of the screen (similar place every time)

Out of curiosity I set the pixel to a different colour to make sure I was actually doing something to the framebuffer, but the screen is still showing up white suggesting that I'm not even writing to the framebuffer. Odd seeing as I did get a very colourful test screen working as part of Screen01. I've spent several hours checking my code and I fixed a few things that weren't quite right but nothing I've done changes anything on the screen.

I'd appreciate some extra eyes on my code (attached) to see what I'm overlooking. I should mention that I'm a bit of a C newbie and using my Pi as a way to learn more, so any constructive criticism would be great.
Attachments
07_Screen02.zip
(9.86 KiB) Downloaded 251 times

User avatar
DexOS
Posts: 876
Joined: Wed May 16, 2012 6:32 pm
Contact: Website

Re: Bare metal framebuffer in C

Sat Sep 29, 2012 9:56 pm

Dasaan wrote:I've been following along with the Baking Pi lesson objectives (sort of) in C. I got OK01->Screen01 working (had to Frankenstein my code with some of the other C frame buffer examples).
After that I thought I'd make a simple ClearScreen function that turns all the pixels the same colour. I started off turning the pixels white and it seemed to kind of work with the following oddities:
- On first power up the framebuffer constantly failed to initialise.
- Subsequent power ups showed a white screen with a small line of coloured pixels near the top of the screen (similar place every time)

Out of curiosity I set the pixel to a different colour to make sure I was actually doing something to the framebuffer, but the screen is still showing up white suggesting that I'm not even writing to the framebuffer. Odd seeing as I did get a very colourful test screen working as part of Screen01. I've spent several hours checking my code and I fixed a few things that weren't quite right but nothing I've done changes anything on the screen.

I'd appreciate some extra eyes on my code (attached) to see what I'm overlooking. I should mention that I'm a bit of a C newbie and using my Pi as a way to learn more, so any constructive criticism would be great.
This is wrong now PhysicalToARM (with later loader files), so try it without adding 0xC0000000 to address

Code: Select all

UINT32 PhysicalToARM(VOID *p)

{

	// Some things (e.g: the GPU) expect bus addresses, not ARM physical

	// addresses

	return ((UINT32)p) + 0xC0000000;

}
You needed to add that when the pi was first out, but then it changed.
Make sure you get the latest loader files.
Batteries not included, Some assembly required.

Dasaan
Posts: 7
Joined: Mon Sep 24, 2012 6:34 pm

Re: Bare metal framebuffer in C

Sun Sep 30, 2012 12:20 pm

DexOS wrote:
This is wrong now PhysicalToARM (with later loader files), so try it without adding 0xC0000000 to address

Code: Select all

UINT32 PhysicalToARM(VOID *p)
{
	// Some things (e.g: the GPU) expect bus addresses, not ARM physical
	// addresses
	return ((UINT32)p) + 0xC0000000;
}
You needed to add that when the pi was first out, but then it changed.
Make sure you get the latest loader files.
I downloaded the latest loader files from the github page and changed the above code to:

Code: Select all

UINT32 PhysicalToARM(VOID *p)
{
	// Some things (e.g: the GPU) expect bus addresses, not ARM physical
	// addresses
	return ((UINT32)p);
}
Booting up now just shows a black screen. In main.c I make the OK LED turn on constantly after the FrameBuffer has been initialised. This isn't happening, indicating that InitialiseFrameBuffer() is just being run endlessly.

I added a couple of loops that flash the OK LED at different rates, slowly if the mailbox read is invalid and quickly if fb->Pointer == 0.

Every time I tested the above the LED flashed quickly so my pointer == 0

Now as for what's causing it to always be 0... I've not worked that out yet.

mvdhoning
Posts: 18
Joined: Fri Sep 14, 2012 2:47 pm

Re: Bare metal framebuffer in C

Sun Sep 30, 2012 6:34 pm

Same for me ;-)

But yesterday (and today) i decided to take another side step and use the mailbox interface to read out screen resolution and that gave me wrong values also namely 0.

Info on the mailbox property interface:
https://github.com/raspberrypi/firmware ... -interface

Brian Widdas has worked that out in an example. Something that he does and i did not before is assigning the record that is used with the mailbox to a specific place in memory $1000 (the load address of old style kernels)

Code: Select all

/* Use some free memory in the area below the kernel/stack */
#define BUFFER_ADDRESS	0x1000
... snip ...
volatile unsigned int *mailbuffer = (unsigned int *) BUFFER_ADDRESS;
so instead of using a record an array of unsigned int are used.

For his complete example: https://github.com/brianwiddas/pi-baremetal

With that (and a fix to the unsigned int to hex chars function) i now can read out the resolution set by the bootloader.

My freepascal solution:
http://code.google.com/p/fprpbm/source/ ... /mailfirm/

Next weekend i give the framebuffer another go.

ps i only now realized Brian Widdas started this thread ;-)

User avatar
DexOS
Posts: 876
Joined: Wed May 16, 2012 6:32 pm
Contact: Website

Re: Bare metal framebuffer in C

Sun Sep 30, 2012 7:04 pm

Do you add 1 to the write mailbox 0x2000B8A0 +1 ?, i may of just mist it.
Batteries not included, Some assembly required.

mvdhoning
Posts: 18
Joined: Fri Sep 14, 2012 2:47 pm

Re: Bare metal framebuffer in C

Sun Sep 30, 2012 7:10 pm

DexOS wrote:Do you add 1 to the write mailbox 0x2000B8A0 +1 ?, i may of just mist it.
He does not seem to do that ( i don't do that either ) is there a reason why we should not use MAILBOX0_WRITE?

Return to “Bare metal, Assembly language”