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

[mega8][c]zapamietanie zmiennej na czas restartu (nie EEPROM

KowalD 05 Paź 2010 14:13 1878 22
REKLAMA
  • #1 8585953
    KowalD
    Poziom 17  
    Mam taki problem. Procesor wykonuje jedną z kilku pętli nieskończonych, w przerwaniu przychodzi rozkaz zmiany wykonywanej pętli. W pętlach nie chciałbym zawierać kodu odpowiedzialnego za sprawdzenie flagi konieczności zmiany pętli i jej przerwania. Wymyśliłem, że będę restartował procesor (układem watchdog), jednak muszę zapamiętać gdzieś numer pętli która ma być wykonywana po restarcie. Nie chciałbym wykorzystywać EEPROMu do tego celu (skończona liczba zapisów) i zastanawiam się, czy mógłbym zapamiętać jakoś tą wartość w pamięci ram, czy jakimś rejestrze??
  • REKLAMA
  • #2 8585970
    _Robak_
    Poziom 33  
    Możesz dodać pamięc FRAM, steruje się nią po I2C i do takich celów jest idealna.
  • #3 8585977
    KowalD
    Poziom 17  
    oj, zapomniałem dodać, układ już zaprojektowany i wyprodukowany, żadne zmiany sprzętowe nie są możliwe. I jeśli nie uda się gdzieś zapamiętać tej zmiennej to w pętlach będę musiał porobić przerywanie ich działania.
  • #4 8585992
    _Robak_
    Poziom 33  
    Zmienne możesz też przechowywać we flashu, poczytaj o progmem.
  • #5 8586003
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Sorry, ale tak poronionego pomysłu to już dawno nie widziałem... To jest TAK BANALNE do zrobienia "po ludzku", że nie wiem skąd pomysł takich kombinacji z wymuszanym resetem...

    4\/3!!
  • #6 8586027
    KowalD
    Poziom 17  
    Freddie Chopin napisał:
    Sorry, ale tak poronionego pomysłu to już dawno nie widziałem... To jest TAK BANALNE do zrobienia "po ludzku", że nie wiem skąd pomysł takich kombinacji z wymuszanym resetem...

    4\/3!!
    dobra... poddaje się, proszę o podpowiedź :)...
  • REKLAMA
  • #7 8586061
    Freddie Chopin
    Specjalista - Mikrokontrolery
    // gdzies na poczatku
    volatile uint8_t program;
    // ...
    int main(void)
    {
    //...
    while (1)
    {
    while (program == 0)
    {
    // program 0
    }
    
    while (program == 1)
    {
    // program 1
    }
    
    // ...
    }
    
    // przerwanie
    void ISR(void)
    {
    program++;
    }


    Najprościej. Nikt nie wymyśli tego za ciebie skoro nie znamy dokładnych wymagań.

    4\/3!!
  • #8 8586074
    gaskoin
    Poziom 38  
    a nie możesz tak?

    
    volatile unsigned char loop_no;
    
    ISR(){
    
    if(++loop_no > 3) loop_no = 0;
    
    }
    
    int main(){
    
    while(1){
    
    while(loop_no == 0){
    // coś
    }
    
    
    while(loop_no == 1){
    // coś
    }
    
    
    while(loop_no == 2){
    // coś
    }
    
    
    while(loop_no == 3){
    // coś
    }
    
    }
    }
    
    
  • #9 8586114
    KowalD
    Poziom 17  
    no ale chodzi mi o to, ze to //program 1, czy //coś jest działaniem, którego jedna iteracja może trwać nawet np. 2sek, a mnie bardziej interesuje szybkie zmienienie wykonywanych obliczeń, niż ich zakończenie, czy w ogóle wynik... i przy takich założeniach, trochę te pomysły kuleją... czy może ja źle je rozumiem??
    rozumiem, że mógłbym w te obliczenia "powkładać" co kilka linijek sprawdzenie warunku przerywania obliczeń i je przerywać, ale chciałbym tego uniknąć...
  • #10 8586148
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Zrób tak żeby trwały krócej, to mniejszy będzie poślizg między akcją a reakcją. Rozwiązania z wywoływaniem resetu nie są zbyt profesjonalne.

    Zamiast "wkładać" co kilka linii warunek, to wystarczy rozdzielić obliczenia na mniejsze bloki, a potem wywoływać je np w pętli

    i = 0;
    while (program == 0)
    {
    if (i == 0)
    {
    // pierwsza czesc obliczen
    }
    else if (i == 1)
    {
    // druga czesc obliczen
    }
    else if (i == 2)
    {
    // trzecia czesc obliczen
    }
    // ...
    i++;
    if (i < 8)
    i = 0;
    }


    4\/3!!
  • REKLAMA
  • #11 8586169
    KowalD
    Poziom 17  
    no właśnie tego typu kombinacji chciałem uniknąć... ze względu na przejrzystość kodu i dość spore, sztucznie wstawiane funkcją _delay_ms() opóźnienia, które w takim razie będę musiał zastąpić czymś innym...
  • #12 8586218
    szelus
    Poziom 34  
    To jeszcze podpowiem - chociaż, nie chciałbym tego debugować ;), parę funkcji setjmp/longjmp. Na AVR w zasadzie można by to wykorzystać nawet do wyskoczenia z obsługi przerwania (dodając sei() po setjmp()), ale jesteś absolutnie 100% pewien, że te Twoje pętle główne przetrzymają takie traktowanie? Masz w nich blokowane przerwania w miejscach, ktore takiego traktowania (w tym tego przez reset) by nie przetrzymały?
    Poza tym, AVR ma RAM statyczny, więc jego zawartość (na 99%) przetrzymuje reset. Z tym, że na poczekaniu nie mogłem się doszukać nic na ten temat w DS.
  • REKLAMA
  • #13 8586341
    tmf
    VIP Zasłużony dla elektroda
    Reset przetrzymuje, można więc taką zmienną, której zawartość chcemy zachować umieścić w sekcji .noinit i problem z głowy. Z tym, że jak pisze Freddie Chopin pomysł jest poroniony.
  • #14 8586413
    KowalD
    Poziom 17  
    wykorzystalem pomysl z setjmp i longjmp :)... narazie dziala :)... jesli pojawia sie problemy to bede dalej kombinowal :)...

    mam cos takiego, kod bardzo symboliczny ;)...
    main()
    {
    	//Inicjalizacja
    	setjmp(env);
    	sei();
    	
    	switch(...)
    	{
    		case 0: Program0();break;
    		case 1: Program1();break;
    		case 2: Program2();break;
    	}
    }
    
    ISR(...)
    {
    	//zmiana numeru wykonywanego programu
    	longjmp(env,1);
    }
    mam nadzieje, ze wszystko bedzie ok :)... no i rozumiem, ze jest to mocno nieeleganckie rozwiazanie :)...


    tmf napisał:
    Reset przetrzymuje, można więc taką zmienną, której zawartość chcemy zachować umieścić w sekcji .noinit i problem z głowy. Z tym, że jak pisze Freddie Chopin pomysł jest poroniony.
    sprobowalem z .noinit, ale mi sie nie udalo :(... po restarcie bylo 0... a probowalem tak (zmienna numer jest globalna):
    uint8_t numer __attribute__ ((section(".noinit")));
  • #15 8586598
    gaskoin
    Poziom 38  
    Więc przed restartem też musiało. Umieszczenie zmiennej w sekcji noinit powoduje, że nie jest ona inicjowana jako 0 podczas startupu. Jeżeli nigdzie nie ma prawa się nadpisać nim sprawdzisz, tzn, że przed sprawdzeniem, przed resetem gdzieś się zeruje.

    Ewentualnie zmiennym może być przypisany nowy adres w ramie i czytasz to skąd innąd, ale podejżewam, że raczej tak być nie może więc to nie to :P
  • #16 8586674
    Krauser
    Poziom 26  
    uint8_t numer __attribute__ ((section(".noinit")));
    tego możesz używać, ale zawsze musisz zadbać o zainicjowanie takiej zmiennej samodzielnie. Przykładowo reset wywołany przez POR zeruje zmienną, a w przypadku wykrycia, że przyczyna resetu jest inna zmiennej nie zerujesz. Wystarczy odpowiednio wcześnie sprawdzic zawartość rejestru MCUSR
  • #17 8586930
    michalko12
    Specjalista - Mikrokontrolery
    KowalD napisał:
    wykorzystalem pomysl z setjmp i longjmp :)... narazie dziala :)... jesli pojawia sie problemy to bede dalej kombinowal :)...

    mam cos takiego, kod bardzo symboliczny ;)...
    main()
    {
    	//Inicjalizacja
    	setjmp(env);
    	sei();
    	
    	switch(...)
    	{
    		case 0: Program0();break;
    		case 1: Program1();break;
    		case 2: Program2();break;
    	}
    }
    
    ISR(...)
    {
    	//zmiana numeru wykonywanego programu
    	longjmp(env,1);
    }
    mam nadzieje, ze wszystko bedzie ok :)... no i rozumiem, ze jest to mocno nieeleganckie rozwiazanie :)...


    A o stosie to mistrz zapomniał? Troche podziała i po stosie. To juz lepszym rozwiazaniem jest edycja wskaźnika stosu i podstawienie adresu procedury jako adresu powrotu z przerwania.
  • #18 8587208
    tmf
    VIP Zasłużony dla elektroda
    Dokładnie, wyskakiwanie z procedury obsługi przerwania powoduje, że za każdym razem na stosie pozostają odłożone rejestry i adres powrotu. Nie ma siły, w końcu to wszystko musi się zwiesić. Jeśli już kolega musi tak nieelegancko to oprogramować to proponuję całe ISR napisać w assemblerze i odtwarzać wskaźnik stosu przed wyskokiem z ISR. W C właściwie nie można tego osiągnąć. Druga rzecz - jeśli poszczególne programy nie mogą po prostu testować jakiejś flagi co byłoby zdecydowanie najlepszym rozwiązaniem to zastosuj jakiś RTOS i po prostu kiluj wątki. Troche to nietypowe zastosowanie RTOS, ale zadziała. Prościutki RTOS to zaledwie kilkaset bajtów pamięci.
  • #19 8587389
    KowalD
    Poziom 17  
    cos tak przeczuwalem z tym stosem, ze to za latwa metoda, zeby byla dobra ;)... ale dla mnie to czarna magia niestety :(... dzieki za uwage :)... chyba jednak jak radzicie, gdy bede mial wiecej czasu to posiedze i przerobie to na sprawdzanie flagi :)... albo moze to .noinit uda mi sie rozkminic :)...
  • #20 8588230
    janbernat
    Poziom 38  
    "a mnie bardziej interesuje szybkie zmienienie wykonywanych obliczeń, niż ich zakończenie, czy w ogóle wynik..."
    Może cały algorytm jest zły.
    Jak Cię nie interesuje zakończenie obliczeń i w ogóle wynik to po co one są?
    No i co ma decydować żeby przerwać to obliczanie?
    Watchdog- no to tylko że zbyt długo trwają.
    Interpretuje to tak że program się zawiesił.
    On tylko do tego służy.
    Ale program powinien być tak napisany żeby watchdog nie był koniecznym elementem programu.
  • #21 8588492
    Konto nie istnieje
    Konto nie istnieje  
  • #22 8588906
    szelus
    Poziom 34  
    KowalD napisał:
    cos tak przeczuwalem z tym stosem, ze to za latwa metoda, zeby byla dobra ;)... ale dla mnie to czarna magia niestety


    Tak, jak napisał albertb - koledzy michalko i tmf muszą doczytać sobie jak działają setjmp/lonjmp. Nic na stosie nie zostaje, to najlepsze rozwiązanie na takie sztuki, jak chcesz tutaj stosować. Moim zdaniem najlepsze, bo bardziej przejrzyste, niż sztuki z watchdogiem, resetem i .noinit. Oczywiście, o ile się słyszało o setjmp/longjmp.

    Tyle tylko, że biorąc pod uwagę to, co napisałeś o czarnej magii ;) obawiam się, że nie jesteś w stanie przewidzieć wszystkich "skutków ubocznych" takiego przenoszenia sterowania przerwaniem i program polegnie w najmniej spodziewanym momencie (zgodnie z prawem Murphy'ego).
    ----
    Uzupełniając o tych skutkach ubocznych. Zależy, co robi ten przerywany program. Jeżeli np. pisze do jakichś rejestrów konfiguracyjnych, albo nawet na LCD, gdzie wymagane jest zachowanie pewnej sekwencji, to niezamaskowane to przerwanie może rozwalić całą konfiguracje itp. itd.
  • #23 8588984
    KowalD
    Poziom 17  
    pogram pwm-ami steruje oswietleniam (pewnie jakimis ledami bedzie), przerwania to mozna napisac, ze od przyciskow, ktorymi operator zmienia wykonywane efekty :D... obliczenia nie musza trwac do onca, bo nawet jako takiego go nie maja ;)...

    czyli w koncu to rozwiazanie z setjmp/longjmp nie grozi przepelnieniem stosu... a jedynie moze mi przerwac jakas operacje, ktora przerwana powinna nie byc... zaryzykuje i potestuje takie rozwiazanie... jesli nie bedzie problemow to moze zaryzykuje i zostawie :)... bo mnie tez sie podoba :D...
REKLAMA