jFoster
Posts: 57
Joined: Fri Jul 03, 2015 7:32 pm
Location: British Columbia, Canada
Contact: Website

How To Use The Framebuffer?

Sun Jul 31, 2016 6:57 pm

I'm trying to initialize the framebuffer on my Raspberry Pi 3 in order to get text printed to the screen.

The mailboxes are working, I am able to communicate with the GPU and it responds back. I'm using mailbox channel 8 and writing these tags:

Code: Select all

SET_PHYSICAL_SIZE, 640, 480
SET_VIRTUAL_SIZE, 640, 480
SET_DEPTH, 32
TAG_ALLOCATE_BUFFER, 16
I know the mailboxes are working because my screen changes from the rainbow pattern to black. When I read from the contents of TAG_ALLOCATE_BUFFER, I get the proper response from the GPU, with the base address and the size of the framebuffer. The address returned is "0xCE9A2000" and the size is "0x00258000".

My problem is when I try to write to the framebuffer at the designated address, nothing happens on the display. I've tried subtracting 0x40000000 from the address returned and then writing to it, also tried "&'ing" it with 0x3fffffff to convert it into the ARM address, but no luck.

I am using a simple put32 instuction to write to the address of the framebuffer in RAM. I've tried writing many different values but right now I'm filling the entire buffer with 0xFFFFFFFF (not sure what to write into it).

Any help would be appreciated,

Judd

mnicolella
Posts: 4
Joined: Sat Jul 30, 2016 4:26 pm

Re: How To Use The Framebuffer?

Mon Aug 01, 2016 1:36 am

Maybe you're mixing up physica/virtual addresses? I'm not personally familiar, but someone here has a fair amount of framebuffer code and I see some physical/virtual translation in there: https://github.com/brianwiddas/pi-barem ... mebuffer.c

User avatar
Ultibo
Posts: 160
Joined: Wed Sep 30, 2015 10:29 am
Location: Australia
Contact: Website

Re: How To Use The Framebuffer?

Mon Aug 01, 2016 1:49 am

Hi Judd,
jFoster wrote:The address returned is "0xCE9A2000" and the size is "0x00258000".
Something seems odd about a returned address of 0xCE9A2000 since the address returned by the GPU will normally be (once converted to a physical address) within the assigned GPU RAM (towards the top of the first 1GB).

The area of GPU memory depends on the ARM <-> GPU split assigned in config.txt but for the one I have in front of me the GPU memory starts at 0x3B000000 and goes to 0x3F000000 (64MB).

The framebuffer address in my case is returned as 0xFD402000 which translates to a physical address of 0x3D402000 which is nicely within the GPU RAM.
jFoster wrote:I've tried subtracting 0x40000000 from the address returned and then writing to it, also tried "&'ing" it with 0x3fffffff to convert it into the ARM address
To convert the returned bus address to a physical address you should do AND NOT(0xC0000000) so your returned address of 0xCE9A2000 gives a physical address of 0x0E9A2000 which would normally be in ARM memory not GPU memory.

Not quite sure how you are getting this return address if the mailbox call is otherwise successful.
Ultibo.org | Make something amazing
https://ultibo.org

Threads, multi-core, OpenGL, Camera, FAT, NTFS, TCP/IP, USB and more in 3MB with 2 second boot!

jFoster
Posts: 57
Joined: Fri Jul 03, 2015 7:32 pm
Location: British Columbia, Canada
Contact: Website

Re: How To Use The Framebuffer?

Mon Aug 01, 2016 2:21 am

AND(0x3fffffff) yields the same result: 0x0e9a2000.

I sent a tag and received the valid response code (0x80000000), so I am assuming that the mailbox request / response is succesful. I reset the address and size to zero in my request buffer so I know the GPU is writing those numbers into the buffer.

Sorry for the brief response I am at work and will look into it further when I get back tonight.

Judd

jFoster
Posts: 57
Joined: Fri Jul 03, 2015 7:32 pm
Location: British Columbia, Canada
Contact: Website

