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

AVR-GCC - Jak znaleźć nazwy rejestrów dla ATxmega16A4 w Atmel Studio?

cek 31 Paź 2012 12:29 2802 24
  • #1 11471189
    cek
    Poziom 10  
    Witam, na wstępie zaznaczam, że jestem początkujący i proszę o wyrozumiałość.
    Chciałbym coś zrobić na ATxmega16A4, program chcę pisać w C na Atmel Studio 4.x lub 6.x. Na początek, już na etapie schematu zaistniała potrzeba przetestowania i sprawdzenia możliwości konfiguracji Timera z uwzględnieniem możliwych do współpracy z Timerem portów, a co za tym idzie podłączenia sygnałów zewnętrznych do i z Timera.
    No więc, siadam do Atmel Studio z zamiarem zapisania paru linijek kodu w celu skonfigurowania Timera i współpracujących z nim portów i symulacji tego kawałeczka sprzętu xmegi i jak po grudzie.
    W związku z tym mam pytanie zupełnie podstawowe, może głupie, ale...
    Skąd mam brać informacje o nazwach rejestrów procesora dla GCC?
    Czy muszę bawić się w interpretację pliku iox16a4.h , który na marginesie dodam ma prawie 300KB?
    Czy tą mękę muszę przechodzić za każdym razem i z każdym prockiem po którego sięgnę w projekcie?
    A może jest jakiś inny sposób?
  • #2 11471481
    Konto nie istnieje
    Poziom 1  
  • #3 11471499
    cek
    Poziom 10  
    Datasheet opisuje dostępne funkcje i rejestry konfiguracyjne procesora w GCC ?
  • #5 11471551
    Sparrowhawk
    Poziom 22  
    Datasheet opisuje procesor, jego rejestry, dostępne peryferia. Dokument ten nie jest tworzony z myślą o GCC. Bez zapoznania się z datasheet'em, nie ma mowy o tworzeniu oprogramowania na uc.

    Nazwy zdefiniowane w plikach ioxxx.h są symboliczne. Krótko ujmując są to zdefiniowane adresy rejestrów procesora. Równie dobrze można napisać DDRB = 0xFF, jak i wsk* = (Adres rejestru DDRB), wsk = 0xFF.

    Tak swoją drogą, w AVR studio należy dołączyć plik IO.h, a nie konkretny plik IOxxxx.h.

    Freddie -> No nie mów, że o tym nie wiedziałeś? :D
  • #6 11471776
    tmf
    VIP Zasłużony dla elektroda
    cek napisał:
    Datasheet opisuje dostępne funkcje i rejestry konfiguracyjne procesora w GCC ?

    W 99% nazwy rejestrów, bitów i pól z noty pokrywają się z nazwami zdefiniowanymi w io.h.
  • #7 11472089
    cek
    Poziom 10  
    Pisząc najprostszy program, o jakim mówię, a więc (dla przykładu) zwykłą konfigurację Timera, w GCC powinienem, jak sądzę, oprócz samych rejestrów i ich nazw, które - zgoda - będą takie same jak w datasheet, użyć dziesiątków definicji deklarowanych w plikach ioxxx.h, oczywiście po uprzednim podłączeniu io.h
    W celu ustawienia CLK dla Timera0 -
    korzystając jedynie z rejestrów mogę napisać tak:
    - no właśnie, jak zapisać rejestr CTRLA sterujący podłączeniem CLK jeśli ta nazwa jest taka sama dla wszystkich Timer'ów
    Ale mogę skorzystać z deklaracji w pliku iox16a4.h
    /* TC - 16-bit Timer/Counter With PWM */
    /* TC0.CTRLA bit masks and bit positions */
    #define TC0_CLKSEL_gm 0x0F /* Clock Selection group mask. */
    #define TC0_CLKSEL_gp 0 /* Clock Selection group position. */
    #define TC0_CLKSEL0_bm (1<<0) /* Clock Selection bit 0 mask. */
    #define TC0_CLKSEL0_bp 0 /* Clock Selection bit 0 position. */
    #define TC0_CLKSEL1_bm (1<<1) /* Clock Selection bit 1 mask. */
    #define TC0_CLKSEL1_bp 1 /* Clock Selection bit 1 position. */
    #define TC0_CLKSEL2_bm (1<<2) /* Clock Selection bit 2 mask. */
    #define TC0_CLKSEL2_bp 2 /* Clock Selection bit 2 position. */
    #define TC0_CLKSEL3_bm (1<<3) /* Clock Selection bit 3 mask. */
    #define TC0_CLKSEL3_bp 3 /* Clock Selection bit 3 position. */

    Tergo rodzaju deklaracji jest dla samego Timera0 baaardzo wiele.

    Przetrawienie tego (plik iox16a4.h to prawie 300KB) zajmie chyba więcej czasu niż pisanie programu i to dużo bardziej złożonego niż to co chcę teraz zrobić.
  • #8 11472286
    tmf
    VIP Zasłużony dla elektroda
    Te deklaracje nie są losowe, jest pewien schemat ich tworzenia, na tyle prosty, że po paru minutach się nie zastanawiasz co i jak, w dosdatku w AS6 masz autouzupełnianie i listę wyboru. Łącznie daje to wygodny sposób programowania. Zasady tworzenia nazw masz opisane w jednym z not Atmela.
  • #9 11472341
    Sparrowhawk
    Poziom 22  
    Programuję AVR'y od lat. Nigdy nie miałem potrzeby zagłębiać się w definicje zawarte w plikach .h pakietu gcc w taki sposób, jak Ty to robisz.

    Zadam Ci pytanie: Czy pisałeś już kiedyś jakiś program na uc? Czy potrafisz na avr zapalić i zgasić diody na którymś z portów?

    Wziąłem do ręki datasheet od Atmega16. Timer1 ma być taktowany z zewnętrznego źródła. Z datasheet'u wynika, że odpowiedzialne za to są CS10, 11, 12 w rejestrze TCCR1B.

    Więc w programie zapisuje to tak: TCCR1B |= (1<<CS12)|(1<<CS11)|(1<<CS10);

    I już. Proste prawda? W ten sposób timer1 będzie brał zegar z zewnętrznego źródła i reagował na zbocze narastające tego sygnału.
  • #10 11472538
    cek
    Poziom 10  
    Pisałem, pod AVRy, sporo w asemblerze, trochę w GCC, ale upłynęło dużo czasu a umiejętności nie używane mają tendencje do odparowywania ;)
    Ale to wymaga odświeżenia i jakoś pójdzie.
    Problem obecny polega chyba głównie na przesiadce na ATxmega.
    Sparrowhawk dał przykład ustawienia bitów w rejestrze, ok, zgoda, w asemblerze będą to 3 rozkazy, czasem 1.
    Ale jak zaprogramować CLK Timera w ATxmega16A4???
    Rejestr odpowiedzialny to CTRLA, cztery bity odpowiedzialne za ustawienie go nazwane są CLKSEL.
    Nazwa rejestru podawana w datasheet (CTRLA), jak również wyświetlana w AVR Studio 4.x i 6.x zarówno w projekcie asemlerowym jak i GCC w oknie I/O View figuruje również jako CTRLA, ale w programie w C jak i w asemblerze nazwa tego rejestru nie jest rozpoznawana.
    To jak mam ustawić CLK dla Timer'a ?
  • #11 11473059
    szulat
    Poziom 23  
    cek napisał:
    Ale jak zaprogramować CLK Timera w ATxmega16A4???

    ale w czym problem?

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #12 11474571
    Konto nie istnieje
    Poziom 1  
  • #13 11475079
    cek
    Poziom 10  
    Dzięki serdeczne koledze Szulat za przykłady, naprowadziły mnie na jakąś ścieżkę, dały jakieś konkrety do przemyślenia.
    A przy okazji głowię się i nie bardzo rozumiem jednej linijki:
    zrob_cos_z_timerem(TC0_t* timer)
    a dokładniej : (TC0_t* timer), a jeszcze dokładniej * po TC0_t, co robi TC0_t* ?
  • #14 11475153
    tmf
    VIP Zasłużony dla elektroda
    A o wskaźnikach kolega słyszał? Jedną z zalet pogrupowania rejestrów w XMEGA i ułożenia ich w struktury jest możliwość przekazania adresu do struktury. Dzięki temu, jak to kolega wyżej pokazał, jedna funkcja moze inicjalizować różne instancje np. timera.
  • #15 11475169
    cek
    Poziom 10  
    A wracając do głównego problemu.
    Próbowałem w asemblerze i GCC. Jeśli chodzi o asembler to sprawa jest prostsza, nazwy rejestrów w datasheet odpowiadają nazwom rejestrów w asemblerze, ALE jak przyjrzymy się plikowi deklaracji ATxmega16A4def.inc to okaże się, że mamy tam doczynienia z mnóstwem nowych deklaracji zachowujących nazewnictwo takie jak iox16a4.h Extra, wspólne nazewnictwo, jestem za, ale żeby z czegoś korzystać trzeba najpierw o tym wiedzieć, odwrotnie się nie da, prawda?
    Ktoś się napracował w Atmelu żeby nam ułatwić życie, ale nie łatwo posiąść informacje o tym co zostało zrobione.
    Pisząc w C mogę się posiłkować podpowiedziami, ale żeby się pojawiła podpowiedź muszę napisać choć pierwszą literę, ale jaką?
    W asemblerze nie mamy podpowiedzi, musimy klepać z pamięci, więc w praktyce wyklepiemy tylko to co mamy w datasheet, czyli skorzystamy z ułamka tego co zostało zawarte w plikach *def.inc
    Czyli, nie ma innego sposobu dowiedzenia się o deklaracjach jak interpretacja plików io*.h dla C i *def.inc dla asemblera?

    Dodano po 7 [minuty]:

    Jestem z półki początkujących, o wskaźnikach słyszałem, ale z tego co wiem, to * jest operatorem i występuje przed nazwą wskaźnika, a w przykładzie jest TC0_t* czyli za, tego nie łapię i nie mogę doszukać się w książce.
  • #16 11475300
    tmf
    VIP Zasłużony dla elektroda
    Napisałem ci, że Atmel wydał stosowny dokument, w którym opisuje sposób tworzenia nazewnictwa. Jest on zresztą banalny - np. timer, zaczyna się na T, więc wszystko co jest z nim związane też :)
    Co do wskaźników - wskaźnik definiuje się podając nazwę typu i gwiazdkę (*), czyli TC0_t* to wskaźnik na typ TC0_t (T jak timer, 0 - typ timera (w XMEGA masz timery typów 0, 1, 2, nie mylić z instancjami nazywanymi literami portów), _t - typ). Pomyliłeś * z operatorem wyłuskania, który służy do dereferencji wskaźnika. Jeśli to co piszę wydaje ci się niezrozumiałe to niestety czas kupić książkę do C, lub skorzystać z materiałów online.
  • #17 11476073
    cek
    Poziom 10  
    No właśnie posiłkuję się książką.
    Cytat z książki:
    Deklaracja wskaźnika przybiera następującą postać:
    nazwa_typu *nazwa_wskaźnika
    koniec cytatu.
    Mi chodzi o tę nieszczęsną spację, w książce jest nazwa_typu, spacja, *,nazwa_wskaźnika(bez spacji pomiędzy * a nazwa_wskaźnika), czyli jeszcze inaczej, spacja jest pomiędzy nazwa_typu a *, a w przykładzie spacja jest pomiędzy * a nazwa_wskaźnika.
    Powtarzam, nie jestem orłem, ale dlaczego w przykładzie spacja jest po * anie przed nią jak w mojej książce?
  • #18 11476106
    tmf
    VIP Zasłużony dla elektroda
    Bo nie ma to żadnego znaczenia, gdzie jest spacja?

    Dodano po 3 [minuty]:

    BTW, zapis typ *zmienna, to nie deklaracja, a definicja zmiennej. Deklaracją byłoby np. extern "C" typ *zmienna.
  • #19 11476158
    Halkilor
    Poziom 15  
    Dodałbym jeszcze do odpowiedzi kolegi tmf link, może to komuś coś rozjaśni.
  • #20 11477132
    cek
    Poziom 10  
    Kolega tmf na końcu zdania postawił znak zapytania.
    To ja jeszcze muszę zadać pytanie, czy lokalizacja tej spacji (przed *, lub za *) nie ma znaczenia?
    W mojej książce nie doczytałem takiego stwierdzenia, w przykładach jakie widziałem, widuję chyba zawsze spację przed *.
    Przyszło mi wcześniej do głowy, że może to nie ma znaczenia, ale takie stwierdzenie, jeśli tak jest, chciałbym usłyszeć od fachowców.
    W zapisie mogę pominąć w ogóle spacje?
  • #22 11477187
    cek
    Poziom 10  
    Już, dzięki i sorki,
    znalazłem informację - kompilator C jest niewrażliwy na białe znaki.
    A mówiłem, że jestem początkujący.
  • #23 11477348
    Freddie Chopin
    Specjalista - Mikrokontrolery
    cek napisał:
    W mojej książce nie doczytałem takiego stwierdzenia, w przykładach jakie widziałem, widuję chyba zawsze spację przed *.

    Zwykła konwencja. Wbrew pozorom "*" nie modyfikuje typu w definicji, jak napiszesz coś takiego:

    char* p1, p2;

    to możesz odnieść błędne wrażenie, że stworzyłeś sobie dwa wskaźniki, co niestety nie będzie prawdą.

    char *p1, c;

    To daje lepszy pogląd na sytuację, ponieważ tylko to przy czym jest "*" będzie wskaźnikiem... Ja proponuję więc pisać właśnie tak żeby wszystko zawsze było oczywiste na pierwszy rzut oka, nawet wiedząc, że te spacje czy nawiasy są zbędne.

    A tak w ogóle to powyższy przykład lepiej napisać tak:

    char *p;
    char c;

    Wtedy już w ogóle nie ma wątpliwości żadnych.

    Sprawa nie dotyczy oczywiście typów zdefiniowanych przez typedef.

    4\/3!!
  • #24 11483053
    cek
    Poziom 10  
    Dziękuję Wam, naprowadziliście mnie, ale mimo wszystko nie mogę czegoś załapać.
    W iox16a4u.h jest :

    /* 16-bit Timer/Counter 0 */
    typedef struct TC0_struct
    {
    register8_t CTRLA; /* Control Register A */
    register8_t CTRLB; /* Control Register B */
    register8_t CTRLC; /* Control register C */
    register8_t CTRLD; /* Control Register D */
    register8_t CTRLE; /* Control Register E */
    register8_t reserved_0x05;
    register8_t INTCTRLA; /* Interrupt Control Register A */
    register8_t INTCTRLB; /* Interrupt Control Register B */
    register8_t CTRLFCLR; /* Control Register F Clear */
    register8_t CTRLFSET; /* Control Register F Set */
    register8_t CTRLGCLR; /* Control Register G Clear */
    register8_t CTRLGSET; /* Control Register G Set */
    register8_t INTFLAGS; /* Interrupt Flag Register */
    register8_t reserved_0x0D;
    register8_t reserved_0x0E;
    register8_t TEMP; /* Temporary Register For 16-bit Access */
    register8_t reserved_0x10;
    register8_t reserved_0x11;
    register8_t reserved_0x12;
    register8_t reserved_0x13;
    register8_t reserved_0x14;
    register8_t reserved_0x15;
    register8_t reserved_0x16;
    register8_t reserved_0x17;
    register8_t reserved_0x18;
    register8_t reserved_0x19;
    register8_t reserved_0x1A;
    register8_t reserved_0x1B;
    register8_t reserved_0x1C;
    register8_t reserved_0x1D;
    register8_t reserved_0x1E;
    register8_t reserved_0x1F;
    _WORDREGISTER(CNT); /* Count */
    register8_t reserved_0x22;
    register8_t reserved_0x23;
    register8_t reserved_0x24;
    register8_t reserved_0x25;
    _WORDREGISTER(PER); /* Period */
    _WORDREGISTER(CCA); /* Compare or Capture A */
    _WORDREGISTER(CCB); /* Compare or Capture B */
    _WORDREGISTER(CCC); /* Compare or Capture C */
    _WORDREGISTER(CCD); /* Compare or Capture D */
    register8_t reserved_0x30;
    register8_t reserved_0x31;
    register8_t reserved_0x32;
    register8_t reserved_0x33;
    register8_t reserved_0x34;
    register8_t reserved_0x35;
    _WORDREGISTER(PERBUF); /* Period Buffer */
    _WORDREGISTER(CCABUF); /* Compare Or Capture A Buffer */
    _WORDREGISTER(CCBBUF); /* Compare Or Capture B Buffer */
    _WORDREGISTER(CCCBUF); /* Compare Or Capture C Buffer */
    _WORDREGISTER(CCDBUF); /* Compare Or Capture D Buffer */
    } TC0_t;

    oraz:

    /* Clock Selection */
    typedef enum TC_CLKSEL_enum
    {
    TC_CLKSEL_OFF_gc = (0x00<<0), /* Timer Off */
    TC_CLKSEL_DIV1_gc = (0x01<<0), /* System Clock */
    TC_CLKSEL_DIV2_gc = (0x02<<0), /* System Clock / 2 */
    TC_CLKSEL_DIV4_gc = (0x03<<0), /* System Clock / 4 */
    TC_CLKSEL_DIV8_gc = (0x04<<0), /* System Clock / 8 */
    TC_CLKSEL_DIV64_gc = (0x05<<0), /* System Clock / 64 */
    TC_CLKSEL_DIV256_gc = (0x06<<0), /* System Clock / 256 */
    TC_CLKSEL_DIV1024_gc = (0x07<<0), /* System Clock / 1024 */
    TC_CLKSEL_EVCH0_gc = (0x08<<0), /* Event Channel 0 */
    TC_CLKSEL_EVCH1_gc = (0x09<<0), /* Event Channel 1 */
    TC_CLKSEL_EVCH2_gc = (0x0A<<0), /* Event Channel 2 */
    TC_CLKSEL_EVCH3_gc = (0x0B<<0), /* Event Channel 3 */
    TC_CLKSEL_EVCH4_gc = (0x0C<<0), /* Event Channel 4 */
    TC_CLKSEL_EVCH5_gc = (0x0D<<0), /* Event Channel 5 */
    TC_CLKSEL_EVCH6_gc = (0x0E<<0), /* Event Channel 6 */
    TC_CLKSEL_EVCH7_gc = (0x0F<<0), /* Event Channel 7 */
    } TC_CLKSEL_t;

    a następnie:

    #define TCC0 (*(TC0_t *) 0x0800) /* 16-bit Timer/Counter 0 */

    a w programie piszemy:

    TCC0.CTRLA = TC_CLKSEL_DIV8_gc;

    czyli, w programie TCC0 wygląda mi na strukturę, a deklaracji jest makro zastępujące, które w miejsce TCC0 podstawia (*(TC0_t *) 0x0800), czyli otrzymujemy:
    (*(TC0_t *) 0x0800).CTRLA = TC_CLKSEL_DIV8_gc;

    i to to jest? o co tu chodzi? nie kumam tego.
  • #25 11483165
    szulat
    Poziom 23  
    cek napisał:

    (*(TC0_t *) 0x0800).CTRLA = TC_CLKSEL_DIV8_gc;
    i to to jest? o co tu chodzi? nie kumam tego.

    (TC0_t*)0x0800 - liczba 0x800 rzutowana na wskaźnik, czyli to wyrażenie jest wskaźnikiem na strukturę TC0_t (która jest pod adresem 0x800, tam gdzie akurat sa odpowiednie rejestry timera)
    *(TC0_t*)0x0800 - zawartość struktury TC0_t umieszczonej pod adresem 0x800
    (*(TC0_t*)0x0800).CTRLA - pole struktury TC0_t
REKLAMA