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

Bezpieczne kopiowanie zmiennych 16-bitowych w C na 8051 przy przerwaniach UART

26 Maj 2008 16:53 1764 12
REKLAMA
  • #1 5183113
    Konto nie istnieje
    Konto nie istnieje  
  • REKLAMA
  • REKLAMA
  • #3 5183246
    szelus
    Poziom 34  
    Posty: 1508
    Pomógł: 315
    Ocena: 53
    Freddie Chopin napisał:
    jezyk C radzi sobie z tym sam.


    Bynajmniej. Jeżeli, z uwagi na architekturę procesora, np. podstawienie czy inna instrukcja wymaga więcej niż jednego rozkazu procesora to kompilator wygeneruje oczywiście właściwą sekwencję rozkazów, ale w żaden sposób nie będzie ona zabezpieczona przed (potencjalnym) zakłóceniem jej przez przerwanie.
    Jeżeli zatem dostęp do danych jest zarówno w przerwaniu jak i poza nim, dostęp w różnych wątkach itp. dostęp współbieżny, to trzeba zastosować odpowiednie zabezpieczenia również w C. Np. blokować przerwania w odpowiednich miejscach itp.
  • #4 5185590
    Konto nie istnieje
    Konto nie istnieje  
  • #5 5185635
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    root-5 napisał:
    Ale poprzedni gość jest w błędzie bo język C sobie z tym nie radzi.

    zato wy chyba nie bardzo macie pojecie o czym gadacie...

    Cytat:

    Przerwanie może przyjść w każdym momencie i przerwać wykonywanie jakiejs operacji np. przepisywania intów lub mnożenia doublów.

    przerwanie moze ci przyjsc nawet w srodku liczenia FFT z 10k punktow i nie ma to zadnego znaczenia. tak samo moze ci to przerwanie przyjsc 38x w czasie kopiowania 10kB tablicy liczb typu double i rowniez nie ma to znaczenia. jezyk C radzi sobie z tym SAM.

    jedyny problem to chwile, gdy DWIE (lub wiecej) operacje ASSEMBLEROWE musza zostac wykonane NATYCHIAST po sobie. rozne sa przyklady takich chwil, np w 16-b PIC blokowanie zmian rejestry oscylatora polega na wpisaniu do niego 2 roznych wartosci i musi to zajac 2 cykle. czasem dla przykladu odczyt wartosci 32-b licznikow w 16-b procku polega na odczycie NAJPIERW wartosci dolnej, potem gornej i zeby to mialo sens, to raczej przerwanie nie powinno tego rozdzielac.

    czasem problem pojawia sie tez, gdy kod glowny i przerwania operuja na tych samych danych, ale taki sam problem wystepuje w assemblerze i jest on do rozwiazania.

    a teraz odpowiedz sobie sam, jak czesto trafiaja sie chwile, gdy cos musi zostac wykonane z takimi restrykcjami.
    HINT: czestosc << 1% przypadkow.

    0x41 0x56 0x45!!
  • REKLAMA
  • #6 5186008
    Bigfoot
    Poziom 25  
    Posty: 982
    Pomógł: 74
    Ocena: 13
    :arrow: root-5: Oczywiscie, ze masz racje. W sytuacji, o ktorej piszesz musisz uzyc jakiejs flagi, ktora zwolni sie po dokonaniu przepisania i dopiero wtedy zezwoli na aktualizacje danych z przerwania (choc samego przerwania wcale wylaczac nie musisz). Ta prosta czynnosc zapobiegnie przeklamaniu danych przez przerwanie, ktore wystapiloby w trakcie (potencjalny problem: jedna polowka inta ze starej paczki, druga z nowej).

    :arrow: Freddie Chopin: Jezyk C sam sobie z niczym nie radzi. Wszystko zalezy tylko i wylacznie od poprawnego rozumenia i pisania kodu przez programiste. Zly programista uzywajac jezyka C w sytuacji, o ktorej rozmawiamy nie zastosuje jednej banalnej flagi i bug murowany. Dobry programista pomysli tak jak pomyslal kolega root-5, uzyje flagi i program bedzie dzialal OK.

    BF
  • #7 5186042
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    tyle ze uzycie tej flagi (czy jakiegokolwiek innego sposobu) to nie kwestia jezyka C, tylko kazdego jaki istnieje, z assemblerem wlacznie.

    inna sprawa jest to, ze koniecznosc rownoczesnego wspoldzielenia zmiennych przez przerwanie i funkcje zachodzi raczej nieczesto, a jak juz zajdzie, to i tak mozna jej czesto uniknac na conajmniej kilka sposobow. dlatego tez tworzenie zabezpieczen o jakich jest tu mowa jest potrzebne naprawde niezmienie rzadko, a pomysly jakie tu padaja spowodowalyby jedynie to, ze 90% kodu to bedzie wlaczanie i wylaczanie przerwan.

    0x41 0x56 0x45!!
  • #8 5186096
    Bigfoot
    Poziom 25  
    Posty: 982
    Pomógł: 74
    Ocena: 13
    No nie ja pisalem, ze C sam sobie z tym radzi. Programista musi sobie z tym radzic, niewazne w czym pisze.

    Fakt, ze nieczesto zachodzi potencjalnie niebezpieczna sytuacja przeklamania danych przez przerwanie nie jest zadnym przeslaniem do tego by ja ignorowac.

    Przerwan wcale nie trzeba wylaczac i wylaczac (moim zdaniem nawet nie powinno sie tego robic) tylko uzywac metod programowych takich, jak na przyklad flaga (+buforowanie UARTA), o ktorej na samym poczatku napisal root-5.

    BF
  • #9 5186167
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    hipotetyczna sytuacja o ktorej napisano w pierwszym poscie jest... hipotetyczna. [;

    najpierw wystarczy po prostu wyliczyc, a potem nakazac stworzonym przez siebie funkcjom wyslac te dwa bajty - problemu nie ma. jak musi byc super szybko, to przeciez uart przyjmuje tylko 1 bajt, wiec drugiego nie dostanie dopoki nie zostanie on obliczony, bo dopoki nie zostanie obliczony, to po prostu nic nie zostanie przepisane z RAMu do buforow.

    P.S. jakby ktos nie zauwazyl, to moja odpowiedz pojawila sie w temacie, gdy jeszcze nie widzialem dodanego do pierwszego posta tekstu. takie sa efekty pisania postow na 3 raty. pomijajac sytuacje opisana w dodatku, moja odpowiedz jest wlasciwa dla pierwszej czesci posta, w ktorej nigdzie nie pisze, ze owe unsigned int jest uzywane gdzies w przerwaniu.

    0x41 0x56 0x45!!
  • #10 5186168
    fantom
    Poziom 31  
    Posty: 1649
    Pomógł: 108
    Ocena: 41
    Bigfoot napisał:

    Przerwan wcale nie trzeba wylaczac i wylaczac (moim zdaniem nawet nie powinno sie tego robic)


    Wlasnie tak to sie robi we wspolbieznych systemach operacyjnych do synchronizacji wiec twoje zdanie jest bledne. Oczywiscie musi to byc ograniczone do absolutnego minimum ale musi byc.

    Oczywiscie jezyk C z niczym sobie sam nie radzi a juz napewno nie z synchronizacja danych ale z drugiej strony tutaj roznicy miedzy C a asemblerem nie ma zadnej bo niby jak miala by ta roznica wygladac.
  • #11 5186224
    Bigfoot
    Poziom 25  
    Posty: 982
    Pomógł: 74
    Ocena: 13
    :arrow: fantom: Nie wiem za duzo o synchronizacji we wspolbieznych systemach operacyjnych - wierze, ze masz racje w tym co piszesz. My jednak rozmawiamy tylko o 8051 i odbiorze z UARTa. Caly czas w tym przypadku nie widze koniecznosci wylaczania przerwania a wrecz balbym sie to zrobic by nie stracic jakiejs z przychodzacych danych...

    BF
  • #12 5193716
    arturt134
    Poziom 27  
    Posty: 792
    Pomógł: 76
    Ocena: 24
    A dlaczego boisz się wyłączania przerwań? Normalną procedurą jest globalne wyłączanie przerwań na czas krytycznych operacji np. kasowanie w programie głównym flagi, która jest ustawiana w przerwaniu.
    Oczywiście nie można ich blokować na zbyt długo, bo można coś zgubić. Najważniejsze jest, aby w czasie gdy przerwania są zablokowane nie pojawiły się DWA takie same przerwania. Bo jedno będzie obsłużone po ponownym włączeniu przerwań, ale jeżeli przyjdą dwa, to obsłużone będzie tylko drugie...
  • REKLAMA
  • #13 5202522
    starob
    Poziom 29  
    Posty: 1088
    Pomógł: 128
    Ocena: 137
    Trochę wróżycie z fusów.
    Nigdzie nie wyczytałem, że jest to przerwanie od UART tylko przerwanie w którym wysyłamy przez UART chyba 2 bajty.
    Tylko autor postu tak naprawę wie "o co chodzi" w tym programie.
    Jeśli utrata przerwania nie zakłóci działania programu można je wyłączyć.
    Jeśli nie, potrzebna będzie flaga "dane gotowe" i obsługa w przerwania przypadku "nie gotowe".
    Jeśli dane można wysłać później - wprowadzić flagę "było przerwanie" i czekać na gotowe dane.
    Wszystko zależy od wagi zdarzeń.
    Dużo niewiadomych i "jeśli".

Podsumowanie tematu

✨ Dyskusja dotyczy problemu bezpiecznego kopiowania 16-bitowych zmiennych typu unsigned int w języku C na mikrokontrolerze 8051 podczas obsługi przerwań UART. Ze względu na architekturę 8051, operacje na 16-bitowych zmiennych są realizowane dwuczęściowo (po jednym bajcie), co może prowadzić do sytuacji, gdy przerwanie nastąpi pomiędzy kopiowaniem poszczególnych bajtów i spowoduje wysłanie niekompletnych lub niespójnych danych. W asemblerze problem ten jest znany i rozwiązywany przez blokowanie przerwań lub stosowanie flag synchronizujących. W języku C kompilator generuje odpowiednią sekwencję instrukcji, ale nie zapewnia automatycznej ochrony przed przerwaniem w trakcie wieloetapowej operacji kopiowania. Konieczne jest więc ręczne zabezpieczenie dostępu do współdzielonych danych, np. przez tymczasowe blokowanie przerwań lub stosowanie flag informujących o stanie kopiowania. Dyskutanci podkreślają, że problem synchronizacji danych między kodem głównym a przerwaniami nie jest specyficzny dla C, lecz dotyczy wszystkich języków programowania, w tym asemblera. Zalecane jest minimalizowanie czasu blokowania przerwań, aby nie utracić danych przychodzących przez UART. Alternatywnie można stosować buforowanie danych i flagi stanu, aby zapewnić spójność przesyłanych informacji bez konieczności wyłączania przerwań. W praktyce problem ten pojawia się rzadko i można go rozwiązać przez odpowiednie projektowanie kodu i synchronizację dostępu do zmiennych współdzielonych.
Wygenerowane przez model językowy.
REKLAMA