W tym krótkim artykule zerkniemy jak wyglądają podstawowe operacje na rejestrach czyli ustawianie i zerowanie bitów/pól bitowych. W tym zakresie posłużymy się dokumentem przygotowanym przez Silicon Labs UM002 .Dokument ten to krótka retrospektywa języka C. Zachęcam aby zapoznać się z nim.. Zagadnienia , które poruszymy w artykule będą dotyczyć tzw "natywnego" programowania MCU z rdzeniem ARM czyli w oparciu o zapis bezpośredni do rejestrów.
Wyjdziemy od tego jak wygląda przykładowy rejestr w tym przypadku jest to rejestr CTRL w module ADCn.
Aby się odwołać do tego rejestru w programie potrzebny jest minimalny narzut abstrakcji. Ten narzut to opisanie rejestru za pomocą struktur , definicji etc. tak aby można było się posługiwać prostym i logicznym nazewnictwem a nie np. wskaźnikami do adresów w pamięci bo w tym przypadku trzeba by było znać dokładnie mapę pamięci i usytuowanie w niej poszczególnych rejestrów i bitów.
Poniżej wygląd jak może wyglądać przykładowy opis rejestrów w bloku DAC :
typedef struct
{
__IO uint32_t CTRL;
__I uint32_t STATUS;
__IO uint32_t CH0CTRL;
__IO uint32_t CH1CTRL;
__IO uint32_t IEN;
__I uint32_t IF;
__O uint32_t IFS;
__O uint32_t IFC;
__IO uint32_t CH0DATA;
__IO uint32_t CH1DATA;
__O uint32_t COMBDATA;
__IO uint32_t CAL;
__IO uint32_t BIASPROG;
uint32_t RESERVED0[8]
__IO uint32_t OPACTRL;
__IO uint32_t OPAOFFSET;
__IO uint32_t OPA0MUX;
__IO uint32_t OPA1MUX;
__IO uint32_t OPA2MUX;
} DAC_TypeDef;
{
__IO uint32_t CTRL;
__I uint32_t STATUS;
__IO uint32_t CH0CTRL;
__IO uint32_t CH1CTRL;
__IO uint32_t IEN;
__I uint32_t IF;
__O uint32_t IFS;
__O uint32_t IFC;
__IO uint32_t CH0DATA;
__IO uint32_t CH1DATA;
__O uint32_t COMBDATA;
__IO uint32_t CAL;
__IO uint32_t BIASPROG;
uint32_t RESERVED0[8]
__IO uint32_t OPACTRL;
__IO uint32_t OPAOFFSET;
__IO uint32_t OPA0MUX;
__IO uint32_t OPA1MUX;
__IO uint32_t OPA2MUX;
} DAC_TypeDef;
_IO - oznacza że pole jest typu R/W
_O - oznacza że pole jest typu R
Opisy dotyczące bloku DAC znajdziemy w pliku nagłówkowym efm32tg11b_adc.h :
Z kolei uzupełniające definicje takie jak np adresy bazowe modułów w pamięci MCU znajdziemy w pliku nagłówkowym efm32tg11b120f128gq48.h
Przybliżmy perspektywę i zerknijmy jak wygląda opisanie pola bitowego REFRSEL w naszym przykładowym rejestrze DACn_CTRL . Pole składa się z dwóch bitów na pozycji 20 i 21 :
Definicje jakie znajdziemy w pliku nagłówkowym efm32tg11b_adc.h dotyczące naszego pola bitowego to m.in :
Mając do dyspozycji powyższe definicje możemy dokonać w polu bitowym REFRSEL dowolnych fikołków w operacjach bitowych np coś takiego :
_DAC_CTRL_REFRSEL_8CYCLES << _DAC_CTRL_REFRSEL_SHIFT = DAC_CTRL_REFRSEL_8CYCLES
Idźmy dalej, teraz zobaczymy jak kasować i ustawiać bit w rejestrze . Weźmiemy dla przykładu nie pole bitowe ale bit. Zerknijmy zatem na rejestr DACn_CTRL i bit opisany jako CH0PRESCRST . Definicje jakie znajdziemy w pliku efm32tg11b_adc.h :
Jeśli chcemy ustawić bit CH0PRESCRST w rejestrze DAC0_CTRL, zrobimy to w/g poniższej konwencji :
DAC0->CTRL = DAC0->CTRL | DAC_CTRL_CH0PRESCRST;
gdzie pierwszy człon DAC0 oznacza nazwę modułu, drugi człon CTRL to nazwa rejestru, strzałeczka -> oznacza wskaźnik na element struktury.
jezyk C daje nam możliwość skrócenia zapisu do takiej postaci :
DAC0->CTRL |= DAC_CTRL_CH0PRESCRST;
Jeśli chcemy wyzerować bit zrobimy to w/g poniższej konwensji :
DAC0->CTRL = DAC0->CTRL & ~DAC_CTRL_CH0PRESCRST;
Postać skrócona zapisu:
DAC0->CTRL &= ~DAC_CTRL_CH0PRESCRST;
O ile przy ustawianiu jednego bitu przy pomocy OR (|) nie ma problemu o tyle w przypadku pola bitowego ten zapis nie zadziała prawidłowo , dlaczego ? weźmy przykład próby ustawienia pola bitowego na wartość 01 w przypadku kiedy zastajemy ustawienie 11
Co powinniśmy zrobić aby prawidłowo zapisać wartość 01 do pola bitowego ? Pierwsze co przychodzi do głowy to wyzerować starą wartość czyli doprowadzić pole bitowe do postaci 00 i wtedy dopiero można dodać wartość 01. Zrobimy to takim karkołomnym zapisem :
DAC0->CTRL = (DAC0->CTRL & ~_DAC_CTRL_REFRSEL_MASK) |
DAC_CTRL_REFRSEL_16CYCLES;
DAC_CTRL_REFRSEL_16CYCLES;
co blokowo wygląda tak :
Tego zapisu nie da się niestety skrócić bo inaczej głupoty wyjdą.
Proponuję dokładnie to zrozumieć bo to jest fundament poruszania się po rejestrach w MCU Silcona i nie tylko .
Generalnie muszę stwierdzić, że bardzo sympatycznie programuje się MCU Silicona mieszając konwencje czyli programowanie "natywne" z użyciem biblioteki emlib.
Pozdrawiam
picmajster.blog@gmail.com
Linki :
UM002 - Introduction to C
Brak komentarzy:
Prześlij komentarz