To start we need to look at the board schematic and determine how the MMC slot is wired to the micro controller. The schematic shows the MMC slot in the upper right corner. Notice that pins 13 and 15 on the MMC slot are labeled "cp1" and "cp2". "cp", in this case stands for "card presence". Examining the schematic further we see that pin 15 is wired to ground with a resistor and pin 13 is wired to power and is also labeled "cp" indicating it is connected to the micro controller. Looking at the micro controller block in the schematic pin PD1 is also labeled "cp" so we can conclude that this is pin connected to the card presence circuit on the MMC slot.
Judging from the schematic we can conclude that PD1 will be a logic high when there is no card and logic low when a card is inserted. You can test this theory for yourself using a multi meter. Set up your meter to measure DC voltage. Attached the black prob to the ground pin and the red prob to the PD1 pin. Power the board and the meter on. The meter will read 3.3 volts. Now insert a card and watch what happens. With a card inserted your meter should read near zero volts.
Next we need to figure out how the interrupt mechanism of the micro controller works. The relevant documentation is in chapter 12 page 84 of the AT90USB data sheet. The interrupt documentation for the avr-libc library is also helpful reading. Note: PD1 also happens to be the same as INT1 or External Interrupt #1
From these two documents we learn that the interrupt can be programed to trigger in four different ways outlined in table 12-1. We want it to trigger whenever there is any change in the value of PD1 so we will need to set ISC11 to zero and ISC10 to one in the EICRA register. Also the the INT1 bit in the EIMSK register will need to be set to enable external interrupt #1. Putting it altogether this is what the code looks like.
#include <avr/io.h>
#include <avr/wdt.h>
#include <avr/sleep.h>
#include <avr/interrupt.h>
#define MMC_IS_PRESENT() (!(PIND & _BV(PIND1)))
#define LED_ON() (PORTD |= _BV(PD4))
#define LED_OFF() (PORTD &= ~_BV(PD4))
int main(int argc, char **argv) {
/* disable the watch dog timer */
MCUSR &= ~_BV(WDRF);
wdt_disable();
/* setup card presence input */
DDRD &= ~_BV(DDD1);
PORTD &= ~_BV(PD1);
/* setup interrupt */
EICRA |= _BV(ISC10);
EICRA &= ~_BV(ISC11);
EIMSK |= _BV(INT1);
/* setup LED in correct state */
DDRD |= _BV(DDD4);
if (MMC_IS_PRESENT()) { LED_ON(); }
else { LED_OFF(); }
sei(); /* enable interrupts */
while(1) { sleep_mode(); }
return 0;
}
/* Interrupt routine */
ISR(INT1_vect) {
if (MMC_IS_PRESENT()) { LED_ON(); }
else { LED_OFF(); }
return;
}
Full code with makefile is available on Github A good exercise is to try modifying the above code to also turn the led on whenever the joystick is clicked.
No comments:
Post a Comment