|
| 1 | +#ifndef F_CPU |
| 2 | +#define F_CPU 8000000 |
| 3 | +#endif |
| 4 | +#include <avr/io.h> |
| 5 | +#include <stdio.h> |
| 6 | +#include <avr/interrupt.h> |
| 7 | +#include <avr/sleep.h> |
| 8 | + |
| 9 | +/* |
| 10 | + * This demonstrate how to use the avr_mcu_section.h file |
| 11 | + * The macro adds a section to the ELF file with useful |
| 12 | + * information for the simulator |
| 13 | + */ |
| 14 | +#include "avr_mcu_section.h" |
| 15 | +AVR_MCU(F_CPU, "atmega48"); |
| 16 | + |
| 17 | +/* This program is very similar to atmega168_test.c, but runs with pull-ups |
| 18 | + * disabled, both by the next macro and by setting the PUD bit in MCUCR. |
| 19 | + * Comment out one or both to check that both ways work. |
| 20 | + */ |
| 21 | + |
| 22 | +AVR_MCU_PORT_NO_PULL; // Pull-ups disabled in simulator. |
| 23 | + |
| 24 | +static int uart_putchar(char c, FILE *stream) { |
| 25 | + if (c == '\n') |
| 26 | + uart_putchar('\r', stream); |
| 27 | + loop_until_bit_is_set(UCSR0A, UDRE0); |
| 28 | + UDR0 = c; |
| 29 | + return 0; |
| 30 | +} |
| 31 | + |
| 32 | +static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, |
| 33 | + _FDEV_SETUP_WRITE); |
| 34 | + |
| 35 | +ISR(INT0_vect) |
| 36 | +{ |
| 37 | + printf("I<%02X ", PIND); |
| 38 | +} |
| 39 | + |
| 40 | +ISR(PCINT0_vect) |
| 41 | +{ |
| 42 | + printf("K "); |
| 43 | +} |
| 44 | + |
| 45 | +ISR(PCINT2_vect) |
| 46 | +{ |
| 47 | + printf("J<%02X ", PORTD); |
| 48 | + PORTD = 0; |
| 49 | +} |
| 50 | + |
| 51 | +int main() |
| 52 | +{ |
| 53 | + stdout = &mystdout; |
| 54 | + |
| 55 | + MCUCR |= _BV(PUD); // Pull-ups disabled by "hardware". |
| 56 | + |
| 57 | + /* Enable output on Port D pins 0-3 and write to them. */ |
| 58 | + |
| 59 | + DDRD = 0xf; |
| 60 | + PORTD = 0xa; |
| 61 | + |
| 62 | + printf("P<%02X ", PIND); // Should say P<2A as caller sets bit 5. |
| 63 | + |
| 64 | + /* Toggle some outputs and PORTD bits. */ |
| 65 | + |
| 66 | + PIND = 3; // PORTD == 0x09, pins now 0x29 |
| 67 | + |
| 68 | + /* Change directions. */ |
| 69 | + |
| 70 | + DDRD = 0x3c; // Pins now 0x9 |
| 71 | + |
| 72 | + /* Change output. */ |
| 73 | + |
| 74 | + PORTD = 0xf0; |
| 75 | + |
| 76 | + /* This should say P<30 - the controlling program turns off bit 0. */ |
| 77 | + |
| 78 | + printf("P<%02X ", PIND); |
| 79 | + |
| 80 | + /* Set-up rising edge interrupt on pin 2 (INT 0). */ |
| 81 | + |
| 82 | + EICRA = 3; |
| 83 | + EIMSK = 1; |
| 84 | + |
| 85 | +#ifdef NOTYET |
| 86 | + /* Clear external interrupt flags, but INT0 (PD3) will |
| 87 | + * immediately reset, as the pin is low. |
| 88 | + */ |
| 89 | + |
| 90 | + EIFR = 0xff; |
| 91 | +#endif |
| 92 | + /* Turn off pin 4, signal the controlling program to raise pin 2. */ |
| 93 | + |
| 94 | + PORTD = 0xe0; |
| 95 | + |
| 96 | + /* Verify the interrupt flag is set. Result should be 3. */ |
| 97 | + |
| 98 | + printf("F<%02X ", EIFR); |
| 99 | + |
| 100 | + sei(); |
| 101 | + |
| 102 | + /* This duplicates the value in the INT0 handler, but it |
| 103 | + * takes sufficient time to be sure that there is only one |
| 104 | + * interrupt. There was a bug that caused continuous interrupts |
| 105 | + * when this was first tried. |
| 106 | + */ |
| 107 | + |
| 108 | + printf("P<%02X ", PIND); |
| 109 | + |
| 110 | + /* TODO: Test the level-triggered interupt. It can be started |
| 111 | + * by a pin-value change or by writing to either of EICRA and EIMSK. |
| 112 | + */ |
| 113 | + |
| 114 | + /* Try pin change interrupt. */ |
| 115 | + |
| 116 | + PCICR = (1 << PCIE2); /* Interrupt enable. */ |
| 117 | + PCMSK2 = 0x0a; /* Pins 1 and 3. */ |
| 118 | + DDRD = 3; |
| 119 | + PORTD = 1; /* No interrupt. */ |
| 120 | + PORTD = 3; /* Interrupt. */ |
| 121 | + |
| 122 | + /* Allow time for second interrupt. */ |
| 123 | + |
| 124 | + printf("P<%02X ", PIND); |
| 125 | + |
| 126 | + // Test "write 1 to clear" on PORT B. |
| 127 | + |
| 128 | + DDRB = 0xff; |
| 129 | + PCICR = (1 << PCIE0); /* Interrupt enable. */ |
| 130 | + PCMSK0 = 3; /* Pins 0 and 1. */ |
| 131 | + cli(); |
| 132 | + PORTB = 1; |
| 133 | + PCIFR = 1; /* Clear interrupt. */ |
| 134 | + sei(); |
| 135 | + printf("| "); |
| 136 | + cli(); |
| 137 | + PORTB = 3; |
| 138 | + PCIFR = 6; |
| 139 | + sei(); /* Interrupt. */ |
| 140 | + printf("| "); |
| 141 | + |
| 142 | + /* Prompt for input with IOPORT_IRQ_PIN_ALL_IN. */ |
| 143 | + |
| 144 | + DDRB = 2; |
| 145 | + printf("P<%02X ", PIND); // Should get 98, not 99 because DDRD == 3. |
| 146 | + |
| 147 | + // this quits the simulator, since interupts are off |
| 148 | + // this is a "feature" that allows running tests cases and exit |
| 149 | + cli(); |
| 150 | + sleep_cpu(); |
| 151 | +} |
0 commit comments