Kanał - ATNEL tech-forum
Wszystkie działy
Najnowsze wątki



Teraz jest 29 lis 2024, o 13:34


Strefa czasowa: UTC + 1





Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 7 ] 
Autor Wiadomość
PostNapisane: 14 lut 2015, o 16:07 
Offline
Użytkownik

Dołączył(a): 13 lut 2015
Posty: 99
Pomógł: 6

Witam.

Chciałbym zaprezentować swoją bibliotekę do obsługi USART'a.
Jest to mój pierwszy "projekt" na taką skale, więc prosił bym o trochę wyrozumiałośći.

Powodem popełnienia tej biblioteki jest to iż wiele z ogólnodostępnych bibliotek dedykowanych C++, jest doskonałym przykładem jak NIE NALEŻY tworzyć bibliotek w C++.

Zamysł był taki aby biblioteka ta:

-była prosta w użyciu
-obsługiwała najpopularniejsze mikrokontrolerki AVR
-możliwie jak najbardziej zoptymalizowana
-obsługiwała 2 uarty UPDATE: teraz 4
-umożliwiała transmisje binarną (szybka implementacja pewnych protokołów np. xmodem)
-dawała użytkownikowi wybór czego chce używać a czego nie, bez grzebania w kodzie


dla prostego przykładu

Składnia: [ Pobierz ] [ Ukryj ]
język cpp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


uzyskujemy
Kod:
         text      data       bss       dec       hex   filename
          514         8         2       524       20c   avrtpp.elf
   
Program Memory Usage    :   522 bytes   1,6 % Full
Data Memory Usage       :   10 bytes   0,5 % Full

Oczywiście rzeczywiste 'Data Memory Usage' jest większe o bufory i kilka zmiennych pomocniczych.

Ze zdefiniowaną flagą NO_USART_RX uzyskujemy wolny pin rx oraz
Kod:
         text      data       bss       dec       hex   filename
          424         8         2       434       1b2   avrtpp.elf

Program Memory Usage    :   432 bytes   1,3 % Full
Data Memory Usage       :   10 bytes   0,5 % Full


Jak widać rozmiarowo biblioteka ta jest porównywalna z analogicznymi tworami w C, nawet pomimo narzutu obiektowości.
Oczywiście dobrze napisana biblioteka C raz będzie większa albo mniejsza zależnie od użycia jak i "jakości" tej biblioteki.


Funkcje udostępniane przez nią są już dosyć znane i chyba nie trzeba tłumaczyć jak działają ;)

Składnia: [ Pobierz ] [ Ukryj ]
język cpp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.




Spotkałem się już z wieloma przeróżnymi sposobami na operowanie w przerwaniach na składowych klasy, każda kolejna jeszcze bardziej zagmatwana od poprzedniej. (oczywiście z wiadomym skutkiem dla zasobów)

Składnia: [ Pobierz ] [ Ukryj ]
język cpp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Zastosowałem również raczej rzadko spotykaną optymalizacje operacji na zmiennych 'volatile'.
Mianowicie kompilator zakłada że zmienna taka będzie się zmieniać co każdy cykl zegarowy, więc co każde kolejne wywołanie pobiera jej wartość z pamięci. My natomiast wiemy że jest to konieczne jedynie ze względu na metodykę działania przerwań które nie mają dostępu do zmiennych trzymanych w rejestrze i zrzucanych na stos po wejściu w nie. Natomiast wewnątrz funkcji/przerwań ciągłe wczytywanie tej samej wartości z pamięci nie jest ani trochę oszczędne, a tak się właśnie dzieje z 'volatile'.

Składnia: [ Pobierz ] [ Ukryj ]
język cpp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


Dzięki temu udało mi się zrzucić kilkadziesiąt bajtów z kodu wynikowego zbliżając sie do tego co można uzyskać w C.
Oczywiście biblioteki C również można odchudzić tą metodą i bez użycia drugiego uarta będą znów mniejsze niż ich obiektowe odpowiedniki.

EDIT: Aktualny kod dostępny jest na githubie
https://github.com/jnk0le/Easy-AVR-USART-Class-Library

Dla miłośników C już jest dostępna odpowiednia wersja tej biblioteki ;)
https://github.com/jnk0le/Easy-AVR-USART-C-Library

wszelkie uwagi i pomysły odnośnie tego co można dodać/poprawić mile widziane. :)

_________________
AVR-UART-lib
AVR-FAST-ENCODER
RFM7x-lib



Ostatnio edytowano 17 kwi 2016, o 16:24 przez jnk0le, łącznie edytowano 19 razy

Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 14 lut 2015, o 16:43 
Offline
Użytkownik
Avatar użytkownika

