Baking Pi screen01


50 posts   Page 2 of 2   1, 2
by Chadderz » Wed Sep 12, 2012 5:42 pm
I'm afraid it's much more likely that it worked because the extra instructions altered the framebuffer's address. I've certainly had that before which puzzled me for a while.
User avatar
Posts: 63
Joined: Thu Aug 30, 2012 12:50 pm
Location: Cambridge, UK
by stevenf » Tue Sep 25, 2012 7:40 pm
I also had trouble getting screen01 to work.

After reading through this thread, I got it working with two changes to the prepackaged solution download:

- Change the .align 12 to .align 4 before FrameBufferInfo in frameBuffer.s
- Add the extra instructions described in CroydonClown's post from 9/12

I haven't changed any other code or my RPi's config.txt. I do not have to unplug and replug the HDMI cable.

I don't have any explanation to offer. Just a data point of what worked for me.
Posts: 5
Joined: Wed Aug 08, 2012 11:54 pm
by CroydonClown » Wed Sep 26, 2012 8:44 pm
Just as a follow up to this, I can confirm Chadderz' suspicions that the extra instructions had the effect of moving the framebuffer address. I could achieve the same results simply by changing the notorious .align statement, so

.align 12 did not work at all
.align 4 worked so long as the HDMI caple was unplugged and replugged
.align 5 (or 6) worked perfectly (so long as test_mode=1 was in config.txt)

In later lessons, I had to use trial and error to get the 'right' value. I'd love to understand what's going on but I'm afraid that I don't.
Posts: 3
Joined: Tue Sep 11, 2012 12:23 pm
by stevenf » Wed Sep 26, 2012 9:19 pm
As a further data point, I was also unable to get BrianW's framebuffer example working:

http://www.raspberrypi.org/phpBB3/viewtopic.php?f=72&t=16662

...until I put the latest boot firmware from GitHub onto my memory card.

https://github.com/raspberrypi/firmware

That seemed to magically sort everything out. Not sure if it affects the Baking Pi samples as well?
Posts: 5
Joined: Wed Aug 08, 2012 11:54 pm
by DexOS » Wed Sep 26, 2012 9:33 pm
These a simple fix that always works.
First the address must be
16 byte aligned
As the first 4 bit of the address can not be used.
So to make sure, i chose a 16 byte align address, say 0x100000 (1mb)
And then fill the needed info at that address, plus the needed offset from that address, then for example the screen_pointer would be at 0x100020.

Yes you need to make sure you have the memory space free.
But i have not had any problem with removing HDMI cable etc or it not working etc.
Batteries not included, Some assembly required.
User avatar
Posts: 860
Joined: Wed May 16, 2012 6:32 pm
by phil95 » Thu Sep 27, 2012 7:19 am
I have the sames problems too.
When I modify my programs, some time it's running, some time not.
It seems to me, that the address of the buffer has unknown constraints, not only align 4.
Remark:
if .align 4 is ok, why .align 12 is not ok ?????
Personnaly, I'm using a start.elf of 2467888 bytes from DexOS, and I have no more problems.
With other boot files, it can run or not.
When I prepare a SD card with some linux images, linux is working but I can have problems
when I replace kernel.img by my prog.
Philippe
Posts: 119
Joined: Wed Sep 12, 2012 8:10 am
Location: Paris
by benntramer » Sat Sep 29, 2012 6:45 pm
When I change alignments these are the results I see:

12: does not work
6: works if hdmi is unplugged/replugged
4: works if hdmi is unplugged/replugged

I tried to use 16, but got an error in the make process.
Posts: 1
Joined: Sat Sep 29, 2012 7:03 am
by DexOS » Sun Sep 30, 2012 7:41 pm
benntramer wrote:When I change alignments these are the results I see:

12: does not work
6: works if hdmi is unplugged/replugged
4: works if hdmi is unplugged/replugged

I tried to use 16, but got an error in the make process.

From reading the forum it seems like the PI takes a power of 2 for the alignment, so 4 is = to 16

But to test if its unalignment that is the problem, try using a set memory address, say 20mb fill the x y as that address plus the offset and see if that fix it.
That is what i do and have no problems with unplugged/replugged etc.
Batteries not included, Some assembly required.
User avatar
Posts: 860
Joined: Wed May 16, 2012 6:32 pm
by Archaeopteryx » Sun Oct 07, 2012 4:00 pm
I don't have inside information about how videocore works, but having worked through the tutorial and experienced these problems myself, this is what I think is going on.

