diff --git a/include/arm11/interrupt.h b/include/arm11/interrupt.h index 72af27e..808a75f 100644 --- a/include/arm11/interrupt.h +++ b/include/arm11/interrupt.h @@ -21,6 +21,7 @@ IRQ_MPCORE_SW13 = 13, IRQ_MPCORE_SW14 = 14, IRQ_MPCORE_SW15 = 15, + IRQ_TIMER = 29, // MPCore timer IRQ_PSC0 = 40, // Unconfirmed IRQ_PSC1 = 41, // Unconfirmed IRQ_PDC0 = 42, // aka VBlank0 @@ -35,7 +36,7 @@ IRQ_SHELL_CLOSED = 98, IRQ_TOUCHSCREEN = 99, // Triggers on hitting the touchscreen. IRQ_HEADPH_JACK = 100, // Headphone jack. Triggers on both plugging in and out? GPIO reg 9, bit 8. - IRQ_MCU_HID = 113, // HOME/POWER pressed/released or shell opened/closed. GPIO reg 19, bit 9. + IRQ_MCU_HID = 113, // HOME/POWER pressed/released, shell opened/closed and WiFi switch pressed. GPIO reg 19, bit 9. IRQ_GAMECARD = 117 // Gamecard inserted } Interrupt; diff --git a/include/arm11/timer.h b/include/arm11/timer.h new file mode 100644 index 0000000..464a0b6 --- /dev/null +++ b/include/arm11/timer.h @@ -0,0 +1,48 @@ +#pragma once + +#include "types.h" + + +#define TIMER_BASE_FREQ (268111856.0) + +#define TIMER_ENABLE (1u) +#define TIMER_SINGLE_SHOT (0u) +#define TIMER_AUTO_RELOAD (1u<<1) +#define TIMER_IRQ_ENABLE (1u<<2) + +// p is the prescaler value and n the frequence +#define TIMER_FREQ(p, n) (TIMER_BASE_FREQ / 2 / ((p) + 1) / (n)) + + + +/** + * @brief Resets/initializes the timer hardware. Should not be called manually. + */ +void TIMER_init(void); + +/** + * @brief Starts the timer. + * + * @param[in] prescaler The prescaler value. + * @param[in] ticks The initial number of ticks. This is also the + * reload value in auto reload mode. + * @param[in] autoReload Set to true for auto reload. false for single shot. + * @param[in] enableIrq Timer fires IRQs on underflow if true. + */ +void TIMER_start(u8 prescaler, u32 ticks, bool autoReload, bool enableIrq); + +/** + * @brief Stops the timer. + */ +void TIMER_stop(void); + +/** + * @brief Halts the CPU for the specified number of ticks. + * Use the macro below for a milliseconds version. + * + * @param[in] ticks The number of ticks to sleep. + */ +void TIMER_sleepTicks(u32 ticks); + +// Sleeps ms milliseconds. ms can be up to 32000. +#define TIMER_sleepMs(ms) TIMER_sleepTicks(TIMER_FREQ(0, 1000.0) * (ms)) diff --git a/source/arm11/exception.s b/source/arm11/exception.s index 681cf87..1d90e45 100644 --- a/source/arm11/exception.s +++ b/source/arm11/exception.s @@ -1,5 +1,4 @@ #include "asmfunc.h" -#include "mem_map.h" .arm .cpu mpcore diff --git a/source/arm11/hardware.c b/source/arm11/hardware.c index 2cb5792..078feed 100644 --- a/source/arm11/hardware.c +++ b/source/arm11/hardware.c @@ -1,5 +1,6 @@ #include "types.h" #include "arm11/interrupt.h" +#include "arm11/timer.h" #include "pxi.h" #include "arm11/hid.h" @@ -8,6 +9,7 @@ void hardwareInit(void) { IRQ_init(); + TIMER_init(); PXI_init(); hidInit(); } diff --git a/source/arm11/timer.c b/source/arm11/timer.c new file mode 100644 index 0000000..0fd8113 --- /dev/null +++ b/source/arm11/timer.c @@ -0,0 +1,46 @@ +#include "types.h" +#include "mem_map.h" +#include "arm11/timer.h" +#include "arm11/interrupt.h" + +#define TIMER_REGS_BASE (MPCORE_PRIV_REG_BASE + 0x600) +#define REG_TIMER_LOAD *((vu32*)(TIMER_REGS_BASE + 0x00)) +#define REG_TIMER_COUNTER *((vu32*)(TIMER_REGS_BASE + 0x04)) +#define REG_TIMER_CNT *((vu32*)(TIMER_REGS_BASE + 0x08)) +#define REG_TIMER_INT_STAT *((vu32*)(TIMER_REGS_BASE + 0x0C)) + + + +void TIMER_init(void) +{ + REG_TIMER_CNT = 0; + REG_TIMER_INT_STAT = 1; + + IRQ_registerHandler(IRQ_TIMER, 12, 0, true, NULL); +} + +void TIMER_start(u8 prescaler, u32 ticks, bool autoReload, bool enableIrq) +{ + REG_TIMER_LOAD = ticks; + REG_TIMER_CNT = prescaler<<8 | (enableIrq ? TIMER_IRQ_ENABLE : 0) | + (autoReload ? TIMER_AUTO_RELOAD : TIMER_SINGLE_SHOT) | TIMER_ENABLE; +} + +void TIMER_stop(void) +{ + REG_TIMER_CNT = 0; + REG_TIMER_INT_STAT = 1; +} + +void TIMER_sleepTicks(u32 ticks) +{ + REG_TIMER_LOAD = ticks; + REG_TIMER_CNT = 0u<<8 | TIMER_IRQ_ENABLE | TIMER_SINGLE_SHOT | TIMER_ENABLE; + + while(REG_TIMER_COUNTER) + { + waitForInterrupt(); + } + + REG_TIMER_INT_STAT = 1; +}