/* * ATmega8A Pin Cycling Test * Version 2: Array in RAM * * Cycles through PB0–PB5, PC0–PC5, PD0–PD7. * Every 200 ms: one pin is driven low, then returned to input with pull-up, * then the next pin is selected. * * Same as version 1, but lookup table loaded to RAM on startup. */ #include #include #include #include #include typedef struct { uint16_t ddrAddr; uint16_t portAddr; uint8_t mask; } PinDesc; // --- Array of test pins in flash (PROGMEM) --- // Use addresses cast to uint16_t PinDesc testPins[] = { { (uint16_t)&DDRB, (uint16_t)&PORTB, _BV(PB0) }, { (uint16_t)&DDRB, (uint16_t)&PORTB, _BV(PB1) }, { (uint16_t)&DDRB, (uint16_t)&PORTB, _BV(PB2) }, { (uint16_t)&DDRB, (uint16_t)&PORTB, _BV(PB3) }, { (uint16_t)&DDRB, (uint16_t)&PORTB, _BV(PB4) }, { (uint16_t)&DDRB, (uint16_t)&PORTB, _BV(PB5) }, { (uint16_t)&DDRC, (uint16_t)&PORTC, _BV(PC0) }, { (uint16_t)&DDRC, (uint16_t)&PORTC, _BV(PC1) }, { (uint16_t)&DDRC, (uint16_t)&PORTC, _BV(PC2) }, { (uint16_t)&DDRC, (uint16_t)&PORTC, _BV(PC3) }, { (uint16_t)&DDRC, (uint16_t)&PORTC, _BV(PC4) }, { (uint16_t)&DDRC, (uint16_t)&PORTC, _BV(PC5) }, { (uint16_t)&DDRD, (uint16_t)&PORTD, _BV(PD0) }, { (uint16_t)&DDRD, (uint16_t)&PORTD, _BV(PD1) }, { (uint16_t)&DDRD, (uint16_t)&PORTD, _BV(PD2) }, { (uint16_t)&DDRD, (uint16_t)&PORTD, _BV(PD3) }, { (uint16_t)&DDRD, (uint16_t)&PORTD, _BV(PD4) }, { (uint16_t)&DDRD, (uint16_t)&PORTD, _BV(PD5) }, { (uint16_t)&DDRD, (uint16_t)&PORTD, _BV(PD6) }, { (uint16_t)&DDRD, (uint16_t)&PORTD, _BV(PD7) } }; #define NUM_PINS (sizeof(testPins)/sizeof(testPins[0])) volatile uint8_t currentPin = 0; volatile uint8_t toggleState = 0; // --- Timer1 Compare ISR --- ISR(TIMER1_COMPA_vect) { PORTB ^= _BV(PB0); // toggle PB0 to signal ISR run // Get current pin description from RAM uint16_t ddrAddr = testPins[currentPin].ddrAddr; uint16_t portAddr = testPins[currentPin].portAddr; uint8_t mask = testPins[currentPin].mask; volatile uint8_t *ddr = (volatile uint8_t*)ddrAddr; volatile uint8_t *port = (volatile uint8_t*)portAddr; /* Also tried: volatile uint8_t *ddr = testPins[currentPin].ddr; volatile uint8_t *port = testPins[currentPin].port; uint8_t mask = testPins[currentPin].mask; */ if (toggleState == 0) { // --- Switch current pin to OUTPUT, drive low --- *ddr |= mask; // set DDRx bit = 1 → output *port &= ~mask; // clear PORTx bit = 0 → low toggleState = 1; } else { // --- Switch current pin back to INPUT, pull-up on --- *ddr &= ~mask; // clear DDRx bit = 0 → input *port |= mask; // set PORTx bit = 1 → pull-up enabled // advance to next pin currentPin++; if (currentPin >= NUM_PINS) { currentPin = 0; } toggleState = 0; } } static void pins_init(void) { DDRB = 0x00; DDRC = 0x00; DDRD = 0x00; PORTB = 0xFF; PORTC = 0xFF; PORTD = 0xFF; DDRB |= _BV(PB0); // PB0 as output PORTB &= ~_BV(PB0); } static void timer1_init(void) { //TCCR1A = 0; TCCR1B = (1 << WGM12) | (1 << CS12); // CTC, prescaler 256 //TCNT1 = 0; OCR1A = 12500 - 1; TIMSK |= (1 << OCIE1A); } int main(void) { for (uint8_t i=0; i<5; i++) { // check if array got loaded and flash PD2 if (testPins[i].ddrAddr != 0) { DDRD |= _BV(PD2); PORTD ^= _BV(PD2); _delay_ms(200); } } pins_init(); timer1_init(); sei(); set_sleep_mode(SLEEP_MODE_IDLE); for (;;) sleep_mode(); }