The message you send to set up the framebuffer is a bus address, not an ARM physical address. If you look at the diagram on page 5 of the BCM2835 ARM Peripherals document you can see how these are mapped. In the bus address namespace, the physical ram is mapped four times, each with different cache behaviour, depending on which alias you use to access the memory. If you give it the address as instructed in the tutorial, videocore will access the memory "L1 and L2 cached". This means memory writes from the videocore will not be visible to the ARM until they are evicted from the cache, which we should assume is unpredictable.

Videocore does not send a reply message until it has finished writing the framebuffer address, size and pitch to the specified address. If it has replied ok, you can assume the address has been written, you should not have to loop to wait for the address to appear. This is a hack. The only reason it does not seem to be there, is it is sitting in the videocore's cache and is not written to memory. All replugging does is give the videocore some work to do which can cause it to evict the relevant cacheline, writing it out to memory.

To make this work as expected, you need to add 0x40000000 to the address you send in your message, this corresponds to the second alias of memory in the bus address namespace "L2 cache coherent (non allocating)". This uses some form of cache coherence which causes writes from videocore to be visible to the ARM immediately. If you do this, you will find the framebuffer description structure has always been filled-in after you receive the ok message, you will not need to loop to wait for it, you will not need to replug the hdmi and it will no longer make a difference where your framebuffer structure happens to be.

DexOS has mentioned a couple of times that you used to have to do this, but then they changed the firmware and then if you did this it would break. A lot of confusion seems to come from subtle changes to firmware revisions, presumably there have been versions in which this was broken. I found using the firmware I downloaded from github on Friday, that it works consistantly if I add 0x40000000, and sometimes works a bit after some aligning and replugging if I don't. I also updated today to the new firmware that doesn't require loader.bin and everything still works.

There is no such thing as an alignment restriction which requires something to be less aligned. If something works if it is 16 byte aligned and doesn't if it 4096 byte aligned, the problem is not an alignment restriction. The only alignment restriction on the framebuffer description structure is that is must be 16 byte aligned for its address to fit through the post box.
Posts: 1
Joined: Sun Oct 07, 2012 3:55 pm
by mister_wavey » Sun Oct 07, 2012 5:17 pm
Finally, an explanation that makes total sense. Thanks so much!
User avatar
Posts: 98
Joined: Sun Sep 02, 2012 8:23 am
Location: Abergavenny, Wales, UK
by DexOS » Sun Oct 07, 2012 6:50 pm
Archaeopteryx, has done a great job of explaining whats going on, the main problem seem to be a mixture of little info and firmware that keep slightly changing from week to week.
I can confirm that 0x40000000 worked fine until about a month ago, than it stopped working, now with the latest firmware, it seem to work with or without adding 0x40000000.
I also know someone that coded a bare metal app that displayed pi info, which it got from the mailboxs, He say it works much better with latest firmware.

Note: firmware in the raspberry pi case means the boot loader files.
Batteries not included, Some assembly required.
User avatar
Posts: 860
Joined: Wed May 16, 2012 6:32 pm
by jeremyp » Sat Oct 20, 2012 3:01 pm
Here's my data point. I was seeing the "need to unplug and replug the cable" issue until I tried Archaeopterix's solution. No it's all working fine.

This was using an SD card with a Raspbian Wheezy image from August. I had used apt-get to upgrade the OS which looks like it upgraded all the boot files.

Anyway, it works now. My code, by the way, is written in C mostly and it can be found here

http://code.google.com/p/pios/source/checkout
Posts: 9
Joined: Wed Sep 26, 2012 3:58 pm
by JacobL » Sat Nov 03, 2012 11:46 pm
Perhaps the address in Archaeopteryx post should be 0xC0000000? That is the address in atags and it is the highlighted memory region in the SoC datasheet.

In any case, is there a FAQ anywhere that this golden piece of information can be stored for new people to see? It seems the tutorial itself does not get updated, but perhaps a sticky post possibly with a link to wiki would be helpful?
Posts: 42
Joined: Sun Apr 15, 2012 2:23 pm
by JacobL » Mon Nov 12, 2012 10:45 pm
JacobL wrote:Perhaps the address in Archaeopteryx post should be 0xC0000000? That is the address in atags and it is the highlighted memory region in the SoC datasheet.