Re: How To Use The Framebuffer?

Mon Aug 01, 2016 4:57 pm

I see some physical/virtual translation in there
He's got the MMU enabled, I think that's why there's a lot of virtual to physical translations.

My knowledge on the writing to the framebuffer was based a lot off of that code as well as these other links:
https://github.com/dwelch67/raspberrypi ... /video01.c
https://github.com/PeterLemon/Raspberry ... ernel8.asm(Only managed to get this one working on Raspberry Pi 3)
https://github.com/BrianSidebotham/arm- ... armc-014.c

The C code examples seem to just be writing directly to the returned framebuffer base address from the mailbox. Not sure what their GPU's sent back though...

I'm able to get about half way through the assembly example, but it all gets very confusing very fast :D

dwelch67
Posts: 962
Joined: Sat May 26, 2012 5:32 pm

Re: How To Use The Framebuffer?

Mon Aug 01, 2016 7:28 pm

There are multiple mmus (we assume). Dont mess with the ARM's mmu until you get this working. Do check the ARM to see that (data) caching is off, for some reason I want to say that it is on even though that doesnt make sense without setting up the mmu.

What mode are you running? booting up from zero in aarch64? pretending you are linux and booting aarch32 at address 0x8000 (svc mode)?

If you are doing the address zero thing with aarch64, make sure you corner the other cores so that you are not trying to do four of everything four requests, etc.

does this code work on a pi2? (maybe you answered that will have to re-read)

dwelch67
Posts: 962
Joined: Sat May 26, 2012 5:32 pm

Re: How To Use The Framebuffer?

Mon Aug 01, 2016 7:31 pm

again I need to read more, Ultibo, isnt the (arm) address space repeated in that 0xFABCD... and 0x3ABCD... would be pointing at the same thing but one address is using some higher level cache and one isnt?

jFoster
Posts: 57
Joined: Fri Jul 03, 2015 7:32 pm
Location: British Columbia, Canada
Contact: Website

Re: How To Use The Framebuffer?

Mon Aug 01, 2016 9:27 pm

Based on this issue and my last thread, I don't think I'll ever mess with the MMU!
What mode are you running? booting up from zero in aarch64?
I'm booting aarch64 mode loading from 0x0000, all four cores have their own separate loops etc. so it's only being done once.
does this code work on a pi2?
Will have to try it out, I have some aarch64 specific assembly code so that will have to change...
Do check the ARM to see that (data) caching is off
It should be off, I read bits from the sctlr register and looked through the datasheet to see if it was on. I'm not sure if it's what you mean, but the enable bit for data and unified caches (bit 2) was set to 0, so I don't think it was on. All the caches should be off.

AlfredJingle
Posts: 69
Joined: Thu Mar 03, 2016 10:43 pm

Re: How To Use The Framebuffer?

Tue Aug 02, 2016 12:23 am

Hi,

I have no experience with aarch64 but using aarch32 on a rpi3 I am able to write on the screen and I am now in the middle of writing windowing-primitives for my Forth-compiler.

The rpi in 32 bit screen-mode uses ARGB, so the highest 8 bits is the alpha channel, the following 8 bits the red channel etc. 0xffffff is full white, 0x00ff00 is full green etc. I haven't played with the alpha-channel yet.

I would in your case start with writing 0xffffff in the whole area where screen-memory could be expected. If you get a white screen that way, you know that the GPU is actually activated, if not than your mailbox-messaging is wrong. Maybe you could publish the relevant parts of your code. I know that I had quit a lot of problems with the actually writing and reading from the mailboxes, once that was working the GPU part was relativly easy. I have tested the effect of caching on writing to the screen, and the caches do exactly what you expect, once activated everything goes a lot faster...

Activating the MMU is not that difficult. Not activating it slows down the rpi by a factor of 20, or more. A rpi1 without its MMU activated is actually faster than a rpi3 without an activated MMU. Just food for thought... ;)
going from a 6502 on an Oric-1 to an ARMv8 is quite a big step...

