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

[avr][C] - gdy wszystkie sprzętowe interfejsy są zajęte (biblioteka)

md5crypt 16 Lis 2016 23:23 993 8
  • #1 16066952
    md5crypt
    Poziom 10  
    Potrzebowałem szybkiej i niewymagającej dokładnego zegara komunikacji pomiędzy dwoma uC, a UART, SPI i i2c miałem zajęte. Wziąłem więc kartkę o ołówek i wyrzeźbiłem bibliotekę. Pomysł nie był specjalnie odkrywczy: dwie linie, linia danych i linia zegarowa, przy czym transmisja bitu wygląda w następujący sposób:
    1) ustawienie stanu linii danych
    2) puls linii zegarowej
    3) czekanie na puls linii zegarowej (potwierdzenie)
    4) goto 1)

    Całość zaimplementowałem z użyciem dowolnego przerwania zewnętrznego (PCINTn lub INTn) i dowolnego innego GPIO. Na początku pliku nagłówkowego jest obszerna konfiguracja pozwalająca skonfigurować bibliotekę do własnych potrzeb (timeouty, długości impulsów, czasy zbocz, użycie wbudowanych pullupów i inne). Nie widzę sensu pisania szczegółów, jako że są one w komentarzach.

    Ustawiając timeout odpowiednio długi można użyć transmisji danych do obudzenia procesora z deep-sleep, co też u mnie okazało się być niezwykle przydatne.

    Wydaję mi się, że odwaliłem kawał porządnej roboty, może komuś się przyda. Szkoda mi tak porostu chować to do szuflady.

    I tak, wiem że pod SPI i i2c można podpiąć więcej niż jedno urządzenie i nie, nie mogłem tego zrobić. Nie chce mi się tłumaczyć dlaczego.

    idi.c Download (4.44 kB)idi.h Download (4.79 kB)
  • #2 16066970
    grko
    Poziom 33  
    Moim zdaniem powinieneś to wrzucić na githuba jeżeli nie chcesz aby odeszło w zapomnienie. Całość wygląda w miarę spoko. Jak chcesz to mogę się przyczepić do paru rzeczy, które mi się nie podobają.
  • #3 16066998
    md5crypt
    Poziom 10  
    grko napisał:
    Jak chcesz to mogę się przyczepić do paru rzeczy, które mi się nie podobają.

    wal (tzn dawaj)
  • #5 16067068
    md5crypt
    Poziom 10  
    dondu napisał:
    Przy jakiej optymalizacji?

    -O2 w gcc 4.9.2, ale pytanie się trochę mija z celem, bo akurat dla tego fragmenty kodu wszytko powyżej -O0 dałoby to samo. Dużo andów i orów albo sts i lds'ów, zależy czy polecimy poprzez castowanie/unie czy przez operacje bitowe.
  • #6 16068086
    grko
    Poziom 33  
    @md5crypt
    1. Trochę nadużywasz słowa kluczowego inline. Zwłaszcza w implementacji. Pozwól kompilatorowi działać w tej materii. Jedno/kilku liniowe funkcje możesz zostawić z inline.
    2. Przy deklaracji/definicji funkcji często masz pustą listę parametrów. W C (w odróżnieniu od C++) nie jest to tożsame z void.
    3. API jest trochę skomplikowane. Wystarczyłby zestaw funkcji wysyłający/odbierający określoną ilość bajtów:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    ewentualnie można dodać dwie funkcje wysyłające/odbierające określoną ilość bitów.

    4. Niektóre makra z nagłówka mogą być właśnie funkcjami inline.
    5. Nie wiem jak sobie kompilator poradzi z wywołaniem ceil(CONST). Może policzy to na etapie kompilacji a może nie;)
    6. W wielu funkcjach zwracasz 0 albo 1. Zamień to na definicje false, true z stdbool a sam typ zamień na bool.
    7. Warto byłoby pomyśleć o czymś takim jak wieloinstancyjność na wypadek jakby ktoś chciał użyć wielu tego typu interfejsów jednocześnie.
  • #7 16068271
    md5crypt
    Poziom 10  
    1. Pozwolę sobie mieć inne zdanie na ten tamat. Tak na marginesie, to gcc bez __attribute__((__always_inline__) i tak ostatecznie robi co chce.
    2)
    Cytat:
    In C, void test() declares a function that takes an unspecified (but not variable) number of parameters (and returns nothing). So all your calls are valid (according to the prototype) in C.

    wooah, tyle lat pisania w C i zawsze znajdzie się coś nowego.
    3) Api jest 100% standardowe. Acz fakt, tych dwóch funkcji w nim brakuję.
    4) pierwsze słyszę by ktoś konfiguracje device-specific robił w funkcjach inline.
    5) aby być bardziej przekonywującym:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    z delay.h w libavrc
    trzbe tylko pamiętać ze funckja w której się urzywa rzeczy z math.h musi być inline (oraz muszą być włączone optymalizację), inaczej wylądują one w kodzie.
    6) zazwyczaj 0 oznacza brak błędu a cokolwiek innego (niekoniecznie 1) błąd
    7) efekt byłby albo wolny i kulawy albo zrobiłoby się z niego coś takiego.
  • #8 16068340
    grko
    Poziom 33  
    1. Właśnie o to mi chodzi. To słówko to tylko hint dla kompilatora. Niech optymalizator zdecyduje co ma być inline a co nie w zależności od flagi -Ox.
    3. Według mnie dwie zaproponowane funkcje pokrywają wszystkie przypadki.
    4. Ale to:
    #define IDI_CHECK_INT_FLAG() (PCIFR&(1<<PCIF1))

    mogłoby być funkcją inline.
    5. Ok.
    6. W C (od C99) istnieje typ bool (_Bool).
    7. Nie o coś takiego mi chodziło. Mam na myśli to aby Twoje API było zorientowane na obiekt który zawiera konfigurację GPIO na których ma działać. Z tą wydajnością to również bym nie przesadzał. W końcu część z tych funkcji co masz i tak blokują.


    BTW: tu masz fajną też implemetnację drzew binarnych:
    https://github.com/freebsd/freebsd/blob/master/sys/sys/tree.h
  • #9 16068490
    md5crypt
    Poziom 10  
    3) oczywiście że się pokrywają, ale często chce się przesłać pojedynczego shorta albo longa wtedy te funkcje są zwyczajnie wygodniejsze. Nikt nie każe ich używać, a miejsca nieużyte nie zajmują przecież.
    4) a PCIFR PCIF1 w tym makrze? Owszem, alternatywnie mogłem zrobić define dla nazwy rejestru i numeru falgi, ale nie wiedzę przewagi tego rozwiązania. Poza tym użytkownik ma idi_can_read które własnie jest funkcją inline wykorzystującą to makro.
    7) tak, oto mi chodziło gdy pisałem, że efekt byłby kulawy, bo implementacja by spuchła (co na attiny może już boleć) i byłaby trudniejsza w użyciu dla prostych jedno instancyjnych zastosowań. W obecnej formie jest czyste minimum używające tylko 1B sramu.
REKLAMA