I just tried this, and it didn't work. Perhaps the GPU L2 cache has been enabled at some point in the firmwares after the documentation was written, which could mean that 0x40000000 is the way to go?
Posts: 42
Joined: Sun Apr 15, 2012 2:23 pm
by Grumps » Sun Nov 18, 2012 1:39 pm
I think I might be a bit late to this party, but have been playing "Bare Metal" using DexOS and now the Baking Pi.
It's the screen (HDMI) startup that's being a pain for me. I've been using http://www.cl.cam.ac.uk/freshers/raspbe ... een02.html
which is the line drawing tutorial, but have been having the same issue as many others in that the HDMI needs to be un-plugged/plugged to make the code continue to run.
Using the screen02 code exactly as it is from the above site, when you make the project and look at the kernel.map you can see that FrameBufferInfo is the 2nd in the .data section (after drawing.o).
I wanted to see what'd happen if FramBufferInfo was on a high address so I set the .data section to begin at 0x100000. I'm a novice when it comes to asm, and I don't know in which order the assembler puts things into the .data section. My guess is that it is alphabetical from the .s sources. So I renamed drawing.s to xdrawing.s. Now when it builds, the first entry in the .data section is FrameBufferInfo; it looks alphabetical to me.
And, with FBI starting from 0x100000 I don't have the requirement to unplug/plug the HDMI - it just runs.

Does any of that make sense with the authors?
Posts: 6
Joined: Tue Mar 06, 2012 8:07 pm
by JacobL » Sun Nov 18, 2012 1:57 pm
Grumps wrote:And, with FBI starting from 0x100000 I don't have the requirement to unplug/plug the HDMI - it just runs.

Does any of that make sense with the authors?


Short answer: There is a bug in the tutorial that does not account for different memory mappings between GPU and CPU. You need to add 0x40000000 to the address sent as the message in MailboxWrite (orr is useful). And you need to subtract 0x40000000 from the framebuffer pointer that is returned.

Long answer, Archaeopteryx explains it so well in his post a bit back in the current thread: http://www.raspberrypi.org/phpBB3/viewtopic.php?p=189643#p189643
Posts: 42
Joined: Sun Apr 15, 2012 2:23 pm
by Grumps » Sun Nov 18, 2012 2:28 pm
Thanks. I read this whole thread late last night (actually, early this morning). That post by Archy just didn't sink in. It makes perfect sense now. And better still, it works (without having to rename my drawing.s either). No more HDMI pulling :)
Posts: 6
Joined: Tue Mar 06, 2012 8:07 pm
by DexOS » Sun Nov 18, 2012 7:11 pm
Grumps wrote:I think I might be a bit late to this party, but have been playing "Bare Metal" using DexOS and now the Baking Pi.
It's the screen (HDMI) startup that's being a pain for me. I've been using http://www.cl.cam.ac.uk/freshers/raspbe ... een02.html
which is the line drawing tutorial, but have been having the same issue as many others in that the HDMI needs to be un-plugged/plugged to make the code continue to run.
Using the screen02 code exactly as it is from the above site, when you make the project and look at the kernel.map you can see that FrameBufferInfo is the 2nd in the .data section (after drawing.o).
I wanted to see what'd happen if FramBufferInfo was on a high address so I set the .data section to begin at 0x100000. I'm a novice when it comes to asm, and I don't know in which order the assembler puts things into the .data section. My guess is that it is alphabetical from the .s sources. So I renamed drawing.s to xdrawing.s. Now when it builds, the first entry in the .data section is FrameBufferInfo; it looks alphabetical to me.
And, with FBI starting from 0x100000 I don't have the requirement to unplug/plug the HDMI - it just runs.

Does any of that make sense with the authors?

@Grumps, you said you use DexOS, do you have to un-plugged/plugged for DexOS ?, as i have had no such problems, if so what ver was it and what boot loader where you using.
Thanks for any info.
Batteries not included, Some assembly required.
User avatar
Posts: 860
Joined: Wed May 16, 2012 6:32 pm
by blm768 » Fri Nov 23, 2012 11:27 pm
I'm also trying to write a Screen01-type program, and I end up with problems even when I add the 0x40000000 offset. I get a success message from the GPU, but my pointer is never set. Here's the code I'm using:

Code: Select all
#include <stdbool.h>
#include <stddef.h>

typedef signed char byte;
typedef unsigned char ubyte;

typedef unsigned int  uint;
typedef unsigned long ulong;

typedef ubyte color_rgb[3];
typedef ubyte color_rgba[4];

typedef struct {
   int width, height;
   int vWidth, vHeight;
   volatile int pitch;
   int depth;
   int x, y;
   volatile color_rgb* buffer;
   uint size;
} __attribute__((__aligned__(16))) FramebufferInfo;

typedef struct {
   uint box: 4;
   uint code: 28;
} Message;

#define MAIL_RECV (*(volatile Message*)0x2000B880)
#define MAIL_SEND (*(int*)0x2000B8A0)
#define MAIL_STATUS (*(volatile int*)0x2000B898)

