22 października 2018

Małe wyjaśnienie pierwszego programu

W poprzednim wpisie wykorzystałem prosty program do przetestowania działania płytki. Wypadałoby jednak napisać kilka słów wyjaśnienia - co i jak działa.
Dioda LD2 jest podłączona na płytce Nucleo do pinu PA5. Ta informacja jest głęboko ukryta w dokumentacji płytki ewaluacyjnej, jednak skoro działa to pewnie wszystko się zgadza.
Pierwsza linijka program to uruchomienie zegara dla portu A:

RCC->AHBENR |= RCC_AHBENR_GPIOAEN;

Moduł RCC jest odpowiedzialny za konfigurację zegarów, po resecie wszystkie moduły poza pamięcią Flash oraz SRAM są wyłączone. Ponieważ chcemy sterować diodą LD2, uruchamiamy taktowanie zegara dla portu A. Więcej o rejestrze AHBENR znajdziemy w dokumentacji:

 
Jak łatwo się domyślić znajdziemy tam piny odpowiadające za taktowanie pozostałych portów (B,C,D,E,F), moduł obliczania sumy kontrolnej (CRC), kontroler pamięci Flash, SRAM oraz DMA.

Po resecie wartość tego rejestru to 0x14, co odpowiada wspomnianemu włączeniu taktowania pamięci Flash oraz SRAM.

Kolejne dwie linijki to ustawienie trybu dla pinu PA5 jako wyjścia:

    GPIOA->MODER |= GPIO_MODER_MODER5_0;
    GPIOA->MODER &= ~GPIO_MODER_MODER5_1;


Za konfigurację każdego pinu odpowiadają dwa bity - co daje 4 możliwe tryby:

  • 0 - wejście
  • 1 - wyjście
  • 2 - moduł peryferyjny
  • 3 - wejście analogowe
Jak zwykle pełny opis tego rejestru znajdziemy w dokumentacji:


 W przykładzie ustawiłem niższy bit, a wyzerowałem wyższy - w ten sposób wybrana została funkcja "1", czyli pin w trybie wyjściowym. Po resecie układu większość pinów jest w trybie wejścia, czyli rejestr MODER ma wartość zero - stąd instrukcję zerowania bitu można byłoby pominąć, ale tym razem ją zostawiłem dla porządku.

Pętla główna to opóźnienia w pętlach for oraz zapalenie i wygaszenie diody instrukcjami:

        GPIOA->ODR |= GPIO_ODR_5;
        GPIOA->ODR &= ~GPIO_ODR_5;

 
Rejestr ODR przechowuje wartości dla pinów w trybie wyjścia - czyli dokładnie to o co nam chodziło:


Ustawienie odpowiedniego bitu sprawia, że na pinie PA5 pojawia się napięcie 3.3V, a dioda LD5 zaczyna świecić. Natomiast wyzerowanie bitu zmienia napięcie na 0V i gasi diodę LD5. W dokumentacji znajdziemy ważną uwagę o braku atomowości przy dostępie do rejestru ODR. Wrócę do tego później, w największym skrócie: lepiej nie pisać programów jak pokazuje ten przykład.
W przypadku naszego mikorkontrolera operator |= oraz &= jest tłumaczony na kilka instrukcji asemblera, możemy się o tym przekonać zatrzymując program za pomocą debuggera i oglądając jego kod:



Jak widzimy, kompilator wygenerował następujący kod:

   ldr     r2, [r2, #20]
   movs    r1, #32
   orrs    r2, r1
   str     r2, [r3, #20]


Instrukcja LDR wczytuje wartość rejestru ODR, następne dwie instrukcje to zapalenie bitu, a końcowy STR to zapis nowej wartości. Niestety pomiędzy LDR, a STR istnieje ryzyko na pojawienie się przerwania. W obecnym programie to nie problem, ale gdyby w przerwaniu zmienić zawartość rejestru ODR, program mógłby zachowywać się nieprawidłowo. Później wrócę do tego przykładu.
Podsumowując: ten program jest poprawny, chociaż zaprezentowanego sposobu dostępu do pinów należy unikać. Później zobaczymy dlaczego oraz jak zrobić to lepiej.

Brak komentarzy:

Prześlij komentarz