I've been using the Atmega 328p's INT0 interrupt to trigger on the rising edge of a signal, but the interrupt triggers just once and does so intermittently. I find this strange considering that INT1 and PCINT, configured on PD6, work without any issues. I've been looking through the forums and can't seem to find anyone who's had the same issue. The datasheet did have something that seemed interesting pertaining to automatically clearing the interrupt flag when using level detection, but after testing I doubt that it is the issue.
So far I've experimented with:
1) Clearing the flag by "hand"
2) Use level detection rather then edge detection
3) Using an oscilloscope to troubleshoot electrical problems
A. Checked signal integrity
B. Signal gets from point A to point B
C. Signal respects logic levels
4) Other inputs (Hooked up directly to VCC (switch) ,used a known signal from another board, function generator)
5) Commenting all of the code except initIO(), initInterrupt() and the ISR
The issue still persists, so I suspect it's either a configuration error or a hardware issue. I'll swap in another chip, but in the mean time I wanted to see if anyone else had a similar problem or could provide some insight.
ISR(INT0_vect) { PORTB|= _BV(PORTB2); uint8_t tempState = (uint8_t)EV_BUTTON; writeRingBuffer(&eventBuf,&tempState); //EIFR = _BV(INTF0); // Clears the INT0 and INT1 flags } // Ready detect ISR(INT1_vect) { if(bit_is_set(PIND, PD3) != 0) { uint8_t tempState = (uint8_t)EV_READY; writeRingBuffer(&eventBuf,&tempState); } else { uint8_t tempState = (uint8_t)EV_NOT_READY; writeRingBuffer(&eventBuf,&tempState); } } // Carrier detect ISR(PCINT2_vect) { if(bit_is_set(PIND, PD6) != 0) { uint8_t tempState = (uint8_t)EV_CONNECTED; writeRingBuffer(&eventBuf,&tempState); } else { uint8_t tempState = (uint8_t)EV_CONNECTION_CLOSED; writeRingBuffer(&eventBuf,&tempState); } } // UART interrupt ISR(USART_RX_vect){ unsigned char temp = (unsigned char)UDR0; //read UART register into value writeRingBuffer(&recBuf,&temp); } // Timer overflow interrupt // This frequency should be 488Hz, 8MHZ/(256*64) ISR(TIMER0_OVF_vect){ // Look at the clock preformance and figure the possible drift as well as the impacts on your time out functions // Consider using the 8MHz clock if drift is too great tickCount +=1; if((tickCount&0xFF) == 0) // Mask increases freq { checkCurrentState = true; } if((tickCount&0x07) < 2 && currentState.associatedState > ST_REBOOT) // Mask increases freq { PORTB|= _BV(PORTB1); if(currentState.associatedState > ST_CONNECTED) PORTD |= _BV(PORTD7); } else { // PORTD &= ~_BV(PORTD7) ; PORTB &= ~_BV(PORTB1); } } int main(void) { // Reception and event buffers unsigned char recievingBuffer[MAX_REC_BUFFER_SIZE],eventBuffer[MAX_EVENT_BUFFER_SIZE]; initRingBuffer(&recBuf,MAX_REC_BUFFER_SIZE,recievingBuffer,false); initRingBuffer(&eventBuf,MAX_EVENT_BUFFER_SIZE,eventBuffer,false); // Init tick counter tickCount = 0; // Init state // Makes sure we start in the correct state currentState.associatedState = 99; // Magic number to trigger the protection condition uint8_t tempState = (uint8_t)EV_NO_EVENT; writeRingBuffer(&eventBuf,&tempState); updateState(&eventBuf); // Finds initial state // Init peripheral devices initIO(); initTimer(); initUART(); initInterrupts(); reset(); // Possibly implement brownout // Brown-out Detection chapter 11.5 // Turn off unused peripherals powerOffPeripheralDevices(); #if PRINT_DEBUG_STATEMENTS // Debug port dbg_tx_init(); #endif // End of PRINT_DEBUG_STATEMENTS while (1) { #if DEBUG_STATE_MATRIX printStateTransitions(); for(int i = 0; i <400;i++) _delay_ms(10); #else PRINT_DEBUG_STATEMENT(currentState.associatedState +40); // +40 makes the state visible currentState.func(); #endif // End of DEBUG_STATE_MATRIX } }
void initInterrupts() { UCSR0B |= _BV(RXCIE0); // Sets Rx interupt enable (KEEP THE PIPE) EICRA = _BV(ISC01) | _BV(ISC00) | _BV(ISC10); // Rising edge detection for INT0 and logic change detection for INT0 EIMSK = _BV(INT1) | _BV(INT0); // Enables both INT0&INT1 PCICR = _BV(PCIF2); // Enables PCINT[23:16] PCMSK2 = _BV(DDD6); // Sets the interupt on PD6 TIMSK0 = _BV(TOIE0); // Enables timer overflow interrupt sei(); // Enable global interrupt } void powerOffPeripheralDevices() { // Can we shut off the SPI and still reprogram? PRR = _BV(PRTWI) | _BV(PRTIM2) | _BV(PRTIM1) | _BV(PRADC); // Consider adding SPI, not sure if that impacts the programmer.. } void initIO() { DDRB = _BV(DDB5); // To be removed later, currently used to debug DDRB |= _BV(DDB2); // To be removed later, currently used to debug DDRB |= _BV(DDB1); // Ready state light DDRD = _BV(DDD7); // Carrier detect light DDRD |= _BV(DDD4); // PTT DDRD |= _BV(DDD5); // RESET DDRD &= ~_BV(DDD2); // User input DDRD &= ~_BV(DDD3); // Ready state input DDRD &= ~_BV(DDD6); // CD state input if(bit_is_set(PIND, PD3)) PORTB |= _BV(PORTB1); else PORTB &= ~_BV(PORTB1); if(bit_is_set(PIND, PD6)) PORTD |= _BV(PORTD7); else PORTD &= ~_BV(PORTD7); } void initTimer() { TCCR0A = 0; TCCR0B = _BV(CS00) | _BV(CS01); } void initUART() { UBRR0H = (BAUD_PRESCALER>>8); UBRR0L = (BAUD_PRESCALER); UCSR0A = _BV(U2X0); UCSR0B = _BV(RXEN0) | _BV(TXEN0); UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); }
If you feel the need to see more code, don't hesitate to ask. Thank you ahead of time,
Felix