static inline volatile int get_send_status() {
   return MAIL_STATUS & (1 << 31);
};

static inline void send_message(int mBox, int msg) {
   while(get_send_status()) {}
   MAIL_SEND = mBox | msg;
}

static inline volatile int get_recv_status() {
   return MAIL_STATUS & (1 << 29);
}

static inline volatile Message recv_message(int mBox) {
   while(get_recv_status()) {}
   //To do: check that this is the right mailbox.
   Message msg = MAIL_RECV;
   while(msg.box != mBox) {
      while(get_recv_status()) {}
      msg = MAIL_RECV;
   }
   return MAIL_RECV;
}

void kmain() {
   send_message(1, (int)(&fb + 0x40000000));
   int status = recv_message(1).code;
   if(status == 0) {
      while(!fb.buffer) {}
      for(size_t x = 0; x < fb.width; ++x) {
         for(size_t y = 0; y < fb.height; ++y) {
            color_rgb* ptr = (color_rgb*)fb.buffer + (y * fb.width + x);
            (*ptr)[0] = y;
            (*ptr)[1] = y;
            (*ptr)[2] = y;
         }
      }
   }
}


kmain() is the entry point for the C code. This bug is really baffling me; the only time I got it to (partially) work, I had a slightly different (and probably incorrect) code structure, and it only worked when I changed one of the GPIO pins right after sending the message (although the function call was probably what caused the difference rather than the GPIO state). My functions seem to look very similar to working samples, so I'm not sure where the bug is.
Posts: 24
Joined: Sun Nov 18, 2012 6:13 am
by JacobL » Fri Nov 23, 2012 11:36 pm
You are not subtracting 0x40000000 from fb.buffer. Safest is probably to just clear the upper 4 bits:

Code: Select all
fb.buffer = (volatile color_rgb*)((unsigned int)fb.buffer & 0x0FFFFFFF);
Posts: 42
Joined: Sun Apr 15, 2012 2:23 pm
by blm768 » Sat Nov 24, 2012 7:12 am
JacobL wrote:You are not subtracting 0x40000000 from fb.buffer. Safest is probably to just clear the upper 4 bits.


That's true, but I was going to test it that way anyway because I got it half-working without adding/subtracting any offsets. It probably wouldn't work, but I'm curious.

Before I can do that, though, I need to actually get a pointer in fb.buffer. Right now, I'm just getting 0, so I don't even get to the place where I'd do the subtraction. Am I just missing a volatile qualifier somewhere, or is this something more sinister?
Posts: 24
Joined: Sun Nov 18, 2012 6:13 am
by JacobL » Sat Nov 24, 2012 2:56 pm
That's true, but I was going to test it that way anyway because I got it half-working without adding/subtracting any offsets. It probably wouldn't work, but I'm curious.


With cache involved, there are many solutions that work on the surface some times, but doesn't work when pushed.

Am I just missing a volatile qualifier somewhere


Actually your definition of MAIL_SEND is missing a volatile qualifier. Do you have the asm listing for the function? You should be able to see if the write is getting optimised out from that.
Posts: 42
Joined: Sun Apr 15, 2012 2:23 pm
by blm768 » Sat Nov 24, 2012 9:01 pm
JacobL wrote:With cache involved, there are many solutions that work on the surface some times, but doesn't work when pushed.


That's definitely true. I kind of miss x86 cache coherency, but the hardware for that must have been a real pain to implement.

JacobL wrote:Actually your definition of MAIL_SEND is missing a volatile qualifier. Do you have the asm listing for the function? You should be able to see if the write is getting optimised out from that.


It doesn't look like adding the volatile qualifier makes it work any better. I looked at the disassembly, and it seems to be writing to MAIL_SEND (although I haven't checked it without the volatile qualifier), but I'm still getting the same results.
Posts: 24
Joined: Sun Nov 18, 2012 6:13 am
by blm768 » Tue Nov 27, 2012 4:51 pm
Still no luck getting the code to work; I think I'll compare my code against some examples and try to find where mine is different. Is there an example that works more consistently than others?
Posts: 24
Joined: Sun Nov 18, 2012 6:13 am
by blm768 » Tue Dec 04, 2012 9:05 am
As it turns out, the message wasn't giving a success code. For some reason, I had it in my head that 0 was the success code. :)

I guess I'd better figure out why it's not liking my call...

Edit: Could the problem be due to the lack of a memory barrier? Where should I put one to ensure that accesses are done in order? Is the standard DMB instruction the proper barrier, or is there one specific to the SoC?
Posts: 24
Joined: Sun Nov 18, 2012 6:13 am