jFoster
Posts: 57
Joined: Fri Jul 03, 2015 7:32 pm
Location: British Columbia, Canada
Contact: Website

Re: How To Use The Framebuffer?

Tue Aug 02, 2016 1:30 am

Here is the code I'm using. There are 3 separate files, mailbox.c, vc_tags.c and framebuffer.c:

Code: Select all

#ifndef mailbox_c
#define mailbox_c

static volatile unsigned int *MAILBOX0READ = (unsigned int *) 0x3f00b880;
static volatile unsigned int *MAILBOX0STATUS = (unsigned int *) 0x3f00b898;
static volatile unsigned int *MAILBOX0WRITE = (unsigned int *) 0x3f00b8a0;

#define MAILBOX_FULL 0x80000000
#define MAILBOX_EMPTY 0x40000000

unsigned int mailbox0_read(unsigned int channel) {
  unsigned int count = 0;
  unsigned int data;
	while (1) {
		while (*MAILBOX0STATUS & MAILBOX_EMPTY) {
			if (count++ > (1 << 25)) {
				return 0xffffffff;
			}
		}
		asm volatile("DMB ISHST");
		data = *MAILBOX0READ;
		asm volatile("DMB ISHST");
		if ((data & 15) == channel)
			return data & 0xfffffff0;
	}
	return 0;
}

void mailbox0_write(unsigned int channel, unsigned int data) {
	while (*MAILBOX0STATUS & MAILBOX_FULL);
	asm volatile("DMB ISHST");
	data &= 0xfffffff0;
	*MAILBOX0WRITE = (data | channel);
}

#endif

Code: Select all

#ifndef vc_tags_c
#define vc_tags_c

#include <stdarg.h>

#define VC_TAGS_BUFFER_SIZE 1024

struct vctags {
	unsigned int buffer[VC_TAGS_BUFFER_SIZE] __attribute__((aligned(16)));
	unsigned int ptr;
} vctags;

void vc_tagmanager_init(void) {
	vctags.buffer[0] = VC_TAGS_BUFFER_SIZE;	// total size (init to 3 bytes)
	vctags.buffer[1] = 0;					// request / response code
	vctags.buffer[2] = 0;					// end tag indicator
	vctags.ptr = 2;
	int i;
	for(i = vctags.ptr; i < VC_TAGS_BUFFER_SIZE; i++) vctags.buffer[i] = 0; // just zero out data
}