Dołączył(a): 04 paź 2011
Posty: 8587
Pomógł: 337

Bardzo ciekawy projekt , ale ...

jnk0le napisał(a):
jest doskonałym przykładem jak NIE NALEŻY tworzyć bibliotek w C++. (z crapem arduino na czele)


proponuje nabrać nieco pokory i wrzucać wszystkiego do jednego worka .....
nie każdemu pasuje c++ i nie każdemu C czy arduino , wersji jest tyle ilu programistów , kogoś mógł kolega obrazić

w konkretnym przykładzie tez widzę parę miejsc które się zemścić mogą, ale nie to jest wątkiem naczelnym postu i niechaj inni się
wypowiadają.

Z życzeniami wiary w "obiektowość" w Cpp z pełnym wsparciem dla paradygmatu funkcyjnego ... (to miał byc sarkazm)

oby tak dalej :)

_________________
Zbuduj swój system [url=https://helion.pl/ksiazki/w-labiryncie-iot-budowanie-urzadzen-z-wykorzystaniem-ukladow-esp8266-i-esp32-andrzej-gromczynski,wlablo.htm#format/d]IOT[/url]



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 14 lut 2015, o 17:11 
Offline
Użytkownik

Dołączył(a): 13 lut 2015
Posty: 99
Pomógł: 6

SunRiver napisał(a):
proponuje nabrać nieco pokory i nie wrzucać wszystkiego do jednego worka .....
nie każdemu pasuje c++ i nie każdemu C czy arduino , wersji jest tyle ilu programistów , kogoś mógł kolega obrazić


No racja, jest wiele bibliotek które są zrobione prawidłowo bez specjalnych fajerwerków.
Chodziło mi o biblioteki które są jawnie naładowane absolutnie bezużytecznym kodem, albo wzięte biblioteki C ze zmienionym uart0_puts(char *str) na const char* str i
Cytuj:
HURR DURR, STWORZYŁEM BIBLIOTEKE DO C++


A co do arduino, widziałem kod, najbardziej mnie urzekły zahardcodowane tablice z UBBR ;)

SunRiver napisał(a):
w konkretnym przykładzie tez widzę parę miejsc które się zemścić mogą, ale nie to jest wątkiem naczelnym postu i niechaj inni się
wypowiadają.

Nieczytelny kod, rozwalone tabulatory (bo wszędzie są inaczej traktowane), czy te moje "optymalizacje" które potrzebują konkretnych testów ?

SunRiver napisał(a):
Z życzeniami wiary w "obiektowość" w Cpp z pełnym wsparciem dla paradygmatu funkcyjnego ... (to miał byc sarkazm)

Niestety implementacja pewnych elementów obiektowości ciągnie za sobą masę zasobów których na AVR'ach nie ma zbyt wiele.
Ta moja "obiektowość" jest widziana po stronie użytkownika który ma obiekt USART i na nim operuje.


mokrowski napisał(a):
Mimo deklaracji kolegi że uwagi będą mile widziane, chciałbym jeszcze raz, jawnie uzyskać ... pozwolenie na przedstawienie szeregu uwag do przedstawionego projektu. Proszę o to bo może to (a kolegi nie znam) być poczytane za ,,tanie krytykanctwo" lub po prostu czepianie się :-/ Zapewniam jednak że jeśli kolega się zgodzi, uwagi będą merytoryczne a pytania z uwagą postawione :-)

Wszelka krytyka jak najbardziej mile widziana, chciałbym się na przyszłość dowiedzieć co powinienem robić, czego nie, a czego należy unikać jak ognia itd.

_________________
AVR-UART-lib
AVR-FAST-ENCODER
RFM7x-lib



Ostatnio edytowano 6 lip 2015, o 23:21 przez jnk0le, łącznie edytowano 1 raz

Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 14 lut 2015, o 21:49 
Offline
Użytkownik

Dołączył(a): 13 lut 2015
Posty: 99
Pomógł: 6

mokrowski napisał(a):
1) Na początek chcę Cię zapytać dlaczego nie użyłeś technik szablonowych do definicji USART.

Gdyż wyszło by dokładnie to samo tylko że w jeszcze mniej czytelny i mniej zrozumiały sposób.

No i szablony miały z założenia wyeliminować wielokrotnie powtarzające się te same funkcje dla typu int, double, float, czy zdefiniowanych przez użytkownika. Uproszcza to klepanie kodu, ale w pliku wynikowym już będą oddzielne funkcje dla każdego typu.
Na pc masz nieograniczone zasoby (że aż nikt nie zdaje sobie sprawy jak wygląda implementacja new(std::nothrow)) to na avr'kach nie można sobie pozwolić na rozrost kodu wynikowego.

