Witam Kolejne drobne pytanie : Kiedy można użyć określenia "register" ? W BB podana jest jedynie informacja iż można go użyć , natomiast procesor decyduje czy będzie to zrealizowane czy nie. W MkClipse dla Atmegi8 gdy użyję :
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
uzyskuję natychmiast komunikat błędu:
main.c: In function '__vector_9': main.c:28:30: error: register name not specified for 'st_line' volatile register uint8_t st_line; ^ ---------------- ERROR --> main.c --> Line: 28
Nie do końca to rozumiem - zmienna st_line jest jedno-bajtowa więc skąd błąd? Czy chodzi o niemożność łączenia "register" z "volatile" ? Jeśli tak to dlaczego ? Czy nie można zastosować zmiennej która mogłaby brać udział i w przerwaniu i w programie głównym , i to tak aby mogła być w przerwaniu odświeżana bardzo szybko? Pozdrawiam WTG
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Pamiętaj, żeby używać tego specyfikatora ostrożnie, to znaczy nie definiować zbyt wielu zmiennych w ten sposób i nie używać np. rejestrów wskaźnikowych, bo to znacznie utrudnia optymalizację kompilatorowi. Stosunkowo bezpiecznie jest użyć rejestru z zakresu r2-r7.
A swoją drogą nie rozumiem uwagi - przecież właśnie "volatile" powoduje wyłączenie optymalizacji, skąd więc uwaga , co może spowodować optymalizacja. Z uwagi rozumiem ,że opcja "register" ponownie ją włącza?
Musisz dodać nazwę rejestru przeznaczonego dla zmiennej, na przykład:
Ja oczywiście nie mam najmniejszego zamiaru tutaj kłócić się z zacnym kolegą andrews ale ...
uważam, że stosowanie specyfikatora "register" ma się kompletnie nijak do wstawki asemblerowej asm("") - ZAZNACZAM przy okazji, że nie wypowiadam się jako znawca i mogę się oczywiście mylić - za to chętnie posłucham kontr-argumentów
otóż wg mnie kolega autor wątku z kolei kompletnie też pomieszał sobie na zasadzie grochu z kapustą specyfikatory
Wg mnie specyfikator "register" dodajemy jedynie do zmiennych lokalnych wewnątrz funkcji gdy nie ma konieczności stosowania specyfikatora "volatile"
Bo co innego oznacza tak na prawdę specyfikator "static" dla zmiennej globalnej wewnątrz plilku *.c a co innego oznacza dla zmiennej lokalnej wewnątrz funkcji, ale tu nie chcę wnikać w szczegóły - odsyłam raczej autora pytania do Bluebooka
Podjąłem dyskusję bo być może kolega andrews ma coś ciekawego do dodania odnośnie możliwości takiego mixu zmiennej globalnej, której "zasadzimy" brzydko mówiąc dwa specydikatory, czyli zarówno "volatile" jak i "register" ... przyznam, że mi to nigdy nie przyszło na myśl i dlatego ciekaw jestem jakichś dodatkowych wyjaśnień kolei andrews bo wiem, że to SPEC w zakresie połączeń C z ASM a mnie być może coś umknęło
i gdzie to stosujesz ? dla zmiennej lokalnej czy globalnej w pliku *.c ? Wiesz czym się różni "static" dla zmiennej globalnej od "static" dla zmiennej lokalnej ?
i gdzie to stosujesz ? dla zmiennej lokalnej czy globalnej w pliku *.c ? Wiesz czym się różni "static" dla zmiennej globalnej od "static" dla zmiennej lokalnej ?
Może wyjaśnię o co chodzi - zmienna ma odzwierciedlać (pobierane próbek) chwilowy stan pewnej magistrali. Próbki mają być pobierane stosunkowo często - co ok .10 us w przerwaniu, a następnie obrabiane w funkcji main.c Stąd potrzeba obsługi zarówno w przerwaniu jak i w funkcji main (volatile) jak też i maksymalnego skrócenia czasu operacji (register).
Oczywiście to wszystko to tylko przymiarka do pewnego rozwiązania i próba zdobycia nieco doświadczenia.
Może wyjaśnię o co chodzi - zmienna ma odzwierciedlać (pobierane próbek) chwilowy stan pewnej magistrali. Próbki mają być pobierane stosunkowo często - co ok .10 us w przerwaniu, a następnie obrabiane w funkcji main.c Stąd potrzeba obsługi zarówno w przerwaniu jak i w funkcji main (volatile) jak też i maksymalnego skrócenia czasu operacji (register).
Proszę nie wymyślaj sam nowych możliwości i funkcjonalności w języku C - bo moim zdaniem to właśnie to w tej chwili robisz ....
Zajrzyj do Bluebooka i spójrz gdzie i w stosunku do jakich zmiennych stosujemy specyfikator "register" bo ty zdaje się naginasz rzeczywistość języka C
Podjąłem dyskusję bo być może kolega andrews ma coś ciekawego do dodania odnośnie możliwości takiego mixu zmiennej globalnej, której "zasadzimy" brzydko mówiąc dwa specydikatory, czyli zarówno "volatile" jak i "register" ... przyznam, że mi to nigdy nie przyszło na myśl i dlatego ciekaw jestem jakichś dodatkowych wyjaśnień kolei andrews bo wiem, że to SPEC w zakresie połączeń C z ASM
Wcale nie jestem wielkim SPECem i mogę się mylić (jak widać ). Skoncentrowałem się na przedstawionym przez autora warningu: main.c:28:30: error: register name not specified for 'st_line' volatile register uint8_t st_line; i jakoś tak bezmyślnie skopiowałem to volatile, podając rozwiązanie problemu. Powinno być:
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.
Zapis ten może faktycznie wydawać się nieco dziwny, ale w ten sposób można zdefiniować zmienną globalną, którą kompilator umieści w rejestrze (link), przy czym (jak próbowałem już wcześniej uświadomić) nie jest to do końca bezpieczne i nie zawsze będzie działać zgodnie z założeniem. Nie chcę się tu zbytnio rozpisywać, ale np. jednym z problemów może okazać się choćby korzystanie z bibliotek standardowych. Takie zdefiniowanie zmiennej mówi kompilatorowi, że nie wolno mu używać rejestru przypisanego do zmiennej do innych celów. Z kolei niektóre funkcje z biblioteki standardowej mogą mieć "na sztywno" przypisane używanie tego rejestru (kompilator nie może tego zmienić), więc taki kod nie będzie działał prawidłowo. Nie jest też dobrze zdefiniować zmiennej w którymś z rejestrów wskaźnikowych (r26-r31), jako że są one kompilatorowi bardzo potrzebne do innych celów, rejestry r8-r25 używane są z kolei do przekazywania argumentów funkcji, rejestr r0 to rejestr tymczasowy, a rejestr r1 przechowuje wartość zerową. Innymi słowami, można z tego korzystać, ale należy dokładnie wiedzieć, co można (a czego nie można) w ten sposób osiągnąć i w jaki sposób (stosunkowo) bezpiecznie można to zrobić.
MisterWhite napisał(a):
A swoją drogą nie rozumiem uwagi - przecież właśnie "volatile" powoduje wyłączenie optymalizacji...
Myślę, że należy na to spojrzeć nieco inaczej. volatile mówi raczej kompilatorowi, że nie powinien używać kopii zmiennej znajdującej się w rejestrze, tylko za każdym razem odczytywać do rejestru aktualną zawartość komórki RAM, w której zmienna się znajduje, ponieważ mogła w międzyczasie zostać zmieniona przez inny wątek. Z tego punktu widzenia volatile dla zmiennej register nie ma większego sensu. Niestety dostęp (odczyt/zapis) do zmiennej zdefiniowanej w rejestrze może być zawsze zoptymalizowany przez kompilator, więc kod może nie działać zgodnie z założeniem (i stąd błąd kompilatora przy zdefiniowaniu zmiennej volatile register).
Proszę nie wymyślaj sam nowych możliwości i funkcjonalności w języku C - bo moim zdaniem to właśnie to w tej chwili robisz ....
Zajrzyj do Bluebooka i spójrz gdzie i w stosunku do jakich zmiennych stosujemy specyfikator "register" bo ty zdaje się naginasz rzeczywistość języka C
No cóż, zanim sięgnąłem po pióro bardzo dokładnie przejrzałem krótki akapit na stronie 82 BB i właśnie informacje w nim zawarte nasunęły mi myśl o wykorzystaniu tego specyfikatora.
Natomiast co do wymyślania nowych możliwości języka C to na pewno nie jest to moim celem. Jestem inżynierem, potrzebne mi są pewne narzędzia i jeśli ich nie posiadam próbuję je sobie sam utworzyć. Tworzenie programów czy aplikacji jest na pewno sztuką samą w sobie i to na pewno niemałą, uznaję geniusz ludzi ją uprawiających , tym niemniej dla mnie jest przede wszystkim drogą prowadzącą do konkretnego fizycznego celu i takiż cel mają moje skromne próby. A jeśli czegoś nie rozumiem to się po prostu pytam.
Chciałbym też bardzo podziękować koledze andrews za cierpliwe i wyczerpujące tłumaczenie które sporo mi wyjaśniło. Wszystkim kolegom dziękuję za pomoc i pozdrawiam
Może wyjaśnię o co chodzi - zmienna ma odzwierciedlać (pobierane próbek) chwilowy stan pewnej magistrali. Próbki mają być pobierane stosunkowo często - co ok .10 us w przerwaniu, a następnie obrabiane w funkcji main.c Stąd potrzeba obsługi zarówno w przerwaniu jak i w funkcji main (volatile) jak też i maksymalnego skrócenia czasu operacji (register).
Moim zdaniem próba realizacji takiego zadania za pomocą przypisania zmiennej globalnej do rejestru aby coś tam wykonywało się "szybciej" jest zupełnie nietrafionym pomysłem ... dlaczego ?
Dlatego, że pewnie nie bierzesz pod uwagę w ogóle (tak mi się wydaje) tego co dzieje się w twoim przerwaniu ale od strony asemblera
Pomijając już kod źródłowy procedury twojego przerwania, którego nie pokazałeś a tu może leżeć klucz do problemów z którymi się borykasz to sam prolog i epilog procedury przerwania w wygenerowanym kodzie asm będzie u ciebie zajmował DRASTYCZNIE, podkreślam DRASTYCZNIE więcej czasu niż to czego się spodziewasz (jak sądzę) po wpeklowaniu zmiennej globalnej do jakiegoś tam rejestru ...
piszesz bowiem o czasie 10 us a tymczasem gdyby tobie miało to co chcesz zrobić zaoszczędzić czas .... to ... liczyłeś w ogóle ile byś go zaoszczędził w stosunku do tego gdy zmienna będzie odczytywana i ew zapisywana do RAM (a szczegółów nie znamy bo kodu nie ma) ...
obojętnie co by nie mówić zaoszczędziłbyś panie na takiej operacji hmmm ze dwa może 3 albo i 4 cykle zegara ! NAWET przy taktowaniu procka 1MHz to jest tak nikła oszczędność w stosunku do czasu trwania prologi u epilogu - że sam szybko uznałbyś rozpatrując to w czystym asemblerze, że jak mówię takie podejście nie ma najmniejszego sensu
ale ... skoro piszesz, że coś tam tobie musi działać co 10us i dokonujesz takich troszkę moim zdaniem karkołomnych operacji to sugeruje, że coś tam jednak u ciebie "nie gra" i pewnie brakuje wg ciebie tego czasu 10us - albo może jest zbyt długi wg ciebie ?
--------------------------------------- Pomijając już całkowicie fakt, że język C nie jest do tego żeby pisać aż tak mocno czaso-zależne operacje - bo jak już to pisze się wtedy w asemblerze a w najlepszym wypadku pisze się albo porządną wstawkę w ASM albo jeśli chodzi o przerwanie to wręcz CAŁE przerwanie pisze się w osobnym pliku *.S w czystym asemblerze i łączy to z programem w C. Oczywiście żeby pisać znowu takie czasówki na poziomie pojedynczych mikrosekund w asemblerze to też nie ma co ukrywać, że trzeba mieć spore doświadczenie w pisaniu kodu w asm - bo kod kodowi nie równy ------------------------------------
ale mówię pomijając to co wyżej napisałem to powiedz mi czy chociaż w jakiś minimalny sposób zabrałeś się za dokonanie jakichś miarodajnych pomiarów czasu wykonywania się twojej procedury przerwania ? Nie twierdzę, że nie ale NIC o tym nie napisałeś i tak tylko mogę podejrzewać, że nie ... i tu chciałbym się ciebie zapytać i zasugerować coś - oglądałeś ten poradnik ?
jeśli nie - to gorąco polecam ci go obejrzeć i zastosować w praktyce to o czym mówię w tym poradniku szczególnie w aspekcie tego co robisz i twojego problemu bo tym sposobem, NAWET jeśli nie znasz jeszcze asemblera i nie umiesz do końca analizować zawartości pliku *.lss po kompilacji to naocznie będziesz mógł dowiedzieć się jakie są zależności czasowe w tym co robisz i od czego zależą ... w TRY-MIGA byś zobaczył, że próba wkładania zmiennej globalnej do rejestru nie ma tu żadnego sensu ...
dlatego ja na twoim miejscu poza tym, że koniecznie zająłbym się dokonaniem pomiarów za pomocą analizatora logicznego na sam początek to poszedłbym CAŁKIEM inną drogą w celu przyśpieszenia pewnych operacji - zakładając oczywiście, że masz optymalnie napisany kod źródłowy bo wiesz - tu nie chodzi o żaden przytyk czy złośliwość - ale jeśli kod będzie napisany kompletnie nieoptymalnie to już w ogóle mijają się z celem jakiekolwiek próby tworzenia tego typu zmiennych w rejestrach ... kompletnie
ale ok zakładając, że kod optymalny to - NIC nie napisałeś na przykład - na temat taktowania twojego procka a już na tym polu możesz dokonywać jak to się mówi samozaorania z tymi szybkościami. Podam przykład - jeśli np masz taktowanie fabryczne 1 MHz to ile wynosi JEDEN cykl zegara w stosunku do 10 us ? hmmm gdyby tak na to spojrzeć i gdybyś miał ten 1 MHz to pierwsze co powinno przyjść do głowy - to moim zdaniem drastyczne zwiększenie taktowania procka, które może nawet zniwelować wady czasowe nieoptymalnego kodu źródłowego.
Krótko mówiąc nawet jeśli masz taktowanie 8Mhz albo i nieco więcej - to zastanowiłbym się nad zastosowaniem chociaż do testów swojego kodu a szczególnie z analizatorem stanów logicznych pod ręką - nad WŁOŻENIEM kwarcucha maksymalnie możliwego czyli np 20 MHz
Jeśli zwiększenie taktowania nie pomoże a sięgasz po czasy mikrosekundowe w przerwaniach to jednak musisz się nastawić na naukę asemblera żeby próbować sobie napisać obsługę takiego przerwania w czystym asemblerze ale nie tylko tak dla idei bo przecież C też generuje optymalny asembler i często osobie początkującej w asm ciężko w ogóle zbliżyć się do napisania tak optymalnego kodu a co dopiero mówić o "prześcignięciu" tego co robi kompilator.... Tu zapewne odezwaliby się zatwardziali asemblerowcy pisząc wręcz, że wkurza ich ten cały kompilator C bo wiele rzeczy robi "na piechotę" albo mało optymalnie - ale z ich punktu widzenia ... tyle, że ci zagorzali asemblerowcy od lat programowali w asemblerze zatem nie ma co się też dziwić takiemu podejściu ...
Może wyjaśnię o co chodzi - zmienna ma odzwierciedlać (pobierane próbek) chwilowy stan pewnej magistrali. Próbki mają być pobierane stosunkowo często - co ok .10 us w przerwaniu, a następnie obrabiane w funkcji main.c Stąd potrzeba obsługi zarówno w przerwaniu jak i w funkcji main (volatile) jak też i maksymalnego skrócenia czasu operacji (register).
Oczywiście to wszystko to tylko przymiarka do pewnego rozwiązania i próba zdobycia nieco doświadczenia.
Nie przedstawiłeś szczegółów projektu, ale z tego co piszesz wnioskuję, że skoro planujesz użyć zmiennej umieszczonej w rejestrze (nie magazynujesz próbek gdzieś w RAM w celu dalszej obróbki), to wszelkie operacje na zmiennej muszą być wykonane w czasie krótszym niż te 10us, czyli zanim nadejdzie następna próbka. Inaczej mówiąc te 10us musi starczyć nie tylko na obsługę procedury obsługi przerwania, ale też na jeden pełny obieg pętli nieskończonej we funkcji main(), bo inaczej niektóre próbki zostaną pominięte. Nawet przy taktowaniu 20MHz będziesz miał na to wszystko tylko 200 taktów zegara, czyli niezbyt wiele (jak już wspomniał kolega Mirek, sam prolog i epilog procedury obsługi przerwania napisanej w C zajmą sporo czasu). Podsumowując: skoro i tak analiza jednej próbki musi zostać wykonana przed nadejściem następnej próbki, to obliczenia lepiej wykonać wewnątrz procedury obsługi przerwania, bo inne zadania wykonywane przez pętlę nieskończoną funkcji main() będą tylko niepotrzebnie przedłużać sprawę. To eliminuje konieczność wymiany danych próbki pomiędzy ISR a main(), czyli użycia register.
Nie wiem jakiego mikrokontrolera używasz, ale alternatywą dla tego, co chciałeś osiągnąć dzięki volatile register może być użycie GPIOR. Rejestry te są osiągalne dla instrukcji IN oraz OUT (czyli 1-taktowy dostęp dla odczytu/zapisu) oraz jest zdefiniowany jako volatile (dostęp do niego nie zostanie zoptymalizowany). Dość łatwo można napisać bardzo krótką procedurę obsługi przerwania w ASM, kopiującą zawartość portu do tego rejestru, trwającą zaledwie 6 taktów zegara (pomijając wejście w procedurę i powrót z niej, czyli instrukcję RETI).
Nie wiem na jakim etapie jest Twój projekt, jednak według mnie - jeśli jeszcze nie jest za późno - dobrze byłoby rozważyć użycie mikrokontrolera z rodziny XMEGA do tego typu zadania. Nie chodzi mi tylko o możliwość pracy rdzenia z większą prędkością, ale o możliwość wykorzystania systemu zdarzeń i DMA. Dzięki temu zbieranie próbek może odbywać się "w tle" bez konieczności angażowania rdzenia w ten proces (czyli bez konieczności użycia przerwania w celu pobrania próbki).
Przede wszystkim chciałbym gorąco podziękować kolegom za poświęcony czas i wnikliwą analizę konstrukcji ktorą chcę uzyskać. Materiał ten dał mi dużo do myślenia i pomógł ponownie przemyśleć pewne sprawy. Co do urządzenia, to ma to być monitor szyny I2C. Z założenia w przerwaniu będzie tylko pobierana próbka stanów SCL i SDA a następnie w procedurze głównej ma działać prosta, oparta na 5-cio elementowym grafie maszyna stanów, określająca zdarzenia na magistrali. To wydaje się być realizowalne, kłopot sprawia sposób szybkiego przekazywania wyników, ale to oddzielny problem. Wygrzebałem gdzieś w domu stare dwie płytki z Atmegą 8 i kwarcem 11059000 na których ktoś kiedyś chciał z miernym skutkiem zrealizować taki monitor. Właśnie po obejrzeniu swojego czasu poradnika poświęconego Saleae pojawiła się myśl iż mając możliwość pomiaru czasu procedur w procku i wykorzystując zasadę "jednodiodowego debugera" mógłbym spróbować sam coś takiego zbudować. Jednak konkretne kształty pomysł przybrał po przeczytaniu gdzieś artykułu o realizacji maszyny stanów w języku C. Tego typu konstrukcja w zasadzie znacznie lepiej realizuje się w strukurze FPGA która (tak mi się wydaje) jest dużo szybsza i bardziej naturalna dla implementowania maszyny stanów ,jednak mając dwie gotowe płytki do oprogramowania chciałem sprawdzić zarówno jak się sprawdzi maszyna stanów w takiej konstrukcji jak też do jakiej prędkości szyny uda mi się to urządzonko wykorzystać. Jak dotąd implementując od paru lat proste systemiki w małych sterownikach PLC przekonałem się , iż konstrukcje oparte na współdziałających maszynach stanów wymagają tylko niewielkich poprawek przy uruchamianiu po czym pracują bezawaryjnie latami nie ujawniając żadnych ukrytych bugów.Dlatego między innymi chcę spróbowac przeniesienia maszyny stanów na mały procek oraz porównać korzyści i straty wynikające z tego tytułu. Jeszcze raz dziękuję za pomoc i proszę o dalsze wsparcie Pozdrawiam
A swoją drogą korzystając z uwag Mirka i andrews'a spróbuję w ramach testu zarówno "wepchnąć" maszynę stanów do przerwania jak też i zrealizować ją w asemblerze. Mając Saleae łatwo będzie porównac wyniki
Rozumiem, że jest to projekt eksperymentalno-edukacyjny, jednak zwróć uwagę na swoje założenia.
Standardowa prędkość magistrali I2C to 100kHz. Próbkowanie powinno odbywać się z prędkością minimum dwukrotnie większą (przy założeniu, że np. wypełnienie sygnału na linii SCL jest równe 50%), czyli 200kHz, co daje okres próbkowania 5us. Jest to dwukrotnie mniej niż założyłeś, więc będziesz musiał się dwukrotnie tak sprężać, lub nawet bardziej, bo przecież taktowanie, którym obecnie dysponujesz nie jest szczególnie imponujące. Będziesz miał na identyfikację zdarzenia tylko ok. 55 taktów, a przecież samo zidentyfikowanie zdarzenia na magistrali to nie wszystko...
Należy też wziąć pod uwagę, że obecnie magistrala ta coraz częściej pracuje z dużo większymi prędkościami
Rozumiem, że jest to projekt eksperymentalno-edukacyjny, jednak zwróć uwagę na swoje założenia.
Standardowa prędkość magistrali I2C to 100kHz. Próbkowanie powinno odbywać się z prędkością minimum dwukrotnie większą (przy założeniu, że np. wypełnienie sygnału na linii SCL jest równe 50%), czyli 200kHz, co daje okres próbkowania 5us. Jest to dwukrotnie mniej niż założyłeś, więc będziesz musiał się dwukrotnie tak sprężać, lub nawet bardziej, bo przecież taktowanie, którym obecnie dysponujesz nie jest szczególnie imponujące. Będziesz miał na identyfikację zdarzenia tylko ok. 55 taktów, a przecież samo zidentyfikowanie zdarzenia na magistrali to nie wszystko...
Należy też wziąć pod uwagę, że obecnie magistrala ta coraz częściej pracuje z dużo większymi prędkościami
Niestety, jest dokladnie tak jak mówisz i zdaję sobie z tego sprawę. Tym niemniej jak bardzo słusznie zauważyłeś jest to projekt eksperymentalno-edukacyjny. Skoro już znalazłem gotowe płytki z kiepskim wprawdzie prockiem , ale stanowiące już gotowy hardware postanowiłem na nich poeksperymentować i sprawdzić słuszność sposobu realizacji. Ponieważ mam do dyspozycji zestaw ATB-105 i doskonałe przykłady realizacji I2C w wersji zarówno programowej jak i sprzętowej podane przez mirka,więc spróbuję trochę przy nich podłubać aby dopasować prędkość magistrali do swoich potrzeb. W ten sposób będę miał zarówno znany wzorzec magistrali (ATB105)o regulowanej prędkości jak też i narzędzie do pomiaru elementów aplikacji (analizator +debuger na jednej diodzie). Jeśli założenia się potwierdzą (bezbłędny odczyt zdarzeń) spróbuję czegoś dużo szybszego. Na razie ma to być tylko szacunek możliwości z wykorzystaniem posiadanych zasobów (0-kosztów)
Użytkownicy przeglądający ten dział: Google [Bot] i 2 gości
Nie możesz rozpoczynać nowych wątków Nie możesz odpowiadać w wątkach Nie możesz edytować swoich postów Nie możesz usuwać swoich postów Nie możesz dodawać załączników