void vc_tagmanager_add(unsigned int tag, ...) {
	va_list args;
	va_start(args, tag);
	vctags.buffer[vctags.ptr++] = tag; // add tag to previous end tag indicator
    switch (tag) {
        case TAG_FIRMWARE_VERSION:
        case TAG_BOARD_MODEL:
        case TAG_BOARD_REVISION:
        case TAG_BOARD_MAC_ADDRESS:
        case TAG_BOARD_SERIAL:
        case TAG_ARM_MEMORY:
        case TAG_VC_MEMORY:
        case TAG_DMA_CHANNELS:
            vctags.buffer[vctags.ptr++] = 8;
            vctags.buffer[vctags.ptr++] = 0;
        	vctags.ptr += (8 >> 2);
            break;
        case TAG_CLOCKS:
        case TAG_COMMAND_LINE:
            vctags.buffer[vctags.ptr++] = 256;
            vctags.buffer[vctags.ptr++] = 0;
            vctags.ptr += (256 >> 2);
            break;
        case TAG_ALLOCATE_BUFFER:
            vctags.buffer[vctags.ptr++] = 8;
            vctags.buffer[vctags.ptr++] = 0;
            vctags.buffer[vctags.ptr++] = va_arg(args, int);
			vctags.buffer[vctags.ptr++] = 0x0;
            break;
		case TAG_GET_PHYSICAL_SIZE:
	    case TAG_GET_VIRTUAL_SIZE:
	    case TAG_GET_VIRTUAL_OFFSET:
			vctags.buffer[vctags.ptr++] = 8;
			vctags.buffer[vctags.ptr++] = 0;
			vctags.ptr += 2;
			break;
	    case TAG_SET_VIRTUAL_OFFSET:
		case TAG_SET_PHYSICAL_SIZE:
		case TAG_SET_VIRTUAL_SIZE:
		case TAG_TEST_VIRTUAL_SIZE:
	    case TAG_TEST_PHYSICAL_SIZE:
			vctags.buffer[vctags.ptr++] = 8;
			vctags.buffer[vctags.ptr++] = 0;
			vctags.buffer[vctags.ptr++] = va_arg(args, int);	// Width
			vctags.buffer[vctags.ptr++] = va_arg(args, int);	// Height
			break;
        case TAG_GET_ALPHA_MODE:
        case TAG_GET_DEPTH:
        case TAG_GET_PIXEL_ORDER:
        case TAG_PITCH:
			vctags.buffer[vctags.ptr++] = 4;
			vctags.buffer[vctags.ptr++] = 0;
			vctags.ptr += 1;
			break;
		case TAG_SET_ALPHA_MODE:
		case TAG_SET_DEPTH:
		case TAG_SET_PIXEL_ORDER:
            vctags.buffer[vctags.ptr++] = 4;
            vctags.buffer[vctags.ptr++] = 0;
			vctags.buffer[vctags.ptr++] = va_arg(args, int);
			break;
        case TAG_GET_OVERSCAN:
			vctags.buffer[vctags.ptr++] = 16;
			vctags.buffer[vctags.ptr++] = 0;
			vctags.ptr += 4;
			break;
        case TAG_SET_OVERSCAN:
			vctags.buffer[vctags.ptr++] = 16;
			vctags.buffer[vctags.ptr++] = 0;
            vctags.buffer[vctags.ptr++] = va_arg(args, int);	// Top pixels
            vctags.buffer[vctags.ptr++] = va_arg(args, int);	// Bottom pixels
            vctags.buffer[vctags.ptr++] = va_arg(args, int);	// Left pixels
            vctags.buffer[vctags.ptr++] = va_arg(args, int);	// Right pixels
            break;
        default:
            // Unsupported tag
            vctags.ptr--;
            break;
    }
    // update null bit at the end
    vctags.buffer[vctags.ptr] = 0;
	va_end(args);
}

unsigned long vc_tagmanager_get(unsigned int tag) {
	// return address of tag in buffer
	unsigned int i = 2;
	while(i < VC_TAGS_BUFFER_SIZE) {
		if(vctags.buffer[i] == 0) return 0; // not found
		if(vctags.buffer[i] == tag) {
			return (unsigned long)i;
		}
		i++;
		i += (vctags.buffer[i] >> 2) + 2;
	}
	return 0;
}

void vc_tagmanager_remove() {
	// remove the latest tag off the buffer
}

unsigned int vc_tagmanager_gettagsize(unsigned int tag) {
	unsigned int p = vc_tagmanager_get(tag);
	return (vctags.buffer[p + 1] >> 2) + 3;
}

#endif

Code: Select all

#ifndef framebuffer_c
#define framebuffer_c

#include "mailbox.c"
#include "vc_tags.c"
#include "memory.c"
#include "uart.c"

unsigned int framebuffer_base = 0;
unsigned int framebuffer_size = 0;
unsigned int framebuffer_pitch = 0;

void debug_tag(unsigned int tag) {
	unsigned int p = vc_tagmanager_get(tag);
	unsigned int s = vc_tagmanager_gettagsize(tag);
	int i;
	for(i = p; i <= p + s; i++) {
		uart_puthex(vctags.buffer[i]);
		uart_putc('\n');
	}
	uart_putc('\n');
}

void debug_entirebuffer() {
	unsigned int s = vctags.buffer[0] / 4;
	int i;
	for(i = 0; i < s; i++) {
		uart_puthex(vctags.buffer[i]);
		uart_putc('\n');
	}
	uart_putc('\n');
}