mokrowski napisał(a):
- każdy USART (a deklarowałeś że co najmniej chcesz dwa) może być ustawiony w trybie który czyni z niego w zasadzie inny obiekt. Np jeden może pracować w trybie wspieranym przez przerwania i bufor kołowy a drugi może być ,,statycznym blokującym USART'em" który po wysłaniu bajtu .. czeka.
- szablon pozwoli Ci łatwo kreować obiekt USART z określonym UBRR (czyli szybkością) bo najczęściej nie przestawiasz jej do końca życia aplikacji. Jeśli jednak przestawiasz, dodatkowa metoda załatwi sprawę.

Zapomniałem przedstawić konstruktorów i zaczyna się to na mnie mścić ;)

Składnia: [ Pobierz ] [ Ukryj ]
język cpp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

do zmiany ustawień "in runtime", można użyć dodatkowej metody jak zaproponowałeś ;)

A jaki jest sens "blokującego" uarta w bibliotece na buforach ? (takie to się widuje w kodzie początkujących, którzy dopiero co zaczęli naukę programowania avr'ów) Szczególnie gdy raz użyty kod nie jest "hardcodowany" ponownie dla użytku drugiego uarta.


mokrowski napisał(a):
- szablon umożliwi Ci także wykonanie pewnych obliczeń w czasie kompilacji bo nie ukrywam że ilość makr w kodzie jest ... nieusprawiedliwiona. One pociągają za sobą utratę kontroli typów oraz kod czynią mało podatnym na debugowanie.

Makra też na to pozwalają, a używam ich głównie do kompilacji warunkowej i "uniwersalizacji" rejestrów pomiędzy różnymi atmegami.


mokrowski napisał(a):
2) Skąd pomysł nieusprawiedliwionego poszerzania kompetencji obiektu USART? USART jako taki zajmuje się wyłącznie wysłaniem bajtu i/lub odebraniem bajtu

Poszerzenie kompetencji polega tu głównie na dodaniu funkcji odbierania/wysyłania do klasy i tyle.
A cała zabawa z dziedziczeniem czy funkcjami wirtualnymi a) może wpłynąć na rozmiar kodu wynikowego b) nic nie zmieni w tak małym przykładzie. Na PC gdzie same metody nieraz mogą mieć po 2k lini oraz występuje masa zależności jest to jak najbardziej uzasadnione.

mokrowski napisał(a):
Co jeśli zdecydujesz Ty lub ktoś używa Twojej klasy by string nie był terminowany zerem '\0' tylko miał inna implementację (np. na początku licznik znaków jak w Pascalu/Delphi). Będziesz poprawiał USART. A powinieneś? Zastanów się...

Biblioteka przygotowana jest do pracy ze stringami zgodnymi z ogólnymi zasadami C, ale nic nie stoi na przeszkodzie aby dopisać sobie funkcje do obsługi takich stringów tak jak do odczytu zrobiłem

Składnia: [ Pobierz ] [ Ukryj ]
język cpp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.


mokrowski napisał(a):
Dalej to samo zagadnienie. Co USART obchodzi skąd wysyła bajt (RAM czy FLASH)? A bo ja bym chciał by z EPROM też.. :-)

EDIT: Z tego co się dowiedziałem to niestety trzeba "na zewnątrz" przygotowywać dane z eepromu do wysłania uartem. No i odczyt epromu wewnątrz klasy uarta byłoby tym o co cały czas mi wytykasz ;)

mokrowski napisał(a):
3) Skąd pomysł że bufor kołowy powinien mieścić się w USART? A co jak będę chciał bufor wykorzystać do wysyłania danych przez I2C lub I2S albo CAN albo OneWire albo...(itd.) Moim zdaniem do USART można przekazać obiekt bufora. Jak USART go dostanie, to będzie z niego korzystał. Jak nie dostanie (bo np. bardzo mało RAM) to nie :-)

Jedyne zastosowanie tego rozwiązania to zewnętrzny sram, ale nie wiem czy takie rozwiązanie korzysta z jakiegoś interfejsu, czy jest "doadresowane" do głównej pamięci więc ciężko mi to ocenić.

No i kwestia zasobów, czy takie dziedziczenie lub trzymanie bufora w oddzielnym obiekcie nie będzie miało wpływy na rozmiar kodu ?

_________________
AVR-UART-lib
AVR-FAST-ENCODER
RFM7x-lib



