136 lines
3.8 KiB
C
136 lines
3.8 KiB
C
/* sd2snes - SD card based universal cartridge for the SNES
|
|
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
|
|
This file was adapted from sd2iec, written by Ingo Korb.
|
|
Original copyright header follows:
|
|
*/
|
|
/* sd2iec - SD/MMC to Commodore serial bus interface/controller
|
|
Copyright (C) 2007-2009 Ingo Korb <ingo@akana.de>
|
|
|
|
Inspiration and low-level SD/MMC access based on code from MMC2IEC
|
|
by Lars Pontoppidan et al., see sdcard.c|h and config.h.
|
|
|
|
FAT filesystem access based on code from ChaN and Jim Brain, see ff.c|h.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License only.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
|
timer.c: System timer (and button debouncer)
|
|
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <avr/interrupt.h>
|
|
#include <avr/io.h>
|
|
#include "avrcompat.h"
|
|
#include "led.h"
|
|
#include "timer.h"
|
|
|
|
volatile tick_t ticks;
|
|
// Logical buttons
|
|
volatile uint8_t active_keys;
|
|
|
|
// Physical buttons
|
|
uint8_t buttonstate;
|
|
tick_t lastbuttonchange;
|
|
|
|
/* Called by the timer interrupt when the button state has changed */
|
|
static void buttons_changed(void) {
|
|
/* Check if the previous state was stable for two ticks */
|
|
if (time_after(ticks, lastbuttonchange+2)) {
|
|
if (active_keys & IGNORE_KEYS) {
|
|
active_keys &= ~IGNORE_KEYS;
|
|
} else if (!(buttonstate & (BUTTON_PREV|BUTTON_NEXT))) {
|
|
/* Both buttons held down */
|
|
active_keys |= KEY_HOME;
|
|
} else if (!(buttonstate & BUTTON_NEXT) &&
|
|
(BUTTON_PIN & BUTTON_NEXT)) {
|
|
/* "Next" button released */
|
|
active_keys |= KEY_NEXT;
|
|
} else if (!(buttonstate & BUTTON_PREV) &&
|
|
(BUTTON_PIN & BUTTON_NEXT)) {
|
|
active_keys |= KEY_PREV;
|
|
}
|
|
}
|
|
|
|
lastbuttonchange = ticks;
|
|
buttonstate = BUTTON_PIN & BUTTON_MASK;
|
|
}
|
|
|
|
/* The main timer interrupt */
|
|
ISR(TIMER1_COMPA_vect) {
|
|
uint8_t tmp = BUTTON_PIN & BUTTON_MASK;
|
|
|
|
if (tmp != buttonstate) {
|
|
buttons_changed();
|
|
}
|
|
|
|
ticks++;
|
|
|
|
#ifdef SINGLE_LED
|
|
if (led_state & LED_ERROR) {
|
|
if ((ticks & 15) == 0)
|
|
DIRTY_LED_PORT ^= DIRTY_LED_BIT();
|
|
} else {
|
|
if ((led_state & LED_BUSY) || (led_state & LED_DIRTY)) {
|
|
DIRTY_LED_ON();
|
|
} else {
|
|
DIRTY_LED_OFF();
|
|
}
|
|
}
|
|
#else
|
|
if (led_state & LED_ERROR)
|
|
if ((ticks & 15) == 0)
|
|
DIRTY_LED_PORT ^= DIRTY_LED_BIT();
|
|
#endif
|
|
|
|
/* Sleep button triggers when held down for 2sec */
|
|
if (time_after(ticks, lastbuttonchange+2)) {
|
|
if (!(buttonstate & BUTTON_NEXT) &&
|
|
(buttonstate & BUTTON_PREV) &&
|
|
time_after(ticks, lastbuttonchange+2*HZ) &&
|
|
!key_pressed(KEY_SLEEP)) {
|
|
/* Set ignore flag so the release doesn't trigger KEY_NEXT */
|
|
active_keys |= KEY_SLEEP | IGNORE_KEYS;
|
|
/* Avoid triggering for the next two seconds */
|
|
lastbuttonchange = ticks;
|
|
}
|
|
}
|
|
#if CONFIG_RTC_VARIANT == 1
|
|
increment_rtc();
|
|
#endif
|
|
|
|
#ifdef CONFIG_REMOTE_DISPLAY
|
|
/* Check if the display wants to be queried */
|
|
if (!(SOFTI2C_PIN & _BV(SOFTI2C_BIT_INTRQ))) {
|
|
active_keys |= KEY_DISPLAY;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void timer_init(void) {
|
|
/* Count F_CPU/8 in timer 0 */
|
|
TCCR0B = _BV(CS01);
|
|
|
|
/* Set up a 100Hz interrupt using timer 1 */
|
|
OCR1A = 1249;
|
|
TCNT1 = 0;
|
|
TCCR1A = 0;
|
|
TCCR1B = _BV(WGM12) | _BV(CS10) | _BV(CS11);
|
|
TIMSK1 |= _BV(OCIE1A);
|
|
|
|
/* Buttons */
|
|
BUTTON_DDR &= (uint8_t)~BUTTON_MASK;
|
|
BUTTON_PORT |= BUTTON_MASK;
|
|
}
|