unsigned char framebuffer_init(int screen_width, int screen_height, int color_depth) {
	vc_tagmanager_init();
	vc_tagmanager_add(TAG_SET_PHYSICAL_SIZE, screen_width, screen_height);
	vc_tagmanager_add(TAG_SET_VIRTUAL_SIZE, screen_width, screen_height * 2);
	vc_tagmanager_add(TAG_SET_DEPTH, color_depth);
	vc_tagmanager_add(TAG_PITCH);
	vc_tagmanager_add(TAG_ALLOCATE_BUFFER, 16);
	mailbox0_write(8, (unsigned long)vctags.buffer | 0x40000000);
	unsigned int data = mailbox0_read(8) & 0x3fffffff; // convert back to ARM memory
	if(data != (unsigned long)vctags.buffer) return 1;
	return 0;
}

void framebuffer_allocate(unsigned int addr, unsigned int size, unsigned int pitch) {
	framebuffer_base = addr;
	framebuffer_size = size;
	framebuffer_pitch = pitch;
	int i;
	for(i = addr; i < size + addr; i++) put32(i, 0);
}

void framebuffer_write(unsigned int offset, unsigned int value) {
	if(offset >= framebuffer_size) return;
	put32(framebuffer_base + offset, value);
}

#endif
main code:

Code: Select all

#include <RaspberryPi.h>
#include <mailbox.c>
#include <vc_tags.c>
#include <framebuffer.c>
#include <uart.c>

int c0_main(void) {
	uart_init(115200);
	while(uart_recv() != 'V');

	uart_puts("SCTLR Register Contents: ");
	uart_puthex(debug_cache());
	uart_putc('\n');

	framebuffer_init(640, 480, 32);
	unsigned int b = vc_tagmanager_get(TAG_ALLOCATE_BUFFER);
	unsigned int p = vc_tagmanager_get(TAG_PITCH);
	framebuffer_allocate(vctags.buffer[b + 3], vctags.buffer[b + 4], vctags.buffer[p + 3]);

	uart_puts("\nFramebuffer Base: ");
	uart_puthex(framebuffer_base);
	uart_puts("\nFramebuffer Size: ");
	uart_puthex(framebuffer_size);

	int i;
	while(1) {
		for(i = 0; i < framebuffer_size; i++) {
			framebuffer_write(i, 0xFFFFFFFF);
		}
	}
}
Like I mentioned before there is no problem communicating to the GPU because 1) the screen turns black instead of the rainbow and 2) it prints the correct response bits back into vctags.buffer[]. Also I know that the vc_tags.c library works properly because I printed out the buffer over serial and it is formatted correctly.
Activating the MMU is not that difficult.
Off topic: Is it possible to initialize the MMU and not have to deal with the virtual memory space etc.? I mean have a 1 to 1 mapping with the physical memory? Would this defeat the purpose of the MMU? I haven't done any reading on the MMU so I don't know anything about it.

EDIT: I realized I was only writing 0xFF000000 to the framebuffer, but after changing it to 0xFFFFFFFF there was no change.

User avatar
Ultibo
Posts: 160
Joined: Wed Sep 30, 2015 10:29 am
Location: Australia
Contact: Website

Re: How To Use The Framebuffer?

Tue Aug 02, 2016 7:48 am

jFoster wrote:Here is the code I'm using. There are 3 separate files, mailbox.c, vc_tags.c and framebuffer.c:
The only thing I can see that doesn't look correct is in the framebuffer_init() function you OR the buffer address with 0x40000000 which I'm pretty sure has to be 0xC0000000 on a Pi2 or 3.

I'm not sure if it only makes a difference once the MMU is enabled but as far as I remember it doesn't work correctly using anything but 0xC0000000
jFoster wrote:Off topic: Is it possible to initialize the MMU and not have to deal with the virtual memory space etc.? I mean have a 1 to 1 mapping with the physical memory? Would this defeat the purpose of the MMU? I haven't done any reading on the MMU so I don't know anything about it.
Yes, you can enable the MMU with a 1 to 1 mapping and get all the benefit of caching (and permissions etc if you want them) without having to setup any virtual memory addressing.
Ultibo.org | Make something amazing
https://ultibo.org

