-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Add Sleep Mode
Kurausukun edited this page Dec 11, 2024
·
4 revisions
By devolov (though wouldn't have been possible without BSBob, SBird, and Kurausukun)
Goal: Allow a sleep function to be used to save battery when playing on a flashcart.
Warning: The sleep function won't work on mGBA and other emulators. It has been tested to work fine on an Everdrive, EZ Flash Omega DE, and EZ Flash IV.
#define KEY_AND_INTR 0x8000
#define DPAD_ANY ((DPAD_RIGHT | DPAD_LEFT | DPAD_UP | DPAD_DOWN))
#define JOY_EXCL_DPAD 0x030F
+#define SLEEP_KEYS ((L_BUTTON | R_BUTTON | SELECT_BUTTON))
+#define WAKE_KEYS ((SELECT_BUTTON | START_BUTTON))
+
// interrupt flags
#define INTR_FLAG_VBLANK (1 << 0)
#define INTR_FLAG_HBLANK (1 << 1)
static void ReadKeys(void)
{
u16 keyInput = REG_KEYINPUT ^ KEYS_MASK;
+
+ if (keyInput == SLEEP_KEYS)
+ {
+ vu16 IeBak, DispCntBak;
+ DispCntBak = REG_DISPCNT; // LCDC OFF
+ REG_DISPCNT = 1 << 7; // DISP_LCDC_OFF = 1 << 7
+ REG_KEYCNT= KEY_AND_INTR | KEY_INTR_ENABLE | WAKE_KEYS;
+ REG_IME = 0;
+ IeBak = REG_IE; // IE save
+ REG_IE = INTR_FLAG_KEYPAD; // Enable Key interrupt
+ REG_IME = 1;
+ asm("swi #3" : : : "r2", "r12", "memory"); // This is the Stop command;
+ REG_IME = 0;
+ REG_IE = IeBak; // IE return
+ REG_IME = 1;
+ REG_DISPCNT = DispCntBak; // LCDC ON
+ VBlankIntrWait();
+ while (keyInput) // Doesn't continue until the wake keys are let go
+ keyInput = REG_KEYINPUT ^ KEYS_MASK;
+ return;
+ }
+
gMain.newKeysRaw = keyInput & ~gMain.heldKeysRaw;
gMain.newKeysReleased = ~keyInput & gMain.heldKeysRaw;
gMain.newKeys = gMain.newKeysRaw;
gMain.newAndRepeatedKeys = gMain.newKeysRaw;
And that's it!
What you're doing is calling the BIOS Stop function (SWI 03) to put the GBA in low-power mode.
You're also setting the wake keys as a hardware interrupt to get the GBA out of Stop mode afterwards.