#132980 - HyperHacker - Mon Jul 02, 2007 10:49 am
I'm noticing this code that used to work with older versions of DKP/libNDS no longer works anymore. If touchReadTemperature() has been called then touchReadXY() will never return and will sometimes turn the sound off. (IPC2->TEST stays at 7.) I tried disabling RTC stuff but the only way I found to make it not hang was to not call touchReadTemperature(). ARM9 is still running.
Here's the ARM7 code, yeah it kinda sucks, it's fairly old and needs cleaning/updating. The relevant parts are in Interrupt(). (Feel free to point out any other bugs too. :-p)
I suspect touchReadTemperature() is leaving the hardware or some internal variable in a state that touchReadXY() doesn't account for.
_________________
I'm a PSP hacker now, but I still <3 DS.
Last edited by HyperHacker on Mon Jul 02, 2007 11:06 pm; edited 1 time in total
Here's the ARM7 code, yeah it kinda sucks, it's fairly old and needs cleaning/updating. The relevant parts are in Interrupt(). (Feel free to point out any other bugs too. :-p)
Code: |
#include "main.h"
/* Entry Point CPU: ARM7 Inputs: -argc: Number of arguments -argv: Pointer to arguments Returns: Program return code */ int main(int argc, char** argv) { s32 i; //Message handling u32 RawData; A7_MESSAGE Message; u8 NumParams; u32 Param[4]; REG_IME = 0; //Blank out IPC IPC2->Time_Month = 12; MEMZERO((u8*)IPC, sizeof(TransferRegion)); MEMZERO((u8*)IPC2, sizeof(CustomIPCData)); //Init interrupts IRQ_HANDLER = Interrupt; //Set handler callback REG_IE = IRQ_VBLANK | IRQ_TIMER3 | IRQ_WIFI; REG_IF = ~0; REG_DISPSTAT = DISP_VBLANK_IRQ; REG_IME = 1; //Enable interrupts //Init IPC REG_IPC_SYNC = IPC_SYNC_IRQ_ENABLE; //Enable IRQs from ARM9 REG_IPC_FIFO_CR = IPC_FIFO_SEND_IRQ | IPC_FIFO_ENABLE; //Enable FIFO and interrupt on send FIFO empty/receive FIFO not empty //Init clock //Copied from a GBADev post. Todo: clean this up. REG_RCNT = 0x8100; //irqSet(IRQ_NETWORK, testSync); // Reset the clock if needed rtcReset(); rtcGetTimeAndDate((uint8 *)&(IPC2->Time_Year)); uint8 command[4]; command[0] = READ_STATUS_REG2; rtcTransaction(command, 1, &command[1], 1); command[0] = WRITE_STATUS_REG2; command[1] = 0x41; rtcTransaction(command, 2, 0, 0); command[0] = WRITE_INT_REG1; command[1] = 0x01; rtcTransaction(command, 2, 0, 0); command[0] = WRITE_INT_REG2; command[1] = 0x00; command[2] = 0x21; command[3] = 0x35; rtcTransaction(command, 4, 0, 0); SOUND_CR = SOUND_VOL(127) | SOUND_ENABLE; swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); if(((*(uint8*)0x027FFCE4) & 8) != 0) IPC2->SysInfo |= SI_GBAONBOTTOM; //See if this is a DS Lite if(readPowerManagement(4) & PM_NDSLITE_ISLITE) IPC2->SysInfo |= SI_DSLITE; //Turn off wifi in case a loader left it on Wifi_Deinit(); //Init timers TIMER3_DATA = 65535 - 34318; //should be one interrupt every ~1ms TIMER3_CR = TIMER_ENABLE | TIMER_IRQ_REQ; SendA9Message(A9_INIT, 0, 0, 0, 0, 0); REG_SPICNT = SPI_ENABLE | SPI_DEVICE_POWER | SPI_BAUD_1MHz | SPI_CONTINUOUS; REG_SPIDATA = 0; //Offset: 0=power management, 1=battery status, 2=amplifier, 3=microphone SerialWaitBusy(); REG_SPICNT = SPI_ENABLE | SPI_DEVICE_POWER | SPI_BAUD_1MHz; REG_SPIDATA = PM_BACKLIGHT_TOP | PM_BACKLIGHT_BOTTOM | PM_SOUND_PWR; //SCHANNEL_TIMER(8) = SOUND_FREQ(2600*8); //SCHANNEL_CR(8) = SOUND_VOL(32) | SOUND_PAN(64) | SCHANNEL_WAVEDUTY(3) | SOUND_FORMAT_PSG | SCHANNEL_ENABLE; //u16 n = 0; while(true) { //Check for messages while(!(REG_IPC_FIFO_CR & IPC_FIFO_RECV_EMPTY)) { RawData = REG_IPC_FIFO_RX; Message = (A7_MESSAGE)(RawData >> 24); NumParams = (RawData >> 16) & 0xFF; if(NumParams > 4) NumParams = 4; for(i=0; i<NumParams; i++) { if(REG_IPC_FIFO_CR & IPC_FIFO_RECV_EMPTY) break; Param[i] = REG_IPC_FIFO_RX; } DoA7Message(Message, i, Param[0], Param[1], Param[2], Param[3], true); IPC2->A7MessageCount++; } swiWaitForVBlank(); } return 0; } /* Processes messages from ARM9. This is a separate function so that ARM7 routines can also perform these tasks without being signalled. CPU: ARM7 Inputs: -Message: Message ID. -NumParams: Number of valid parameters. -Param1..Param4: Message parameters, if any. -FromA9: True if message sent from ARM9, false if called from an ARM7 routine. Used to determine whether to send messages in response. TODO: Disable interrupts while using the SPI bus. */ void DoA7Message(A7_MESSAGE Message, u8 NumParams, u32 Param1, u32 Param2, u32 Param3, u32 Param4, bool FromA9) { u32 PowerStatus = 0; switch(Message) { case A7_NULL: //Dummy message, no parameters. break; case A7_INIT: //Used to pass some data from ARM9 at startup. Param1=Pointer to ARM7StackDump. ARM7StackDump = (u32*)Param1; break; case A7_RETURN: //Return value from a message; param1=message being responded to, others=return value. break; case A7_CHECK: //Used to check that ARM7 is still responding. Return value=anything; just returns a value to let ARM9 know it's still going. if(FromA9) SendA9Message(A9_RETURN, 2, A7_CHECK, 0xD06FECE5, 0, 0); break; case A7_GBAMODE: //Reboot into GBA mode, no parameters. /* //TEST OF ERROR HANDLER __asm ( ".arm\n" "ldr r0, =ASMHackery\n" "str r13, [r0]\n" : : : "r0" ); if(ARM7StackDump) { memcpy(ARM7StackDump, (u32*)(ASMHackery - A7_STACK_DUMP_NUMWORDS), A7_STACK_DUMP_NUMWORDS * 4); SendA9Message(A9_FATALERROR, 2, 0xD06FECE5, ASMHackery, 0, 0); } else SendA9Message(A9_FATALERROR, 2, 0xAAAAAAAA, ASMHackery, 0, 0); REG_IME = 0; while(true) swiWaitForVBlank(); */ __asm (".arm\n" "mov r2, #0x40\n" "swi 0x1F0000\n" ); break; case A7_SETPOWER: //Change power settings; param1=0 to write, 1 to AND, 2 to OR, 3 to XOR; param2=bitflags. Note that System Power bit is reversed; 1=turn off. SerialWaitBusy(); //Get current status REG_SPICNT = SPI_ENABLE | SPI_DEVICE_POWER | SPI_BAUD_1MHz | SPI_CONTINUOUS; REG_SPIDATA = 0x80; //Set high bit for reading SerialWaitBusy(); REG_SPICNT = SPI_ENABLE | SPI_DEVICE_POWER | SPI_BAUD_1MHz; REG_SPIDATA = 0; SerialWaitBusy(); PowerStatus = REG_SPIDATA & 0xFF; REG_SPICNT = SPI_ENABLE | SPI_DEVICE_POWER | SPI_BAUD_1MHz | SPI_CONTINUOUS; REG_SPIDATA = 0; //Offset: 0=power management, 1=battery status, 2=amplifier, 3=microphone SerialWaitBusy(); REG_SPICNT = SPI_ENABLE | SPI_DEVICE_POWER | SPI_BAUD_1MHz; if(Param1 == 0) REG_SPIDATA = Param2; else if(Param1 == 1) REG_SPIDATA = PowerStatus & Param2; else if(Param1 == 2) REG_SPIDATA = PowerStatus | Param2; else if(Param1 == 3) REG_SPIDATA = PowerStatus ^ Param2; break; case A7_GETPOWER: //Retrieve power settings; no parameters, returns power bitflags. SerialWaitBusy(); REG_SPICNT = SPI_ENABLE | SPI_DEVICE_POWER | SPI_BAUD_1MHz | SPI_CONTINUOUS; REG_SPIDATA = 0x80; SerialWaitBusy(); REG_SPICNT = SPI_ENABLE | SPI_DEVICE_POWER | SPI_BAUD_1MHz; REG_SPIDATA = 0; SerialWaitBusy(); if(FromA9) SendA9Message(A9_RETURN, 2, A7_GETPOWER, REG_SPIDATA & 0xFF, 0, 0); break; case A7_SETVOLUME: //Set sound volume; param1=bits 0-6 set master sound volume, 7=1 to enable sound, 0 to disable. SOUND_CR |= SOUND_VOL(Param1 & 0x7F) | ((Param1 & 0x80) ? SOUND_ENABLE : 0); break; case A7_GETVOLUME: //Retrieve sound volume; return bits 0-6=master volume, 7=1 if enabled, 0 if disabled. if(FromA9) SendA9Message(A9_RETURN, 2, A7_GETVOLUME, (SOUND_CR & SOUND_VOL(127)) | ((SOUND_CR & SOUND_ENABLE) ? 0x80 : 0), 0, 0); break; case A7_SETSOUND: //Set flags for a sound channel; param1=channel (low 4 bits), param2=flags, param3=source, param4=length. if(NumParams >= 3) SCHANNEL_SOURCE(Param1 & 0xF) = Param3; if(NumParams >= 4) SCHANNEL_LENGTH(Param1 & 0xF) = Param4; //Flag format: //evvvvvvv pppppppw wwffffff ffffffft SCHANNEL_TIMER(Param1 & 0xF) = ((Param2 >> 1) & 0x1FFF) << 3; SCHANNEL_CR(Param1 & 0xF) = ((Param2 & 0x80000000) ? SCHANNEL_ENABLE : 0) | SOUND_VOL((Param2 >> 24) & 0x7F) | SOUND_PAN((Param2 >> 17) & 0x7F) | SCHANNEL_WAVEDUTY((Param2 >> 14) & 7) | ((Param2 & 1) ? SOUND_FORMAT_PSG : 0); break; case A7_GETSOUNDFLAGS: //Get flags for a sound channel; param1=channel (low 4 bits), return=flags. if(FromA9) SendA9Message(A9_RETURN, 2, A7_GETSOUNDFLAGS, ((SCHANNEL_CR(Param1 & 0xF) & SOUND_FORMAT_PSG) ? 1 : 0) | (SCHANNEL_TIMER(Param1 & 0xF) >> 2) | ((SCHANNEL_CR(Param1 & 0xF) & SCHANNEL_WAVEDUTY(7)) << 14) | ((SCHANNEL_CR(Param1 & 0xF) & SOUND_PAN(0x7F)) << 17) | ((SCHANNEL_CR(Param1 & 0xF) & SOUND_VOL(0x7F)) << 24) | ((SCHANNEL_CR(Param1 & 0xF) & SCHANNEL_ENABLE) ? 0x80000000 : 0), SCHANNEL_SOURCE(Param1 & 0xF), SCHANNEL_LENGTH(Param1 & 0xF)); break; case A7_BOOTNDS: //Enter wait loop to boot .nds file on GBAMP. REG_IME = IME_DISABLE; // Disable interrupts *((vu32*)0x027FFE34) = (u32)0x08000000; // Bootloader start address swiSoftReset(); // Jump to boot loader break; case A7_WIFICTRL: //Wifi control messages if(Param1 == WIFIPARAM_SYNC) Wifi_Sync(); else if(Param1 == WIFIPARAM_INIT) A7InitWifi(Param2); else if(Param1 == WIFIPARAM_STOP) { //todo: stop the LED blinking; this function doesn't seem to do it. Wifi_Deinit(); IPC2->WifiEnabled = false; } break; case A7_BACKLIGHT: //Param1=Top light, Param2=Bottom light (-1=no change, 0=off, 1=on), Param3=Brightness (0-3 or -1 for no change, ignored if not DSLite) if(Param1 == 0xFFFFFFFF); //do nothing else if(Param1 == 0) //turn off DoA7Message(A7_SETPOWER, 2, 1, ~PM_BACKLIGHT_TOP, 0, 0, false); else if(Param1 == 1) //turn on DoA7Message(A7_SETPOWER, 2, 2, PM_BACKLIGHT_TOP, 0, 0, false); else if(FromA9) //invalid parameter SendA9Message(A9_ERROR, 1, 1, 0, 0, 0); if(Param2 == 0xFFFFFFFF); //do nothing else if(Param2 == 0) //turn off DoA7Message(A7_SETPOWER, 2, 1, ~PM_BACKLIGHT_BOTTOM, 0, 0, false); else if(Param2 == 1) //turn on DoA7Message(A7_SETPOWER, 2, 2, PM_BACKLIGHT_BOTTOM, 0, 0, false); else if(FromA9) //invalid parameter SendA9Message(A9_ERROR, 1, 2, 0, 0, 0); if(Param3 == 0xFFFFFFFF); //do nothing else if(Param3 < 4) //set brightness { if(IPC2->SysInfo & SI_DSLITE) writePowerManagement(4, (readPowerManagement(4) & ~3) | Param3); //Set brightness - bits 0-1 of reg 4 } else if(FromA9) //invalid parameter SendA9Message(A9_ERROR, 1, 3, 0, 0, 0); break; default: //Invalid message if(FromA9) SendA9Message(A9_ERROR, 0, 0, 0, 0, 0); break; } } /* Sends a message to ARM9. CPU: ARM7 Inputs: -Message: Message to send. -NumParams: Number of valid parameters. -Param1..Param4: Message parameters. Notes: -If send FIFO is full, it will wait until space is available. Todo: Implement some sort of check that the ARM9 is still responding, so ARM7 doesn't get caught in an infinite loop as well and can at least report the problem. */ void SendA9Message(A9_MESSAGE Message, u8 NumParams, u32 Param1, u32 Param2, u32 Param3, u32 Param4) { while(REG_IPC_FIFO_CR & IPC_FIFO_SEND_FULL) swiDelay(10); REG_IPC_FIFO_TX = (Message << 24) | (NumParams << 16); if(NumParams < 1) return; while(REG_IPC_FIFO_CR & IPC_FIFO_SEND_FULL) swiDelay(10); REG_IPC_FIFO_TX = Param1; if(NumParams < 2) return; while(REG_IPC_FIFO_CR & IPC_FIFO_SEND_FULL) swiDelay(10); REG_IPC_FIFO_TX = Param2; if(NumParams < 3) return; while(REG_IPC_FIFO_CR & IPC_FIFO_SEND_FULL) swiDelay(10); REG_IPC_FIFO_TX = Param3; if(NumParams < 4) return; while(REG_IPC_FIFO_CR & IPC_FIFO_SEND_FULL) swiDelay(10); REG_IPC_FIFO_TX = Param4; } /* Interrupt handler CPU: ARM7 */ void Interrupt() { CustomIPCData Data; s32 t1=0, t2=0; static s16 SecCountdown = 1000; //Counts down to zero every second to signal re-read of RTC touchPosition tempPos; if(REG_IF & IRQ_VBLANK) { if(need_reboot()) reboot(); if(IPC2->WifiEnabled) Wifi_Update(); memcpy((u8*)&Data, (u8*)IPC2, sizeof(Data)); //Read the buttons and touch screen uint32 B = ((~REG_KEYXY) << 10) & (KEY_X | KEY_Y); B |= (~REG_KEYINPUT) & 0x3FF; if(REG_KEYXY & 0x80) B |= KEY_LID; if(!(REG_KEYXY & 0x40)) //touched { B |= KEY_TOUCH; IPC2->TEST = 7; tempPos = touchReadXY(); IPC2->TEST = 8; Data.TouchX = tempPos.px; Data.TouchY = tempPos.py; } Data.ButtonsHeld = (Data.ButtonsHeld | Data.ButtonsPressed) & B; Data.ButtonsPressed = B & ~Data.ButtonsHeld; Data.TouchZ1 = touchRead(TSC_MEASURE_Z1); Data.TouchZ2 = touchRead(TSC_MEASURE_Z2); //Update IPC IPC2->TouchX = Data.TouchX; IPC2->TouchY = Data.TouchY; IPC2->ButtonsHeld = Data.ButtonsHeld; IPC2->ButtonsPressed = Data.ButtonsPressed; IPC2->TouchZ1 = Data.TouchZ1; IPC2->TouchZ2 = Data.TouchZ2; memcpy((u8*)IPC->time.curtime, (u8*)Data.TimeData, sizeof(Data.TimeData)); //libFAT needs this memcpy((u8*)IPC2->TimeData, (u8*)Data.TimeData, sizeof(Data.TimeData)); IPC2->Temperature = Data.Temperature; IPC2->A7FrameCount++; VBLANK_INTR_WAIT_FLAGS |= IRQ_VBLANK; //Signal that vblank interrupt has been processed REG_IF |= IRQ_VBLANK; } else if(REG_IF & IRQ_TIMER3) { IPC2->TEST = 1; IPC2->TickCount++; VBLANK_INTR_WAIT_FLAGS |= IRQ_TIMER3; REG_IF |= IRQ_TIMER3; IPC2->TEST = 2; //Read the time SecCountdown--; if(SecCountdown < 1) { SecCountdown = 1000; IPC2->TEST = 3; syncRTC(); IPC2->TEST = 4; //Read the temperature IPC2->Temperature = touchReadTemperature(&t1, &t2); IPC2->TEST = 5; } } else if(REG_IF & IRQ_WIFI) { IPC2->TEST = 6; if(IPC2->WifiEnabled) Wifi_Interrupt(); VBLANK_INTR_WAIT_FLAGS |= IRQ_WIFI; REG_IF |= IRQ_WIFI; } } /* Reads the clock. Copied from a GBADev post. Todo: clean this up. */ void syncRTC() { int oldhours = IPC->time.rtc.hours; uint8 command[2]; command[0] = READ_STATUS_REG1; rtcTransaction(command, 1, &command[1], 1); IPC->mailSize = REG_RCNT; if ( command[1] & 0x30 ) { IPC->mailRead = command[1]; REG_IF = IRQ_NETWORK; } else { IPC->mailAddr = command[1]; } rtcGetTime((uint8 *)&(IPC->time.rtc.hours)); if(oldhours>IPC->time.rtc.hours) // going from 23 to 0 hours, update whole time struct rtcGetTimeAndDate((uint8 *)&(IPC->time.rtc.year)); memcpy((void*)IPC2->TimeData, (void*)IPC->time.curtime, sizeof(IPC2->TimeData)); } /* Initializes the wifi hardware. Inputs: -A9Param: Parameter passed from ARM9; must be passed to Wifi_Init(). Returns: True on success, false otherwise. */ bool A7InitWifi(u32 A9Param) { Wifi_SetSyncHandler(_A7WifiSync); Wifi_Init(A9Param); IPC2->WifiEnabled = true; return true; } /* Wifi sync handler; called by wifi lib as necessary. */ void _A7WifiSync() { SendA9Message(A9_WIFISYNC, 0, 0, 0, 0, 0); } /* Fatal error handler. Inputs: -Code: Error code to display. Notes: -Does not return. The error code is output in 3 ways: 1) The speakers will emit a tone whose frequency is Code * 100hz. 2) The screen should display an error message if ARM9 is still running. 3) The power LED will blink a number of times equal to the code. There is a small delay afterward, then it begins again. */ void FatalError(u32 Code) { u32 i; //Play sound SCHANNEL_TIMER(8) = SOUND_FREQ(Code * 800); SCHANNEL_CR(8) = SOUND_VOL(32) | SOUND_PAN(64) | SCHANNEL_WAVEDUTY(3) | SOUND_FORMAT_PSG | SCHANNEL_ENABLE; SendA9Message(A9_ERROR, 2, 5, Code, 0, 0); //Send ARM9 a fatal error message //Blink power LED while(true) { for(i=0; i<Code; i++) { writePowerManagement(0, PM_SOUND_PWR | PM_BACKLIGHT_BOTTOM | BIT(4)); //Power LED off (slow blink) swiDelay(3000000); writePowerManagement(0, PM_SOUND_PWR | PM_BACKLIGHT_BOTTOM); //Power LED on swiDelay(3000000); } swiDelay(10000000); } } |
I suspect touchReadTemperature() is leaving the hardware or some internal variable in a state that touchReadXY() doesn't account for.
_________________
I'm a PSP hacker now, but I still <3 DS.
Last edited by HyperHacker on Mon Jul 02, 2007 11:06 pm; edited 1 time in total