#113105 - MrD - Sat Dec 23, 2006 4:18 am
I've read some folks here get a bit riled up that a lot of homebrew doesn't handle the DS' hinge properly by dropping into a low power pause mode.
So, what do folks want the hinge to do, and how would you do it? (Don't just describe it: give code, otherwise I can't do much about it.)
_________________
Not active on this forum. For Lemmings DS help see its website.
#113109 - Firon - Sat Dec 23, 2006 5:03 am
There's some registers/bits that need to be set when going into the lid-closed suspend mode. I'm not exactly sure which ones, though.
http://nocash.emubase.de/gbatek.htm#dspowermanagement
#113131 - Lick - Sat Dec 23, 2006 1:42 pm
I'm going to describe it anyway:
1) Detect hinge status.
2) If closed and the following procedure hasn't been done already:
- a. Turn off the backlight of both screens.
- b. Power off the graphics hardware.
- c. Optional: Power off the LCDs (POWER_LCD = 0). This will turn off the speakers as well.
3) If open and the following procedure hasn't been done already:
- Do 2abc but now turn them on, instead of, off.
You're going to need the following functions: readPowerManagement() and writePowerManagment() and powerON() and powerOFF().
_________________
http://licklick.wordpress.com
#113154 - 0xtob - Sat Dec 23, 2006 7:52 pm
To save CPU power you might also want to send the CPUs to sleep using swiSleep, but I haven't figured out how that works yet. Does anyone here have an example how that is used? :-)
#113156 - Mighty Max - Sat Dec 23, 2006 8:01 pm
I think:
Turn off power to everything not used. Set up the interrupts that should awake the DS again. (i.e. keychange on the lid, a timer or card removal)
And then just call the swiSleep.
After the irq occured it should just continue to execute. And you can power up everything again.
_________________
GBAMP Multiboot
#113178 - HyperHacker - Sun Dec 24, 2006 2:39 am
Depends on the program, obviously in some cases you'll want the speakers to stay on, program to keep running, etc while others should just go into sleep mode. Turning off screens and lights is a given though.
_________________
I'm a PSP hacker now, but I still <3 DS.
#113229 - MrD - Sun Dec 24, 2006 8:21 pm
Eeesh... I'll pass. Thanks anyway though.
_________________
Not active on this forum. For Lemmings DS help see its website.
#113232 - OOPMan - Sun Dec 24, 2006 10:05 pm
We'd rather you didn't...
It's rather irritating when homebrew doesn't handle sleep mode properly...
If nothing else, learning how to do it hones your coding skills ;-)
_________________
"My boot, your face..." - Attributed to OOPMan, Emperor of Eroticon VI
You can find my NDS homebrew projects here...
#113248 - HyperHacker - Mon Dec 25, 2006 9:07 am
Were you looking specifically for code you could drop into your program? It sounded more like you just wanted to know what a program was expected to do.
_________________
I'm a PSP hacker now, but I still <3 DS.
#113264 - MrD - Mon Dec 25, 2006 3:50 pm
Quote: |
Were you looking specifically for code you could drop into your program? |
Sort of, yeah. :)
I probably should have said 'Don't just describe it: give working example code, otherwise I can't do much about it.'
The reason I'm not too enthusiastic about implementing sleep mode is that I assumed the code to do so would be entirely ARM9... Monkeying around with the ARM7 code probably isn't too good an idea until I'm certain I can get it to work together with what's already there.
_________________
Not active on this forum. For Lemmings DS help see its website.
#113267 - Mighty Max - Mon Dec 25, 2006 6:40 pm
The code example (tested in virtual16)
Arm9 Code:
Code: |
/* if lid 'key' */
if (keys & BIT(7)) {
/* hinge is closed */
/* set only key irq for waking up */
unsigned long oldIE = REG_IE ;
REG_IE = IRQ_KEYS ;
*(volatile unsigned short *)0x04000132 = BIT(14) | 255 ; /* any of the inner keys might irq */
/* power off everything not needed */
powerOFF(POWER_LCD) ;
/* set system into sleep */
sleep() ;
/* wait a bit until returning power */
while (REG_VCOUNT!=0) ;
while (REG_VCOUNT==0) ;
while (REG_VCOUNT!=0) ;
/* power on again */
powerON(POWER_LCD) ;
/* set up old irqs again */
REG_IE = oldIE ;
} ;
|
Arm9 assembler for sleep():
Code: |
.global sleep
sleep:
mcr p15,0,r0,c7,c0,4
mov r0,r0 // a nop instruction to prevent failures
BX lr
|
Arm7 code:
Code: |
if (keys & BIT(7)) {
/* set up keychange as powerup signal again */
REG_IE = IRQ_KEYS ;
*(volatile unsigned short *)0x04000132 = BIT(14) | 255 ; /* any of the inner keys might irq */
REG_IME = 1 ;
/* power off not needed things */
powerOFF(POWER_SOUND) ;
/* enter powersave */
swiSleep() ;
/* sleep is over, power up again */
powerON(POWER_SOUND) ;
/* ToDo: save old REG_IE and restore it here */
} ;
|
The code will turn off LCDs/Sound on closing the lid. And reenabling power when a 'inner' key is pressed.
Merry X-Mas
:edit:
The arm7 seems to be unreliable the way it is used, gotta read up there after tomorrow and correct it.
_________________
GBAMP Multiboot
#134688 - ThousandKnives - Sun Jul 15, 2007 9:34 pm
I know this is an old thread but I am having issues setting up "hinge sleeping". Mighty Max's code snippit was very helpful and I have integrated his code suggestions into my program, but I am confused on a few points:
-With regard to the Arm9 section, what is the necessity of the assembly code, and how does one insert such a function into C/C++ code? I tried using asm() but the compiler didn't like the ":" character. I took an x86 assembly course about 10 years ago but we never went over how to combine ASM with C.
-I have modified Mighty Max's Arm7 code for handling the sleep as follows, with these global (Arm7) variables in use:
Code: |
unsigned long oldIE = REG_IE;
bool lidClosed = false;
|
And with this code inserted at the end of the vCount handler.
Code: |
if(!lidClosed && !(but & BIT(0)))
{
oldIE = REG_IE;
REG_IE = IRQ_VCOUNT;
REG_IME = 1;
powerOFF(POWER_SOUND);
REG_SPICNT = BIT(11) | SPI_ENABLE | SPI_BAUD_1MHZ | SPI_DEVICE_POWER;
REG_SPIDATA = PM_CONTROL_REG;
REG_SPICNT &= ~BIT(11);//un-hold
//swiSleep();
lidClosed = true;
}
else if(lidClosed && (but & BIT(0)))
{
REG_IE = oldIE;
powerSET(POWER_SOUND);
REG_SPICNT = BIT(11) | SPI_ENABLE | SPI_BAUD_1MHZ | SPI_DEVICE_POWER;
REG_SPIDATA = PM_CONTROL_REG | PM_BACKLIGHT_TOP;
REG_SPICNT &= ~BIT(11);//un-hold
lidClosed = false;
}
|
Here is the Arm9 code in my main game loop:
Code: |
if(control->Check(KEY_X,CHECK_DOWN))
{
oldIE = REG_IE;
REG_IE = IRQ_KEYS;
powerOFF(POWER_LCD);
oldMode = GetMode();
SwitchMode(MODE_SLEEP);
}
else if(control->Check(KEY_X,CHECK_UP))
{
powerON(POWER_ALL_2D);
REG_IE = oldIE;
SwitchMode(oldMode);
}
|
This code works properly, shutting off the sound and screens when the X button is pressed (X button is for simplicity's sake while testing, rather than having to peep in while closing the lid). However, I have three issues with what I've done:
1. I have had to comment out "swiSleep()". This is because using swiSleep makes the DS go comatose - it doesn't wake up when the lid is re-opened. Why is this function necessary and how can it's effect be "undone" when the lid is opened? Or, more importantly, could using it actually be preventing some of my other code from working?
2. According to the Specifications I used to help me write the SPI code (http://nocash.emubase.de/gbatek.htm) I should use "WaitByLoop(3)" after accessing the SPI. What is WaitByLoop() and why is it neccarity, and more importantly why does this code function properly without?
3. When closing the lid there is a slight popping noise from the speakers, presumably from the sound being turned off. This doesn't happen on commerical games so I'm assuming something can be done about it?
#134778 - bob_fossil - Mon Jul 16, 2007 5:51 pm
To stop the sound popping try:
Code: |
// Turn the speaker down.
swiChangeSoundBias(0,0x400);
// Turn the speaker up.
swiChangeSoundBias(1,0x400);
|
I got swiSleep() to work by storing away REG_IE and then setting it to IRQ_LID. When you open the lid, the interrupt fires and swiSleep returns control. Then you just restore REG_IE to what it was before. This may not be the best way to do it but it works in my game.
#134786 - ThousandKnives - Mon Jul 16, 2007 7:58 pm
Thanks bob fossil. Your sound code stopped the popping noise right on!
As for the swiSleep problem, it actually seemed that it was a result of enabling REG_IME (somehow).
My code causes the LED light to go a bit dim but it doesn't blink. Anyone know how to get the light to blink?
Edit: I have added this code, but it isn't having any effect.
Code: |
REG_SPICNT = BIT(11) | SPI_ENABLE | SPI_BAUD_1MHZ | SPI_DEVICE_POWER;
REG_SPIDATA = PM_LED_SLEEP;
REG_SPICNT &= ~BIT(11);//un-hold
|
I also tried accomplishing the same thing by adding "| PM_LED_SLEEP" to the SPI statement that I use to turn off screen power, and that doesn't work either.
#134790 - Quirky - Mon Jul 16, 2007 9:10 pm
I thought that this was a bug in libnds and wrote this bug report. Code: |
writePowerManagement(PM_CONTROL_REG, PM_LED_CONTROL(1)); |
produces suitable blinking.
#134794 - bob_fossil - Mon Jul 16, 2007 9:47 pm
Quirky wrote: |
I thought that this was a bug in libnds and wrote this bug report. Code: | writePowerManagement(PM_CONTROL_REG, PM_LED_CONTROL(1)); | produces suitable blinking. |
Cheers for that Quirky! I've got my LED blinking away now. Here's the code I've ended up with if anyone's interested. It lives in the arm7 inside the VcountHandler function.
Code: |
but = REG_KEYXY;
// Check if the lid has been closed.
if(but & BIT(7))
{
// Save the current interrupt sate.
u32 ie_save = REG_IE;
// Turn the speaker down.
swiChangeSoundBias(0,0x400);
// Save current power state.
int power = readPowerManagement(PM_CONTROL_REG);
// Set sleep LED.
writePowerManagement(PM_CONTROL_REG, PM_LED_CONTROL(1));
// Register for the lid interrupt.
REG_IE = IRQ_LID;
// Power down till we get our interrupt.
swiSleep(); //waits for PM (lid open) interrupt
REG_IF = ~0;
// Restore the interrupt state.
REG_IE = ie_save;
// Restore power state.
writePowerManagement(PM_CONTROL_REG, power);
// Turn the speaker up.
swiChangeSoundBias(1,0x400);
}
//
|
Seems to do the trick for me. :)
#134795 - ThousandKnives - Mon Jul 16, 2007 10:04 pm
Thanks for the heads up Quirky. I hadn't noticed the writePowerManagement function before. Your bug report is very helpful as well. My blinking light now works- I used essentially the same method as bob_fossil.
I'm wondering if this code makes use of powerOFF/ON(POWER_SOUND) redundant? There is a sound power bit in the Power Management SPI, is that the same thing?
#136773 - yellowstar - Sat Aug 04, 2007 9:03 pm
I know this is an old topic,
but anyway:
I can't get the assembler code for sleep
to compile.
Here's the compile error:
"C:/DOCUME~1/Owner/LOCALS~1/Temp/ccYTxbeM.s(76): Error: selected processor does not support `mcr p15,0,r0,c7,c0,4'"
I tried using an s file for this,
but that won't work either.
It says it can't find the sleep function,
or something like that.
By the way,
there is a function called sleep
in the unistd header file.
It dosen't do the same thing though.
So you get an error when you include it.
In my app I renamed it to Sleep.
Here's the code I am using for the sleep function:
Code: |
__asm("mcr p15,0,r0,c7,c0,4");
__asm("mov r0, r0");
__asm("BX lr");
|
#138810 - melw - Wed Aug 29, 2007 9:18 am
I also stubled upon this topic while looking for lid sleep functionality.
yellowstar wrote: |
I can't get the assembler code for sleep
to compile.
Here's the compile error:
"C:/DOCUME~1/Owner/LOCALS~1/Temp/ccYTxbeM.s(76): Error: selected processor does not support `mcr p15,0,r0,c7,c0,4'" |
The compiler doesn't know you're trying to compile for ARM processor - try using -march=armv5te and/or -marm in your makefile as a compiler parameter.
Here's slightly modified source code for lid sleep. It's working with the latest libnds (CVS 280807) and is based on what Mighty Max, Bob Fossil and Quirky already wrote:
ARM7 VcountHandler:
Code: |
// Check if the lid has been closed.
if(keys & BIT(7)) {
// Save the current interrupt sate.
u32 ie_save = REG_IE;
// Turn the speaker down.
swiChangeSoundBias(0,0x400);
// Save current power state.
int power = readPowerManagement(PM_CONTROL_REG);
// Set sleep LED.
writePowerManagement(PM_CONTROL_REG, PM_LED_CONTROL(1));
// Register for the lid interrupt.
REG_IE = IRQ_LID;
// Power down till we get our interrupt.
swiSleep(); //waits for PM (lid open) interrupt
REG_IF = ~0;
// Restore the interrupt state.
REG_IE = ie_save;
// Restore power state.
writePowerManagement(PM_CONTROL_REG, power);
// Turn the speaker up.
swiChangeSoundBias(1,0x400);
}
|
ARM9:
Code: |
void lidSleep()
{
__asm("mcr p15,0,r0,c7,c0,4");
__asm("mov r0, r0");
__asm("BX lr");
}
// when reading keys
if (keys & KEY_LID) {
/* hinge is closed */
/* set only key irq for waking up */
unsigned long oldIE = REG_IE;
REG_IE = IRQ_KEYS;
*(volatile unsigned short *)0x04000132 = BIT(14) | 255; /* any of the inner keys might irq */
/* power off everything not needed */
powerOFF(POWER_LCD);
/* set system into sleep */
lidSleep();
/* wait a bit until returning power */
while (REG_VCOUNT!=0);
while (REG_VCOUNT==0);
while (REG_VCOUNT!=0);
/* power on again */
powerON(POWER_LCD);
/* set up old irqs again */
REG_IE = oldIE;
};
|
#138843 - Quirky - Wed Aug 29, 2007 7:15 pm
You really don't need asm in there. You can use the libnds call swiIntrWait(1, IRQ_VBLANK);
The idea is this: on the arm7, you turn off the all interrupts when the lid goes down. On the arm9 you set an interrupt for when the next vblank hits. Since the all IRQ are turned off by the arm7, this won't fire ever. But! the arm7 also set an interrupt handler for the lid opening again. Now everything is off. The arm9 waiting for a vblank, the arm7 waiting for the lid to open. Once the lid-open interrupt fires, you switch the vblank irq back on in the arm7, which causes the swiIntrWait for vblank to fire on the arm9 and you are back in business, both processors up and running.
#138852 - Cydrak - Wed Aug 29, 2007 9:04 pm
Err, I'm pretty sure IME, IE, IF are unique to each core, so you couldn't go and halt the ARM9 that way. The reason it would seem to work is that swiSleep() stops _both_ ARMs, and indeed most of the IRQ sources. If you replace swiIntrWait() with a busy loop, you should find (at least I do) that the '9 won't finish counting til the '7 wakes up.
Therefore, I would really recommend having one core initiate the process, not blindly checking keys on both sides! Otherwise, you'd have a lovely race condition, and the '9 might not finish powering down on its end. Especially if it was busy elsewhere. You probably don't want to sleep during a FAT call, for example... ^_^; Other apps (like music players, alarms...) will also need control over when and when not to sleep.
Personally I use swiWaitForIRQ(). It does exactly the same as the ASM above. I send a sleep message over FIFO, and a reply supplies the needed interrupt. I would also make sure graphics, lcd, sound and mic amps, and wifi are all shut down, some of these definitely stay active. (Heh... red sleep LEDs are amusing. At home. :P)
#138871 - laos - Thu Aug 30, 2007 1:53 am
a lot of my homebrew uses the sleep mode support, ironically, my alarm clock for DS sleeps when closed xD
_________________
laos,
In charge of Storyline: Tales of Dagur 2
#138918 - Quirky - Thu Aug 30, 2007 7:11 pm
Cydrak wrote: |
Err, I'm pretty sure IME, IE, IF are unique to each core, so you couldn't go and halt the ARM9 that way. The reason it would seem to work is that swiSleep() stops _both_ ARMs, and indeed most of the IRQ sources. If you replace swiIntrWait() with a busy loop, you should find (at least I do) that the '9 won't finish counting til the '7 wakes up. |
That does make sense, but empirically I've seen that the powerOFF(POWER_LCD); on the arm9 definitely works if you use ideas similar to the code posted above. I'm not sure how you would go about checking that a busy loop was actually paused while the arm7 was stopped either.
Quote: |
Personally I use swiWaitForIRQ(). It does exactly the same as the ASM above. I send a sleep message over FIFO, and a reply supplies the needed interrupt. I would also make sure graphics, lcd, sound and mic amps, and wifi are all shut down, some of these definitely stay active. (Heh... red sleep LEDs are amusing. At home. :P) |
That is certainly more sophisticated. What would be the psuedo code for that? swiWaitForIRQ reacts to any interrupt, so I imagine it would be:
Arm9 turns off all its interrupts. turns on FIFO_NOT_EMPTY.
Arm9 -> arm7 send a message "the lid is down, go to sleep"
arm7 -> arm9 shuts itself (arm7) down, sets up for awaking on ??? then sends a return message.
Arm9 again: the fifo not empty is triggered, if it is the correct FIFO message, then power down and wait for the lid open interrupt.
That just leaves the reverse steps for waking up.
#138940 - Cydrak - Fri Aug 31, 2007 1:16 am
I tried removing the powerOFF too, and the LCD goes dark on sleep, then flashes white on waking anyway. So either it's unnecessary in the first place, or swiSleep() kills something important besides REG_POWERCNT. I think it's the latter--if I go rapidly in and out of sleep I see pixel garbage (in place of white) when I didn't powerOFF myself.
The loop runs long enough to count and watch:
Code: |
DisableIrqs();
SendArm7ToSleep();
for(volatile int i = 0; i < 20000000; i++)
/* spin for about 3 sec */; |
So let's say you close the lid for 10, 15, 20 seconds... If the ARM9 continued running there would be no pause when you opened it back up--the loop would have finished. But that's not what happens. It pauses for roughly 3 sec *after* I open the lid.
I'm not sure what you mean about the ARM9 powering down or the lid interrupt, according to GBAtek only the ARM7 has that. It helps to have a good messaging system, then it's only a few lines:
Code: |
void Sleep9(int irqWakeMask) {
IRQGuard gu(IRQ_FIFO_NOT_EMPTY);
// Also DisableWifi() / EnableWifi() / AutoConnect() if desired..
powerOFF(POWER_ALL);
// Call Sleep7 on the other core
FIFO::Send(PM_SLEEP, 0, irqWakeMask);
// Soon the '7 will get the message and go to sleep;
// wait for the message it will send after it wakes up.
while(!WakeReceived())
swiWaitForIRQ();
powerON(POWER_ALL);
}
void Sleep7(int irqWakeMask) {
u32 prevLed = Power::Led(PM_LED_SLEEP);
swiChangeSoundBias(0, 0x200);
powerOFF(POWER_SOUND);
{
IRQGuard gu(irqWakeMask);
swiSleep();
}
powerON(POWER_SOUND);
swiChangeSoundBias(1, 0x200);
Power::Led(prevLed);
// Wake up the ARM9
FIFO::Send(PM_WAKE);
} |
My setup allows for replies, so I could actually have made PM_SLEEP a blocking call and done away with the wait on PM_WAKE--then FIFO::Send() would swiIntrWait() on the FIFO instead.
(I didn't do that... Sleep7() was deferred to the main loop, for a couple reasons. One was that my FIFO calls were meant to be either async, or else short and sweet. Also, libnds had a nesting issue that has since been fixed.)
#139018 - Quirky - Fri Aug 31, 2007 7:42 pm
Some excellent ideas there, thanks.
Cydrak wrote: |
I'm not sure what you mean about the ARM9 powering down or the lid interrupt, according to GBAtek only the ARM7 has that. |
By power down, I meant what it can, i.e. the screen. Got in a muddle over the lid irq, not sure what I meant either!
#139076 - yellowstar - Sat Sep 01, 2007 5:20 pm
I finally got it to compile!
Once I put the following code before the asm,
it worked!(The compiling part)
I tried to use a s file,
but it still won't work.
I tried putting in the following code in the ARM9 main code,
But it still won't detect the Sleep function.
I get a error similar to this: "Undefined reference to Sleep"
Code: |
extern void Sleep();
|
Here's the asm I am using for the s file:(its name is sleep.s, in the ARM9
source directory)
Code: |
.arm
.global Sleep
Sleep:
mcr p15,0,r0,c7,c0,4
mov r0, r0
BX lr
|
I am not using this s file.
Right now, if I tried to use the s file,
it wouldn't compile.
But now it won't work.(When I try to run it, and use Sleep mode.)
When I close the lid to send it into sleep mode,
it works correctly.
But, when I open the lid to make it leave sleep mode,
it won't leave sleep mode.
The ARM7 enters and leaves sleep mode correctly.
But, the ARM9, once in sleep mode,
won't leave sleep mode.
So the ARM9 is stuck in sleep mode,
once it enters sleep mode.
I also have this function call in the ARM7, before the while loop.
See the comment for why I have it there.
Code: |
writePowerManagement(PM_CONTROL_REG, PM_LED_CONTROL(0));//My DSX has the LED blinking when it turns on.
//This is so that it stops blinking.
|
It does what it is supposed to do.
But, it also turns off both screens.
In the ARM9, I tried this code,
but that didn't fix it.
I have this code before the while loop.
Code: |
swiWaitForVBlank();
powerON(POWER_LCD);
|
Unlike the original code,
I am using IPC, via shared memory,
instead of checking the keys on both processors.
This works fine,
so this isn't the problem.
Here's the code I am using:
IPC.h
Code: |
#define CommandControl ((commandControl*)((uint32)(IPC) + sizeof(TransferRegion)))
struct commandControl
{
bool processed;
bool do_sleep;
};
#ifdef ARM9
void IPCInit()
{
CommandControl->processed = 1;//So the ARM7 dosen't think it's time to sleep.
CommandControl->do_sleep = 0;
}
void ARM7Sleep()
{
CommandControl->processed = 0;
CommandControl->do_sleep = 1;
}
#endif
|
ARM9
Code: |
#include "../../IPC.h"
extern "C" void Sleep();
/*
void Sleep()
{
__asm(".arm");
__asm("mcr p15,0,r0,c7,c0,4");
__asm("mov r0, r0");
__asm("BX lr");
}*/
void CheckSleep()
{
if (keysDown() & KEY_LID)
{
/* hinge is closed */
/* set only key irq for waking up */
unsigned long oldIE = REG_IE;
REG_IE = IRQ_LID;
*(volatile unsigned short *)0x04000132 = BIT(14) | 255; /* any of the inner keys might irq */
/* power off everything not needed */
powerOFF(POWER_LCD);
//Tell ARM7 to sleep
ARM7Sleep();
/* set system into sleep */
Sleep();
/* wait a bit until returning power */
while (REG_VCOUNT!=0);
while (REG_VCOUNT==0);
while (REG_VCOUNT!=0);
/* power on again */
powerON(POWER_LCD);
/* set up old irqs again */
REG_IE = oldIE;
}
}
..
while(1)
{
scanKeys();
CheckSleep();
}
|
ARM7
Code: |
void CheckSleep()
{
// Check if the lid has been closed.
if(CommandControl->processed == 0 && CommandControl->do_sleep==1) {
CommandControl->processed = 1;
CommandControl->do_sleep = 0;
// Save the current interrupt sate.
u32 ie_save = REG_IE;
// Turn the speaker down.
swiChangeSoundBias(0,0x400);
// Save current power state.
int power = readPowerManagement(PM_CONTROL_REG);
// Set sleep LED.
writePowerManagement(PM_CONTROL_REG, PM_LED_CONTROL(1));
// Register for the lid interrupt.
REG_IE = IRQ_LID;
// Power down till we get our interrupt.
swiSleep(); //waits for PM (lid open) interrupt
REG_IF = ~0;
// Restore the interrupt state.
REG_IE = ie_save;
// Restore power state.
writePowerManagement(PM_CONTROL_REG, power);
// Turn the speaker up.
swiChangeSoundBias(1,0x400);
}
}
void VBlankHandler(){
..
CheckSleep();
}
|
Last edited by yellowstar on Sun Sep 02, 2007 8:54 pm; edited 1 time in total
#139091 - Cydrak - Sat Sep 01, 2007 9:52 pm
I don't know enough about the toolchain to see why the *.s is failing... it looks alright to me. Perhaps specify the section, e.g. ".text"? Does it get picked up by the makefile?
Are you compiling C++? Might need to say extern "C" ... instead, C++ function naming uses a different scheme.
As for PM_CONTROL_REG, read <nds/arm7/serial.h> and GBAtek: DS Power Management (specifically the SPI device); that register controls more than just the LED...
The ARM9 probably isn't waking up, as you have it waiting on IRQ_KEYS which has nothing to do with the lid. That only works for the 10 GBA buttons in REG_KEYINPUT. You need use another method from the ARM7 side, like the FIFO or IPC interrupt.
#139149 - yellowstar - Sun Sep 02, 2007 8:52 pm
Cydrak wrote: |
I don't know enough about the toolchain to see why the *.s is failing... it looks alright to me. Perhaps specify the section, e.g. ".text"? Does it get picked up by the makefile?
|
That didn't do anything.(It still won't work.)
Cydrak wrote: |
Are you compiling C++? Might need to say extern "C" ... instead, C++ function naming uses a different scheme.
|
Yes, I am using C++.
I tried that, and it worked!
Cydrak wrote: |
The ARM9 probably isn't waking up, as you have it waiting on IRQ_KEYS which has nothing to do with the lid. That only works for the 10 GBA buttons in REG_KEYINPUT. You need use another method from the ARM7 side, like the FIFO or IPC interrupt. |
That's how the above posted code,(above my first post)
was.
I tried fixing it on the ARM9, by switching it to IRQ_LID,
but it still won't work.
#146349 - yellowstar - Mon Dec 03, 2007 1:28 am
I solved it!
Once I changed the IRQ
the arm9 waits on,
to IRQ_VBLANK, it worked!
But, I'm having problems with noise
when the lid is opened/closed.
When the lid is closed,
it makes a little noise.(I'd perfer no noise,
as for opening)
(But, opening on official games
have some noise on opening,
so I guess I'll go with that amount of noise.)
When opened it makes alot more noise.
I'm enabling/disabling sound
when entering/leaving sleep mode.
#146352 - ThousandKnives - Mon Dec 03, 2007 1:44 am
yellowstar wrote: |
But, I'm having problems with noise
when the lid is opened/closed.
When the lid is closed,
it makes a little noise.(I'd perfer no noise,
as for opening)
(But, opening on official games
have some noise on opening,
so I guess I'll go with that amount of noise.)
When opened it makes alot more noise.
I'm enabling/disabling sound
when entering/leaving sleep mode. |
This behavior was already discussed in this very thread. Here is the relevant post:
bob_fossil wrote: |
To stop the sound popping try:
Code: |
// Turn the speaker down.
swiChangeSoundBias(0,0x400);
// Turn the speaker up.
swiChangeSoundBias(1,0x400);
|
|
#146355 - yellowstar - Mon Dec 03, 2007 2:05 am
My code has that sound bias code.
#150405 - nipil - Sun Feb 03, 2008 10:17 pm
Once again, this thread is taken out of the graveyard.
Sorry about this, i'm just doing something that actually
works, but i don't get why...
Arm7 code from this post which is ok as far as arm7 is concerned : basically IRQ_LID & swiSleep.
First question is : what is this "REG_IF = ~0;" used for, on return the sleep ?!
As i get it, it's forcing all the IRQ flags, to simulate everything happened (on the Arm7 only afaik), but why ?
Arm9 code i use :
Code: |
if (keysDown() & KEY_LID) {
unsigned long oldIE = REG_IE ;
REG_IE = IRQ_VBLANK ;
powerOFF(POWER_LCD) ;
swiIntrWait(1, IRQ_VBLANK);
powerON(POWER_LCD) ;
REG_IE = oldIE ;
} ; |
This last piece was tested on my DS and it "Just works (TM)"
(screens turn off when closes, and back on when open)
But i don't understand why this Arm9 part works !
My first assumption:
- Arm9's interrupts are reduced to VBLANK.
- The screens are turned off
- As such, there should be no vblank happening
- .... Should never wake up ?
=> "Problem" is : it does wake up when i open !
My second assumption:
- Arm9's interrupts are reduced to VBLANK.
- The screens are turned off
- There still are VBLANK interrupts coming
- Arm9 it's directly woken up
- On the next loop, the keysDown() doesn't hold KEY_LID
- As a consequence, it shouldn't be put to sleep again
=> "Problem" is : it stays asleep !
Please, could somebody explain me what makes it working ?
I don't like when i don't understand something, don't let me down :-)
_________________
NDS Lite Gold/Silver, MK5/R4DS, MSI PC54G2, D-Link DI-624
#150417 - Jim e - Mon Feb 04, 2008 12:51 am
nipil wrote: |
First question is : what is this "REG_IF = ~0;" used for, on return the sleep ?! |
If I remember correctly, it acknowledges all pending interrupts. Considering its only allowing 1 interrupt, its not necessary but it doesn't harm anything.
nipil wrote: |
Arm9 code i use :
Code: | if (keysDown() & KEY_LID) {
unsigned long oldIE = REG_IE ;
REG_IE = IRQ_VBLANK ;
powerOFF(POWER_LCD) ;
swiIntrWait(1, IRQ_VBLANK);
powerON(POWER_LCD) ;
REG_IE = oldIE ;
} ; |
This last piece was tested on my DS and it "Just works (TM)"
(screens turn off when closes, and back on when open)
But i don't understand why this Arm9 part works !
My first assumption:
- Arm9's interrupts are reduced to VBLANK.
- The screens are turned off
- As such, there should be no vblank happening
- .... Should never wake up ?
=> "Problem" is : it does wake up when i open !
My second assumption:
- Arm9's interrupts are reduced to VBLANK.
- The screens are turned off
- There still are VBLANK interrupts coming
- Arm9 it's directly woken up
- On the next loop, the keysDown() doesn't hold KEY_LID
- As a consequence, it shouldn't be put to sleep again
=> "Problem" is : it stays asleep !
Please, could somebody explain me what makes it working ?
I don't like when i don't understand something, don't let me down :-) |
If your using the arm7 code, that should be enough. So using the arm9 with it has little effect.
#150420 - yellowstar - Mon Feb 04, 2008 4:08 am
nipil wrote: |
Arm9 code i use :
Code: | if (keysDown() & KEY_LID) {
unsigned long oldIE = REG_IE ;
REG_IE = IRQ_VBLANK ;
powerOFF(POWER_LCD) ;
swiIntrWait(1, IRQ_VBLANK);
powerON(POWER_LCD) ;
REG_IE = oldIE ;
} ; |
This last piece was tested on my DS and it "Just works (TM)"
(screens turn off when closes, and back on when open)
But i don't understand why this Arm9 part works !
My first assumption:
- Arm9's interrupts are reduced to VBLANK.
- The screens are turned off
- As such, there should be no vblank happening
- .... Should never wake up ?
=> "Problem" is : it does wake up when i open !
My second assumption:
- Arm9's interrupts are reduced to VBLANK.
- The screens are turned off
- There still are VBLANK interrupts coming
- Arm9 it's directly woken up
- On the next loop, the keysDown() doesn't hold KEY_LID
- As a consequence, it shouldn't be put to sleep again
=> "Problem" is : it stays asleep !
Please, could somebody explain me what makes it working ?
I don't like when i don't understand something, don't let me down :-) |
Here's how it works:
You put the DS to sleep. Arm9 tells Arm7, and the Arm9 puts itself to sleep, with vblank being the trigger to wake up. Arm7 gets the Arm9's message, sets itself to wake up when the lid
is opened, and puts itself to sleep. When that happens, the Arm7 wakes up.
VBlanks always happen, as long as at least one of the processors are awake. So, in this case, as soon as a VBlank is fired on the Arm7, the same VBlank interrupt happens on the Arm9, waking it up.
I don't know about the second thing...
#150425 - nipil - Mon Feb 04, 2008 8:39 am
yellowstar wrote: |
VBlanks always happen, as long as at least one of the processors are awake... as soon as a VBlank is fired on the Arm7, the same VBlank interrupt happens on the Arm9, waking it up |
So that's the part i didn't understand, thank you for explaining it ;)
_________________
NDS Lite Gold/Silver, MK5/R4DS, MSI PC54G2, D-Link DI-624
#150523 - Cydrak - Wed Feb 06, 2008 3:02 am
I'd leave REG_IF alone--libnds handles it automatically. If I understand right, setting it here will cause IRQs active between the two REG_IE lines to get lost. So I'm not sure why that is there... as soon as the DS wakes up, libnds should see and acknowledge IRQ_LID, anyway. Even without a handler.
The ARM9 code is not, IMHO, doing anything to make it work!
As soon as you call swiSleep() on the '7 side, practically the entire system goes into suspended animation. Sound, video (including vcount/vblanks iirc), timers, and the ARM9--amongst other things--are paused. When a suitable IRQ (such as lid, keys, clock...) wakes the ARM7, the ARM9 comes with it.
swiSleep() also shuts off the backlights, no matter what you do. I don't know about the LCDs, since on my DSLite, I can't see them afterwards.
That's why it "just works", far as I can tell: The ARM9 seems to have no choice in the matter. You might want to watch out if you're doing things like file I/O.