Skocz do zawartości

Elvis

Użytkownicy
  • Zawartość

    2596
  • Rejestracja

  • Ostatnio

  • Wygrane dni

    189

Posty napisane przez Elvis


  1. To jakiś konkurs na największą ilość kodu która nic nie robi? Może chociaż spróbuj wyjaśnić co starasz się osiągnąć - bo jeszcze niechcący ktoś początkujący kiedyś znajdzie ten wątek i zacznie się z tego uczyć...


  2. W tym co napisałem nie ma nic sprzecznego z notą katalogową. PINx zwaca faktyczny stan pinów wybranego portu - zapis od PORTx jedynie próbuje zapisać określoną wartość. Jeśli zapis się uda, to po pewnym czasie np. 0.5-1.5 cyklu masz taki wynik jak chciałeś. Więc szybciej (optymalniej) będzie działało użycie zmiennej - a inna sprawa, że w zależności od konfiguracji pinu i tego co do niego jest podłączone ten kod może po prostu nie działać tak jak oczekujesz.

    • Pomogłeś! 1

  3. Zacznijmy od nieporozumienia - PORTB i PINB to nie są zmienne. To rejestry i chociaż czasem zachowują się podobnie do zmiennych to zupełnie co innego.

    Z rejestru PORTB możesz odczytać to co niego zapisałeś - więc zamiast sprawdzać PINB lepiej sprawdzać bit PORTB. Ale w niektórych mikrokontrolerach, np. stm32 jest tak, że dostęp do rejestru zajmuje o wiele więcej czasu niż odczyt ze zmiennej, czy rejestru procesora.

    Natomiast to co odczytujesz z PINB to faktyczny stan piny PB5. Okazuje się, że może być on inny niż wynikałoby z zapisu do PORTB - dlatego to może zupełnie nie działać. Jeśli wyjście jest typu push-pull to na 99% będzie działało, ale już mając wyjście open-drain, zapis do PORTB może nie mieć wpływu na wartość w PINB. Wystarczy, że zewnętrzny układ zewrze do masy i PINB zwróci 0 nawet jeśli PORTB zapisywał 1. Czegoś takiego mniej więcej się spodziewałem, stąd było moje pytanie.


  4. Ok, teraz rozumiem o co chodziło 🙂 W każdym razie używanie PINB jako zmiennej jest mocno mylące, może być mało wydajne, albo i zupełnie nie działać.

    Nie wiem jak jest na AVR, ale na ARM dostęp do rejestrów może być o wiele wolniejszy niż do pamięci. Poza tym PINB może zwrócić inną wartość niż wpisałeś do PORTB... Proponuję po prostu dodać zmienną, która będzie przechowywała stan diody i odpowiednio do jej stanu sterować programem. Będzie prościej, szybciej i czytelniej.


  5. Tak dla wyjaśnienia i zamknięcia offtopu - w przypadku większości mikrokontrolerów i mikroprocesorów z rdzeniem ARM, dostępny jest tzn. barrel-shifter. Dzięki niemu wczytując wartość instrukcją LDR można jednocześnie i niejako "za darmo" wykonać przesunięcie bitowe. Oczywiście nie mamy gwarancji że kompilator wygeneruje akurat taki kod i nie powinno się takich optymalizacji wprowadzać bez potrzeby. Ale tak jako ciekawostkę warto wiedzieć, że ARM to niby RISC, a potrafi mieć zaskakująco skomplikowane instrukcje asemblera 🙂

    • Lubię! 1

  6. W każdym razie:

    10 minut temu, ethanak napisał:

    Zauważ: zakładając, że PB5 to stała a PINB to odwołanie się do zawartości rejestru - 1 << PB5 obliczany jest w czasie kompilacji. PINB >> PB5 w czasie wykonania.

    Ergo: jeśli moje założenia są słuszne, nie jest optymalny niezależnie od mikrokontrolera 😉

    to nieprawda. Są takie architektury gdzie oba kody mogą być tak samo wydajne.


  7. Przy okazji warto jeszcze wyjaśnić jak ten pin jest skonfigurowany i jak niby miało działać - bo najpierw używany jest rejestr PORTB, czyli wygląda jakby to miał być pin w trybie wyjścia, ale chwilę później następuje odczyt z rejestru PINB, więc jednak wejście. Jestem bardzo ciekaw jak autor rozumie działanie takiego programu.

    @ethanak zostawmy te optymalizacje w spokoju, może warto zacząć od poprawności programu. Może nie być różnicy, czy przesunięcie jest wykonywane podczas kompilacji, czy wykonywania.


  8. Niestety nie znam metody na użycie GPS w małym robocie, dlatego zapytałem. Dokładność 2m to bardzo optymistyczne założenie. Filtr Kalmana to dobry pomysł, sprawdza się w nawigacji samochodowej - ale znowu, przy rozmiarze i szybkości reakcji robota raczej nie zadziała poprawnie.

    Można uzyskać wysoką dokładność w przypadku GPS, taki sprzęt używany jest np. w geodezji - ale ceny są zupełnie inne niż w przypadku opisywanych modułów, czas pomiaru jest dość długi no i konieczny jest abonament na dane dla DGPS.


  9. Robiłeś może jakąś analizę dokładności danych z GPS? Pytam bo to dość mały robot i kilka metrów to dla niego spory dystans, a z moich doświadczeń z odbiornikami GPS otrzymywanie "szumu", który wygląda jak skoki po kilka metrów to normalne działanie. I bardzo mnie ciekawi jak sobie poradziłeś z tym problemem.


  10. Dobra, z tymi timerami to był zły pomysł - jednak na esp32 jest zupełnie inaczej niż na stm32, a mi się wszystko pomieszało 😞

    W każdym razie jak chodzi o gotowca to proponuję popatrzeć na kod biblioteki FabGL: https://github.com/fdivitto/FabGL

    Jest tam kod sterownika VGA, który wykorzystuje DMA, ale zamiast jak myślałem GPIO używane jest I2S - pozostaje przeanalizować kod, a może i przetestować.

    Tak jako ciekawostka, że ESP32 może faktycznie generować obraz VGA:

     

     


  11. Ja bym proponował zostawić DMA na moment i zacząć od czegoś prostszego, czyli timera. Niezależnie, czy używając DMA, czy CPU i tak konieczne jest ustalenie prędkości transmisji do wyświetlacza - podejście z liczeniem cykli maszynowych się nie sprawdzi, więc proponuję uruchomić timer i na początek programowo go używać. Czyli to co może zrobić DMA najpierw niech robi drugi rdzeń - jest nawet szansa, że to zadziała i DMA nie będzie niezbędne (chociaż zawsze warto czegoś nowego się nauczyć).


  12. Oczywiście, że taki sposób istnieje. Możesz po prostu wyrzucić FreeRTOS, przejąć pełną kontrolę i wszystko sam zrobić. Będzie to dość trudne, ale jak najbardziej możliwe.

    Wydaje mi się jednak, że po prostu źle do tego podchodzisz. W przypadku AVR takie sterowanie pinami mając policzone takty zegara działało - w nowszych układach będzie bardzo skomplikowane. O wiele łatwiej i dokładniej byłoby użyć do tego odpowiednich modułów peryferyjnych. Do odmierzania czasu - timer, a do transmisji DMA.


  13. Zakładałem że scheduler na ESP32 używa dwóch rdzeni i sam uruchomi zadanie na drugim. Ale możliwe, że to było zbyt optymistyczne założenie. Wydawało mi się, że użycie priorytetów jest mniej "inwazyjne" niż wskazywanie rdzenia, ale oczywiście użycie xTaskCreatePinnedToCore zadziała na pewno, a z priorytetami trzeba byłoby przetestować.


  14. Nie mieszajmy innym w głowie, czasem lepiej nic nie pisać niż pisać nieprawdziwe rzeczy. Wskaźnik i tablica to co innego w języku C, więc zapis

    const char *napis = "jakis napis";

    oraz:

    const char napis[] = "jakis napis";

    nie są równoważne, chociaż podobne. Zachęcam do poczytania podstaw języka C oraz sprawdzenia czym się różnią.

    • Lubię! 1

  15. Prawdopodobnie całe nieporozumienie wzięło się z warunku w pętli:

    for(t=0;t<=6;t++){
      

    Jak słusznie zauważył kolega @Hudyvolt, taka pętla wykona się 7 razy, za pierwszym razem t=0, a za ostatnim t=6, czyli t=0,1,2,3,4,5,6 daje razem 7. Powodem tego zamieszania jest użycie warunku <= (mniejszy-równy), popularniejsze jest używanie ostrej nierówności, czyli kodu:

    for(t=0;t<6;t++){
      

    Domyślam się, że o to chodziło autorowi tematu i taka postać jest używana znacznie częściej. Pętla chyba miała się wykonać 6 razy, czyli t=0,1,2,3,4,5 i wówczas po wyjściu z pętli wartość t wynosiłaby 6, a więc oryginalny warunek byłby spełniony.

×
×
  • Utwórz nowe...