diff --git a/TODO b/TODO index eb9bb0a..360005e 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,9 @@ -- screen, display -- timer -- gray engine +- multi-getkey repeats (if possible, which doesn't seem likely) +- getkey() may unwantedly repeat a key if it was triggered for multigetkey() + +- write and test gray engine - full rtc driver (time) +- callbacks and complete user API _ 7305.h _ libc diff --git a/ginttest.c b/ginttest.c index 5133959..3211a45 100644 --- a/ginttest.c +++ b/ginttest.c @@ -3,11 +3,26 @@ #include #include #include +#include + +extern unsigned int gint_vbr, bgint, egint, gint_data; + +/* + A few procedures for displaying text in the system's vram. +*/ extern void __Print(const char *msg, int x, int y); -extern unsigned int gint_vbr, bgint, egint, gint_data; -#define print __Print +void print_clear(void) +{ + char *empty_line = " "; + int i = 0; + while(i < 8) print(empty_line, 0, i++); +} +void print(const char *str, int x, int y) +{ + __Print(str, x, y); +} void print_hex(unsigned int n, int x, int y) { char ch[11] = "0x"; @@ -19,7 +34,7 @@ void print_hex(unsigned int n, int x, int y) n >>= 4; } ch[10] = 0; - print(ch, x, y); + __Print(ch, x, y); } void print_bin(unsigned char n, int x, int y) { @@ -32,9 +47,8 @@ void print_bin(unsigned char n, int x, int y) n >>= 1; } ch[8] = 0; - print(ch, x, y); + __Print(ch, x, y); } - void print_hexa(unsigned int n, int digits, int x, int y) { char ch[20]; @@ -47,29 +61,35 @@ void print_hexa(unsigned int n, int digits, int x, int y) } ch[digits] = 0; - print(ch, x, y); + __Print(ch, x, y); } -// Don't forget to enable key state debugging in the interrupt handler. +/* + Keyboard tests. +*/ + void keyboard_test(void) { - const char *names[] = { - "MPU_Unkown", - "MPU_SH7337", - "MPU_SH7355", - "MPU_SH7305", - "MPU_SH7724", - "Error" - }; +/* + print_bin(keyboard_state[0], 0, 2); + print_bin(keyboard_state[1], 0, 3); + print_bin(keyboard_state[2], 0, 4); + print_bin(keyboard_state[3], 0, 5); + print_bin(keyboard_state[4], 0, 6); + + print_bin(keyboard_state[5], 9, 2); + print_bin(keyboard_state[6], 9, 3); + print_bin(keyboard_state[7], 9, 4); + print_bin(keyboard_state[8], 9, 5); + print_bin(keyboard_state[9], 9, 6); +*/ + int x = 0; char str[3]; int keys[4] = { 0 }; int i; - print(names[MPU_CURRENT < 5 ? MPU_CURRENT : 5], 0, 0); - - print("gint size:", 0, 1); - print_hex(&egint - &bgint, 11, 1); + print_clear(); while(1) { @@ -251,7 +271,7 @@ void btest_gint_icon(void) } */ -int main(void) +void bitmap_test(void) { extern Image binary_symbol_start; extern Image binary_symbol2_start; @@ -307,5 +327,69 @@ int main(void) dupdate(); while(getkey() != KEY_EXE); +} + +void test(void) +{ + static int x = 0; + x++; + + print_hex(x, 0, 0); +} + +int main_menu(void) +{ + /* + Main menu. + */ + + const char *mpu_names[] = { + "MPU_Unkown", + "MPU_SH7337", + "MPU_SH7355", + "MPU_SH7305", + "MPU_SH7724", + "MPU Error !" + }; + int key; + + print_clear(); + + print("gint test application", 0, 0); + print("---------------------", 0, 1); + + print("[1] Keyboard test", 2, 3); + print("[2] Drawing test", 2, 4); + + print("mpu type:", 0, 6); + print(mpu_names[MPU_CURRENT < 5 ? MPU_CURRENT : 5], 11, 6); + print("gint size:", 0, 7); + print_hex(&egint - &bgint, 11, 7); + + while(1) + { + key = getkey(); + if(key == KEY_EXIT) return 0; + + if(key == KEY_1) return 1; + if(key == KEY_2) return 2; + } + + return 0; +} + +int main(void) +{ + int app; + + while(1) + { + app = main_menu(); + if(!app) break; + + if(app == 1) keyboard_test(); + if(app == 2) bitmap_test(); + } + return 0; } diff --git a/ginttest.g1a b/ginttest.g1a index 4e1e26d..ab24651 100644 Binary files a/ginttest.g1a and b/ginttest.g1a differ diff --git a/include/gint.h b/include/gint.h index de06883..34fc394 100644 --- a/include/gint.h +++ b/include/gint.h @@ -22,6 +22,20 @@ unsigned int gint_getVBR(void); */ unsigned int gint_systemVBR(void); +/* + gint_setRTCCallback() + Sets the callback function for the real-time clock interrupt. If + frequency is non-NULL, the clock frequency is set to the given value. +*/ +void gint_setRTCCallback(void (*callback)(void), enum GintFrequency frequency); + +/* + gint_getRTCCallback() + Returns the callback function. If frequency is non-NULL, it is set to + the current frequency value. +*/ +void (*(gint_getRTCCallback)(void))(enum GintFrequency *frequency); + //--- @@ -79,8 +93,8 @@ void gint(void) __attribute__(( section(".gint.int.entry"), interrupt_handler )); -void gint_7705(void) __attribute__((section(".gint.int"))); -void gint_7305(void) __attribute__((section(".gint.int"))); +void gint_7705(void) __attribute__((section(".gint.int"))); +void gint_7305(void) __attribute__((section(".gint.int"))); @@ -89,8 +103,11 @@ void gint_7305(void) __attribute__((section(".gint.int"))); //--- #define GINT_INTP_WDT 4 -#define GINT_INTP_RTC 9 +#define GINT_INTP_RTC 12 + +#define GINT_INTP_GRAY 15 #define GINT_INTP_KEY 8 +#define GINT_INTP_TIMER 10 diff --git a/include/keyboard.h b/include/keyboard.h index 534f570..b8aa1c7 100644 --- a/include/keyboard.h +++ b/include/keyboard.h @@ -83,42 +83,24 @@ // Keyboard configuration. //--- -/* - enum KeyboardFrequency - Describes the various frequencies available for the keyboard analysis. - Default frequency is 16 Hz (system frequency is about 40 Hz). Very few - applications will need to change this setting. - Be aware that you will miss key hits at low frequencies. - At high frequencies, you will lose important execution power. Some - loop-driven programs will freeze at 64 Hz because they will never - leave the interrupt handling routine. SH3 also have difficulties with - 64 Hz. -*/ -enum KeyboardFrequency { - KeyFreq_500mHz = 7, - KeyFreq_1Hz = 6, - KeyFreq_2Hz = 5, - KeyFreq_4Hz = 4, - KeyFreq_16Hz = 3, - KeyFreq_64Hz = 2, - KeyFreq_256Hz = 1, -}; - /* keyboard_setFrequency() - Sets the keyboard frequency. Does nothing when the argument is not a - valid KeyboardFrequency value. + Sets the keyboard frequency. The default frequency is 32 Hz. Very few + Very few applications will need to change this setting. + The actual frequency is guaranteed to be greater than the argument. + Be aware that you will miss key hits at low frequencies. At higher + frequencies, you will lose important execution power. - @arg frequency + @arg frequency Frequency in Hz (1 Hz = 1 event / second). */ -void keyboard_setFrequency(enum KeyboardFrequency frequency); +// Currently not implemented. +// void keyboard_setFrequency(int frequency); /* keyboard_setRepeatRate() Sets the default repeat rate for key events. The unit for the argument - is the keyboard period. - For example at 16 Hz, values of (10, 2) will imitate the system - default. + is the keyboard period. For example at 32 Hz, values of (20, 4) will + imitate the system default. Set to 0 to disable repetition. If first = 0, no repetition will be allowed. If first != 0 and next = 0, only one repetition will be allowed. @@ -170,6 +152,19 @@ enum GetkeyOpt */ int keylast(int *repeat_count); +/* + keystate() + Returns the address of the keyboard state array. The keyboard state + consists in 10 bytes, in which every key is represented as a bit. + The returned address is the original buffer address. You should avoid + editing the array. It wouldn't influence the behavior of the keyboard + functions, but the buffer data is very volatile. Therefore, data + written to the buffer could be replaced anytime. + + @return 10-byte keyboard state buffer. +*/ +volatile unsigned char *keystate(void); + /* getkey() Blocking function with auto-repeat and SHIFT modifying functionalities. @@ -251,4 +246,41 @@ int keychar(int key); */ enum KeyType keytype(int key); + + +//--- +// Internal API. +// Reference here for documentation purposes only. Do not call. +//--- + +/* + keyboard_interrupt() + Notifies the keyboard module that an interrupt request has been issued, + and updates the keyboard state. +*/ +void keyboard_interrupt(void) __attribute__((section(".gint.int"))); + +/* + keyboard_updateState() + Updates the keyboard state. + + @arg state 10-byte state buffer. +*/ +void keyboard_updateState_7705(volatile unsigned char *state) + __attribute__((section(".gint.int"))); +void keyboard_updateState_7305(volatile unsigned char *state) + __attribute__((section(".gint.int"))); + +/* + keyboard_init() + Starts the keyboard timer. +*/ +void keyboard_init(void) __attribute__((constructor)); + +/* + keyboard_quit() + Stops the keyboard timer. +*/ +void keyboard_quit(void) __attribute__((destructor)); + #endif // _KEYBOARD_H diff --git a/include/timer.h b/include/timer.h index 786b259..84b6dde 100644 --- a/include/timer.h +++ b/include/timer.h @@ -13,9 +13,9 @@ #define TIMER_2 2 #define TIMER_TMU2 TIMER_2 // Timer function identifiers. -#define TIMER_GRAY TIMER_TMU0 -#define TIMER_USER1 TIMER_TMU1 -#define TIMER_USER2 TIMER_TMU2 +#define TIMER_KEYBOARD TIMER_TMU0 +#define TIMER_GRAY TIMER_TMU1 +#define TIMER_USER TIMER_TMU2 // Timer prescalers. #define TIMER_Po_4 0 @@ -31,11 +31,12 @@ //--- /* - timer_set() + timer_start() Configures and starts a timer. - @arg timer Timer identifier. Use only TIMER_USER1 and - TIMER_USER2. + @arg timer Timer name. Use only TIMER_USER. You may use + TIMER_GRAY, if you're not running the gray + engine. @arg delay Delay before expiration, in clock counts. @arg prescaler Clock prescaler value. Possible values are TIMER_Po_4, TIMER_Po_16, TIMER_Po_64, @@ -43,7 +44,7 @@ @arg callback Callback function. @arg repetitions Number of repetitions, 0 for infinite. */ -void timer_set(int timer, int delay, int prescaler, void (*callback)(void), +void timer_start(int timer, int delay, int prescaler, void (*callback)(void), int repetitions); /* @@ -68,6 +69,6 @@ void timer_stop(int timer); @timer Timer that generated the interrupt. */ -void timer_interrupt(int timer); +void timer_interrupt(int timer) __attribute__((section(".gint.int"))); #endif // _TIMER_H diff --git a/libc.a b/libc.a index 3e386fd..102244a 100644 Binary files a/libc.a and b/libc.a differ diff --git a/libgint.a b/libgint.a index 5af816a..82f815b 100644 Binary files a/libgint.a and b/libgint.a differ diff --git a/src/gint_7305.c b/src/gint_7305.c index 0947749..25330e9 100644 --- a/src/gint_7305.c +++ b/src/gint_7305.c @@ -1,17 +1,17 @@ #include +#include +#include #include <7305.h> -extern void print_hex(unsigned int value, int x, int y); -extern void print_bin(unsigned char value, int x, int y); - - - //--- // Interrupt codes. //--- #define IC_RTC_PRI 0xaa0 #define IC_KEYSC 0xbe0 +#define IC_TMU0_TUNI0 0x400 +#define IC_TMU0_TUNI1 0x420 +#define IC_TMU0_TUNI2 0x440 @@ -19,9 +19,6 @@ extern void print_bin(unsigned char value, int x, int y); // Keyboard management. //--- -extern volatile unsigned char keyboard_state[10]; -extern void keyboard_interrupt(void); - /* kdelay() Should sleep during a few milliseconds. Well... @@ -143,16 +140,14 @@ static int krow(int row) } /* - kstate() + keyboard_updateState() Updates the keyboard state. */ -static void kstate(void) +void keyboard_updateState_7305(volatile unsigned char *keyboard_state) { int i; for(i = 0; i < 10; i++) keyboard_state[i] = krow(i); - - keyboard_interrupt(); } @@ -169,23 +164,19 @@ void gint_7305(void) switch(code) { case IC_RTC_PRI: - // Clearing the interrupt flag. RTC.RCR2.PEF = 0; - // Updating the keyboard state. - kstate(); -/* - print_bin(keyboard_state[0], 0, 2); - print_bin(keyboard_state[1], 0, 3); - print_bin(keyboard_state[2], 0, 4); - print_bin(keyboard_state[3], 0, 5); - print_bin(keyboard_state[4], 0, 6); + break; - print_bin(keyboard_state[5], 9, 2); - print_bin(keyboard_state[6], 9, 3); - print_bin(keyboard_state[7], 9, 4); - print_bin(keyboard_state[8], 9, 5); - print_bin(keyboard_state[9], 9, 6); -*/ + case IC_TMU0_TUNI0: + timer_interrupt(TIMER_TMU0); + break; + + case IC_TMU0_TUNI1: + timer_interrupt(TIMER_TMU1); + break; + + case IC_TMU0_TUNI2: + timer_interrupt(TIMER_TMU2); break; } } @@ -245,7 +236,10 @@ static void gint_priority_lock_7305(void) // Allowing RTC. Keyboard analysis is done regularly using a RTC // because SH7305's special KEYSC interface does not allow us to clear // the keyboard interrupt flags. - INTX.IPRK._RTC = GINT_INTP_RTC; + INTX.IPRK._RTC = GINT_INTP_RTC; + INTX.IPRA.TMU0_0 = GINT_INTP_KEY; + INTX.IPRA.TMU0_1 = GINT_INTP_GRAY; + INTX.IPRA.TMU0_2 = GINT_INTP_TIMER; } static void gint_priority_unlock_7305(void) diff --git a/src/gint_7705.c b/src/gint_7705.c index 02ff8b2..563958b 100644 --- a/src/gint_7705.c +++ b/src/gint_7705.c @@ -1,17 +1,17 @@ #include +#include +#include #include <7705.h> -extern void print_hex(unsigned int value, int x, int y); -extern void print_bin(unsigned char value, int x, int y); - - - //--- // Interrupt codes. //--- #define IC_RTC_PRI 0x4a0 #define IC_PINT07 0x700 +#define IC_TMU0_TUNI0 0x400 +#define IC_TMU1_TUNI1 0x420 +#define IC_TMU2_TUNI2 0x440 @@ -19,12 +19,11 @@ extern void print_bin(unsigned char value, int x, int y); // Keyboard management. //--- -extern volatile unsigned char keyboard_state[10]; -extern void keyboard_interrupt(void); - /* kdelay() - Low-level sleep using the watchdog. + Used to be a low-level sleep using the watchdog, as in the system. This + way seems ok at least, and it doesn't create column effects as for + SH7305. */ static void kdelay(void) { @@ -39,7 +38,7 @@ static void kdelay(void) #undef r4 -/* + /* Watchdog version. const int delay = 0xf4; // Disabling the watchdog timer interrupt and resetting the @@ -64,7 +63,7 @@ static void kdelay(void) // Enabling back the watchdog timer interrupt. INTC.IPRB.BIT._WDT = GINT_INTP_WDT; -*/ + */ } /* @@ -134,16 +133,14 @@ static int krow(int row) } /* - kstate() + keyboard_updateState() Updates the keyboard state. */ -static void kstate(void) +void keyboard_updateState_7705(volatile unsigned char *keyboard_state) { int i; for(i = 0; i < 10; i++) keyboard_state[i] = krow(i); - - keyboard_interrupt(); } @@ -160,23 +157,19 @@ void gint_7705(void) switch(code) { case IC_RTC_PRI: - // Clearing the interrupt flag. RTC.RCR2.BIT.PEF = 0; - // Updating the keyboard state. - kstate(); -/* - print_bin(keyboard_state[0], 0, 2); - print_bin(keyboard_state[1], 0, 3); - print_bin(keyboard_state[2], 0, 4); - print_bin(keyboard_state[3], 0, 5); - print_bin(keyboard_state[4], 0, 6); + break; - print_bin(keyboard_state[5], 9, 2); - print_bin(keyboard_state[6], 9, 3); - print_bin(keyboard_state[7], 9, 4); - print_bin(keyboard_state[8], 9, 5); - print_bin(keyboard_state[9], 9, 6); -*/ + case IC_TMU0_TUNI0: + timer_interrupt(TIMER_TMU0); + break; + + case IC_TMU1_TUNI1: + timer_interrupt(TIMER_TMU1); + break; + + case IC_TMU2_TUNI2: + timer_interrupt(TIMER_TMU2); break; } } @@ -214,7 +207,10 @@ static void gint_priority_lock_7705(void) INTX.IPRH.WORD = 0x0000; // Allowing RTC, which handles keyboard. - INTC.IPRA.BIT._RTC = GINT_INTP_RTC; + INTC.IPRA.BIT._RTC = GINT_INTP_RTC; + INTC.IPRA.BIT._TMU0 = GINT_INTP_KEY; + INTC.IPRA.BIT._TMU1 = GINT_INTP_GRAY; + INTC.IPRA.BIT._TMU2 = GINT_INTP_TIMER; } static void gint_priority_unlock_7705(void) diff --git a/src/keyboard.c b/src/keyboard.c index 8b3985a..0ec7a0e 100644 --- a/src/keyboard.c +++ b/src/keyboard.c @@ -1,14 +1,18 @@ #include +#include #include //--- // Keyboard variables. //--- -volatile unsigned char keyboard_state[10] = { 0 }; +// These ones get modified by interrupts. +static volatile unsigned char keyboard_state[10] = { 0 }; +static volatile int interrupt_flag = 0; + +// Key statistics. static int repeat_first = 10, repeat_next = 2; static int last_key = KEY_NONE, last_repeats = 0, last_events = 0; -static volatile int interrupt_flag = 0; @@ -18,9 +22,9 @@ static volatile int interrupt_flag = 0; /* sleep() - Puts the CPU in sleep mode and waits for an interrupt to return. + Puts the CPU to sleep and waits for an interrupt. */ -void sleep(void) +static void sleep(void) { __asm__ ( @@ -34,7 +38,7 @@ void sleep(void) @return A pressed key. */ -int getPressedKey(void) +static int getPressedKey(void) { int row = 1, column = 0; int state; @@ -62,7 +66,7 @@ int getPressedKey(void) @return Number of actual pressed keys found. */ -int getPressedKeys(int *keys, int count) +static int getPressedKeys(int *keys, int count) { int row = 1, column; int found = 0, actually_pressed; @@ -109,16 +113,46 @@ int getPressedKeys(int *keys, int count) return actually_pressed; } + + +//--- +// Interrupt management. +//--- + /* keyboard_interrupt() Callback for keyboard update. Allows keyboard analysis functions to - wake only when RTC interrupts happen. + wake only when keyboard interrupts happen. */ void keyboard_interrupt(void) { + if(isSH3()) + keyboard_updateState_7705(keyboard_state); + else + keyboard_updateState_7305(keyboard_state); + interrupt_flag = 1; } +/* + keyboard_init() + Starts the keyboard timer. +*/ +void keyboard_init(void) +{ + timer_start(TIMER_KEYBOARD, 1700, TIMER_Po_256, keyboard_interrupt, + 0); +} + +/* + keyboard_quit() + Stops the keyboard timer. +*/ +void keyboard_quit(void) +{ + timer_stop(TIMER_KEYBOARD); +} + //--- @@ -127,20 +161,12 @@ void keyboard_interrupt(void) /* keyboard_setFrequency() - Sets the keyboard frequency. Does nothing when the argument is not a - valid KeyboardFrequency value. + Sets the keyboard frequency. - @arg frequency + @arg frequency In Hz. */ -void keyboard_setFrequency(enum KeyboardFrequency frequency) +void keyboard_setFrequency(int frequency) { - volatile unsigned char *rcr2; - - if(frequency < 1 || frequency > 7) return; - rcr2 = (unsigned char *)(isSH3() ? 0xfffffede : 0xa413fede); - - frequency <<= 4; - *rcr2 = (*rcr2 & 0x8f) | frequency; } /* @@ -185,6 +211,21 @@ int keylast(int *repeat_count) +/* + keystate() + Returns the address of the keyboard state array. The returned address + if the handler's buffer, therefore it contains volatile data. + + @return 10-byte keyboard state buffer. +*/ +volatile unsigned char *keystate(void) +{ + return keyboard_state; +} + + + + /* getkey() Blocking function with auto-repeat and SHIFT modifying functionalities. @@ -330,6 +371,18 @@ void multigetkey(int *keys, int count, int max_cycles) if(max_cycles > 0) max_cycles--; number = getPressedKeys(keys, count); + + // We need to update the last key data, in case multigetkey() + // returns a single key, and getkey() is called a short time + // after. Otherwise getkey() could re-send an event for this + // key. + if(number == 1) + { + last_key = keys[0]; + last_repeats = 0; + last_events = 0; + } + if(number) return; // Handle key repetitions. diff --git a/src/timer.c b/src/timer.c index f05b1a0..d7afc15 100644 --- a/src/timer.c +++ b/src/timer.c @@ -77,7 +77,7 @@ void timer_get(int timer, struct mod_tmu **tmu, unsigned char **tstr) } /* - timer_set() + timer_start() Configures and starts a timer. @arg timer Timer identifier. @@ -86,7 +86,7 @@ void timer_get(int timer, struct mod_tmu **tmu, unsigned char **tstr) @arg callback Callback function. @arg repetitions Number of repetitions, 0 for infinite. */ -void timer_set(int timer, int delay, int prescaler, void (*callback)(void), +void timer_start(int timer, int delay, int prescaler, void (*callback)(void), int repetitions) { // Getting the timer address. Using a byte to alter TSTR.