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

AVR-GCC w Atmel Studio 7.0.948 - Makro jako argument dla makro

lelekx 04 Lis 2016 22:38 1290 23
  • #1 16040819
    lelekx
    Poziom 30  
    Witajcie.

    Kombinuję trochę jak koń pod górę, próbuję osiągnąć efekt jak najbardziej optymalnego kodu zachowując jego przejrzystość.

    Kompilator to AVR-GCC zintegrowany z Atmel Studio 7.0.948.

    Próbowałem następującej konstrukcji:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    i używać jej tak:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Kompilator, słusznie z resztą wypomina mi, że macro "GPO_Set"
    Cytat:
    requires 2 arguments, but only 1 given
    .

    Jak mogę poprosić preprocesor o rozwinięcie makr w kolejności:
    1) GPO_LED_1
    2) GPO_Set(C, 4)
    ?
  • #2 16040862
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Cytat:
    The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming. [...] Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.

    https://en.wikiquote.org/wiki/Donald_Knuth

    Zdziwiłbyś się jakie cuda potrafi zrobić kompilator którego używasz np. z normalnymi funkcjami inline czy funkcjami statycznymi.
  • #3 16040937
    grko
    Poziom 33  
    @lelekx Możesz to zrobić np tak:

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


    W tym zastosowaniu funkcje inline są lepsze od preprocesora.
  • #4 16040938
    Konto nie istnieje
    Konto nie istnieje  
  • #5 16040944
    lelekx
    Poziom 30  
    Freddie Chopin napisał:
    Cytat:
    The real problem is that programmers have spent far too much time worrying about efficiency in the wrong places and at the wrong times; premature optimization is the root of all evil (or at least most of it) in programming. [...] Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs, and these attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%.

    https://en.wikiquote.org/wiki/Donald_Knuth

    Zdziwiłbyś się jakie cuda potrafi zrobić kompilator którego używasz np. z normalnymi funkcjami inline czy funkcjami statycznymi.


    Ja wychodzę z założenia, że przedwczesna optymalizacja jest źródłem wszelkiego zła. Wcale się nie zdziwiłem cudami inline, bo wiedziałem, że nie ma problemu ze zbudowaniem funkcji, które skompilują się do jednej instrukcji. Tylko to spaghetti kłuje mnie w oczy.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

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


    Da się to ładnie przystrzyc?
  • Pomocny post
    #6 16040949
    grko
    Poziom 33  
    @lelekx Przekazuj port przez adres. Coś w stylu:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #7 16040968
    lelekx
    Poziom 30  
    grko napisał:
    @lelekx Przekazuj port przez adres.

    Tylko to mnie zmusza do zrobienia trzech definicji na każdy IO, osobno do zapisu PORTx, DDRx i odczytu PINx.

    Chciałbym:
    - w pliku .h miał zdefiniowane wejścia/wyjścia za pomocą jednej linii (np. #define GPIO_Jakis_Coś Port, Pin)
    - żebym mógł wywołać z tym 3 różne funkcje: zmiana kierunku wejście<->wyjście, ustawienie wyjścia, czytanie wejścia: GPIO_Set_Direction(GPIO_Jakiś_Coś, GPIO_OUT), GPI_Get(GPIO_Jakiś_Coś), GPO_Set(GPIO_Jakiś_Coś), GPO_Clear(GPIO_Jakiś_Coś).
    Da się jakoś upakować rejestry _SFR_IO8 w strukturę, np.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    wtedy nie będzie problemu z przekazaniem parametru jako wskaźnik na strukturę, funkcja inline będzie wiedziała, który element wyłuskać do danej operacji.
  • #9 16041008
    lelekx
    Poziom 30  
    Chyba mam
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #10 16041014
    jnk0le
    Poziom 18  
    Abstrahując od wyższości pewnych metod nad preprocesorem, makra sklejąjące ( A ## B ) trzeba opakować podwójnie aby prawidłowo się kompilowały.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #11 16041096
    Konto nie istnieje
    Konto nie istnieje  
  • #13 16041196
    Konto nie istnieje
    Konto nie istnieje  
  • #14 16041209
    lelekx
    Poziom 30  
    Piotrus_999 napisał:
    [ciach...]
    port_cos_tam(&PORTB, 5, 1 , 1);


    Chcę oddzielić definicję rejestrów sprzętowych od głównego programu. Taki styl kodu nie daje nic, gdyż nadal odwołuje się bezpośrednio do rejestrów GPIO, co równie dobrze mogę zrobić w ciele właściwej funkcji. Na potrzeby takiego kodu potrzebuję się odwołać do trzech różnych rejestrów chcąc czytać, pisać i zmieniać kierunek pinu. To nie jest przenośne.

    Definicje pinów i funkcję sprzętowe daję w osobnych plikach, zależnym od użytego mikrokontrolera. Prototyp powstaje na bazie ATMega8 i staram się rozwiązać problem z myślą o tym konkretnym mikrokontrolerze. Docelowo jeżeli okaże się, że zabraknie mocy obliczeniowej, wybiorę któryś MCU z Cortex M0 od NXP, albo Cortex M4 od ST Micro - zależy który będzie lepiej pasował.

    albertb napisał:
    @lelekx: Rozważ też XMACRO https://en.wikipedia.org/wiki/X Macro.
    Przykładowo dla AVR
    https://www.elektroda.pl/rtvforum/topic2955211.html

    Albert
    Dzięki, przyglądnę się temu.
    Póki co zostawiam taki twór:
    avrgpio.h
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


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


    main.c
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #15 16041220
    Konto nie istnieje
    Konto nie istnieje  
  • #16 16041231
    grko
    Poziom 33  
    @Piotrus_999 To normalna praktyka, że wydziela się pinologię do osobnych modułów. Niby jak sobie wyobrażasz utrzymywanie kilku wersji HW, które są już u klienta? Zresztą cały temat byłby bezsensowny w wypadku jakby każdy firmware był robiony pod konkretny hardware bo autor mógłby sobie napisać po prostu:

    DDRA = (1 << 5);

    i byłby z tym szczęsliwy.
  • #17 16041241
    lelekx
    Poziom 30  
    Dziękuję za rady, posypałem "pomogłami".

    Co do przenośności: stosuję różne rodziny mikrokontrolerów w swoich projektach. Często przydaje się pożyczyć fragment kodu z innego projektu, o ile nie zawiera specyficznych konstrukcji dla konkretnego układu. Dobre przygotowanie się przed oszczędza wiele czasu w przyszłości.

    Makaronu w kodzie nie toleruję.

    Temat zostawiam otwarty, może ktoś pochwali się lepszym rozwiązaniem.
  • #18 16041279
    Konto nie istnieje
    Konto nie istnieje  
  • #19 16041319
    Konto nie istnieje
    Konto nie istnieje  
  • #20 16041328
    lelekx
    Poziom 30  
    albertb napisał:
    Znacznie krótsze niż Twoje (tak odnośnie makaronu) ale wybór należy do Ciebie.
    Wiem że dalej mam makaron, ale stopniowo go ubywa.
    Póki co bex X Macro mam to:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Dodano po 13 [minuty]:

    Piotrus_999 napisał:
    albertb napisał:
    Nie zmieniaj jak cytujesz

    [ciach]
    jedynie includujesz watunkowo odpowiednie dla sprzętu. Inicjalizacja portu dla ARM-a jest zdecydowanie inna niż dla AVR-a a Ty chcesz wszystko wcisnąć (inicjalizację, pisanie i czytanie w jakiegoś potworka)

    Dodatkowo i tak projekt pod inną rodzinę procesorów i tak będzie używał innego toolchaina i narzędzi, tak że w projekcie wystarczy oddzielić je w sposób logiczny, ale nie przekombinowany. To co próbujesz zrobić nie jest przenośne i do tego mało przemyślane. Takie jest moje zdanie.


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


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


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


    Co w tym kodzie Twoim zdaniem jest nieprzenośnego?
  • Pomocny post
    #21 16041429
    michalko12
    Specjalista - Mikrokontrolery
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #22 16041431
    lelekx
    Poziom 30  
    @michalko12
    Dziękuję!
  • #23 16041442
    michalko12
    Specjalista - Mikrokontrolery
    W wersji krótszej też działa.
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Edit:

    Można jeszcze dodać zmianę wyjścia na przeciwny w oparciu o rejestr PINx

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


    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #24 16041559
    lelekx
    Poziom 30  
    michalko12 napisał:
    Można jeszcze dodać zmianę wyjścia na przeciwny w oparciu o rejestr PINx

    Z tym byłbym ostrożny, bo nie wszystkie AVR mają funkcję odwrócenia stanu portu przez zapis do PINx. Dziękuję Ci bardzo za pomoc, dostałem dokładnie to czego potrzebowałem. Temat uważam za wyczerpany.
REKLAMA