Ostatnio edytowano 27 mar 2015, o 20:20 przez jnk0le, łącznie edytowano 4 razy

Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 15 lut 2015, o 01:35 
Offline
Użytkownik

Dołączył(a): 13 lut 2015
Posty: 99
Pomógł: 6

@mokrowski
1. A jakie obliczenia mogą wykonać szablony, których nie wykonają makra, i co w moim kodzie można obliczyć jeszcze poza BAUD_CALC ? Mi się od zawsze wydawało że obliczenia w trakcie kompilacji wykonuje kompilator ustawiony na inną flagę niż -O0 niezależnie od tego czy są jakieś szablony czy jest to bezpośrednio w kodzie.
2. W zasadzie mogło by oszczędzić paru makr, ale nie bardzo wiem jak to uzyskać w obecnym kodzie.
3. A którą implementacje masz na myśli ?
Składnia: [ Pobierz ] [ Ukryj ]
język cpp
Musisz się zalogować, aby zobaczyć kod źródłowy. Tylko zalogowani użytkownicy mogą widzieć kod.

Nie jestem pewien czy obecne biblioteki standardowe libc++, MSVCRT itd. posiadają tą "funkcjonalność" bo wszystko jest zaszyte w skompilowanych dll'kach i nie bardzo można to sprawdzić :(.

4. wyjątkowa racja ;)
5. Problem jest taki że takie ATiny co mają wyjątkowo mało ramu raczej nie posiadają drugiego uarta ;)
W zasadzie transmisje blokującą można uzyskać przez ustawienie buforu na 1 bajt (kod obsługi bufora jest współdzielony więc nie ma "puchnięcia" na drugim uarcie). Niestety w obecnym kodzie obsługa takich różniących sie buforów nie obędzie się bez doładowania biblioteki kodem do obsługi tychże.
(jakieś warunki w konstruktorze, potrzebne są zmienne dla rozmiaru bufora/maski, może nawet jakieś dodatkowe metody pracy na tymże buforze, No i jak by wyglądało "dobieranie" się do takiego bufora w przerwaniu ;) )
7. Biblioteka ta w zamyśle miała służyć do operacji znakowych jakimi są właśnie putstr() putint() itd. (tak jak w wielu innych bibliotekach), których jest tylko 7 (+2 makra) z czego używanych będzie najwyżej 4. Dla tak małej ilości funkcji, praktycznie tego samego zastosowania (operacje znakowe) jakoś niewielki jest sens rozdzielania klasy na podklasy z 'przeklejonymi' kilkoma funkcjami.

No i kwestia zasobów - co z tego że oddzielę bufor od głównej klasy skoro rozwiązanie zachowujące obecny rozmiar kodu nie będzie się niczym różniło od obecnego. (czyli nadal mamy umieszczony w klasie bufor definiowany makrem)
Ale mimo wszystko zewnętrzny bufor który jest rzeczywiście reużywalny (a nie że jest po prostu 'wycięty' z jakiejś konkretnej klasy) dla i2c, usb, adc itd. to dosyć ciekawy pomysł i czekam z niecierpliwością na dalszy cykl poradników :) (może jakoś mnie nakierują na właściwą drogę)
A sama biblioteka na obecnym etapie najbardziej by zyskała na przepisaniu jej do C co by zrzuciło kolejne bajty narzutu.

EDIT:
mokrowski napisał(a):
Dość że kod który prezentujesz w mojej ocenie nie spełnia roli wzorcowego a wypowiedź: ,,Powodem popełnienia tej biblioteki jest to iż wiele z ogólnodostępnych bibliotek dedykowanych C++, jest doskonałym przykładem jak NIE NALEŻY tworzyć bibliotek w C++", potraktuję z dużym przymrużeniem oka :-)

Właśnie mi przypomniałeś dlaczego tak a nie inaczej napisałem: jest ich masa i 99% z nich nie spełnia twoich założeń, a jak by tego było mało, są one napisane do obsługi jednego uarta a próba implementacji drugiego skończyła by się ... na przepisaniu CAŁEJ biblioteki od nowa ;), czyli jawnie łamią zasadę reużywalności (bo hardcodowanie w C wyjdzie znacznie lepiej).

No i obawiam się że użycie zewnętrznych buforów wymaga dynamicznej alokacji.

EDIT2:
Mimo wszystko dzięki za wszelkie uwagi odnośnie "obiektowości" mojego kodu. :)
Prawdopodobnie z tym hardcorowym podejściem do optymalizacji przeniosę się do C, a tej bibliotece pozwolę trochę napuchnąć o obiektowość ;)
Tak apropo, to ile flasha zajmuje twoja implementacja (lub celujesz że będzie zajmowała) dla zwykłego "hello worlda" i bardziej rozbudowanych przykładów ?

