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.

[C]Zmienna lokalna vs globalna, a szybkość wykonywania programu przerwania

kamil94goldman 08 Lis 2017 00:11 1551 14
  • #1 08 Lis 2017 00:11
    kamil94goldman
    Poziom 3  

    Witam,

    Mam takie pytanie:

    Załóżmy, że w programie obsługi przerwania potrzebuje zmienną, która nie będzie wykorzystywana poza obsługą tego przerwania(czyli można zadeklarować zmienną lokalną w przerwaniu). Lecz zastanawia mnie, jaka jest różnica pod względem szybkości wykonywania programu, gdyby zamiast zmiennej lokalnej, zadeklarować na początku programu głównego, zmienną globalną z specyfikatorem volatile, zamiast tamtej zmiennej lokalnej.

    Zmienna globalna będzie deklarowana na początku programu, przez co, cały czas będzie zajmowała miejsce w pamięci RAM, a zmienna lokalna będzie deklarowana w momencie wykonywania przerwania i kasowana po wyjściu z niego. Więc w jakim przypadku, procedura obsługi przerwania, wykona się szybciej?

    0 14
  • Pomocny post
    #2 08 Lis 2017 00:39
    WX3V
    Poziom 17  

    Zadałeś pytanie: Jak działa mój kompilator C ?
    Zatem jeśli zmienna lokalna (ulotna) jest pamiętana w rejestrze procesora, po odłożeniu na Stos jej początkowej wartości, to będzie ona dostępna szybciej niż zmienna globalna. Natomiast jeśli jest pamiętana w SRAMie to czas dostępu do niej nie powinien różnić się od czasu dostępu do zmiennej globalnej.
    Chcąc nie chcąc musisz zajrzeć do opisu działania kompilatora lub wykonać eksperyment stosując symulator lub emulator procka. Innych wyjść nie widzę.
    Pozdrawiam.

    0
  • #4 08 Lis 2017 08:35
    JacekCz
    Poziom 36  

    kamil94goldman napisał:
    ... , gdyby zamiast zmiennej lokalnej, zadeklarować na początku programu głównego, zmienną globalną z specyfikatorem volatile, zamiast tamtej zmiennej lokalnej.


    Kolejne przesądy volatile? Musisz jeszcze splunąć 3x przez lewe ramię przy pełni księżyca.

    volatile, w sensie o który pytasz, ma odwrotny sens "proszę cię kompilatorze, NIE TRZYMAJ wartości zmiennej w rejestrze i ODKŁADAJ ją do RAM-u".
    Zmienna ma oddawać sens programu. Przy okazji, statystycznie najczęściej to, co jest w dobrym stylu, jest szybsze (albo nie jest wolniejsze).

    Jak masz problem z dwoma taktami CPU, tzn masz grubszy problem. Zgaduję: marnujesz wiele, wiele taktów na co innego.


    EDIT: w darmowych narzędziach da się skompilować C do listingu kodu maszynowego AVR, i są dostępne tabele ile rozkazy trwają. To jest chyba ostatnia linia procesorów (nie posiadająca cache itd), że taka kalkulacja jeszcze ma jakiś sens.


    Dodano po 2 [minuty]:
    kamil94goldman napisał:

    Zmienna globalna będzie deklarowana na początku programu, przez co, cały czas będzie zajmowała miejsce w pamięci RAM, a zmienna lokalna będzie deklarowana w momencie wykonywania przerwania i kasowana po wyjściu z niego. Więc w jakim przypadku, procedura obsługi przerwania, wykona się szybciej?


    A to źródło, które sugeruje volatile, nie objaśnia ile kosztuje 'zadeklarowanie' i 'skasowanie' zmiennej lokalnej?

    0
  • #5 08 Lis 2017 12:04
    kamil94goldman
    Poziom 3  

    WX3V napisał:
    Zatem jeśli zmienna lokalna (ulotna) jest pamiętana w rejestrze procesora, po odłożeniu na Stos jej początkowej wartości, to będzie ona dostępna szybciej niż zmienna globalna.

    Czyli, generalnie zmienna lokalna zadeklarowana w przerwaniu, też będzie odłożona przez kompilator do rejestru i potem wszystkie operacje będą wykonywane na tym rejestrze?

    A jak wygląda sprawa z zmienną lokalną z specyfikatorem "static" ? Taka zmienna, jest niby tworzona w pamięci RAM, tam gdzie zmienne globalne, ale jej dostęp jest możliwy tylko dla funkcji/przerwania w którym została zadeklarowana. Czy taka zmienna też zostanie "przeniesiona" do rejestru i na tym rejestrze będą wykonywane działania?

    Korzystam z atmel studio

    0
  • Pomocny post
    #6 08 Lis 2017 13:05
    JacekCz
    Poziom 36  

    kamil94goldman napisał:
    WX3V napisał:
    Zatem jeśli zmienna lokalna (ulotna) jest pamiętana w rejestrze procesora, po odłożeniu na Stos jej początkowej wartości, to będzie ona dostępna szybciej niż zmienna globalna.

    Czyli, generalnie zmienna lokalna zadeklarowana w przerwaniu, też będzie odłożona przez kompilator do rejestru i potem wszystkie operacje będą wykonywane na tym rejestrze?

    A jak wygląda sprawa z zmienną lokalną z specyfikatorem "static" ? Taka zmienna, jest niby tworzona w pamięci RAM, tam gdzie zmienne globalne, ale jej dostęp jest możliwy tylko dla funkcji/przerwania w którym została zadeklarowana. Czy taka zmienna też zostanie "przeniesiona" do rejestru i na tym rejestrze będą wykonywane działania?

    Korzystam z atmel studio


    Na AVR każde działanie jest ostatecznie wykonane na rejestrach. Pytanie jest jak długo w tych rejestrach przebywa, zmienna 'auto' (tak się mówi - nie ma na to słowa kluczowego, "prawdziwa" niestatyczna zmienna lokalna) może nigdy nie mieć obrazu w pamięci, lub być tam obecna. Zależy od optymalizatora.

    Mam wrażenie, ze kombinujesz. SENS, naukowo mówiąc semantyka zmiennej 'static' jest zupełnie inny niż 'auto' (w przerwaniach nawet BARDZO). Nie ma sensu dla pozornych zysków (jednego bajta/pojedynczych taktów) zmieniać istoty algorytmu, wcześniej czy później się zemści. Pokaż proponowany kod.

    0
  • Pomocny post
    #7 08 Lis 2017 13:28
    WX3V
    Poziom 17  

    kamil94goldman napisał:
    Czyli, generalnie zmienna lokalna zadeklarowana w przerwaniu, też będzie odłożona przez kompilator do rejestru i potem wszystkie operacje będą wykonywane na tym rejestrze?

    Dokładnie tak będzie.

    kamil94goldman napisał:
    A jak wygląda sprawa z zmienną lokalną z specyfikatorem "static" ? Taka zmienna, jest niby tworzona w pamięci RAM, tam gdzie zmienne globalne, ale jej dostęp jest możliwy tylko dla funkcji/przerwania w którym została zadeklarowana. Czy taka zmienna też zostanie "przeniesiona" do rejestru i na tym rejestrze będą wykonywane działania?

    Dla większości przypadków operacje asemblerowe są wykonywane przy użyciu rejestrów. Zatem i zmienna static będzie musiała być przeniesiona do któregoś z nich. Aczkolwiek zawartość tego rejestru nie będzie chroniona czyli rejestr będzie mógł być nadpisany w następnych instrukcjach. Natomiast kolejne odwołanie (w tej samej procedurze) do takiej zmiennej będzie powodowało ponowne jej ściągnięcie z przestrzeni SRAM lub Flash i wpisanie do któregoś z rejestrów - niekoniecznie tego samego co poprzednio.
    Cóż, zwykle kilka kolejnych "przebiegów kompilacji" służy minimalizacji długości kodu wynikowego, a nie minimalizacji czasu jego wykonania. Zresztą taka funkcja celu jest zdecydowanie trudniejsza do praktycznego wykonania.
    W przypadku konieczności minimalizacji czasu obsługi przerwania najczęściej pisze się procedurę obsługi w asm'ie wpisując wyniki w miejsca zmiennych z C usytuowanych w SRAMie. Niestety wymaga to "podglądania" pracy kompilatora C, a dokładniej tego jak organizuje on zmienne w SRAMie. Jest z tym nieco "zachodu".

    kamil94goldman napisał:
    Korzystam z atmel studio

    Też korzystam z tego pakietu. Aczkolwiek mam świadomość, że niektóre z komercyjnych pakietów są znacznie lepiej dopracowane i mają znacznie lepsze możliwości.
    Pozdrawiam.

    0
  • #8 08 Lis 2017 14:21
    kamil94goldman
    Poziom 3  

    JacekCz napisał:
    Pokaż proponowany kod.


    Chodzi mi o moją funkcję regulacji, regulatora PI, w przetwornicy impulsowej. Czy można tutaj może coś lepiej zrobić? (mikrokontroler XMEGA)

    Kod: csharp
    Zaloguj się, aby zobaczyć kod

    0
  • #9 08 Lis 2017 14:55
    BlueDraco
    Specjalista - Mikrokontrolery

    To, co kompilator zrobi ze zmienną, zależy od fantazji jego autora, wybranego stopnia optymalizacji, liczby zmiennych zadeklarowanych w procedurze i 10 innych czynników. Nie należy polegać na tym, że w jakiejś sytuacji kompilator potraktował daną zmienną w określony sposób (np. umieścił w rejestrze). Teoretycznie np. zmienna volatile może też być w rejestrze.

    0
  • #10 08 Lis 2017 15:44
    WX3V
    Poziom 17  

    BlueDraco napisał:
    To, co kompilator zrobi ze zmienną, zależy od fantazji jego autora...

    Z "bólem serca" przyznam, że masz rację. Dlatego pisałem tylko o zasadach (pobożnych życzeniach), według których należy pisać kompilatory. Myślę jednak, że zasada związana z alokacją zmiennych w pamięci SRAM (zgodnie z ich typem i/lub kolejnością w deklaracjach) jest przestrzegana. Gdyby tak nie było to bardzo utrudnionym byłoby pisanie "wstawek" asemblerowych, a to deprecjonowałoby wartość kompilatora w oczach użytkowników - głównie tych nieco bardziej zaawansownych. Zatem napisanie programu w C z obsługą przerwań w asm'ie powinno być realnym rozwiązaniem. Jego jedyną trudnością jest zdekodowanie lub przeczytanie informacji związanej z układaniem zmiennych w SRAM stosowanym przez używany kompilator.
    Natomiast sporą niedogodnością może być to, że ten sam kod źródłowy skompilowany innym kompilatorem może nie działać poprawnie. Nie widzę też szans na stworzenie jakiegoś standardu w tej kwestii.
    Pozdrawiam.

    0
  • #11 08 Lis 2017 16:18
    Sareph
    Poziom 19  

    WX3V napisał:
    Myślę jednak, że zasada związana z alokacją zmiennych w pamięci SRAM (zgodnie z ich typem i/lub kolejnością w deklaracjach) jest przestrzegana.
    Żebyś się nie zdziwił. W końcu GCC z jakiegoś powodu ma parametr "-fno-toplevel-reorder".

    0
  • Pomocny post
    #12 08 Lis 2017 16:19
    Marek_Skalski
    Moderator Projektowanie

    @WX3V
    To co napisałeś to jakiś zbiór życzeń i dziwnych przemyśleń. Albo dopiero zacząłeś programować, albo do tej pory pisałeś programy w asemblerze. Nie ma nic takiego jaki zachowanie kolejności zmiennych, sortowanie po typie czy innym kryterium. Zagnieżdżenie wstawki asm w funkcji obsługi przerwania jest możliwe i nie ma tutaj wątpliwości. Ale pojawia się pytanie czy to ma sens? Szczególnie w takim prostym przerwaniu.
    @kamil94goldman
    Takie sterowanie przetwornicą jest do niczego. Taki układ może bardzo łatwo zdestabilizować, ponieważ nie ma tutaj żadnego filtra/kompensatora.
    Jaka jest częstotliwość PWM, jaka ADC, a z jaką częstotliwością pracuje serwo? Jeżeli wszystko pracuje z taką samą częstotliwością, to popełniłeś jeden z typowych błędów projektując kontroler. Taki układ nie będzie pracował stabilnie i może niszczyć elementy, np. tranzystory.
    Serwo może spokojnie pracować 7x wolniej niż PWM, a rozdzielczość PWM powinna być większa od rozdzielczości ADC. Musisz też mieć odpowiedni margines fazy, inaczej układ zacznie się wzbudzać, albo będzie bardzo leniwie reagować na zmiany obciążenia.
    Polecam materiały dotyczące SMPS na stronach Microchip: prezentacje dotyczące różnych topologii i zasad dobierania elementów, ale też szczegółowe opisy zrealizowanych układów. Znajdziesz tam całkiem udane połączenie teorii z praktyką. Na przykład Tutaj

    0
  • #13 08 Lis 2017 17:54
    JacekCz
    Poziom 36  

    1. Podrzucę Ci pomysł, pomocny lub nie.
    Zrobiłem PWN Atmega8 (czyli straszny dziad) generator miłego dla ucha sinusoidalnego dźwięku (w oparciu o przerwanie timera). Czystość uzyskałem, gdy na samym początku przerwania ustawiałem wartość ze zmiennej do PWM, a potem mogłem ją sobie opracowywać "na nastepny raz" do woli, nieczuły że obliczenia (mnożenia, if'y) trwają za każdym razem nieco inaczej. Inaczej dzwięk charczał.

    2. Z jaką częstotliwością będzie to przerwanie?
    Albo nie mamy problemu wcale, i cała dyskusja o pojedynczych taktach nie ma sensu - albo mamy problem i np głupie dzielenie zjada więcej taktów niż reszta kodu (może koledzy sprostują, jak się dzieli w XMega?)

    3. Zgadzam się z @Marek_Skalski , szczegółowe rady 1 i 2 nie oznaczają, że sama idea algorytmu przetwornicy mnie przekonuje.

    4. dzięki, że zauważasz odmienny sens 'static'. To jest decyzja na poziomie projektowania algorytmu, uzyskanie konkretnego efektu, a nie pojedynczych taktów.

    5. aha, jeszcze jedno, rozwiązanie zagadki :) powołanie zmiennej lokalnej C jest w zasadzie za darmo, zależy jak to oceniamy, a kasowanie zupełnie za darmo (to nie jest alokowanie na heap'ie)

    Dodano po 41 [sekundy]:

    WX3V napisał:

    Dla większości przypadków operacje asemblerowe są wykonywane przy użyciu rejestrów.

    Na niektórych architekturach oblicza się TYLKO w oparciu o rejestr, AVR do nich nalezy (są takie, które zrobią proste obliczenia w oparciu o zmienną RAM). Ale za to rejestrów jest więcej, i są niemal równoważne, znakomicie zwiększa to szanse optymalizatora (w odróżnieniu od Intela 8086, gdzie każdy z niewielu rejestrów jest nieco inny) . Czasy genialnych programistów asemblerowych również z tych powodów odchodzą w przeszłość, jest zupełnie odwrotnie niż 30 lat temu, od wielu generacji cała architektura CPU jest pod wydajną automatyczną kompilację (a nie programista dziubie z niuansami procesora - z kolei jest trudność intelektualnego ogarnięcia przez człowieka kilkunastu rejestrów, kompilator zwykle zrobi to lepiej)

    Użycie słów "operacje assebletrowe " budzi mój sprzeciw, jest totalnie niejasne. Piszesz o kodzie ręcznym? Wygenerowanym automatycznie?

    WX3V napisał:

    Zatem i zmienna static będzie musiała być przeniesiona do któregoś z nich. Aczkolwiek zawartość tego rejestru nie będzie chroniona czyli rejestr będzie mógł być nadpisany w następnych instrukcjach. Natomiast kolejne odwołanie (w tej samej procedurze) do takiej zmiennej będzie powodowało ponowne jej ściągnięcie z przestrzeni SRAM lub Flash i wpisanie do któregoś z rejestrów - niekoniecznie tego samego co poprzednio.
    Cóż, zwykle kilka kolejnych "przebiegów kompilacji" służy minimalizacji długości kodu wynikowego, a nie minimalizacji czasu jego wykonania. Zresztą taka funkcja celu jest zdecydowanie trudniejsza do praktycznego wykonania.


    Tu jest kilka przesmyknięć się nad faktami. M.in. najbardziej typową optymalizacją jest szybkość a nie długość kodu.

    0
  • #14 08 Lis 2017 21:21
    kamil94goldman
    Poziom 3  

    Marek_Skalski napisał:
    Jaka jest częstotliwość PWM, jaka ADC, a z jaką częstotliwością pracuje serwo?

    ADC (12 bit) pracuje w trybie freerunning, z częstotliwością próbkowania około 150 ksps, częstotliwość PWM wynosi 50 kHz, funkcja regulacji przetwornicy, czyli przerwań od timera jest z taką samą częstotliwością, co PWM, czyli 50 kHz w przerwaniach od przepełnienia timera PWM.

    Generalnie układ działa dosyć stabilnie, bez obciążenia napięcie waha się, o około 0,1 V, niekiedy 0,2. Z obciążeniem napięcie jest stabilne co do dziesiętnych części.

    Marek_Skalski napisał:
    Serwo może spokojnie pracować 7x wolniej niż PWM, a rozdzielczość PWM powinna być większa od rozdzielczości ADC.

    Czy to oznacza że funkcja regulacji może być wykonywana około 7x wolniej od częstotliwości PWM? Nie mogę za bardzo zrozumieć dlaczego. Czy układ zdąży zareagować wówczas w stanach dynamicznych?

    Marek_Skalski napisał:
    Takie sterowanie przetwornicą jest do niczego. Taki układ może bardzo łatwo zdestabilizować, ponieważ nie ma tutaj żadnego filtra/kompensatora.

    Z tym kompensatorem chodzi o to, że zmierzona wartość rzeczywista, powinna być uśredniona, za parę cykli pomiaru?

    Marek_Skalski napisał:
    Musisz też mieć odpowiedni margines fazy, inaczej układ zacznie się wzbudzać, albo będzie bardzo leniwie reagować na zmiany obciążenia.

    Co to oznacza margines fazy? nie rozumiem tego za bardzo, ani nigdzie specjalnie nie mogę znaleźć.

    0
  • Pomocny post
    #15 08 Lis 2017 22:39
    Marek_Skalski
    Moderator Projektowanie

    ADC robi 3 pomiary na jeden cykl obliczeniowy. Z tych 3 pomiarów wykorzystujesz tylko 1. Jeżeli nie są synchroniczne, to może się pojawić dodatkowa częstotliwość w obwodzie sterowania. To zależy od częstotliwości charakterystycznej obwodu wyjściowego, m.in. pojemności kondensatora filtrującego. Ciebie trochę ratuje regulator PI, który realizuje prosty filtr dolnoprzepustowy i dlatego możesz osiągnąć dokładność rzędu 0,1V/40V -> 0,25%.
    Regulator zazwyczaj może pracować wolniej niż PWM, ponieważ na wyjściu układu jest jakiś bufor energii. Zazwyczaj jest to kondensator, o znanych parametrach: pojemność C, zastępcza rezystancja szeregowa ESR, napięcie pracy U, itp. Ten element wprowadza inercję w układzie i powinien być starannie dobrany. Mała pojemność powoduje większe tętnienia i niestabilność, zbyt duża pojemność to duży koszt elementu, gorsze ESR, więcej miejsca na płytce.
    Ponownie odsyłam do materiałów dotyczących teorii regulacji, ponieważ bez tego nie zaprojektujesz stabilnej przetwornicy. W skrócie: W praktyce częstotliwość pracy regulatora może być 6x-9x mniejsza niż częstotliwość PWM, a uchyb regulacji nie przekracza 3 LSB PWM.
    Regulator może być synchroniczny, np. każde 7 przerwanie PWM wyzwala ADC, a ten po zakończeniu konwersji wyzwala obliczenia regulatora. Taki układ działa najlepiej, kiedy stosujesz ograniczenie prądu klucza w każdym cyklu.
    Regulator asynchroniczny może pracować w połączeniu z ADC pędzącym w trybie free-running mode, który nie jest synchronizowany z PWM. Taki układ jest niekiedy koniecznością, kiedy regulator jest nieliniowy lub kiedy platforma sprzętowa nie pozwala na synchronizację ADC i PWM. W Twoim przypadku regulator może być synchroniczny, więc powinno wystarczyć wywołanie funkcji regulatora z prędkością ~7kHz. Zamiast regulatora PID, możesz rozważyć regulatory/kompensatory typowe dla przetwornic: 2p-2z, 3p-3z, 4p-4z. Po szczegóły odsyłam do materiałów Microchip (np. DCDT) oraz Biricha.
    Wartość sterująca nie jest uśredniana, ale filtrowana, aby zniwelować/skompensować wpływ poszczególnych częstotliwości charakterystycznych.
    A margines fazy, to inaczej okno czasowe, albo minimalna ilość próbek w obliczeniach, aby mieć pewność, że sygnał sprzężenia zwrotnego, np. mierzone napięcie i/lub prąd ma odpowiedni znak i regulator jest zawsze w obszarze stabilnej pracy; nie wzbudzi się. Do tego właśnie służą narzędzia typu DCDT i diagramy.

    0