Threads, multi-core, OpenGL, Camera, FAT, NTFS, TCP/IP, USB and more in 3MB with 2 second boot!

AlfredJingle
Posts: 69
Joined: Thu Mar 03, 2016 10:43 pm

Re: How To Use The Framebuffer?

Tue Aug 02, 2016 9:27 am

Boy do I hate C. But that as an aside. ;)

I see several things you could try:

1. You definitely have to 'or' your buffer data address with 0xc000000 (0x8000000 in fact also works) as ultibo already said, but not with 0x4000000

2. The GPU returns the frame buffer-size in bytes. In c0_main where you write to the frame buffer you write 32 bit words but you increment the index with 1. Might be that I misunderstand C (being a Forth-nerd) but I increment the index with 4.

3. Again in c0_main you write 0xFFFFFFFF, but white = 0x00FFFFFF. The highest 8 bits are alpha-channel bits and you would normally use 0x00 for them.

In addition I am not totally sure why you would have a virtual screen height of twice the height of the physical screen, but it explains the size reported back by the GPU.


MMU: you always create virtual memory with the MMU but you can have a simpel 1 to 1 mapping. In its ultra-simplest form it is in fact just 1 32bit entry at a 0x4000 aligned address (in case you only use the bottom 1 Mb of memory of your rpi3), but more normal the simplest form is a table with 4k 32 bit entries starting at a 0x4000 aligned address, where each entry describes a 1 Mb memory part. On the rpi3 only the bottom 1024 entries are relevant as it has 1 Gb memory.
going from a 6502 on an Oric-1 to an ARMv8 is quite a big step...

dwelch67
Posts: 962
Joined: Sat May 26, 2012 5:32 pm

Re: How To Use The Framebuffer?

Tue Aug 02, 2016 1:49 pm

The mmu allows you to isolate memory regions for various reasons like protection and caching as Ultibo mentioned. So for example, in general, if you want the data cache enabled to try to improve performance there, you dont want to be caching peripherals. You read the status of a peripheral through a cache, the second, third, nth time you read it if it is cached then you get the stale answer, the old status. If you want to have the real status from a peripheral every time you need to mark that peripherals address space as not cached. But where you have ram that you do want to cache you mark that address space as cached. Generally that can only be done with an mmu. MMUs, esp in an ARM design are part of the core and dont know what the system design is, they dont know where ram is or peripheral space, etc. We the programmers do and have to tell the MMU, through tables we setup. A one to one helps for bare metal that you can use the data cache but not lose your peripherals. When you add an operating system the mmu can be also used to implement protections to keep one task from going outside its memory space. Can also be used to combine fragments of memory together in one linear space for memory allocation, dont have to actually copy/move memory around when changing an allocation.

One/some of ARMs microcontroller cores have caching, data caching, but have taken the model of ram is below this line and peripherals above this line, so that they can hardcode the do not cache for you. I think that the cortex-m4 still has some mmu controls but I have not dug into that end of it. and I have some cortex-m7s but have not dug into the mmu on those. One could imagine though a system design where some things like this are known (and the mmu is possibly not required for data caching, so I say in general), for this ARM core in the pi, it is meant for running operating systems so you are managing the mmu anyway, no need for bare metal shortcuts in logic. I dont remember/think I dug into the mmu on the pi3 yet.

Each and every access when an mmu is enabled has to be looked up in the tables. There are forms of caching of table entries so the first random access the table in ram however slow that is (and it shouldnt be a cache enabled access since the mmu is doing the access and it would be a chicken and an egg thing if the mmu has to look at the tables in ram to find the tables in ram to find if they are in a cached space before looking at the tables in ram to find out if they can use the cache to read the tables in ram...), then save the answer for that lookup, if you do another lookup in that space right away then the mmu doesnt have to go to ram it uses a cached version of the answer inside the mmu. But you can understand that in general the mmu makes things slower as it is doing a lot of churn doing table lookups. Once you look at an mmu table you can also see sometimes there are multiple levels, the space broken up into larger chunks, then sometimes if you want finer control the first entry can instead of giving the answer (the physical address portion plus controls) can point at a second level, another access that it doesnt know it needs until the data comes back on the first one. Further slowing everything down. So in bare metal are you really getting a performance gain or not by using the mmu to gain access to the data cache? Depends on how linear vs random your data accesses are.

