0

Currently, I am implementing a stop watch using atmega32 and six 7-segment.

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

unsigned char sec1,sec2,min1,min2,hours1,hours2;
unsigned char finished_flag = 0;

int main(){
    DDRC |= 0x0F;                       //PC0 - PC3 ARE OUTPUT
    DDRA |= 0x3F;                       //PA0 - PA5 ARE OUTPUT
    DDRD &= ~((1<<PD2) | (1<<PD3));     // PD2 , PD3 ARE INPUT
    DDRB &= ~(1<<PB2);                  // PB2 IS INPUT

    //ACTIVATING THE INTERNAL PULL-UP FOR PD2 AND PB2
    PORTD |= 1<<PD2;
    PORTB |= 1<<PB2;
    PORTC &= (0xF0);  //ZERO IS THE INITIAL VALUE FOR THE SIX 7-SEGMENTS.

    SREG |= 1<<7;
    timer1();
    interrupt_int0();
    interrupt_int1();
    interrupt_int2();

    for(;;){
        if(finished_flag){
            TCCR1A = 0;
            TCCR1B = 0;
            sec1 = 9, sec2 = 9, min1 = 9, min2 = 9; hours1 = 9, hours2 = 9;
        }
        display_six_7_segment();
    }

}

then when I run the program on proteus, it says:

"PC=0x1976. [AVR MEMORY] Writing to memory location 0x08BE outside of memory size 0x0860. [U1]"

and it resets my program because it returns the address to the org 0x0000 as showed below:

"PC=0x0000. [AVR CPU] RETI address = 0x0000 [U1]".

I need to know how to reduce the usage of the memory because I only use 7 global variables (6 for each 7-segment and finished_flag variable) and the rest of the code includes ISRs for the external interrupts and timer interrupts.

SOLVED!!!

The problem was in the code of display_six_7_segment(); function.

this is the code before editing:

void display_six_7_segment(){
    PORTA = (1<<PA5) | (PORTA & 0xC0);
    PORTC = (sec1 & 0x0F) | (PORTC & 0xF0);
    _delay_us(2);

    PORTA = (1<<PA4) | (PORTA & 0xC0);
    PORTC = (sec2 & 0x0F) | (PORTC & 0xF0);
    _delay_us(2);

    PORTA = (1<<PA3) | (PORTA & 0xC0);
    PORTC = (min1 & 0x0F) | (PORTC & 0xF0);
    _delay_us(2);

    PORTA = (1<<PA2) | (PORTA & 0xC0);
    PORTC = (min2 & 0x0F) | (PORTC & 0xF0);
    _delay_us(2);

    PORTA = (1<<PA1) | (PORTA & 0xC0);
    PORTC = (hours1 & 0x0F) | (PORTC & 0xF0);
    _delay_us(2);

    PORTA = (1<<PA0) | (PORTA & 0xC0);
    PORTC = (hours2 & 0x0F) | (PORTC & 0xF0);
    _delay_us(2);
}

what I did is just replacing _delay_us(2); with _delay_ms(2);, and then the project worked finely without resetting or errors.

But actually I don't understand what is the problem with _delay_us(2); I know it's very short time but that is what we want to display the six 7-segment at the same time.

  • Your program aborts when `PC=0x1976` Convert that to a line number in your [single] `.c` file. Then, we can see the line of C code that causes the error. Your ISR routine can _not_ produce this error directly [AFAICT]. So, we need to see _all_ of your code. Please _edit_ your question and post this in a code block. I'm not familiar with atmega32 interrupts, but your ISR does _not_ clear the "interrupt pending flag" for the timer. Does the [hidden] prolog/epilog code do this? – Craig Estey Sep 14 '22 at 19:02
  • how can I convert the pc number "0x1976" to a line number in my ```.c``` file? – Ahmed Halim Sep 14 '22 at 22:05
  • In AVR MCUs, the interrupt flag is cleared automatically at the end of the ISR so I don't have to clear it by myself. – Ahmed Halim Sep 14 '22 at 22:09
  • @Craig I managed to solve the problem but actually I don't understand why is this a solution. I've edited my question so you can see it. – Ahmed Halim Sep 14 '22 at 23:44
  • Why writing to the same port 6 times when you could do `PORTA |= 1< – hcheung Sep 16 '22 at 02:24
  • @hcheung I think that would make that multiplexing bit difficult – KIIV Sep 17 '22 at 11:46
  • I guess the problem is in some ISR routine. Reported error is tied with IRET instruction. This instruction is used to return from interrupts. It's look like stack overflow or unwanted modification of the stack frames. And in declaration `finished_flag` variable have to use `volatile` qualifier. – Peter Plesník Sep 27 '22 at 17:59

0 Answers0