logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

ATmega8 + WinAVR + optymalizacja = dziwny wynik kompilacji

kl4m4 15 Paź 2008 00:34 2153 13
  • #1 5632844
    kl4m4
    Poziom 10  
    Witam,
    Programuję w C Atmege8 za pomocą AVR Studio 4.14 i WinAVR 20080610. W funkcji main() po kilku podstawowych operacjach typu ustawienie kierunku portów chcę wywołać funkcję która na razie nic nie zwraca:
    unsigned char ResetPulse(){
    	return 0;
    }
    

    Okazuje się że po wywołaniu tej funkcji w dalszej części programu mikrokontroler się zawiesza (a na pewno nie wykonuje dalszych poleceń), wykonuje tylko przerwania związane z obsługą wyświetlacza.
    Po skompilowaniu oglądam sobie Disassemblerem co z tego wychodzi, i oto wynik (tylko funkcja main):
    ---- main.c ---------------------------------------------------------------------------------------
    9:        int main(void){
    +0000002F:   D00D        RCALL   PC+0x000E        Relative call subroutine
    11:       	INITIALIZE_1WIRE;
    +00000030:   9A89        SBI     0x11,1           Set bit in I/O register
    +00000031:   9A91        SBI     0x12,1           Set bit in I/O register
    13:       	ucDigit1_char = 20;
    +00000032:   E184        LDI     R24,0x14         Load immediate
    +00000033:   9380007B    STS     0x007B,R24       Store direct to data space
    14:       	ucDigit2_char = 20;
    +00000035:   93800078    STS     0x0078,R24       Store direct to data space
    15:       	ucDigit3_char = 20;
    +00000037:   93800079    STS     0x0079,R24       Store direct to data space
    16:       	ucBlink = 0;
    +00000039:   9210007A    STS     0x007A,R1        Store direct to data space
    21:       	ucResetResult = ResetPulse();
    +0000003B:   D0D6        RCALL   PC+0x00D7        Relative call subroutine
    +0000003C:   CFFF        RJMP    PC-0x0000   
    

    Widać że kompilator zakończył main pustą pętlą, jednak w moim kodzie są dalej jeszcze polecenia. Gdy wyłączę optymalizację, sytuacja się poprawia i powstaje poprawny assembler, jednak już przy bardzo prostym programie potrzeba większości zasobów ATmegi, a w planach mam jeszcze sporo kodu. Czy ktoś wie jak obejść ten problem? Nadmienię, że nie jest to fikcyjny problem obserwowany tylko w disassemblerze, ale mikrokontroler faktycznie tak się zachowuje. Wiem że pisanie w asmie było by dużo oszczędniejsze i dałoby lepszą kontrolę nad kodem, ale naprawdę mam swoje powody by pisać w C.

    Pozdrawiam i czekam na pomoc,
    Mateusz K.
  • #3 5632876
    kl4m4
    Poziom 10  
    Oto cały main:
    #define F_CPU 4000000
    #include <avr/io.h>
    #include <util/delay.h>
    #include <avr/interrupt.h>
    #include "display.h"
    #include "1wire.h"
    
    int main(void){
    	Init_Display();
    	INITIALIZE_1WIRE;
    
    	ucDigit1_char = 20;
    	ucDigit2_char = 20;
    	ucDigit3_char = 20;
    	ucBlink = 0;
    
    
    	unsigned char ucResetResult=4;
    	ucResetResult = ResetPulse();
    	
    	ucDigit2_char = ucResetResult;
    	ucBlink = 1;
    
    	while(1){	
    	}
    }
    

    Ostatnie 2 polecenia już się nie wykonują
  • #5 5632892
    kl4m4
    Poziom 10  
    W main nie, ale są mi potrzebne, bo zmienna ucDigit2_char to jedna z cyfr wyświetlana na wyświetlaczu, a ucBlink steruje miganiem wyświetlacza. Więc zależy mi na nich.
  • #6 5633005
    bobbyAIR
    Poziom 20  
    dyrektywa volatile
  • #8 5634995
    bobbyAIR
    Poziom 20  
    Freddie ja bym z tymi rzadkimi to nie przesadzał. Wyobraź sobie np. że kompilator pewnej znanej firmy zmiennej globalnej nie zdeklarowanej jako statyczna używa sobie jako zmiennej tymczasowej przy innych operacjach (mam na mysli obszar pamięci gdzie ta zmienna siedzi). Wynik oczywiście jest losowy a dochodzenie czemu tak się dzieje potrafi sporo czasu zająć.
  • #9 5635051
    ZbeeGin
    Poziom 39  
    AVR GCC z pakietu WinAVR 20080610 jest bardzo agresywny i przy optymalizacji często nieskończona pętla while(1) zostaje przekształcona w RJMP +0 i... reszta programu jest pomijana! Doświadczyłem tego sam, jak i parę innych osób - nawet na tym fourm.

    Przykład skrócony (z forum):
    int main(void) 
    { 
      unsigned int sect; 
      timer_init(); 
      SPIinit(); 
    
        DDRD |= (1<<PD6) | (1<<PD7);
        PORTD = 0x40; 
        sei();                                   // enable interrupts 
        for(sect=0; sect<62760; sect++) 
        { 
          sendmmc(sect);
        } 
    
      while(1) 
      { 
        PORTD &= ~(1<<PD7); 
        _delay_ms(500); 
        PORTD |= (1<<PD7); 
        _delay_ms(500);    
      }
    }

    Przy optymalizacji "s" tego co po while(1) nie ma!! A symulacja potwierdza, że program się zapęta w pustym RJMP. Kompilacja w jednej z poprzedniej wersji WINAVR (z 2007 roku) nie powoduje tego błędu.
  • #10 5641692
    szeryf.rm
    Poziom 22  
    ZbeeGin napisał:
    AVR GCC z pakietu WinAVR 20080610 jest bardzo agresywny i przy optymalizacji często nieskończona pętla while(1) zostaje przekształcona w RJMP +0 i... reszta programu jest pomijana! Doświadczyłem tego sam, jak i parę innych osób - nawet na
    tym fourm.


    Umieść kod tak, żebym mógł go skompilować, bo jak zwykle nie wierzę. Mam ten kompilator, korzystam i nie takie cuda pisałem... Daj kod, który ma wszystko a potem napiszę ci, co zrobiłeś źle i co rozumiesz przez

    Cytat:
    Przy optymalizacji "s" tego co po while(1) nie ma!! A symulacja potwierdza, że program się zapęta w pustym RJMP. Kompilacja w jednej z poprzedniej wersji WINAVR (z 2007 roku) nie powoduje tego błędu.


    Moja wersja kompilatora, taka jak podałeś daje prawidłowy kod, brak zapętlenia. Mało tego, działa także:

    #include <avr/io.h>
    
    
    int main(void) 
    { 
       DDRD = 0;
       PORTD = 0;
       uint32_t l;
       while(1)
       {
          l++;
          if (PIND & _BV(1)) break;
       }
    
       PORTD = 0xFF;
    
       while(1);
    }
    




    A teraz od siebie. Panowie, o czym wy u licha gadacie. Jak patrzę na część postów to dostrzegam tutaj problem z mnóstwem osób, które ignorowały kurs j. C a teraz mają pretensje do świata o to... volatile to nie dyrektywa a specyfikator, podobnie jak const. Dyrektywy to są kompilatora np. #include, #define itd. To po pierwsze, ale zwał jak zwał, nie będę się tego czepiał. Polecam zapoznać się wszystkim z tym słówkiem, którzy jeszcze tego nie zrobili, bo są przyzwyczajeni, że działa tylko jeden program... ale tak nie jest. W rzeczywistości wszystko co wisi na przerywaniach jest innymi "wątkami"! Program główny zmiennej nie zmienia, ale może ją zmienić przerywanie i od tego jest volatile.

    A tak poza tym to radzę, by częściej niektórzy przed korzystaniem z przerywań zapoznali się chociażby z podstawami wielowątkowości w programach, bo potem widzę nie dość że ktoś pisze, że z O0 działa a z Os nie, to jeszcze jest tam taki myk, że program w części main korzysta ze zmiennych np 16 bitowych do zapisu i odczytu oraz przerywanie korzysta z tych samych zmiennych. Rzadko kto dostrzega problem, że program główny korzystając z tych zmiennych powinien wyłączyć przerywania!

    bobbyAIR rozwiń myśl o tej zmiennej statycznej i nie, bo się pogubiłem a chętnie się dowiem co kompilator robił źle (chyba że to jakiś dziwny kompilator i ma błąd)... jeszcze raz.

    PS. uczcie się C :) no i oczywiście te uwagi nie dotyczą ludzi co znają język np. ciebie Freddie Chopin :P - no chyba że znasz go średnio :)
  • #11 5641751
    ZbeeGin
    Poziom 39  
    szeryf.rm napisał:
    Umieść kod tak, żebym mógł go skompilować, bo jak zwykle nie wierzę. Mam ten kompilator, korzystam i nie takie cuda pisałem... Daj kod, który ma wszystko a potem napiszę ci, co zrobiłeś źle i co rozumiesz przez
    Cytat:
    Przy optymalizacji "s" tego co po while(1) nie ma!! A symulacja potwierdza, że program się zapęta w pustym RJMP. Kompilacja w jednej z poprzedniej wersji WINAVR (z 2007 roku) nie powoduje tego błędu.

    Moja wersja kompilatora, taka jak podałeś daje prawidłowy kod

    Kod do testowania. Różnica jest podczas włączenie -O0 a -Os.

    #include <avr/io.h> 
    #include <avr/interrupt.h> 
    #include <stdio.h> 
    #include <inttypes.h> 
    #include <util/delay.h> 
    
    
    unsigned char test[512] = 
    { 
      128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 
      128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 129, 127, 129, 128, 127, 133, 
      117, 109, 125, 121, 116, 132, 140, 126, 114, 114, 116, 120, 114, 93, 73, 66, 76, 116, 142, 129, 
      128, 129, 120, 119, 118, 104, 87, 123, 181, 194, 196, 198, 189, 176, 160, 162, 172, 164, 164, 183, 
      197, 188, 168, 167, 170, 165, 185, 209, 206, 196, 196, 199, 185, 162, 156, 167, 176, 173, 170, 166, 
      151, 142, 140, 134, 130, 127, 113, 86, 67, 66, 69, 75, 73, 75, 86, 90, 91, 84, 65, 48, 
      41, 30, 26, 56, 91, 88, 72, 70, 73, 82, 89, 73, 57, 60, 74, 89, 92, 77, 63, 60, 
      53, 47, 56, 64, 63, 61, 56, 54, 52, 36, 16, 22, 51, 66, 67, 70, 76, 88, 99, 92, 
      77, 74, 85, 100, 106, 97, 83, 85, 96, 108, 133, 160, 164, 144, 113, 96, 91, 82, 74, 76, 
      89, 97, 97, 97, 82, 54, 40, 41, 41, 43, 56, 74, 78, 64, 55, 64, 72, 72, 84, 102, 
      108, 116, 126, 127, 124, 127, 134, 134, 138, 148, 152, 156, 164, 165, 169, 171, 160, 156, 157, 152, 
      151, 145, 133, 136, 153, 166, 165, 163, 165, 161, 156, 158, 155, 147, 148, 160, 185, 209, 215, 220, 
      220, 204, 200, 208, 205, 200, 202, 209, 214, 213, 205, 198, 194, 194, 203, 219, 231, 235, 230, 219, 
      200, 184, 177, 170, 170, 177, 172, 164, 163, 158, 156, 160, 163, 161, 142, 116, 103, 96, 89, 93, 
      101, 105, 111, 116, 120, 110, 89, 80, 78, 75, 73, 80, 93, 91, 77, 69, 70, 77, 91, 98, 
      89, 87, 93, 95, 95, 94, 97, 96, 91, 94, 99, 100, 101, 95, 83, 78, 79, 71, 56, 41 
    }; 
    
    unsigned char znacznik_przerwania_timera = 0; 
    
    #define SPIDI   6   // Port B bit 6 (pin7): data in (data from MMC) 
    #define SPIDO   5   // Port B bit 5 (pin6): data out (data to MMC) 
    #define SPICLK  7   // Port B bit 7 (pin8): clock 
    #define SPICS   4   // Port B bit 4 (pin5: chip select for MMC 
    
    
    ISR(TIMER1_COMPA_vect) 
    { 
      znacznik_przerwania_timera = 1; 
    } 
    
    
    void timer_init(void) 
    { 
      TCCR0 = (1<<WGM01) | (1<<WGM00) | (1<<COM01) | (1<<COM00) | (0<<CS02) | (0<<CS01) | (1<<CS00);
      OCR0 = 0x00;
      DDRB |= (1<<PB3); 
      
      TCCR1A = (0<<WGM10) | (0<<WGM11); 
      TCCR1B = (0<<WGM13) | (1<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10); 
      OCR1A = 0x5DC; 
      TIMSK = (1<<OCIE1A); 
    } 
    
    void SPIinit(void) 
    { 
       DDRB &= ~(1<<SPIDI);     // set port B SPI data input to input 
       DDRB |= (1<<SPICLK);     // set port B SPI clock to output 
       DDRB |= (1<<SPIDO);      // set port B SPI data out to output 
       DDRB |= (1<<SPICS);      // set port B SPI chip select to output 
       SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); 
       PORTB &= ~(1<<SPICS);    // set chip select to low (MMC is selected) 
    } 
    
    char SPI(char d) 
    {  // send character over SPI 
       char received = 0; 
       
       SPDR = d; 
       while(!(SPSR & (1<<SPIF))); 
       received = SPDR; 
       return (received); 
    } 
    
    char Command(char cmd, uint32_t adr ) 
    {    
       SPI(0xFF); 
       SPI(cmd); 
       SPI((uint8_t)(adr >> 24)); 
       SPI((uint8_t)(adr >> 16)); 
       SPI((uint8_t)(adr >> 8)); 
       SPI((uint8_t)(adr)); 
       SPI(0xFF);    
       SPI(0xFF); 
       return SPI(0xFF); 
    } 
    
    
    int MMC_Init(void) 
    {  // init SPI 
       char i; 
       
       PORTB |= (1<<SPICS); 
       PORTB |= (1<<SPIDI); 
        
       // start MMC in SPI mode 
       for(i=0; i < 10; i++) SPI(0xFF); 
       PORTB &= ~(1<<SPICS); 
    
       if (Command(0x40,0) != 1) goto mmcerror; // reset MMC 
    
    st: // if there is no MMC, prg. loops here 
       if (Command(0x41,0) !=0) goto st; 
       return 1; 
    mmcerror: 
       return 0; 
    } 
    
    
    uint16_t sendmmc(uint32_t sector) //, uint16_t stop) { // send 512 bytes from the MMC via the serial port 
       { 
       int i; 
       // 512 byte-read-mode 
    //   uint8_t ix; 
    //   char r1 =  Command(0x51,sector); 
    
    //   for (ix = 0; ix < 50000; ix++) 
    //   { 
    //     if (r1 == (char)0x00) break; 
    //     r1 = SPI(0xFF); 
    //   } 
    
    //   if (r1 != (char)0x00) 
    //   { 
    //     return 1; 
    //   } 
    
    //   while(SPI(0xFF) != (char)0xFE); 
    
    
       for(i=0; i<512; i++) 
       { 
         znacznik_przerwania_timera = 0; 
         OCR0 = test[i]; //SPI(0xFF); 
         while(znacznik_przerwania_timera != 1); 
       } 
    // SPI(0xFF); 
    // SPI(0xFF); 
       return 0; 
    } 
    
    
    int main(void) 
    { 
      unsigned int sect; 
     //init(); 
      timer_init(); 
      SPIinit(); 
    
    //  if (MMC_Init() == 1) 
    //  { 
        DDRD |= (1<<PD6) | (1<<PD7);
        PORTD = 0x40; 
        sei();                                   // enable interrupts 
        for(sect=0; sect<62760; sect++) 
        { 
          sendmmc(sect);
        } 
    //  } 
    
      while(1) 
      { 
        PORTD &= ~(1<<PD7); 
        _delay_ms(500); 
        PORTD |= (1<<PD7); 
        _delay_ms(500);    
      }
    }


    To co widzi AVR Studio w main() przy optymalizacji -Os:

    @000000D3: main
    143:      { 
    +000000D3:   E789        LDI     R24,0x79         Load immediate
    +000000D4:   BF83        OUT     0x33,R24         Out to I/O location
    +000000D5:   BE1C        OUT     0x3C,R1          Out to I/O location
    +000000D6:   9ABB        SBI     0x17,3           Set bit in I/O register
    +000000D7:   BC1F        OUT     0x2F,R1          Out to I/O location
    +000000D8:   E089        LDI     R24,0x09         Load immediate
    +000000D9:   BD8E        OUT     0x2E,R24         Out to I/O location
    +000000DA:   ED8C        LDI     R24,0xDC         Load immediate
    +000000DB:   E095        LDI     R25,0x05         Load immediate
    +000000DC:   BD9B        OUT     0x2B,R25         Out to I/O location
    +000000DD:   BD8A        OUT     0x2A,R24         Out to I/O location
    +000000DE:   E180        LDI     R24,0x10         Load immediate
    +000000DF:   BF89        OUT     0x39,R24         Out to I/O location
    +000000E0:   98BE        CBI     0x17,6           Clear bit in I/O register
    +000000E1:   9ABF        SBI     0x17,7           Set bit in I/O register
    +000000E2:   9ABD        SBI     0x17,5           Set bit in I/O register
    +000000E3:   9ABC        SBI     0x17,4           Set bit in I/O register
    +000000E4:   E583        LDI     R24,0x53         Load immediate
    +000000E5:   B98D        OUT     0x0D,R24         Out to I/O location
    +000000E6:   98C4        CBI     0x18,4           Clear bit in I/O register
    151:          DDRD |= (1<<PD6) | (1<<PD7);
    +000000E7:   B381        IN      R24,0x11         In from I/O location
    +000000E8:   6C80        ORI     R24,0xC0         Logical OR with immediate
    +000000E9:   BB81        OUT     0x11,R24         Out to I/O location
    152:          PORTD = 0x40; 
    +000000EA:   E480        LDI     R24,0x40         Load immediate
    +000000EB:   BB82        OUT     0x12,R24         Out to I/O location
    153:          sei();                                   // enable interrupts 
    +000000EC:   9478        SEI                      Global Interrupt Enable
    +000000ED:   92100260    STS     0x0260,R1        Store direct to data space
    +000000EF:   91800060    LDS     R24,0x0060       Load direct from data space
    +000000F1:   BF8C        OUT     0x3C,R24         Out to I/O location
    +000000F2:   CFFF        RJMP    PC-0x0000        Relative jump
    +000000F3:   94F8        CLI                      Global Interrupt Disable
    +000000F4:   CFFF        RJMP    PC-0x0000        Relative jump

    Jak widzisz nie ma tu żadnych skoków lub wywołań do czegokolwiek, co by zmieniało stan PD7 w pętli z opóźnieniem. Kompilator chyba jeszcze nie jest taki mądry by zamienić to na przerwanie sterowane z Timer-a...

    To co widzi AVR Studio w main() przy braku optymalizacji -O0:

    @00000189: main
    143:      { 
    +00000189:   93DF        PUSH    R29              Push register on stack
    +0000018A:   93CF        PUSH    R28              Push register on stack
    +0000018B:   B7CD        IN      R28,0x3D         In from I/O location
    +0000018C:   B7DE        IN      R29,0x3E         In from I/O location
    +0000018D:   976E        SBIW    R28,0x1E         Subtract immediate from word
    +0000018E:   B60F        IN      R0,0x3F          In from I/O location
    +0000018F:   94F8        CLI                      Global Interrupt Disable
    +00000190:   BFDE        OUT     0x3E,R29         Out to I/O location
    +00000191:   BE0F        OUT     0x3F,R0          Out to I/O location
    +00000192:   BFCD        OUT     0x3D,R28         Out to I/O location
    146:        timer_init(); 
    +00000193:   940E005E    CALL    0x0000005E       Call subroutine
    147:        SPIinit(); 
    +00000195:   940E0084    CALL    0x00000084       Call subroutine
    151:          DDRD |= (1<<PD6) | (1<<PD7);
    +00000197:   E3A1        LDI     R26,0x31         Load immediate
    +00000198:   E0B0        LDI     R27,0x00         Load immediate
    +00000199:   E3E1        LDI     R30,0x31         Load immediate
    +0000019A:   E0F0        LDI     R31,0x00         Load immediate
    +0000019B:   8180        LDD     R24,Z+0          Load indirect with displacement
    +0000019C:   6C80        ORI     R24,0xC0         Logical OR with immediate
    +0000019D:   938C        ST      X,R24            Store indirect
    152:          PORTD = 0x40; 
    +0000019E:   E3E2        LDI     R30,0x32         Load immediate
    +0000019F:   E0F0        LDI     R31,0x00         Load immediate
    +000001A0:   E480        LDI     R24,0x40         Load immediate
    +000001A1:   8380        STD     Z+0,R24          Store indirect with displacement
    153:          sei();                                   // enable interrupts 
    +000001A2:   9478        SEI                      Global Interrupt Enable
    154:          for(sect=0; sect<62760; sect++) 
    +000001A3:   8E1E        STD     Y+30,R1          Store indirect with displacement
    +000001A4:   8E1D        STD     Y+29,R1          Store indirect with displacement
    +000001A5:   C00E        RJMP    PC+0x000F        Relative jump
    156:            sendmmc(sect);
    +000001A6:   8D8D        LDD     R24,Y+29         Load indirect with displacement
    +000001A7:   8D9E        LDD     R25,Y+30         Load indirect with displacement
    +000001A8:   01CC        MOVW    R24,R24          Copy register pair
    +000001A9:   E0A0        LDI     R26,0x00         Load immediate
    +000001AA:   E0B0        LDI     R27,0x00         Load immediate
    +000001AB:   01BC        MOVW    R22,R24          Copy register pair
    +000001AC:   01CD        MOVW    R24,R26          Copy register pair
    +000001AD:   940E0156    CALL    0x00000156       Call subroutine
    +000001AF:   8D8D        LDD     R24,Y+29         Load indirect with displacement
    +000001B0:   8D9E        LDD     R25,Y+30         Load indirect with displacement
    +000001B1:   9601        ADIW    R24,0x01         Add immediate to word
    +000001B2:   8F9E        STD     Y+30,R25         Store indirect with displacement
    +000001B3:   8F8D        STD     Y+29,R24         Store indirect with displacement
    +000001B4:   8D8D        LDD     R24,Y+29         Load indirect with displacement
    +000001B5:   8D9E        LDD     R25,Y+30         Load indirect with displacement
    +000001B6:   EF25        LDI     R18,0xF5         Load immediate
    +000001B7:   3288        CPI     R24,0x28         Compare with immediate
    +000001B8:   0792        CPC     R25,R18          Compare with carry
    +000001B9:   F360        BRCS    PC-0x13          Branch if carry set
    162:          PORTD &= ~(1<<PD7); 
    +000001BA:   E3A2        LDI     R26,0x32         Load immediate
    +000001BB:   E0B0        LDI     R27,0x00         Load immediate
    +000001BC:   E3E2        LDI     R30,0x32         Load immediate
    +000001BD:   E0F0        LDI     R31,0x00         Load immediate
    +000001BE:   8180        LDD     R24,Z+0          Load indirect with displacement
    +000001BF:   778F        ANDI    R24,0x7F         Logical AND with immediate
    +000001C0:   938C        ST      X,R24            Store indirect
    +000001C1:   E080        LDI     R24,0x00         Load immediate
    +000001C2:   E090        LDI     R25,0x00         Load immediate
    +000001C3:   EFAA        LDI     R26,0xFA         Load immediate
    +000001C4:   E4B3        LDI     R27,0x43         Load immediate
    +000001C5:   8F89        STD     Y+25,R24         Store indirect with displacement
    +000001C6:   8F9A        STD     Y+26,R25         Store indirect with displacement
    +000001C7:   8FAB        STD     Y+27,R26         Store indirect with displacement
    +000001C8:   8FBC        STD     Y+28,R27         Store indirect with displacement
    ---- c:\WinAVR\avr\include\util\delay.h -----------------------------------------------------------
    145:      	double __tmp = ((F_CPU) / 4e3) * __ms;
    +000001C9:   E020        LDI     R18,0x00         Load immediate
    +000001CA:   E830        LDI     R19,0x80         Load immediate
    +000001CB:   E34B        LDI     R20,0x3B         Load immediate
    +000001CC:   E455        LDI     R21,0x45         Load immediate
    +000001CD:   8D69        LDD     R22,Y+25         Load indirect with displacement
    +000001CE:   8D7A        LDD     R23,Y+26         Load indirect with displacement
    +000001CF:   8D8B        LDD     R24,Y+27         Load indirect with displacement
    +000001D0:   8D9C        LDD     R25,Y+28         Load indirect with displacement
    +000001D1:   940E032E    CALL    0x0000032E       Call subroutine
    +000001D3:   01DC        MOVW    R26,R24          Copy register pair
    +000001D4:   01CB        MOVW    R24,R22          Copy register pair
    +000001D5:   8B8D        STD     Y+21,R24         Store indirect with displacement
    +000001D6:   8B9E        STD     Y+22,R25         Store indirect with displacement
    +000001D7:   8BAF        STD     Y+23,R26         Store indirect with displacement
    +000001D8:   8FB8        STD     Y+24,R27         Store indirect with displacement
    146:      	if (__tmp < 1.0)
    +000001D9:   E020        LDI     R18,0x00         Load immediate
    +000001DA:   E030        LDI     R19,0x00         Load immediate
    +000001DB:   E840        LDI     R20,0x80         Load immediate
    +000001DC:   E35F        LDI     R21,0x3F         Load immediate
    +000001DD:   896D        LDD     R22,Y+21         Load indirect with displacement
    +000001DE:   897E        LDD     R23,Y+22         Load indirect with displacement
    +000001DF:   898F        LDD     R24,Y+23         Load indirect with displacement
    +000001E0:   8D98        LDD     R25,Y+24         Load indirect with displacement
    +000001E1:   940E02AD    CALL    0x000002AD       Call subroutine
    +000001E3:   2388        TST     R24              Test for Zero or Minus
    +000001E4:   F42C        BRGE    PC+0x06          Branch if greater or equal, signed
    147:      		__ticks = 1;
    +000001E5:   E081        LDI     R24,0x01         Load immediate
    +000001E6:   E090        LDI     R25,0x00         Load immediate
    +000001E7:   8B9C        STD     Y+20,R25         Store indirect with displacement
    +000001E8:   8B8B        STD     Y+19,R24         Store indirect with displacement
    +000001E9:   C03F        RJMP    PC+0x0040        Relative jump
    148:      	else if (__tmp > 65535)
    +000001EA:   E020        LDI     R18,0x00         Load immediate
    +000001EB:   EF3F        SER     R19              Set Register
    +000001EC:   E74F        LDI     R20,0x7F         Load immediate
    +000001ED:   E457        LDI     R21,0x47         Load immediate
    +000001EE:   896D        LDD     R22,Y+21         Load indirect with displacement
    +000001EF:   897E        LDD     R23,Y+22         Load indirect with displacement
    +000001F0:   898F        LDD     R24,Y+23         Load indirect with displacement
    +000001F1:   8D98        LDD     R25,Y+24         Load indirect with displacement
    +000001F2:   940E032A    CALL    0x0000032A       Call subroutine
    +000001F4:   1618        CP      R1,R24           Compare
    +000001F5:   F54C        BRGE    PC+0x2A          Branch if greater or equal, signed
    151:      		__ticks = (uint16_t) (__ms * 10.0);
    +000001F6:   E020        LDI     R18,0x00         Load immediate
    +000001F7:   E030        LDI     R19,0x00         Load immediate
    +000001F8:   E240        LDI     R20,0x20         Load immediate
    +000001F9:   E451        LDI     R21,0x41         Load immediate
    +000001FA:   8D69        LDD     R22,Y+25         Load indirect with displacement
    +000001FB:   8D7A        LDD     R23,Y+26         Load indirect with displacement
    +000001FC:   8D8B        LDD     R24,Y+27         Load indirect with displacement
    +000001FD:   8D9C        LDD     R25,Y+28         Load indirect with displacement
    +000001FE:   940E032E    CALL    0x0000032E       Call subroutine
    +00000200:   01DC        MOVW    R26,R24          Copy register pair
    +00000201:   01CB        MOVW    R24,R22          Copy register pair
    +00000202:   01BC        MOVW    R22,R24          Copy register pair
    +00000203:   01CD        MOVW    R24,R26          Copy register pair
    +00000204:   940E02B1    CALL    0x000002B1       Call subroutine
    +00000206:   01DC        MOVW    R26,R24          Copy register pair
    +00000207:   01CB        MOVW    R24,R22          Copy register pair
    +00000208:   8B9C        STD     Y+20,R25         Store indirect with displacement
    +00000209:   8B8B        STD     Y+19,R24         Store indirect with displacement
    +0000020A:   C00F        RJMP    PC+0x0010        Relative jump
    +0000020B:   E28C        LDI     R24,0x2C         Load immediate
    +0000020C:   E091        LDI     R25,0x01         Load immediate
    +0000020D:   8B9A        STD     Y+18,R25         Store indirect with displacement
    +0000020E:   8B89        STD     Y+17,R24         Store indirect with displacement
    ---- c:\WinAVR\avr\include\util\delay_basic.h -----------------------------------------------------
    105:      	__asm__ volatile (
    +0000020F:   8989        LDD     R24,Y+17         Load indirect with displacement
    +00000210:   899A        LDD     R25,Y+18         Load indirect with displacement
    +00000211:   9701        SBIW    R24,0x01         Subtract immediate from word
    +00000212:   F7F1        BRNE    PC-0x01          Branch if not equal
    +00000213:   8B9A        STD     Y+18,R25         Store indirect with displacement
    +00000214:   8B89        STD     Y+17,R24         Store indirect with displacement
    ---- c:\WinAVR\avr\include\util\delay.h -----------------------------------------------------------
    156:      			__ticks --;
    +00000215:   898B        LDD     R24,Y+19         Load indirect with displacement
    +00000216:   899C        LDD     R25,Y+20         Load indirect with displacement
    +00000217:   9701        SBIW    R24,0x01         Subtract immediate from word
    +00000218:   8B9C        STD     Y+20,R25         Store indirect with displacement
    +00000219:   8B8B        STD     Y+19,R24         Store indirect with displacement
    152:      		while(__ticks)
    +0000021A:   898B        LDD     R24,Y+19         Load indirect with displacement
    +0000021B:   899C        LDD     R25,Y+20         Load indirect with displacement
    +0000021C:   9700        SBIW    R24,0x00         Subtract immediate from word
    +0000021D:   F769        BRNE    PC-0x12          Branch if not equal
    +0000021E:   C014        RJMP    PC+0x0015        Relative jump
    161:      		__ticks = (uint16_t)__tmp;
    +0000021F:   896D        LDD     R22,Y+21         Load indirect with displacement
    +00000220:   897E        LDD     R23,Y+22         Load indirect with displacement
    +00000221:   898F        LDD     R24,Y+23         Load indirect with displacement
    +00000222:   8D98        LDD     R25,Y+24         Load indirect with displacement
    +00000223:   940E02B1    CALL    0x000002B1       Call subroutine
    +00000225:   01DC        MOVW    R26,R24          Copy register pair
    +00000226:   01CB        MOVW    R24,R22          Copy register pair
    +00000227:   8B9C        STD     Y+20,R25         Store indirect with displacement
    +00000228:   8B8B        STD     Y+19,R24         Store indirect with displacement
    +00000229:   898B        LDD     R24,Y+19         Load indirect with displacement
    +0000022A:   899C        LDD     R25,Y+20         Load indirect with displacement
    +0000022B:   8B98        STD     Y+16,R25         Store indirect with displacement
    +0000022C:   878F        STD     Y+15,R24         Store indirect with displacement
    +0000022D:   858F        LDD     R24,Y+15         Load indirect with displacement
    +0000022E:   8998        LDD     R25,Y+16         Load indirect with displacement
    +0000022F:   9701        SBIW    R24,0x01         Subtract immediate from word
    +00000230:   F7F1        BRNE    PC-0x01          Branch if not equal
    +00000231:   8B98        STD     Y+16,R25         Store indirect with displacement
    +00000232:   878F        STD     Y+15,R24         Store indirect with displacement
    ---- dacmmc.c -------------------------------------------------------------------------------------
    164:          PORTD |= (1<<PD7); 
    +00000233:   E3A2        LDI     R26,0x32         Load immediate
    +00000234:   E0B0        LDI     R27,0x00         Load immediate
    +00000235:   E3E2        LDI     R30,0x32         Load immediate
    +00000236:   E0F0        LDI     R31,0x00         Load immediate
    +00000237:   8180        LDD     R24,Z+0          Load indirect with displacement
    +00000238:   6880        ORI     R24,0x80         Logical OR with immediate
    +00000239:   938C        ST      X,R24            Store indirect
    +0000023A:   E080        LDI     R24,0x00         Load immediate
    +0000023B:   E090        LDI     R25,0x00         Load immediate
    +0000023C:   EFAA        LDI     R26,0xFA         Load immediate
    +0000023D:   E4B3        LDI     R27,0x43         Load immediate
    +0000023E:   878B        STD     Y+11,R24         Store indirect with displacement
    +0000023F:   879C        STD     Y+12,R25         Store indirect with displacement
    +00000240:   87AD        STD     Y+13,R26         Store indirect with displacement
    +00000241:   87BE        STD     Y+14,R27         Store indirect with displacement
    +00000242:   E020        LDI     R18,0x00         Load immediate
    +00000243:   E830        LDI     R19,0x80         Load immediate
    +00000244:   E34B        LDI     R20,0x3B         Load immediate
    +00000245:   E455        LDI     R21,0x45         Load immediate
    +00000246:   856B        LDD     R22,Y+11         Load indirect with displacement
    +00000247:   857C        LDD     R23,Y+12         Load indirect with displacement
    +00000248:   858D        LDD     R24,Y+13         Load indirect with displacement
    +00000249:   859E        LDD     R25,Y+14         Load indirect with displacement
    +0000024A:   940E032E    CALL    0x0000032E       Call subroutine
    +0000024C:   01DC        MOVW    R26,R24          Copy register pair
    +0000024D:   01CB        MOVW    R24,R22          Copy register pair
    +0000024E:   838F        STD     Y+7,R24          Store indirect with displacement
    +0000024F:   8798        STD     Y+8,R25          Store indirect with displacement
    +00000250:   87A9        STD     Y+9,R26          Store indirect with displacement
    +00000251:   87BA        STD     Y+10,R27         Store indirect with displacement
    +00000252:   E020        LDI     R18,0x00         Load immediate
    +00000253:   E030        LDI     R19,0x00         Load immediate
    +00000254:   E840        LDI     R20,0x80         Load immediate
    +00000255:   E35F        LDI     R21,0x3F         Load immediate
    +00000256:   816F        LDD     R22,Y+7          Load indirect with displacement
    +00000257:   8578        LDD     R23,Y+8          Load indirect with displacement
    +00000258:   8589        LDD     R24,Y+9          Load indirect with displacement
    +00000259:   859A        LDD     R25,Y+10         Load indirect with displacement
    +0000025A:   940E02AD    CALL    0x000002AD       Call subroutine
    +0000025C:   2388        TST     R24              Test for Zero or Minus
    +0000025D:   F42C        BRGE    PC+0x06          Branch if greater or equal, signed
    +0000025E:   E081        LDI     R24,0x01         Load immediate
    +0000025F:   E090        LDI     R25,0x00         Load immediate
    +00000260:   839E        STD     Y+6,R25          Store indirect with displacement
    +00000261:   838D        STD     Y+5,R24          Store indirect with displacement
    +00000262:   C03F        RJMP    PC+0x0040        Relative jump
    +00000263:   E020        LDI     R18,0x00         Load immediate
    +00000264:   EF3F        SER     R19              Set Register
    +00000265:   E74F        LDI     R20,0x7F         Load immediate
    +00000266:   E457        LDI     R21,0x47         Load immediate
    +00000267:   816F        LDD     R22,Y+7          Load indirect with displacement
    +00000268:   8578        LDD     R23,Y+8          Load indirect with displacement
    +00000269:   8589        LDD     R24,Y+9          Load indirect with displacement
    +0000026A:   859A        LDD     R25,Y+10         Load indirect with displacement
    +0000026B:   940E032A    CALL    0x0000032A       Call subroutine
    +0000026D:   1618        CP      R1,R24           Compare
    +0000026E:   F54C        BRGE    PC+0x2A          Branch if greater or equal, signed
    +0000026F:   E020        LDI     R18,0x00         Load immediate
    +00000270:   E030        LDI     R19,0x00         Load immediate
    +00000271:   E240        LDI     R20,0x20         Load immediate
    +00000272:   E451        LDI     R21,0x41         Load immediate
    +00000273:   856B        LDD     R22,Y+11         Load indirect with displacement
    +00000274:   857C        LDD     R23,Y+12         Load indirect with displacement
    +00000275:   858D        LDD     R24,Y+13         Load indirect with displacement
    +00000276:   859E        LDD     R25,Y+14         Load indirect with displacement
    +00000277:   940E032E    CALL    0x0000032E       Call subroutine
    +00000279:   01DC        MOVW    R26,R24          Copy register pair
    +0000027A:   01CB        MOVW    R24,R22          Copy register pair
    +0000027B:   01BC        MOVW    R22,R24          Copy register pair
    +0000027C:   01CD        MOVW    R24,R26          Copy register pair
    +0000027D:   940E02B1    CALL    0x000002B1       Call subroutine
    +0000027F:   01DC        MOVW    R26,R24          Copy register pair
    +00000280:   01CB        MOVW    R24,R22          Copy register pair
    +00000281:   839E        STD     Y+6,R25          Store indirect with displacement
    +00000282:   838D        STD     Y+5,R24          Store indirect with displacement
    +00000283:   C00F        RJMP    PC+0x0010        Relative jump
    +00000284:   E28C        LDI     R24,0x2C         Load immediate
    +00000285:   E091        LDI     R25,0x01         Load immediate
    +00000286:   839C        STD     Y+4,R25          Store indirect with displacement
    +00000287:   838B        STD     Y+3,R24          Store indirect with displacement
    +00000288:   818B        LDD     R24,Y+3          Load indirect with displacement
    +00000289:   819C        LDD     R25,Y+4          Load indirect with displacement
    +0000028A:   9701        SBIW    R24,0x01         Subtract immediate from word
    +0000028B:   F7F1        BRNE    PC-0x01          Branch if not equal
    +0000028C:   839C        STD     Y+4,R25          Store indirect with displacement
    +0000028D:   838B        STD     Y+3,R24          Store indirect with displacement
    +0000028E:   818D        LDD     R24,Y+5          Load indirect with displacement
    +0000028F:   819E        LDD     R25,Y+6          Load indirect with displacement
    +00000290:   9701        SBIW    R24,0x01         Subtract immediate from word
    +00000291:   839E        STD     Y+6,R25          Store indirect with displacement
    +00000292:   838D        STD     Y+5,R24          Store indirect with displacement
    +00000293:   818D        LDD     R24,Y+5          Load indirect with displacement
    +00000294:   819E        LDD     R25,Y+6          Load indirect with displacement
    +00000295:   9700        SBIW    R24,0x00         Subtract immediate from word
    +00000296:   F769        BRNE    PC-0x12          Branch if not equal
    +00000297:   CF22        RJMP    PC-0x00DD        Relative jump
    (...)
    +000003B9:   94F8        CLI                      Global Interrupt Disable
    +000003BA:   CFFF        RJMP    PC-0x0000        Relative jump
    
    ; the final cut



    Program jest przerobioną na testy wersją programu z tematu https://www.elektroda.pl/rtvforum/topic1106650.html
  • #12 5641783
    szeryf.rm
    Poziom 22  
    ok, już sprawdzam

    Sprawdziłem... wnioski: chyba zaczne nauczać C za grubą kasę. Ponoć jak ktoś płaci za błędy to zamiast płacić ich po prostu nie popełnia :P.

    A tak na poważnie, to pisałem o volatile i co? i nic... a właśnie o to tutaj chodziło. Ile głów myślało nad rozwiązaniem?

    
    #include <avr/io.h> 
    #include <avr/interrupt.h> 
    #include <stdio.h> 
    #include <inttypes.h> 
    #include <util/delay.h> 
    
    
    unsigned char test[512] = 
    { 
      128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 
      128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 129, 127, 129, 128, 127, 133, 
      117, 109, 125, 121, 116, 132, 140, 126, 114, 114, 116, 120, 114, 93, 73, 66, 76, 116, 142, 129, 
      128, 129, 120, 119, 118, 104, 87, 123, 181, 194, 196, 198, 189, 176, 160, 162, 172, 164, 164, 183, 
      197, 188, 168, 167, 170, 165, 185, 209, 206, 196, 196, 199, 185, 162, 156, 167, 176, 173, 170, 166, 
      151, 142, 140, 134, 130, 127, 113, 86, 67, 66, 69, 75, 73, 75, 86, 90, 91, 84, 65, 48, 
      41, 30, 26, 56, 91, 88, 72, 70, 73, 82, 89, 73, 57, 60, 74, 89, 92, 77, 63, 60, 
      53, 47, 56, 64, 63, 61, 56, 54, 52, 36, 16, 22, 51, 66, 67, 70, 76, 88, 99, 92, 
      77, 74, 85, 100, 106, 97, 83, 85, 96, 108, 133, 160, 164, 144, 113, 96, 91, 82, 74, 76, 
      89, 97, 97, 97, 82, 54, 40, 41, 41, 43, 56, 74, 78, 64, 55, 64, 72, 72, 84, 102, 
      108, 116, 126, 127, 124, 127, 134, 134, 138, 148, 152, 156, 164, 165, 169, 171, 160, 156, 157, 152, 
      151, 145, 133, 136, 153, 166, 165, 163, 165, 161, 156, 158, 155, 147, 148, 160, 185, 209, 215, 220, 
      220, 204, 200, 208, 205, 200, 202, 209, 214, 213, 205, 198, 194, 194, 203, 219, 231, 235, 230, 219, 
      200, 184, 177, 170, 170, 177, 172, 164, 163, 158, 156, 160, 163, 161, 142, 116, 103, 96, 89, 93, 
      101, 105, 111, 116, 120, 110, 89, 80, 78, 75, 73, 80, 93, 91, 77, 69, 70, 77, 91, 98, 
      89, 87, 93, 95, 95, 94, 97, 96, 91, 94, 99, 100, 101, 95, 83, 78, 79, 71, 56, 41 
    }; 
    
    volatile unsigned char znacznik_przerwania_timera = 0; 
    
    #define SPIDI   6   // Port B bit 6 (pin7): data in (data from MMC) 
    #define SPIDO   5   // Port B bit 5 (pin6): data out (data to MMC) 
    #define SPICLK  7   // Port B bit 7 (pin8): clock 
    #define SPICS   4   // Port B bit 4 (pin5: chip select for MMC 
    
    
    ISR(TIMER1_COMPA_vect) 
    { 
      znacznik_przerwania_timera = 1; 
    } 
    
    
    void timer_init(void) 
    { 
      TCCR0 = (1<<WGM01) | (1<<WGM00) | (1<<COM01) | (1<<COM00) | (0<<CS02) | (0<<CS01) | (1<<CS00); 
      OCR0 = 0x00; 
      DDRB |= (1<<PB3); 
      
      TCCR1A = (0<<WGM10) | (0<<WGM11); 
      TCCR1B = (0<<WGM13) | (1<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10); 
      OCR1A = 0x5DC; 
      TIMSK = (1<<OCIE1A); 
    } 
    
    void SPIinit(void) 
    { 
       DDRB &= ~(1<<SPIDI);     // set port B SPI data input to input 
       DDRB |= (1<<SPICLK);     // set port B SPI clock to output 
       DDRB |= (1<<SPIDO);      // set port B SPI data out to output 
       DDRB |= (1<<SPICS);      // set port B SPI chip select to output 
       SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0); 
       PORTB &= ~(1<<SPICS);    // set chip select to low (MMC is selected) 
    } 
    
    char SPI(char d) 
    {  // send character over SPI 
       char received = 0; 
        
       SPDR = d; 
       while(!(SPSR & (1<<SPIF))); 
       received = SPDR; 
       return (received); 
    } 
    
    char Command(char cmd, uint32_t adr ) 
    {    
       SPI(0xFF); 
       SPI(cmd); 
       SPI((uint8_t)(adr >> 24)); 
       SPI((uint8_t)(adr >> 16)); 
       SPI((uint8_t)(adr >> 8)); 
       SPI((uint8_t)(adr)); 
       SPI(0xFF);    
       SPI(0xFF); 
       return SPI(0xFF); 
    } 
    
    
    int MMC_Init(void) 
    {  // init SPI 
       char i; 
        
       PORTB |= (1<<SPICS); 
       PORTB |= (1<<SPIDI); 
        
       // start MMC in SPI mode 
       for(i=0; i < 10; i++) SPI(0xFF); 
       PORTB &= ~(1<<SPICS); 
    
       if (Command(0x40,0) != 1) goto mmcerror; // reset MMC 
    
    st: // if there is no MMC, prg. loops here 
       if (Command(0x41,0) !=0) goto st; 
       return 1; 
    mmcerror: 
       return 0; 
    } 
    
    
    uint16_t sendmmc(uint32_t sector) //, uint16_t stop) { // send 512 bytes from the MMC via the serial port 
       { 
       int i; 
       // 512 byte-read-mode 
    //   uint8_t ix; 
    //   char r1 =  Command(0x51,sector); 
    
    //   for (ix = 0; ix < 50000; ix++) 
    //   { 
    //     if (r1 == (char)0x00) break; 
    //     r1 = SPI(0xFF); 
    //   } 
    
    //   if (r1 != (char)0x00) 
    //   { 
    //     return 1; 
    //   } 
    
    //   while(SPI(0xFF) != (char)0xFE); 
    
    
       for(i=0; i<512; i++) 
       { 
         znacznik_przerwania_timera = 0; 
         OCR0 = test[i]; //SPI(0xFF); 
         while(znacznik_przerwania_timera != 1); 
       } 
    // SPI(0xFF); 
    // SPI(0xFF); 
       return 0; 
    } 
    
    
    int main(void) 
    { 
      unsigned int sect; 
     //init(); 
      timer_init(); 
      SPIinit(); 
    
    //  if (MMC_Init() == 1) 
    //  { 
        DDRD |= (1<<PD6) | (1<<PD7); 
        PORTD = 0x40; 
        sei();                                   // enable interrupts 
        for(sect=0; sect<62760; sect++) 
        { 
          sendmmc(sect); 
        } 
    //  } 
    
      while(1) 
      { 
        PORTD &= ~(1<<PD7); 
        _delay_ms(500); 
        PORTD |= (1<<PD7); 
        _delay_ms(500);    
      } 
    }
    


    Spradź teraz. Jedno słowo a tak wiele znaczy. To po pierwsze! A po drugie właśnie przed sek pisałem o korzystaniu ze zmiennych globalnych. Tutaj akurat problemu nie ma, ale przy 16 bitowej by był. Istnieje pojęcie sekcji lokalnej i sekcji krytycznej. Zapoznaj się z nimi. To prócz volatile drugi poważny błąd
  • #13 5641980
    ZbeeGin
    Poziom 39  
    Widzę zależność pomiędzy tym, że volatile pozbawia możliwości wyjścia z

    while(znacznik_przerwania_timera != 1);

    Ale do jasnej ch....y czy kompilator jest tak ograniczony, że nie może wskazać, że w tym miejscu np. "Condition is not effective in line ..."?? Już nie musi myśleć za piszącego program, ale swoje drastyczne działania powinien wzmiankować.
  • #14 5642317
    szeryf.rm
    Poziom 22  
    To nie jest dyrastyczne działanie. Wiesz ile takich ostrzerzeń byś miał? Nie? Policz ile zmiennych masz w programie... Każda z nich może mieć i nie mieć sensu ale to jest C a nie pascal, żeby pisał wszystko. Wyobraź sobie 1000 linii kodu, gdzie specjalnie piszesz while(1) i co? dostajesz 800 warningów?

    A tak na poważnie ZbeeGin poczytaj o parametrach kompilacji. Jest tam jeden parametr:
    -Wunreachable-code
    który jak dodasz o dziwo uzyskasz to czego oczekujesz :).

    Jeśli chodzi o przyczynę nie działania to już tłumaczę. Kod z O0 jest wierny, na chłopski rozum. W zasadzie kod taki jest tak nieoptymalny jeśli chodzi o wykorzystanie rejestrów, że można by zrezygnować z ponad połowy z nich... a przecież to one zapewniają optymalizację. Kod z O0 czytasz jak książkę. Żeby wykonać:
     i++; i += 2; i <<= 1; 

    kompilator postąpi tak łopatologicznie że szkoda w ogóle gadać. On postąpi wg algorytmu
    1. Wczytaj i z pamięci do rejestru
    2. Zwiększ wartość o 1 w rejestrze
    3. Zapisz i do pamięci
    4. Wczytaj i z pamięci do rejestru
    5. Dodaj 2 do rejestr
    6. Zapisz i do pamięci
    7. Wczytaj i z pamięci do rejestru
    8. Przesuń zawartość rejestru
    9. Zapisz i do pamięci

    Nie trzeba być geniuszem, żeby zauważyć, że po co zapisywać i odczytywać coś co jest już w rejestrze. Więc prosta optymalizacja a usuwa kroki 3,4,6,7 czyli prawie połowę kroków. Pomijając oczywiście zależność pierwszych dwóch instrukcji które można zapisać jako i+= 3
    Skąd więc biorą się błędy?
    Błędy polegają na tym, że podczas braku optymalizacji, każda zmienna jest za każdym razem wczytywana z pamięci i nie ma znaczenia czy co się dzieje z tymi danymi, bo ZAWSZE jest pewność, że zaraz po wczytaniu wartości zostaną przeprowadzone operacje i wartość zostanie zapisana ponownie do pamięci.
    Niestety tak nie jest w przypadku optymalizacji. Po optymalizacji dane są wczytywane w każdym "wątku" z osobna (wątek to program głowny, dowolne przerywanie itd.) Dane te każdy "wątek" może przechowywać w pamięci a może także w rejestrze. I teraz zachodzi taka sytuacja, że odpala się sendmmc. Zmienna znacznik_przerwania_timera zostaje na początek ustawiona na 0, ale nie musi być zapisana do pamięci, tymczasowo przebywa w rejestrze, bo przecież za chwile będzie wykorzystana. A więc pojawia się pętla, która oczekuje aż ten rejestr się zmieni. Kompilator głupi nie jest i zauważa, że rejestr sam wartości nie zmieni, więc pętla ta nigdy się nie skończy z powodu zewnętrznego zachowania. Pojawiające się przerywanie zmieni wartość w pamięci, ale już nie w rejestrze, bo przerywanie nie wie co się dzieje w innym miejscu programu, więc dlaczego ma zmieniać rejestr? Kompilator zauważa te zależności i stwierdza, że skoro pętla while nie może się skończyć w funkcji sendmmc, to całą funkcję można zastąpić zwrotem while(1). Funkcja ta została wykorzystana w main() w pętli for i tutaj też jest bez sensu, bo pętla for ma powtarzać pętlę nieskończoną. Więc pętla for też będzie nieskończona, a skoro tak to zastępujemy ją while(1) a następnie mamy już pewność że nic poza nią się nie wykona.
    Gdy zmienna dostaje przedrostek volatile to kompilator zamiast przechowywać ją w rejestrze zawsze pobiera ją z pamięci, tak jak bez optymalizacji.

    Kolejna sprawa to wykorzystanie zmiennych dzielonych. W zasadzie program główny jak i przerywania pracujące z ustawioną maską przerwań (czyli te które się wywołują, ale pozwalają na to, żeby podczas ich pracy wywoływały się inne przerywania jeśli będą chciały) koniecznie i obowiązkowo powinny wyłączać przerywania na czas korzystania ze zmiennych, które wykorzystuje program główny lub inne przerywania. Dlaczego? Prześledźmy ten kod dla atmega8:
    
    #include <avr/io.h> 
    #include <avr/interrupt.h> 
    
    
    volatile uint32_t licznik = 0;
    volatile uint32_t licznik2 = 0;
    
    SIGNAL(SIG_OVERFLOW0) 
    {
      if (licznik == licznik2)
      {
        PORTD ^= _BV(PD1);
      }
      else
      {
        while(1) PORTD = 0;
      }
    }
    
    int main()
    {
      TCCR0 = _BV(CS00);  
      TCNT0 = 0;  
      TIMSK |= _BV(TOIE0);
      sei();
      while(1)
      {
        licznik = ++licznik2;
      }
    }
    


    Dlaczego program się zawiesi zarówno dla -O0 jak też dla -Os? Przecież z logicznego punktu widzenia, nie powinien. A jednak się zawiesi. Dlaczego? W pętli while w programie głównym przypisujemy zmiennej licznik wartość zmiennej licznik2 po zwiększeniu o jeden. Po każdym wykonaniu tej linii zmienne są identyczne, więc przerywanie nie powinno wejść w pętle nieskończoną a jednak wchodzi, bo zanim licznik dostanie wartość licznik2 to pomiędzy tymi instrukcjami wskoczy przerywanie i odczyta wartości różne! Jak tutaj zadziałać?

    
    #include <avr/io.h> 
    #include <avr/interrupt.h> 
    
    
    volatile uint8_t licznik = 0;
    volatile uint8_t licznik2 = 0;
    
    SIGNAL(SIG_OVERFLOW0) 
    {
      if (licznik == licznik2)
      {
        PORTD ^= _BV(PD1);
      }
      else
      {
        while(1) PORTD = 0;
      }
    }
    
    int main()
    {
      TCCR0 = _BV(CS00);  
      TCNT0 = 0;  
      TIMSK |= _BV(TOIE0);
      sei();
      while(1)
      {
        cli();
        licznik = ++licznik2;
        sei();
      }
    }
    


    I po problemie.

    Sorki za łopatologiczny opis, ale może ktoś następny trafi na ten wątek i zrozumie, że volatile to obowiązek jeśli dotyczy danych dzielonych. Podobnie jest z przerywaniami.

    PS. w zasadzie to może ktoś to ładniej sformatować i wyjdzie mały poradnik, bo stosunkowo rzadko jestem w tym dziale, ale problem pojawia się przynajmniej w jednym poście na 1,2 stronie.
REKLAMA