In this case, until you figure out what is going on beyond the ARM core boundary with the frame buffer I would not mess with the MMU. If you are messing with the mmu, stop for now, and then mess with it later. Perhaps the topic came up because messing with it could be why you are not able to access the framebuffer as you wanted.

Ultibo no doubt and some others here have likely been able to use the framebuffer on a pi3. Are you using a non-standard or strange-ish display, have you tried different displays/monitors? I dont know enough about it to know if they change their answer based on the request and display found, but if the answer from the GPU is different from the answer that these other folks have gotten and succeeded I would maybe try to understand that. Are you and are they using the latest-greatest GPU images on the sdcard?

jFoster
Posts: 57
Joined: Fri Jul 03, 2015 7:32 pm
Location: British Columbia, Canada
Contact: Website

Re: How To Use The Framebuffer?

Tue Aug 02, 2016 4:08 pm

Thank you for all the suggestions and explanations!

I changed this line in my framebuffer_init():
mailbox0_write(8, (unsigned long)vctags.buffer | 0xC0000000); // changed 0x40000000

I changed this line in main():
framebuffer_allocate(vctags.buffer[b + 3] & 0x3fffffff, vctags.buffer[b + 4], vctags.buffer[p + 3]); // added 0x3fffffff

I changed framebuffer_write() to 0x00FFFFFF.

I also changed my i++ to i += 4, in framebuffer_allocate() as well as main().

I changed my virtual screen size from 480 * 2 back to 480. For some reason I saw people doing it on other sites and I was trying to replicate their code as much as possible.

Now there is a single pixel (assuming (0, 0)) lit on the screen! I wrote a debug function for the framebuffer after writing 0x00ffffff to it:

Code: Select all

void debug_framebuffer() {
	unsigned int i;
	uart_puts("\nFramebuffer Contents:\n");
	for(i = framebuffer_base; i < framebuffer_base + framebuffer_size; i += 4) {
		uart_puthex(get32(i));
		uart_putc('\n');
	}
}
This gives me the number 0x0012C000 at zero on the framebuffer (the size of the framebuffer) but everything else after that is 0x00, which would explain why the screen is black except that one pixel.

Now to figure out why the writes aren't going through...
I read bits from the sctlr register and looked through the datasheet to see if it was on. I'm not sure if it's what you mean, but the enable bit for data and unified caches (bit 2) was set to 0, so I don't think it was on. All the caches should be off.
Is this the correct way to check for data caching?

Thanks for all the help so far,

Judd

jFoster
Posts: 57
Joined: Fri Jul 03, 2015 7:32 pm
Location: British Columbia, Canada
Contact: Website

Re: How To Use The Framebuffer?

Tue Aug 02, 2016 4:17 pm

Progress has been made, but at this point I'm sure I must be missing something glaringly obvious.

When I have this function it prints the single pixel as described before:

Code: Select all

void framebuffer_write(unsigned int offset, unsigned int value) {
	if(offset >= framebuffer_size || (framebuffer_base + offset) % 4 != 0) {
		return;
	}
	put32(framebuffer_base + offset, value);
}
But with this function it prints the white screen that I want:

Code: Select all

void framebuffer_write(unsigned int offset, unsigned int value) {
	if(offset >= framebuffer_size || (framebuffer_base + offset) % 4 != 0) {
		uart_puts("\nNot Possible.\n");
		return;
	}
	put32(framebuffer_base + offset, value);
}
EDIT: It was because int i in my main code was signed, not unsigned. Not sure why that would have made a difference though...

Return to “Bare metal, Assembly language”