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

[atmega32] zapios do eepromu i reset mikrokontrolera

qnrad 12 Maj 2010 13:17 1965 18
REKLAMA
  • #1 8066305
    qnrad
    Poziom 10  
    Korzystam z atmegi 32. Problem polega na tym że chcę zapisywać wartości do eeprom-u. Zapis robię co przerwanie timera2 od przepełnienia. I za każdym razem jak dochodzi do zapisywania do eeprom-u to mikrokontroler się resetuje.
    Czytałem coś o fuse bitach coś zmieniłem, ale nie pomogło. Trzeba oddzielnie eeprom i flash programować?
    Zestaw ewaluacyjny zl15avr i programator avtprog1:
    środowisko AVR studio.
     
     #define TIMER2_INIT 0
     #define SOFTWARE_OVERFLOW2 630
    
     int overflow_tmp=0;
    
     static EEMEM unsigned int tc77_temp_min=0;
     static EEMEM unsigned int tc77_temp_max=0;
     static EEMEM unsigned int mscp77_temp_min=0;
     static EEMEM unsigned int mscp77_temp_max=0;
     static EEMEM unsigned int two_temp_min_avg=0;
     static EEMEM unsigned int two_temp_max_avg=0;
    
    /*  */
    
    //konfiguracja timera2
    TIMSK = 0b01000001;
    TCCR2=0x05;		//prescaler	    				 			
    TCNT2 = TIMER2_INIT;
    
    /* */
    
    SIGNAL (SIG_OVERFLOW2)
    {
    
    	char disp;
    	unsigned int anal_temp,digital_temp,avg_temp;
    	// globalne blokowanie przerwań 
            cli();
    
    	
    	overflow_tmp++;
    	if (overflow_tmp>SOFTWARE_OVERFLOW2)
    	{
    		overflow_tmp=0;
    						
    		digital_temp=tc77digital_temp(disp);
    		anal_temp=get_temp_mcp9701();
    		avg_temp=(digital_temp+anal_temp)/2;		
    
    		if(digital_temp<eeprom_read_byte(&tc77_temp_min))
    		{
    			eeprom_write_byte(&tc77_temp_min, digital_temp);
    		}
    		
    
    		if(digital_temp>eeprom_read_byte(&tc77_temp_max))
    		{
    			eeprom_write_byte(&tc77_temp_max, digital_temp);
    		}
    
    		if(anal_temp<eeprom_read_byte(&mscp77_temp_min))
    		{
    			eeprom_write_byte(&mscp77_temp_min,anal_temp);
    		}
    
    		if(anal_temp>eeprom_read_byte(&mscp77_temp_max))
    		{
    			eeprom_write_byte(&mscp77_temp_max,anal_temp);
    		}
    
    		if(avg_temp<eeprom_read_byte(&two_temp_min_avg))
    		{
    			eeprom_write_byte(&two_temp_min_avg,avg_temp);
    		}
    			
    		if(avg_temp>eeprom_read_byte(&two_temp_max_avg))
    		{
    			eeprom_write_byte(&two_temp_max_avg,avg_temp);
    		}
    	}
    	
    	TCNT2 = TIMER2_INIT;
    	sei();
    	
    }
  • REKLAMA
  • #2 8066339
    chudybyk
    Poziom 31  
    Po co wyłączasz przerwania w procedurze przerwania? Podejrzewam, że po sei() przychodzi kolejne przerwanie zanim system zdąży wrócić z aktualnego. Tak parę razy z rzędu, przepełnia się stos i ... reset.
    Wyrzuć cli() i sei(). Po co w przerwaniu inicjujesz TCNT2? Nie prościej puścić przerwanie w trybie CTC, żeby wszystko poszło z automatu?
    Pozdrawiam!
  • #3 8066346
    tadzik85
    Poziom 38  
    return przydałby się na końcu. I zacznij stosować ISR()
  • REKLAMA
  • #4 8066447
    qnrad
    Poziom 10  
    Dzięki za zainteresowanie.
    wyrzuciłem
    cli() i sei()
    dałem returny
    CTC nie ustawiłem,ale to chyba nie ma znaczenia w tym momencie
    nadal nie działa
  • #5 8066502
    tadzik85
    Poziom 38  
    Przerwanie masz dobrze zadeklarowane? zadeklaruj bad interrupt.

    I bardzo ładnie dobrane typy zmiennych. Inty zapisywać write_byte. Coś chyba jest nie tak?
  • REKLAMA
  • #6 8066533
    loocasm
    Poziom 15  
    I działania na zmiennych w przerwaniu, gdy nie są volatile...
  • #7 8066570
    tmf
    VIP Zasłużony dla elektroda
    Żadnych return nie trzeba. loocasm - jakie zmienne wg ciebie mają być volatile? Chyba nie te wskaźniki do EEPROM? Oczywiscie te *_temp muszą być, ale tego jak są zadeklarowane nie widać.
    Jeden błąd jaki widzę to to, że za pomocą read/write_byte odczytujesz/zapisujesz zmienne 16-bitowe. Druga rzecz - jak często są przerwania? Bo zapis do EEPROM troche trwa, tu potencjalnie zapisów może być sporo, więc czas staje się bardzo długi. Kolejna rzecz - funkcje operujące na EEPROM niszczą niektóre rejestry, m.in. rejestr adresowy i rejestr danych EEPROM. Jeśli w innym miejscu programu coś z nimi robisz (bo np. czytasz EEPROM) to robi się kaszana.
  • Pomocny post
    #8 8066611
    mirekk36
    Poziom 42  
    tadzik85 napisał:
    return przydałby się na końcu. I zacznij stosować ISR()


    Matko boska! tadzik weź ty się ze 4 albo 6 razy zastanów jak coś podpowiesz - RETURN w procedurze obsługi przerwania w C ????? Chyba że ty piszesz swoje programy w Bascomie ze wstawkami w C albo odwrotnie.


    do autora - żadnego polecenia return w przerwaniu bo będziesz miał tylko jeszcze gorzej.

    Po drugie zastanów się w ogóle nad zapisywaniem w przerwaniu timera do EEPROM'a - toż ty jakąś masakrę odstawiasz ;) Wprawdzie dzielisz jeszcze przez 630 czyli wynikałoby zapisywanie co kilka sekund ale cały czas pod te same komórki pamięci - też masakra. Toż z powodzeniem możesz to zapisywać do pamięci RAM - a raz na jakiś tam duży okres czasu jeśli już trzeba - ew zapisać do EEPROM

    W ogóle to w przerwaniu ustawiasz sobie tylko flagę gdy ten twój licznik dojdzie do 630 i w pętli głównej po bożemu będziesz pisał do EEPROM'a
  • #9 8066870
    uuidgen
    Poziom 12  
    qnrad - pojedynczy zapis do eepromu to ponad 8ms przy 1MHz - zobacz stronę 21. Zapis co kilka sekund do eepromu to dobry sposób, żeby go zarżnąć w kilka dni - wytrzymałość jest na poziomie 100k zapisów.


    mirekk36 napisał:
    do autora - żadnego polecenia return w przerwaniu bo będziesz miał tylko jeszcze gorzej.
    return na końcu funkcji void (a takie są przerwania) nie ma żadnego wpływu. return w przerwaniach jest przydatny, aby wyjść z niego wcześniej:
    if(!warunek)
      return;
    //tu dużo kodu

    zamiast
    if(warunek)
    {
      //tu dużo kodu
    }
    Dzięki czemu unikasz zbędnego wzrostu poziomu zagnieżdżenia.
  • #10 8066888
    tadzik85
    Poziom 38  
    W interrupt.h masz zdefiniowane reti();
  • REKLAMA
  • #11 8067237
    mirekk36
    Poziom 42  
    uuidgen --> masz rację z tym wcześniejszym wychodzeniem z przerwania za pomocą pustego return - ale to nie ma nic wspólnego z podawaniem return na końcu funkcji

    a już nie daj co reti(); - jak znowu tadzik85 wymyśla swoje fantasmagorie. reti(); to już by ci w ogóle rozwaliło przerwanie. Wiesz co to jest prolog i epilog makra definiującego wstępnie procedurę obsługi przerwania???? mieszasz dowolnie jak ci do głowy przyjdzie pojęcia i bez pojęcia. (widać , że masz naleciałości i brzydkie nawyki czy przyzwyczajenia z Bascoma - gdzie czy to funckja, czy procedura czy przerwanie - wszystko zawsze kończyło się tym samym rozkazem RETURN. reti a return to nie to samo. Coś uszłyszałeś na temat reti(), wiesz, że dzwonią ale nie wiesz w którym kościele. Poczytaj choć troszkę o asemblerze to ci się sporo wyjaśni. Albo spróbuj choć raz wstawkę asemblerową do C napisać - np kod własnej obsługi jakiegoś przerwania - to też ci dużo wyjaśni)
  • #12 8067482
    qnrad
    Poziom 10  
    volatile pomogło dzięki

    Dodano po 11 [minuty]:


    Cytat:
    Wprawdzie dzielisz jeszcze przez 630 czyli wynikałoby zapisywanie co kilka sekund ale cały czas pod te same komórki pamięci - też masakra.


    No ale chce nadpisywać wcześniejsze nieaktualne już dane co w tym złego?

    Cytat:
    Toż z powodzeniem możesz to zapisywać do pamięci RAM


    Za dużo z atmega nie miałem do czynienia jak to zrobić?
  • Pomocny post
    #13 8067595
    tmf
    VIP Zasłużony dla elektroda
    To w tym złego, że ilość zapisów do EEPROM jest ograniczona. Zapis do RAM jest problematyczny, bo co jak wysiądzie zasilanie? Trzeba robić sygnalizację i podtrzymanie na czas zapisu danych do EEPROM i specjalną obsługę tej sytuacji w programie. Dlatego albo zastosuj programowe rozwiązanie - wear leveling, albo wsadź pamięć FRAM.
  • #14 8067621
    qnrad
    Poziom 10  
    ok rozumiem, jeszcze raz dzięki za wszelka pomoc
  • #16 8071080
    mirekk36
    Poziom 42  
    loocasm --> nie chodzi o to żeby wszystkie zmienne, których używa się w przerwaniu od razu deklarować jako volatile ale tylko te, które są jednocześnie używane zarówno w przerwaniu jak i w pozostałej części programu w różnych funkcjach. (nie do końca rozumiesz może jeszcze volatile)

    W tym konkretnym przypadku gdy zmienna overflow_tmp jest używana tylko w przerwaniu to wcale nie musi być volatile. W zasadzie to autor powinien zrobić jej definicję w procedurze przerwania ale w ten sposób:

    static uint16_t overflow_tmp=0;


    wtedy byłoby wszystko jasne.
  • #17 8071116
    tmf
    VIP Zasłużony dla elektroda
    Dokładnie jak pisze Mirek. Poza tym jeśli overflow_tmp ma użyte gdzieś jeszcze w programie, to mogę założyć się o bardzo konkretną kasę, że ma jeszcze jeden błąd, którego póki co nie zauważył, ale prędzej czy później da znać o sobie.
  • #18 8071206
    Konto nie istnieje
    Poziom 1  
  • #19 8073681
    loocasm
    Poziom 15  
    Czułem, że ta zmienna jest jeszcze gdzieś wykorzystywana przez autora. Czułem, że to, że nie jest volatile stanowi w tym konkretnym przykładzie problem, więc zasugerowałem to autorowi, co okazało się pomocne (a o to chyba chodziło, czy nie?).
    Skąd od razu domysło-zarzuty, że ja nie do końca rozumiem volatile, Mirku?
    Człowiek komuś pomoże, to go jeszcze zbesztają, że czegoś nie rozumie... Heh.. :)
REKLAMA