« Reply #1675 on: 28 / March / 2013, 06:25:05 »
Hi guys,
This reply is going to be a long one, sorry for that.
It seems the forum didn't sent any mail notifications to me and I'm way behind this conversation.
So here we go...
Looks like I successfully locked vram. OLC can't change anything on screen after lock, but direct write to vram still works .
DEF(TakeVramSemaphore, 0xFF92E41C) //
DEF(GiveSemaphore__, 0xFF92E468) // goes in funclist.txt
#define VramInstance_address *(int*)0x5190
TakeVramSemaphore(VramInstance_address); // takes vram semaphore so other tasks have to wait for it to free before thay can write to vram
SleepTask(2000);
bmp_printf(50, 134, "test", COLOR_BLACK, COLOR_GRAY); //writes directly to vram
SleepTask(7000);
GiveSemaphore__(VramInstance_address); //releases the semaphore
Not exactly what I needed but it can be used for custom windows on OLC screen or maybe to hide menu screen when firmware goes into 400plus menu.
This is very good finding, I think this can be useful in many cases, though may be not what exactly we dreamed of
.
Thanks for sharing it.
Well, firmware waits for semaphore to free before it starts menu, so I guess it's no way to hide the menu screen.
I've expected that, by locking this semaphore, we are blocking some tasks (the one that want to Take it).
I think this can turn out to be dangerous (ErrXX or something) if we block for too long.
But on a second thought these ErrXX stuff only shows when the MPU cant do something or return error to main CPU.
I guess the main firmware is not locking up with ErrXX on it's own, it does only when MPU is in trouble. This is just a guess.
Very interesting, thanks for sharing.
I guess this could be used to make our own menus, writing directly to VRAM, no? And I should probably update our overlay code, and use that semaphore.
But, do you think this could be used to avoid flickering? Actually, we do not want to lock the OLC, we just want to know when somebody else writes to the display; perhaps we could "watch" that semaphore, or get informed each time it is released, so we can update our overlay afterwards. Just some thoughts...
Edu, It can be used for some stuff, but not for full display control. If we TAKE the semaphore we will block one or more canon TASKs.
I think blocking canon tasks for long time is not a good idea. On the other hand, only experiments can prove me right or wrong.
I guess we wont find an easy way to be informed of screen updates, at least not with this semaphore.
Watching the semaphore wont be efficient, since it's not atomic operation, so we may miss some changes. At least I do not know if we can watch it.
Busy-looping to watch the semaphore is out of question too.
If "everybody else" who writes to the main display uses this same semaphore (looks like they should, that is what semaphores are for, no?), and we could somehow intercept all calls to TakeVramSemaphore, then we would know when to refresh our overlay. Could the "cache hack" be used here?
I think you are right, everyone who wants to write to display should rely on this semaphore, though it could be only one task (GUI) and everyone else talk to this task. Quite possible, but not so reasonable... If this is the case, then why would it need a Semaphore ?
The approach with "cache hacks" sounds possible, I will try to find some time soon to implement them in 400Plus.
I see one major disadvantage to this, wrapping the real TakeVramSemaphore means to execute extra code (time) on every call to it.
And if I'm not mistaken the Semaphore routines are atomic. This is very important, since it guarantees that no race-condition can happen.
Yes, you're right, it will not help to stop flickering. I'm not familiar with semaphores but it looks like it is just a flag and some info, so you will have to check it all the time to know if something is using it. Would be nice to find a way to execute a function on semaphore access without checking it all the time.
Sergei, semaphores are just flags (similar to mutex'es in posix). The idea of these flags are to block you if someone is using the flag.
The idea of semaphore is to prevent race conditions.
Here is an example:
Basically you have 2 tasks and one variable which is used (read/write) in both tasks.
var x=0;
taks1() {
if (x) {
do_something();
} else {
do_other();
}
}
task2() {
while(1) {
x = !x; // invert x
}
}
now the problem comes when task1() is in this line:
if (x) {
lets say x == 1 in this case.
durring the check the x is 1, and task1() is going to do_something();
but before executing the call (Branch) to do_something(), the scheduler changes to task2() and task2() sets x to 0.
then in this case task1() is still going to call do_something() which is wrong already.
to prevent this you need atomic instructions
but i guess you already know the rest of the story...
Final notes:
I think this conversation should be pasted to the forum thread, so others can learn about it. And ML guys can join the conversation if they know more.