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

[STM32F1][c/asm] - ilość cykli zegara miedzy dwoma kolejnymi instrukcjami ldr

smarq8 01 Lis 2018 16:05 864 7
REKLAMA
  • #1 17532168
    smarq8
    Poziom 3  
    Posty: 75
    Ocena: 20
    Witam.
    Dla ćwiczebności napisałem sobie funkcję zwracającą ilość cykli zegara w celu pomiaru długości wykonywania funkcji itp.
    Aby to osiągnąć odczytuję "PENDSTSET" oraz stan licznika SysTick. Jednak pomiędzy tymi dwoma odczytami upływa trochę czasu i wartość licznika jestem w stanie skorygować znając czas jaki upłynął miedzy tymi dwoma instrukcjami oraz stan licznika ms wiedząc czy miała nastąpić aktualizacja czy też nie. Wszystko to oczywiści w sekcji krytycznej bo wywołanie przerwania zaburzy w sposób znaczący pomiar.
    Moje pytanie więc brzmi: czy wykonując 2 instrukcję ldr jedna po drugiej mogę mieć pewność, że zostaną one wykonane zawsze w tym samym czasie?

    Przy okazji miałbym także kilka innych pytań:
    - Czy aby mieć pewność, że flaga PENDSTSET jest aktualna muszę wcześniej wykonać dsb,isb? Albo czy w ogóle istnieje ryzyko, że ta flaga wystąpi z pewnym opóźnieniem?
    - flaga PENDSTSET zapala się w momencie kiedy licznik dojdzie do 0 czy zaraz potem?
    - jak we wstawkach mogę bezpośrednio wykorzystywać rejestry np jako tymczasowa zmienna ale tak aby nie nadpisać jakiegoś rejestru i żeby nie musieć deklarować zmiennej poza wstawka (w moim przykładzie jest to "priMsk")? W momencie kiedy zamiast %[priMsk] użyję np R5 to zostaje on potem nadpisany przez pbrOut który także jest zapisywany w R5, czyli kompilator w żaden sposób nie widzi tego, że we wstawce mogło dojść do nadpisania jakiś danych jeśli nie zadeklaruję wcześniej jakiejś zmiennej.

    Jest to moja pierwsza wstawka asm oraz przy okazji pisania tej funkcji dowiedziałem się, że CORTEX nie koniecznie wykonuje czynności w spodziewanej kolejności czy w spodziewany sposób, przekonałem się o tym dobitnie po kilku dniach nieustającej próby napisania tego w c/c++ bez podglądu na wygenerowany kod (tzn algorytm działał jednak występowały jittery nie spowodowane przerwaniami a przewidywanie stanu licznika zależało od ustawionego stopnia optymalizacji kompilatora oraz sposobu wykorzystania funkcji)

    W chwili obecnej funkcja wydaję się już działać poprawnie, wolę jednak rozwiać wszelkie wątpliwości szczególnie jeśli chodzi o pierwsze pytanie

    REKLAMA


    Moja platforma to "BluePill" STM32F103C
    Arduino IDE + biblioteki STM https://github.com/rogerclarkmelbourne/Arduino_STM32

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Kod wygenerowany po kompilacji:
     
    ...
     800215e:	4a26      	ldr	r2, [pc, #152]	; (80021f8 <_Z4loopv+0x9c>)
     8002160:	4926      	ldr	r1, [pc, #152]	; (80021fc <_Z4loopv+0xa0>)
     8002162:	f3ef 8010 	mrs	r0, PRIMASK
     8002166:	b672      	cpsid	i
     8002168:	680d      	ldr	r5, [r1, #0]
     800216a:	6813      	ldr	r3, [r2, #0]
     800216c:	f380 8810 	msr	PRIMASK, r0
    ...
    
  • REKLAMA
  • Pomocny post
    #2 17532312
    Konto nie istnieje
    Poziom 1  
  • REKLAMA
  • #3 17532766
    smarq8
    Poziom 3  
    Posty: 75
    Ocena: 20
    stmx napisał:
    Gdybyś musiał za każdym razem stosować instrukcje blokujące aby coś odczytać to żadne czytanie flag nie miałoby sensu.


    w tym przypadku jest to konieczne gdyż muszę znać stan licznika SysTick oraz stan licznika ms który jest inkrementowany w przerwaniu a z racji, że niemożliwym jest odczyt 2 zmiennych dokładnie w tym samym czasie (a przynajmniej ja nie znam takiej metody) to muszę odczytać to sekwencyjnie a potem wyliczyć jaka była wartość w konkretnym momencie. Gdyby tak przerwania następowały pomiędzy tymi odczytami albo gdyby licznik ms inkrementował w trakcie to wyliczenie dokładnych wartości staje się NIEMOŻLIWE oraz będzie wprowadzać bliżej nieokreślone opóźnienia w pomiarze. Tak więc czytając flagę PENDSTSET jestem w stanie stwierdzić czy licznik ms jest aktualny czy też nie i w razie potrzeby zrobić korektę a przerwanie SysTick ma całą 1ms na to aby się wykonać. Tak samo jeśli wiem, że pomiędzy 2 instrukcjami następuje x cykli i jednocześnie widzę, że licznik SysTick jest zaraz po "przeładowaniu" a x cykli temu był przed przeładowaniem na co wskazywałaby także flaga PENDSTSET to także jestem w stanie to skorygować ale tylko pod warunkiem, że ilość cykli między tymi dwoma odczytami jest z góry znana. Zawsze można także zatrzymać timer SysTick i odczytać dane i wznowić jego pracę ponownie ale jest to z mojego punktu widzenia metoda 'inwazyjna' która z kolei będzie mi akumulować błąd w liczniku ms.

    stmx napisał:
    Tak przy okazji - lepiej zapoznać się z dokumetacją procesora niż uczyć się instrukcji asemblera. Kompilator i tak będzie je pamiętał lepiej, a jestem przekonany, że stosowalność asemblera w programowaniu ARM-ów jest mniej niż znikoma.

    Całego programu w asm nie mam zamiaru pisać ale jego podstawowa znajomość mi nie zaszkodzi w krytycznych miejscach gdzie muszę mieć 100% pewność w jaki sposób coś mi się wykona, analizowanie kodu wynikowego też mi zaczyna pomagać (do przedwczoraj myślałem, że można odczytać pamięć pod konkretnym adresem wyłącznie jedna instrukcją ;))
  • REKLAMA
  • Pomocny post
    #4 17533425
    Konto nie istnieje
    Poziom 1  
  • #5 17533588
    smarq8
    Poziom 3  
    Posty: 75
    Ocena: 20
    stmx napisał:
    A nie prościej wyłaczyć przerwania na te 4 takty zegara.

    Widzę nie do końca rozumiemy się... patrz na kod z 1 postu.

    stmx napisał:
    (proponuję zapoznać się z DWT).

    Kilkukrotnie przekopałem dokumentację i nie przykuło to mojej uwagi. a Tu jest rozwiązanie które wykona się w 3-4 cykle zegara a nie 60+.
    Wcześniej zrobiłem coś podobnego z wykorzystaniem innego timera ale potrzebowałem go do innych celów dlatego chciałem napisać coś co będzie korzystać z czegoś co już jest dostępne i jednocześnie nie będzie marnować innych zasobów. Myślę, że DWT jest rozwiązaniem wszystkich moich problemów, mimo wszystko człowiek nauczył się czegoś o timerach i asm.
    serdecznie podziękował.

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #6 17533675
    Konto nie istnieje
    Poziom 1  
  • REKLAMA
  • #7 17533698
    _lazor_
    VIP Zasłużony dla elektroda
    Posty: 3795
    Pomógł: 259
    Ocena: 1132
    Zgodzę się z przedmówcą. Dodam tylko od siebie, że pisząc w języku, który dostarcza nam kolejnej warstwy abstrakcji nad kodem w assemblerze warto dogłębnie poznać zachowanie kompilatora oraz zasad jakimi rządzi się sam język.
    Jak wiadomo diabeł tkwi w szczegółach i to te szczegóły często determinują jaki kod wynikowy dostaniemy z kompilatora.
  • #8 17533739
    Konto nie istnieje
    Poziom 1  

Podsumowanie tematu

LABEL_AI_GENERATED
Dyskusja dotyczy pomiaru cykli zegara między instrukcjami ldr w kontekście mikrokontrolerów STM32F1. Użytkownik poszukuje sposobu na dokładne odczytanie stanu licznika SysTick oraz flagi PENDSTSET, aby uniknąć zakłóceń spowodowanych przerwaniami. Odpowiedzi wskazują na różne czynniki wpływające na czas wykonania instrukcji, takie jak dostęp do pamięci FLASH oraz dekodowanie instrukcji. Proponowane są alternatywne metody, takie jak użycie rejestru DWT do pomiaru cykli zegara, co może być bardziej efektywne niż manipulowanie przerwaniami. Wskazano również na znaczenie znajomości architektury procesora oraz możliwości kompilatora, co może przynieść lepsze rezultaty w programowaniu.
Podsumowanie AI na podstawie dyskusji. Może zawierać błędy.
REKLAMA