Teraz potrzebował bym jeszcze zebrać opinie o samym kodzie, jego 'jakości', komentarzach (za dużo, za mało, są miejsca niejasne, albo po prostu brakuje komentarzy z serii 'captain obvious' ;) ) czy nawet sposobie (i brakach) w przedstawieniu tej biblioteki.

_________________
AVR-UART-lib
AVR-FAST-ENCODER
RFM7x-lib



Ostatnio edytowano 1 kwi 2015, o 19:16 przez jnk0le, łącznie edytowano 3 razy

Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 1 mar 2015, o 23:06 
Offline
Użytkownik

Dołączył(a): 13 lut 2015
Posty: 99
Pomógł: 6

Ostatnio troszkę popracowałem nad biblioteką, która obecnie znacznie się różni od wersji pierwotnej.

changelog:

-poprawione makra w tablicach uniwersalizujących, oraz dodanie paru atmeg do tychże
-funkcja putc() mogła wpaść w nieskończoną pętle po zapełnieniu buforu wysyłania (mimo że w początkowych testach działało dla 5x dłuższych stringów niż bufor i nagle nie działa ...)

-ogólna poprawa czytelności kodu
-redukcja kodu wynikowego o ok. 10 bajtów (i nie wiem właściwie jak :))
-dodanie pełnej obsługi 4 interfejsów szeregowych (ATmega 640/1280/2560)
-oraz dodanie drobnej funkcjonalności (AvailableBytes, oraz planowane putfloat)

Obecnie zastanawiam się nad implementacją zewnętrznych buforów, aby nie uzależniać się od jednego możliwego rozmiaru bufora dla wszystkich nadajników/odbiorników.

_________________
AVR-UART-lib
AVR-FAST-ENCODER
RFM7x-lib



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
PostNapisane: 3 mar 2015, o 20:34 
Offline
Użytkownik

Dołączył(a): 13 lut 2015
Posty: 99
Pomógł: 6

mokrowski napisał(a):
Trochę off-top, ale wbrew pozorom związane.
Zerknij tu a wyjaśni Ci się co i jak szablony liczą... topic10671.html
A .. i na marginesie.. jeśli wyznacznikiem czegokolwiek jest objętość, to kod liczący UBRR po konkretyzacji ma 0 (zero) bajtów a mimo to wykonuje obliczenia poprawnie :-)


Z szablonami jest ten problem że same w sobie są mało czytelne, sam musiałem kilka razy to "przelecieć" aby ogarnąć jak to mniej więcej dziala.
1. Tolerancja 2% lub dowolna inna - u mnie działa 57600 @8MHz co daje 4%, natomiast w pewnych sytuacjach nawet 0,2% to może być za dużo.
2. Automatyczne wybranie najbliższego "pasującego" UBBR - a co potem wpisać w putty ?
3. Co z ustawianiem bitu U2X dla kilku różnych seriali ? (bez tego to nie mam nawet co próbować implementować liczenia na szablonach)
4. Mam nadzieje że static_assert wywala błąd kompilacji, choć nic na to nie wskazuje (szablony i czytelność)

Zamiast sprawdzania siłowego kolejnych baudrate w swoich projektach, lepiej zapoznać się z tabelkami i mieć z głowy problem zapuszczania szablonowego skryptu na pc.

np. 1 wynik z gógla http://wormfood.net/avrbaudcalc.php?postbitrate=57600&postclock=8&u2xmode=1

EDIT: No i widzę że rozwiązanie w Cy wymaga globalnej definicji baudrate, co odpada z miejsca.

I co to za zwyczaj nie używania 'using namespace std;' ? :)


PS putfloat już dodane.

_________________
AVR-UART-lib
AVR-FAST-ENCODER
RFM7x-lib



Góra
 Zobacz profil  
cytowanie selektywne  Cytuj  
Wyświetl posty nie starsze niż:  Sortuj wg  
Utwórz nowy wątek Odpowiedz w wątku  [ Posty: 7 ] 

Strefa czasowa: UTC + 1


Kto przegląda forum

Użytkownicy przeglądający ten dział: Brak zidentyfikowanych użytkowników i 0 gości


Nie możesz rozpoczynać nowych wątków
Nie możesz odpowiadać w wątkach
Nie możesz edytować swoich postów
Nie możesz usuwać swoich postów
Nie możesz dodawać załączników

Szukaj:
Skocz do:  
Sitemap
Technologię dostarcza phpBB® Forum Software © phpBB Group phpBB3.PL
phpBB SEO