Elektroda.pl
Elektroda.pl
X
Computer ControlsComputer Controls
Proszę, dodaj wyjątek dla www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

Sterowanie wyswietlacza 8-bit z różnych portów.

28 Cze 2016 22:03 3666 70
  • Poziom 16  
    Witam,

    Posiadam wyświetlacz TFT, gdzie sterowanie odbywa się przez magistralę 8-bitową. Wyświetlacz pomyślany jest jako shield do arduino. Do tej pory z powodzeniem sterowałem go z procesorków AVR (Atmega, Xmega), podłączając jego magistralę pod cały port.

    Tym razem chcę go podłączyć do płytki Nucleo 144, a tam magistralą steruje każdy inny pin. Jak więc napisać procedurę samego wpisu 8-bitowej wartości na każdy inny pin portu?
  • Computer ControlsComputer Controls
  • Użytkownik usunął konto  
  • Poziom 36  
    mas24 napisał:
    chcę go podłączyć do płytki Nucleo 144, a tam magistralą steruje każdy inny pin


    W Nucleo jest tak samo jak w AVR tylko porty są 16-bitowe i jeśli coś jeszcze wisi na pozostałych bitach to trzeba odpowiednio maskować, lub stosować zapis bajtowy do rejestrów GPIO.

    Ale teraz widzę Twój kłopot jak spojrzałem do dokumentacji Nukleo144.
    Przypuszczam że chodzi Ci o piny D0-D7, które w Arduino były kompletnym portem PD (nie wiem jak sobie radzisz z RX, ale to nie ważne tutaj). W Nucleo faktycznie jest zbieranina z trzech portów i to nie po kolei.
    Czyli nie ma rady, musisz rozdzielić to na co najmniej trzy operacje zapisu z maskowaniem nieużywanych bitów a chyba czytelniej po prostu użyć ośmiu ustawień pojedynczych bitów.

    Coś w tym kształcie :

    Kod: c
    Zaloguj się, aby zobaczyć kod


    nie testowałem tego, więc trzeba jeszcze sprawdzić gdyby użyć.

    Ale na przykład w mbed jest klasa BusOut pozwalająca powiązać dowolne piny (nawet róznych fizycznych portów) w jedną "magistralkę".
    Po za tym sprawdź czy na mbed nie ma już Twojego wyświetlacza. Po co wyważać otwarte już przez innych drzwi.
  • Poziom 16  
    Dzięki za odpowiedzi.

    Z pinoutu Nucleo wykombinowałem taki oto wlasny pinout:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Co do gotowców, to widzialem obsługę ILI9327 na stronie Tilena Majerle (http://stm32f4-discovery.net/), lecz tamta miała obsługę po SPI. Z drugiej zaś strony, gdyby napisać na nowo jedynie funkcje WriteData i WriteCom, to mogłoby się udać. Na razie chce przetestować swoją bibliotekę, jako najlepiej poznaną, a potem porównam z tym, co na necie piszą.

    Nie mam HALa, jedynie STDPERIF, in mam taką oto procedurę:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Czy się nada?
  • Poziom 36  
    mas24 napisał:
    //D0 - PF12
    //D1 - PD15


    Czyli przekładając na arduinowy AVR to bity 0 i 1 z portu B.
    Wychodzi na to że Twój shield jednak i tak dzielił te osiem linii do LCD na dwa porty PD i PB.

    Tak dociekam, bo nurtowało mnie (szczególnie że wspomniałeś o całym porcie) w jaki sposób taki typowy arduinowy shield mógłby dostać cały, kompletny ośmiobitowy port, kiedy na D0 i D1 wisi ten nieszczęsny UART (szczególnie że dostaje stały, niewyłączalny sygnał z konwertera USB-RS232). A teraz już rozumiem.


    Cytat:
    Z drugiej zaś strony, gdyby napisać na nowo jedynie funkcje WriteData i WriteCom, to mogłoby się udać.


    Pewnie tak.
    Jest taka biblioteka UTFT i jest w niej ILI9327, także w trybie równoległym 8-bit.
    Tak pobieżnie patrząc na jej źródła, wydaje mi się że zmiana interfejsu z SPI na 8-bit to w sumie prosta sprawa, załatwiona w tej bibliotece jednym parametrem.



    mas24 napisał:
    Czy się nada?


    Ta funkcja SPL robi dokładnie to co funkcja HAL.
    Tylko trzeba nazwy stałych zmienić.

    Oczywiście wcześniej trzeba ustawić te konkretne bity portów jako wyjścia, włączyć zegary portów itd. . Ale to oczywistość, wspominam o tym tylko dla pewności.
  • Poziom 16  
    Dla ścisłości:

    To, że wyswietlacz przeznaczony jest dla Arduino, osobiście nigdy nie podłączałem go do jakiegokolwiek Arduino, aż do teraz. Wykonałem Footprint tego wyświetlacza i projektowałem własne płytki, gdzie Atmega (Xmega) sterowała normalnie całym portem, jak napisałem na początku tego wątku.

    Właśnie kminię, jak zbudować WriteData i WriteCom na podstawie tego, co napisano powyżej. Jak uda sie wysterować wyświetlacz, zapodam kod.

    Kombinuję z tymi bitami, jak na razie mam takie coś (przykład dla pierwszych dwóch bitów):

    Kod: c
    Zaloguj się, aby zobaczyć kod
  • Poziom 36  
    mas24 napisał:
    projektowałem własne płytki, gdzie Atmega (Xmega) sterowała normalnie całym portem, jak napisałem na początku tego wątku.


    No to już mam pełna jasność. Dzięki za wytłumaczenie.

    Jeszcze wspomnę tu o bibliotece Adafruit GFX, używanej między innymi, pod dokładnie taki shield z ILI9327 jak Twój (interfejs 8-bit, identycznie ten sam rozkład bitów na dwa porty). Pierwotnie była napisana pod Arduino, ale ostatnimi czasy czesto portowana pod STM32. Sam korzystałem z takiej adaptacji na Nucleo (ściślej środowisko mbed), tyle że z innym wyświetlaczem. I powiem że nawet przyjemna ta biblioteka.
    Choć w Twoim przypadku (wyświetlacz) trzeba by chyba wyszukać stare arduinowe źródła drivera dla Twojego wyświetlacza i jakoś połączyć z wersją dla STM32 (nie zauważyłem by ktoś akurat używał tej szczególnej kombinacji i dał źródła).
  • Poziom 16  
    Na razie nie działa najlepiej, nie jest juz statyczny biały kolor, a miga na biało z dużą częstotliwością.

    Tutaj

    jest wątek, jak portowałem tą bibliotekę z Arduino na zwykły C i się udawało. Tym razem zmieniłem jedynie funkcje wpisu do portu na takie:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Nie wiem, co jest grane, może to wina, że na magistrali nie pojawiaja się wszystkie bity naraz?
  • Computer ControlsComputer Controls
  • Poziom 36  
    mas24 napisał:
    Nie wiem, co jest grane, może to wina, że na magistrali nie pojawiaja się wszystkie bity naraz?


    To że nie naraz nie ma znaczenia. Jedyne co można by brać pod uwagę to odstęp czasowy między ustawieniem ostatniego z ośmiu bitów a zboczem sygnału WR (choć nie wiem na którym zboczu jest faktyczny wpis do sterownika, sprawdź może).
    Może jakiś delay przed WR potrzebny (w końcu STM32 to szybka maszyna). Albo ustawienie dla bitów tej "magistralki" większej szybkości działania (GPIO_Speed w inicjalizacji).
    Co do upewnienia się poprawnego ustawiania tych ośmiu bitów to może warto sprawdzić statycznie, "w naturze" na pinach czy coś nie pokręcone (skoro te bity takie porozrzucane).


    Cytat:
    WR_0; WR_1;


    Jeśli to są makra takie jak te w ustawianiu tych 8 bitów, to niezbyt mi się to podoba, z tego względu że piny (fizycznie) mogą potrzebować więcej czasu na ustalenie poprawnych poziomów napięć niż czas wynikający z sekwencji instrukcji.
    Sam sterownik jak widzę, jest szybki w interpretacji sygnałów i to może akurat działać na niekorzyść. Chociaż wpisuje dane zboczem narastającym WR to wciąż jest dla mnie zagadką czy napięcie na jego pinach będzie w tym momencie pewnie ustalone (pojemności montażowe , prędkość wynikająca z wybranej prędkości portów w incjalizacji itp. )
  • Poziom 16  
    Próbowałem wprowadzać różne timingi pomiędzy wskazane przez Ciebie makra (tak jak się domyslaleś, sa to SetBits i ResetBits), próbowałem wszystkich dostepnych częstotliwości pinów, nawet 100MHz i nic to nie pomogło. Wyświatlacz nadal idiotycznie miga. Próbowałem tez z wyłączonym SysTickiem, który miga diodami, ale też nic, gdyż wyświetlacz startuje pierwszy, a SysTick zaraz zanim.

    Dobra, wyświetlacz ruszył. Nie dokonfigurowałem jednego pinu (PF14), ale wyświetlacz działa koszmarnie wolno, tak wolno działał mi na Xmega z 2MHz zegara. Jest jeszcze kilka innych drobnych usterek, ale to już pikuś, najgorsze to spowolnienie. Wywaliłem wszystkie instrukcje opóźniające, i nadal wolno działa.
  • Poziom 24  
    Witam,
    Większość wyświetlaczy oparta jest o standard HITAC HI (HD44780), jest w opisie algorytm inicjalizacji 8 bitowego interfejsu. Zawsze starałem się używać odczytu bitu BF. Odpadają koszmarne opóźnienia.

    Ale w zasadzie nie o tym chciałem napisać. Mam sugestię jak zorganizować 'luźne' piny w port. Do tego nadaje się właśnie 'bit banding'. Np.
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Pzdr
  • Poziom 16  
    Wow, to daje szanse na działanie wyświetlacza bez wykonywania płytki patchującej na PORTD. Ponieważ temat dla mnie zupełnie nowy, zadam kilka pytań:

    Co to są za liczby przy każdym z dwóch pinów? Ich adresy? Jeśli tak, to znając adres bazowy portu, trzeba dodać jeszcze bity dla odpowiedniego pinu?

    W funkcji "writeb" jest pętla, która także da opóźnienia, czy się mylę?

    No dobra, znalazłem równanie:

    bit_word_addr = bit_band_base + (byte_offset x 32) + (bit_number × 4)

    Bit Band Base to odczytam powyżej, nie wiem, jak wyznaczyć byte offset, czy jest to offset adres portu? numer bitu jest oczywisty.
  • Poziom 24  
    W stm32f4xx.h są wszystkie niezbędne informacje:

    #define PERIPH_BB_BASE ((uint32_t)0x42000000) /*!< Peripheral base address in the bit-band region */
    #define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000)
    #define GPIOG_BASE (AHB1PERIPH_BASE + 0x1800)
    __IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */

    tak więc adres bb_PG13_ODR wyliczamy następująco:
    0x42000000 + (0x20000 + 0x1800 + 0x14) * 32 + 13 * 4 = 0x424302B4

    Przykładowo na STM32F429i_DISCO na tym pinie jest dioda, więc definiując:
    #define LD3 (*(volatile uint32_t *)0x424302B4) // bb_PG13 ODR
    mogę ją zapalać w C
    LD3=1;
    albo zamrugać/zmienić
    LD3 ^= 1;
    Idealne do aktywacji np. sygnału RS, WR itp.

    Pzdr
  • Poziom 36  
    Może łatwiej użyć takich makr (może nawet w bibliotece, z której korzystasz już są)

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Wtedy zamiast liczyć adres, wpisujesz nazwy rejestrów i nie przejmujesz się wartością liczbową.

    i wtedy poszczególne bity będą u Ciebie osobnymi zmiennymi.
    Np.

    Kod: c
    Zaloguj się, aby zobaczyć kod


    wtedy je używasz np. tak:

    LCD_D0=1;
    LCD_D1=0;
    itd.


    Ciekawi mnie tez kwestia tej niskiej prędkości.
    Co prawda ustawianie bitów poprzez osobne wywołania SPL jest faktycznie mało wydajne czasowo (właściwie nadaje się jedynie do wstępnych testów) i pójście w kierunku bit-bandingu czy podobnej też wydajnej metody z użyciem BSRR, to jedyny rozsądny kierunek.
    Ale mnie zastanawia czy masz taktowanie rdzenia na pełna prędkość?



    Jeszcze tak na marginesie. Jeśli byś się decydował na dedykowaną płytkę z STM32 i chciał zgrupować te bity na jeden port, to polecałbym raczej skorzystanie z FSMC jako najlepszego rozwiązania oferowanego w większych STM32 (100 pinów lub więcej).
    Jest nawet filmik na YT z ILI9327 sterowanym przez tą peryferię. Szybkość robi duże wrażenie.
  • Specjalista - Mikrokontrolery
    mas24 napisał:
    W funkcji "writeb" jest pętla, która także da opóźnienia, czy się mylę?

    Opóźnienia pomiędzy ustawieniami kolejnych bitów na magistrali mogą być dowolnie długie, ponieważ są one całkowicie bez znaczenia - jak zrobisz kod który będzie miał tam opóźnienie jednej godziny to też będzie działać. Skoro u Ciebie nie działa, to masz błąd gdzieś indziej i magiczne metody niczego nie rozwiążą. To co zmieniałeś ("timingi" typu 2MHz, 10MHz, 50MHz i 100MHz) nie ma nic wspólnego z opóźnieniami. Istnieje spora szansa, że impulsy na linii "enable" są zbyt krótkie, więc użycie bit-bandingu tylko pogorszy sprawę.
  • Poziom 24  
    Ręcznie policzyłem dla zilustrowania metody, faktycznie do tego służy preprocesor języka C. To oczywiste.
    A dla konkretnego hardware wystarczy raz zdefiniować np.
    #include <board.h>

    Mam taki zwyczaj by jeszcze w start-up uaktywnić używane porty, pamięci SDRAM, LCD, do poziomu takiego aby najprostszy program w C "Hello World!" już działał.
    Pzdr

    PS Zauważyłem wpis Freddiego powyżej i ma on rację co do timingów. Jak STM chodzi na powiedzmy 168MHz, wyświetlacz HD44780 nie wyłapie impulsu np. na linii WR. Wymagane timingi są w opisie chipa.
  • Poziom 36  
    PDT napisał:
    Zauważyłem wpis Freddiego powyżej i ma on rację co do timingów.


    Owszem ale są tu dwie różne sprawy. Jedna to "składanie" portu 8 bit z bitów różnych portów. I tu Twoją sugestię użycia bit-bandingu uważam za jak najbardziej rozsądną. Użycie funkcji SPL do ustawiania każdego bitu jest według mnie nieuzasadnionym marnotrawstwem.

    Ale druga sprawa, tj, użycie szybkiego bezpośredniego ustawiania bitów "strobujących" np. przez bitbanding, może powodować po prostu gubienie tych sygnałów. Tak że użycie wywołań SPL, wprowadza przy okazji pewne opóźnienia, akurat pożądane w tej kwestii.
  • Poziom 24  
    Podczas inicjowania HD44780 potrzebne są kolejne opóźnienia: 15ms, 4.1ms, 100us.
    Ponadto trzeba zapewnić od 200ns do 800ns czasy trwania poszczególnych sygnałów (Bus Timing Characteristics).
    Trzeba więc zapewnić zwłaszcza te 15ms (+10ms power up) oraz 4.1ms za pomocą delay-a. Nie ma co żałować to tylko sekwencja inicjująca. Gorzej jest jeśli projekt nie przewiduje odczytu bitu BF. Wówczas trzeba uwzględnić "czas wykonania" przez wyświetlacz poszczególnych poleceń, bardzo zmienny w zależności od polecenia (Clear Display, Set Mode itp.).

    Raczej nie liczyłbym na opóźnienia SPL-a, trzeba to samemu zaprogramować.

    Pzdr
  • Poziom 36  
    PDT napisał:
    Podczas inicjowania HD44780 potrzebne są kolejne opóźnienia: 15ms, 4.1ms, 100us.


    Ale tu generalnie o inny kontroler chodzi, ILI9327.
  • Poziom 24  
    OK, masz całkowitą rację. Moja pomyłka. Zasugerowałem się początkowym postem, gdzie mowa była o interfejsie 8-bitowym.
    Tego ILI9327 nie miałem przyjemności używać. Ale jeśli on ma takie same 'features' jak tryb landscape ILI9341 :) to może być ciekawie.
    Pzdr
  • Poziom 16  
    Dobra, więc chyba trzeba się nieco cofnąć. Jeśli mam źle ustawiony zegar systemowy, to by wiele mogło wyjaśnić. Procedurę ustawienia zegara ma taką:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Przepisaną niegdyś z internetu. Może być tam błąd, więc zacząłbym od pytania do Kolegów, czy ta procedura jest dobrze napisana i uaktywni mi 168MHz zegar w STM32F629ZI ?
  • Użytkownik usunął konto  
  • Poziom 36  
    mas24 napisał:
    uaktywni mi 168MHz zegar w STM32F629ZI ?


    Coś pokręciłeś. Przypuszczam że chyba chodzi Ci o STM32F429ZI. A w jego przypadku max to 180MHz (choć jak się uprzeć to 168MHz też się da).
    Co do poprawności Twojego ustawiania zegara to trudno mi się wypowiedzieć. Osobiście do tego używam CubeMX i jak dla mnie robi to świetnie i bezstresowo.
    Nawet jeśli zdecydowałeś się na trzymanie się SPLa, to i tak polecam gorąco to narzędzie, choćby by nawet tylko podejrzeć jak ustawia zegary CubeMX i przenieść to na argumenty funkcji SPL.



    Wracając do ustawiania tej ośmiobitowej magistralki z pomocą bitbandingu, to dla zamknięcia pewnego wątku myślowego z mojej strony, zamieszczam fragment działającego (pod mbed) kodu.
    Dla Nucleo144 trzeba tylko wymienić szczegóły dotyczące konkretnych portów i bitów:

    Kod: c
    Zaloguj się, aby zobaczyć kod



    Tak że myślę że jeśli masz coś z zegarem i po poprawkach pójdzie lepiej, to bitbanding przy tej "magistralce" chyba i tak będzie miał pewien sens w kwestii wydajności.
  • Użytkownik usunął konto  
  • Specjalista - Mikrokontrolery
    rb401 napisał:
    (wartosc&0x01)?BUS_D0=1:BUS_D0=0;

    Nie prościej byłoby dać tak:

    BUS_D0 = (wartosc & 0x01) != 0;

    ?

    mas24 napisał:
    Może być tam błąd, więc zacząłbym od pytania do Kolegów, czy ta procedura jest dobrze napisana i uaktywni mi 168MHz zegar w STM32F629ZI ?

    Jeśli komentarze mówią prawdę, to bardziej obstawiam zegar 45MHz. Wciąż jednak nie wiem jakie miałoby to niby mieć znaczenie - dobry kod dla wyświetlacza będzie dobrze działał niezależnie od częstotliwości, co najwyżej na mniejszej będzie działał wolniej i tyle.
  • Poziom 16  
    No właśnie działa mi wolniej :)

    To znaczy, że dla mikrokontrolerów STM32 są 3 zestawy bobliotek? SPF, HAL i Cube, tak? Nie upieram się na SPF, a czy duże są różnice pomiedzy SPF i Cube?
  • Specjalista - Mikrokontrolery
    To może warto zacząć od dobrego opisania problemu, bo wg mnie opis:
    mas24 napisał:
    Na razie nie działa najlepiej, nie jest juz statyczny biały kolor, a miga na biało z dużą częstotliwością.

    nie sugeruje, że całość działa zbyt wolno, tylko że działa po prostu źle.
  • Poziom 16  
    Tak właśnie z nim miałem - migał, bo nie dokonfigurowałem jednego bitu jako wyjście cyfrowe. Jak znalazłem błąd, wyświetlacz ruszył, tylko wolno działa, gdyż postawienie jednego piksela na ekranie dużo zajmuje czasu. A te 180MHz by się przydało, bo procek będzie sporo liczył. Chciałem przebrnąć pzrez peryferia, by móc się zajać pisaniem samego programu, np. menu pod ten wyświetlacz, ale utknąłem na nim, a potem okazało się, ze usrtawienia zegara są...jakieśtam.

    Byl gdzieś konfigurator zegara jako arkusz w Excelu, szukam teraz, ale dla 429ZI i 180MHz nie mogę znaleźć, sa dla mniejszych F4 i pozwalaja ustawić 168MHz.
  • Poziom 36  
    Freddie Chopin napisał:
    (wartosc&0x01)?BUS_D0=1:BUS_D0=0;

    Nie prościej byłoby dać tak:

    BUS_D0 = (wartosc & 0x01) != 0;

    ?


    Myślę że to akurat szczegół bez większego znaczenia.
    A ta akurat postać instrukcji, która Ci się nie podoba, "wyewoluowała" jakoś w tym wątku, a po za tym, jest też pierwszą która zadziałała autorowi. Teoretycznie (bo i tak kompilator zrobi po swojemu) też powinna być szybsza bo zapisuje stałe a druga postać wylicza pośrednio zmienną do podstawienia.

    Myślę że generalnie istnieje teraz ważniejszy problem z zegarem a z optymalizacją czasu ustawiania tych ośmiu bitów, można by się ewentualnie bawić później. Choć osobiście jakoś nie widzi mi się by można tu jeszcze coś znacząco poprawić (bez wchodzenia w assembler).
  • Specjalista - Mikrokontrolery
    rb401 napisał:
    Myślę że to akurat szczegół bez większego znaczenia.
    A ta akurat postać instrukcji, która Ci się nie podoba, "wyewoluowała" jakoś w tym wątku, a po za tym, jest też pierwszą która zadziałała autorowi. Teoretycznie (bo i tak kompilator zrobi po swojemu) też powinna być szybsza bo zapisuje stałe a druga postać wylicza pośrednio zmienną do podstawienia.

    Skoro tak twierdzisz i tak skupiacie się na szybkości działania, to popatrz sam. Obydwa przykłady dla optymalizacji -O2.

    Twój:

    Code:
    080001e4 <LCDWriteBus(unsigned char)>:
    



    void LCDWriteBus(uint8_t wartosc)
    {
        (wartosc&0x01)?BUS_D0=1:BUS_D0=0;
     80001e4:   f010 0301    ands.w   r3, r0, #1
     80001e8:   d03f         beq.n   800026a <LCDWriteBus(unsigned char)+0x86>
     80001ea:   4b39         ldr   r3, [pc, #228]   ; (80002d0 <LCDWriteBus(unsigned char)+0xec>)
     80001ec:   2201         movs   r2, #1
     80001ee:   601a         str   r2, [r3, #0]
        (wartosc&0x02)?BUS_D1=1:BUS_D1=0;
     80001f0:   f000 0302    and.w   r3, r0, #2
     80001f4:   f003 02ff    and.w   r2, r3, #255   ; 0xff
     80001f8:   2b00         cmp   r3, #0
     80001fa:   d03e         beq.n   800027a <LCDWriteBus(unsigned char)+0x96>
     80001fc:   4b35         ldr   r3, [pc, #212]   ; (80002d4 <LCDWriteBus(unsigned char)+0xf0>)
     80001fe:   2201         movs   r2, #1
     8000200:   601a         str   r2, [r3, #0]
        (wartosc&0x04)?BUS_D2=1:BUS_D2=0;
     8000202:   f000 0304    and.w   r3, r0, #4
     8000206:   f003 02ff    and.w   r2, r3, #255   ; 0xff
     800020a:   2b00         cmp   r3, #0
     800020c:   d03d         beq.n   800028a <LCDWriteBus(unsigned char)+0xa6>
     800020e:   4b32         ldr   r3, [pc, #200]   ; (80002d8 <LCDWriteBus(unsigned char)+0xf4>)
     8000210:   2201         movs   r2, #1
     8000212:   601a         str   r2, [r3, #0]
        (wartosc&0x08)?BUS_D3=1:BUS_D3=0;
     8000214:   f000 0308    and.w   r3, r0, #8
     8000218:   f003 02ff    and.w   r2, r3, #255   ; 0xff
     800021c:   2b00         cmp   r3, #0
     800021e:   d03c         beq.n   800029a <LCDWriteBus(unsigned char)+0xb6>
     8000220:   4b2e         ldr   r3, [pc, #184]   ; (80002dc <LCDWriteBus(unsigned char)+0xf8>)
     8000222:   2201         movs   r2, #1
     8000224:   601a         str   r2, [r3, #0]
        (wartosc&0x10)?BUS_D4=1:BUS_D4=0;
     8000226:   f000 0310    and.w   r3, r0, #16
     800022a:   f003 02ff    and.w   r2, r3, #255   ; 0xff
     800022e:   2b00         cmp   r3, #0
     8000230:   d03b         beq.n   80002aa <LCDWriteBus(unsigned char)+0xc6>
     8000232:   4b2b         ldr   r3, [pc, #172]   ; (80002e0 <LCDWriteBus(unsigned char)+0xfc>)
     8000234:   2201         movs   r2, #1
     8000236:   601a         str   r2, [r3, #0]
        (wartosc&0x20)?BUS_D5=1:BUS_D5=0;
     8000238:   f000 0320    and.w   r3, r0, #32
     800023c:   f003 02ff    and.w   r2, r3, #255   ; 0xff
     8000240:   2b00         cmp   r3, #0
     8000242:   d03a         beq.n   80002ba <LCDWriteBus(unsigned char)+0xd6>
     8000244:   4b27         ldr   r3, [pc, #156]   ; (80002e4 <LCDWriteBus(unsigned char)+0x100>)
     8000246:   2201         movs   r2, #1
     8000248:   601a         str   r2, [r3, #0]
        (wartosc&0x40)?BUS_D6=1:BUS_D6=0;
     800024a:   f000 0340    and.w   r3, r0, #64   ; 0x40
     800024e:   f003 02ff    and.w   r2, r3, #255   ; 0xff
     8000252:   2b00         cmp   r3, #0
     8000254:   d039         beq.n   80002ca <LCDWriteBus(unsigned char)+0xe6>
     8000256:   4b24         ldr   r3, [pc, #144]   ; (80002e8 <LCDWriteBus(unsigned char)+0x104>)
     8000258:   2201         movs   r2, #1
     800025a:   601a         str   r2, [r3, #0]
        (wartosc&0x80)?BUS_D7=1:BUS_D7=0;
     800025c:   0602         lsls   r2, r0, #24
     800025e:   4b23         ldr   r3, [pc, #140]   ; (80002ec <LCDWriteBus(unsigned char)+0x108>)
     8000260:   bf4c         ite   mi
     8000262:   2201         movmi   r2, #1
     8000264:   2200         movpl   r2, #0
     8000266:   601a         str   r2, [r3, #0]
     8000268:   4770         bx   lr



    void LCDWriteBus(uint8_t wartosc)
    {
        (wartosc&0x01)?BUS_D0=1:BUS_D0=0;
     800026a:   4a19         ldr   r2, [pc, #100]   ; (80002d0 <LCDWriteBus(unsigned char)+0xec>)
     800026c:   6013         str   r3, [r2, #0]
        (wartosc&0x02)?BUS_D1=1:BUS_D1=0;
     800026e:   f000 0302    and.w   r3, r0, #2
     8000272:   f003 02ff    and.w   r2, r3, #255   ; 0xff
     8000276:   2b00         cmp   r3, #0
     8000278:   d1c0         bne.n   80001fc <LCDWriteBus(unsigned char)+0x18>
     800027a:   4b16         ldr   r3, [pc, #88]   ; (80002d4 <LCDWriteBus(unsigned char)+0xf0>)
     800027c:   601a         str   r2, [r3, #0]
        (wartosc&0x04)?BUS_D2=1:BUS_D2=0;
     800027e:   f000 0304    and.w   r3, r0, #4
     8000282:   f003 02ff    and.w   r2, r3, #255   ; 0xff
     8000286:   2b00         cmp   r3, #0
     8000288:   d1c1         bne.n   800020e <LCDWriteBus(unsigned char)+0x2a>
     800028a:   4b13         ldr   r3, [pc, #76]   ; (80002d8 <LCDWriteBus(unsigned char)+0xf4>)
     800028c:   601a         str   r2, [r3, #0]
        (wartosc&0x08)?BUS_D3=1:BUS_D3=0;
     800028e:   f000 0308    and.w   r3, r0, #8
     8000292:   f003 02ff    and.w   r2, r3, #255   ; 0xff
     8000296:   2b00         cmp   r3, #0
     8000298:   d1c2         bne.n   8000220 <LCDWriteBus(unsigned char)+0x3c>
     800029a:   4b10         ldr   r3, [pc, #64]   ; (80002dc <LCDWriteBus(unsigned char)+0xf8>)
     800029c:   601a         str   r2, [r3, #0]
        (wartosc&0x10)?BUS_D4=1:BUS_D4=0;
     800029e:   f000 0310    and.w   r3, r0, #16
     80002a2:   f003 02ff    and.w   r2, r3, #255   ; 0xff
     80002a6:   2b00         cmp   r3, #0
     80002a8:   d1c3         bne.n   8000232 <LCDWriteBus(unsigned char)+0x4e>
     80002aa:   4b0d         ldr   r3, [pc, #52]   ; (80002e0 <LCDWriteBus(unsigned char)+0xfc>)
     80002ac:   601a         str   r2, [r3, #0]
        (wartosc&0x20)?BUS_D5=1:BUS_D5=0;
     80002ae:   f000 0320    and.w   r3, r0, #32
     80002b2:   f003 02ff    and.w   r2, r3, #255   ; 0xff
     80002b6:   2b00         cmp   r3, #0
     80002b8:   d1c4         bne.n   8000244 <LCDWriteBus(unsigned char)+0x60>
     80002ba:   4b0a         ldr   r3, [pc, #40]   ; (80002e4 <LCDWriteBus(unsigned char)+0x100>)
     80002bc:   601a         str   r2, [r3, #0]
        (wartosc&0x40)?BUS_D6=1:BUS_D6=0;
     80002be:   f000 0340    and.w   r3, r0, #64   ; 0x40
     80002c2:   f003 02ff    and.w   r2, r3, #255   ; 0xff
     80002c6:   2b00         cmp   r3, #0
     80002c8:   d1c5         bne.n   8000256 <LCDWriteBus(unsigned char)+0x72>
     80002ca:   4b07         ldr   r3, [pc, #28]   ; (80002e8 <LCDWriteBus(unsigned char)+0x104>)
     80002cc:   601a         str   r2, [r3, #0]
     80002ce:   e7c5         b.n   800025c <LCDWriteBus(unsigned char)+0x78>
     80002d0:   424002a4    .word   0x424002a4
     80002d4:   4241029c    .word   0x4241029c
     80002d8:   424002a8    .word   0x424002a8
     80002dc:   4240828c    .word   0x4240828c
     80002e0:   42408294    .word   0x42408294
     80002e4:   42408290    .word   0x42408290
     80002e8:   424082a8    .word   0x424082a8
     80002ec:   424002a0    .word   0x424002a0


    Mój:
    Code:
    080001e4 <LCDWriteBus(unsigned char)>:
    




    void LCDWriteBus(uint8_t wartosc)
    {
     80001e4:   b5f0         push   {r4, r5, r6, r7, lr}
        BUS_D0 = (wartosc & 0x01) != 0;
     80001e6:   f8df e060    ldr.w   lr, [pc, #96]   ; 8000248 <LCDWriteBus(unsigned char)+0x64>
        BUS_D1 = (wartosc & 0x02) != 0;
     80001ea:   4f10         ldr   r7, [pc, #64]   ; (800022c <LCDWriteBus(unsigned char)+0x48>)
        BUS_D2 = (wartosc & 0x04) != 0;
     80001ec:   4d10         ldr   r5, [pc, #64]   ; (8000230 <LCDWriteBus(unsigned char)+0x4c>)
        BUS_D3 = (wartosc & 0x08) != 0;
     80001ee:   4911         ldr   r1, [pc, #68]   ; (8000234 <LCDWriteBus(unsigned char)+0x50>)
        BUS_D4 = (wartosc & 0x10) != 0;
     80001f0:   4e11         ldr   r6, [pc, #68]   ; (8000238 <LCDWriteBus(unsigned char)+0x54>)
        BUS_D5 = (wartosc & 0x20) != 0;
     80001f2:   4c12         ldr   r4, [pc, #72]   ; (800023c <LCDWriteBus(unsigned char)+0x58>)
        BUS_D6 = (wartosc & 0x40) != 0;
     80001f4:   4a12         ldr   r2, [pc, #72]   ; (8000240 <LCDWriteBus(unsigned char)+0x5c>)
        BUS_D7 = (wartosc & 0x80) != 0;
     80001f6:   4b13         ldr   r3, [pc, #76]   ; (8000244 <LCDWriteBus(unsigned char)+0x60>)



    void LCDWriteBus(uint8_t wartosc)
    {
        BUS_D0 = (wartosc & 0x01) != 0;
     80001f8:   f000 0c01    and.w   ip, r0, #1
     80001fc:   f8ce c000    str.w   ip, [lr]
        BUS_D1 = (wartosc & 0x02) != 0;
     8000200:   f3c0 0e40    ubfx   lr, r0, #1, #1
     8000204:   f8c7 e000    str.w   lr, [r7]
        BUS_D2 = (wartosc & 0x04) != 0;
     8000208:   f3c0 0780    ubfx   r7, r0, #2, #1
     800020c:   602f         str   r7, [r5, #0]
        BUS_D3 = (wartosc & 0x08) != 0;
     800020e:   f3c0 05c0    ubfx   r5, r0, #3, #1
     8000212:   600d         str   r5, [r1, #0]
        BUS_D4 = (wartosc & 0x10) != 0;
     8000214:   f3c0 1700    ubfx   r7, r0, #4, #1
        BUS_D5 = (wartosc & 0x20) != 0;
     8000218:   f3c0 1540    ubfx   r5, r0, #5, #1
        BUS_D6 = (wartosc & 0x40) != 0;
     800021c:   f3c0 1180    ubfx   r1, r0, #6, #1
        BUS_D7 = (wartosc & 0x80) != 0;
     8000220:   09c0         lsrs   r0, r0, #7
    {
        BUS_D0 = (wartosc & 0x01) != 0;
        BUS_D1 = (wartosc & 0x02) != 0;
        BUS_D2 = (wartosc & 0x04) != 0;
        BUS_D3 = (wartosc & 0x08) != 0;
        BUS_D4 = (wartosc & 0x10) != 0;
     8000222:   6037         str   r7, [r6, #0]
        BUS_D5 = (wartosc & 0x20) != 0;
     8000224:   6025         str   r5, [r4, #0]
        BUS_D6 = (wartosc & 0x40) != 0;
     8000226:   6011         str   r1, [r2, #0]
        BUS_D7 = (wartosc & 0x80) != 0;
     8000228:   6018         str   r0, [r3, #0]
     800022a:   bdf0         pop   {r4, r5, r6, r7, pc}
     800022c:   4241029c    .word   0x4241029c
     8000230:   424002a8    .word   0x424002a8
     8000234:   4240828c    .word   0x4240828c
     8000238:   42408294    .word   0x42408294
     800023c:   42408290    .word   0x42408290
     8000240:   424082a8    .word   0x424082a8
     8000244:   424002a0    .word   0x424002a0
     8000248:   424002a4    .word   0x424002a4


    Już nawet pomijając długość, nie wiem jak można twierdzić że kod w którym na pierwszy rzut oka widać minimum 8 skoków jest bardziej optymalny od takiego w którym jest ich zero... Swoją drogą ten mój można pewnie ulepszyć, bo chyba przy bitbandingu nie ma znaczenia czy zapisujemy 1, 5, 100 czy cokolwiek innego niż zero, więc nawet te wszystkie "!= 0" by mogły odpaść.