Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[ATmega32U4][avr-gcc] - Timer0 - niezrozumiałe zachowanie

lucasz 06 Lis 2013 23:21 1248 5
  • #1 06 Lis 2013 23:21
    lucasz
    Poziom 7  

    Witam jestem nowy na forum i w mikrokontrolerach. Po wielu godzinach doszedłem do tego, że aby instrukcja zawarta w ISR została wykonana muszę dorzucić pewną ilość cykli zegarowych w postaci np. pętli "for". Czy ktoś może mi pomóc zrozumieć dlaczego tak się dzieje ? Niezrozumiałe jest także to, dlaczego w pliku "*.lss" po funkcji "main" jest polecenie "RET".

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0 5
  • #2 06 Lis 2013 23:25
    dondu
    Moderator Mikrokontrolery Projektowanie

    Witaj.
    Pętla główna musi być nieskończona, a Twoja się kończy :)
    Zastosuj:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    Nie definiuj zegara w kodzie z tych powodów: http://mikrokontrolery.blogspot.com/2011/03/fcpu-gcc-gdzie-definiowac.html

    Używaj zdefiniowanych nazw pinów np. PF7:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    0
  • #3 06 Lis 2013 23:29
    excray
    Poziom 39  

    lucasz napisał:
    dlaczego w pliku "*.lss" po funkcji "main" jest polecenie "RET".
    Jak sam zauważyłeś main jest funkcją. Funkcją która u Ciebie zwraca int. RET jest asemblerową komendą powrotu z funkcji stąd z asemblerze jest RET. Jakbyś zwrócił uwagę na samym początku pliku *.lss funkcja main jest wywoływana właśnie komemdą CALL stąd kończy się też RET.
    Kod: asm
    Zaloguj się, aby zobaczyć kod

    A co do problemu z ISR to ja nie zauważyłem u siebie żadnego problemu więc może zobacz jaką masz optymalizację włączoną.
    Kod: asm
    Zaloguj się, aby zobaczyć kod

    0
  • #4 06 Lis 2013 23:43
    dondu
    Moderator Mikrokontrolery Projektowanie

    To ja jeszcze dodam, że przy braku pętli nieskończonej w main po powrocie (jak u Ciebie) wykonywany jest skok do _exit:

    Kod: asm
    Zaloguj się, aby zobaczyć kod


    a tam jest :

    Kod: asm
    Zaloguj się, aby zobaczyć kod

    zablokowanie przerwań i pętla __stop_program, ... czyli wrażenie zawieszenia się mikrokontrolera, przy działających timerach itp.

    0
  • #5 07 Lis 2013 07:07
    lucasz
    Poziom 7  

    Dziękuję za szybkie odpowiedzi i rady. Nie wiedziałem, że petla musi być nieskończona i nie zauwazyłem skoku do "exit", instrukcji "cli" oraz pętli "_stop program". Myślałem, że po ostatniej instrukcji w funkcji "main" są wykonywane nopy, a tu się okazało że main jest podprogramem. Możecie wyjaśnić dlaczego "main" jest podprogramem ? Z czego wykonywany jest skok do "main" ?

    0
  • #6 09 Lis 2013 09:32
    lucasz
    Poziom 7  

    Odpowiem na własne pytanie zamieszczając cytat z avrfreaks forum. Autor: clawson.

    "This is dependent on your C compiler. In the case of GCC there is some "hidden" assembler:
    Code:
    0x0000 JMP reset
    0x0001
    .. interrupt vector table
    0x00NN
    0x00NN+1 reset: clear register R1
    0x00NN+2 clear SREG (including I)
    0x00NN+3 set stack pointer
    0x00NN+4 if .data vars copy from flash to RAM
    0x00NN+X if .bss vars wipe their RAM
    0x00NN+Y CALL main (enters your program)
    0x00NN+Z JMP _exit
    ..
    .. the code of your main()
    ..
    0xMMMM _exit: CLI (prevent interrrupts)
    0xMMMM+1 _stop_program:
    RJMP _stop_program

    So there is a CALL to main() so if the code ever reaches a "return" or the last '}' in main() it will return back to the instruction after the CALL. This is a jump to a label called "_exit". At that location is a CLI opcode which turns off any possible interrupts and then the very next opcode is an RJMP that simply jumps back to the same RJMP.

    So the processor does not "stop". It continues fetching opcodes it's simply that it's the very same opcode over and over again and nothing can break it out of the loop (because of the CLI).

    For GCC this means that if you have a program with the structure:
    Code:
    main() {
    configure stuff
    enable interrupts
    }

    ISR_handler() {
    do all the work
    }

    this STILL needs an empty, infinite loop:
    Code:
    main() {
    configure stuff
    enable interrupts
    while(1);
    }

    because if the code returns from main() it does a CLI before the infinite loop and so the ISR_handler will never get called and everything comes to a complete stop (apart from that RJMP being fetched and executed infinitely).

    Your C compiler may vary - either look at its generated code to see how it enters/exits main() and what happens next or consult its user manual.

    Cliff"

    0