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

STM32 C Newlib - Próba dodania nowego strumienia danych typu Terminal

szczepar 14 Lis 2013 09:54 2394 4
REKLAMA
  • #1 12950188
    szczepar
    Poziom 20  
    Posty: 333
    Pomógł: 27
    Ocena: 59
    Witam
    Na wstępie środowisko
    środowisko na bazie tutorialu Freddie Chopin-a , z dołączonym "STM32F10x_StdPeriph_Lib_V3.5.0"
    Płytka bazowa ZL27 Kamami.
    Kompilator CodeBench Lite for ARM EABI
    Praca bez systemu operacyjnego (na ARM)

    Problem jest następujący.
    Chciałem uzyskać możliwość pełnego wysyłania danych przy pomocy Printf na wiecej niż standardowe 2 strumienie (STDO , STDE).
    Znalazłem dość ciekawy temat pokazujący inne podejście do problemu syscalls.c niż przykład dołączany do Newlib : Link
    Postępując zgodnie z przykładem utworzyłem odpowiednio strukturę.

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


    Wszytko ładnie się kompiluje i pojawia się problem z funkcją fopen:

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


    O ile funkcja fopen wywołuje się poprawnie - tzn jest zwracany adres podobny do adresu SDIO w pamięci (po wywołaniu funkcji open).
    To funkcja pfrintf nie wywołuje żadnej z funkcji odpowiedzialnych za zapis do LCD.

    Czy ktoś spotkał się z poprawnie działającą implementacją Newlib w której dodano dodatkowe strumienie danych wyjściowych typu Terminal?
    Najlepiej w raz z kawałkiem kodu który to wywołuje.
  • REKLAMA
  • #2 12950390
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    Aby ci to działało to MUSISZ zaimplementować swoje własne syscalls dla open, read, write, close itd. (nie wszystkie muszą działać prawidłowo, choć powinny). Pod tym linkiem który podałeś są przecież nawet podane funkcje (_read_r(), _write_r(), _open_r(), ...).

    Dodatkowo konieczna jest implementacja DZIAŁAJĄCEGO _sbrk_r(), ponieważ fopen() (a w zasadzie stdio) używa dynamicznej alokacji pamięci.

    Funkcja fopen() powinna zwracać adres struktury FILE znajdującej się w RAM, a nie adres SDIO czy jakiegokolwiek innego układu peryferyjnego.

    4\/3!!
  • REKLAMA
  • #3 12950465
    szczepar
    Poziom 20  
    Posty: 333
    Pomógł: 27
    Ocena: 59
    Zle mnie zrozumiałeś :), albo ja źle zapisałem :)
    _sbrk_r() razem z malloc działają :)

    Ale kolejno bo inaczej będzie chaos.

    printf ("Hej, ja działam!"); - wywołuje w pracy krokowej kolejno :
    1. ssize_t _write_r ( struct _reent *r, int file, char *buf, size_t nbyte)
    2. No source available for "_fflush_r() "
    3. No source available for "_vfprintf_r() "
    4. No source available for "printf() "

    LCD_Wyswietlacz = fopen( "lcd", "w" ); - wywołuje kolejno :
    1. int _open_r ( struct _reent *ptr, char *file, int flags, int mode ) -> int com4_open_r(struct _reent *r, char *path, int flags, int mode )
    2. No source available for "_fopen_r() "

    Po po powrocie z funkcji _fopen_r() - wartość LCD_Wyswietlacz = 0x20002f34
    Gdyby było null to znaczyło by że mam gdzieś wcześniej błąd :)
    Kod _open_r i com4_open_r
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod



    Wywołanie funkcji fprintf(LCD_Wyswietlacz, "Test" );- wywołuje w pracy krokowej kolejno :
    1. int _fstat_r(struct _reent *r, int file, struct stat *st)
    2. No source available for "__smakebuf_r() "
    3. int _isatty_r(struct _reent *r, int file)
    4. No source available for "__smakebuf_r() "
    5. No source available for "__swsetup_r() "
    6. No source available for "__sfvwrite_r() "
    7. No source available for "_fwrite_r() "
    8. No source available for "fwrite() "

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


    Natomiast wywołanie fprintf(stdout,"TEST" ); - jest zupełnie inne
    stdout = 0x20002e64 - zakres podobny jak LCD_Wyswietlacz
    1. ssize_t _write_r ( struct _reent *r, int file, char *buf, size_t nbyte) ->ssize_t com1_write_r(struct _reent *r, int file, char *buf, size_t nbyte)
    2. No source available for "__sfvwrite_r() "
    3. No source available for "_fwrite_r() "
    4. No source available for "fwrite() "

    I teraz pytanie - czy gdzieś jest kompletna lista funkcji które nie są zaimplementowane w Bare Metal ? Bo widać ze w przypadku użycia
    fprintf(stdout,"TEST" ); - dana jest wypluwana juz w 1 procedurze.
    Natomiast w przypadku drugim już nie - brak jest wywołania procedury Write będącej w syscalls.c

    Problem leży gdzieś z poinformowaniem procedur niejawnych (chyba) o tym że FILE w tym konkretnym wypadku jest Terminalem, ewentualnie jakaś procedura nie jest napisana. Niestety nigdzie nie znalazłem aby ktoś dodawał dodatkowy strumień danych typu Terminal (w systemie bez OS).
    Teoretycznie funkcja _fstat_r zwracajaca parametr S_IFCHR mówi o tym.
    Prawdopodobnie robię coś źle , niestety nie jestem sam w stanie znaleść rozwiązania problemu.
    Mam nadzieję że tym razem napisałem jasno co się dzieje :)
  • REKLAMA
  • Pomocny post
    #4 12950582
    Freddie Chopin
    Specjalista - Mikrokontrolery
    Posty: 13336
    Pomógł: 1712
    Ocena: 870
    A teraz pytanie - wiesz co to buforowanie strumieni? Jeśli nie wiesz, to proponuję wywołać PO Twoim fprintf() do wyświetlacza funkcje fflush().

    szczepar napisał:
    I teraz pytanie - czy gdzieś jest kompletna lista funkcji które nie są zaimplementowane w Bare Metal ?

    Wszystkie są zaimplementowane. Uwierz mi że to wszystko działa tak jak trzeba - używam osobiście do obsługi plików na kartach SD, UARTów, socketów, ...

    szczepar napisał:
    Teoretycznie funkcja _fstat_r zwracajaca parametr S_IFCHR mówi o tym.

    Jak doczytasz więcej o znaczeniu tej flagi, to dowiesz się, że taki strumień domyślnie jest buforowany "do linii".

    4\/3!!
  • #5 12950605
    szczepar
    Poziom 20  
    Posty: 333
    Pomógł: 27
    Ocena: 59
    Masz rację mój błąd polegał na tym że zapomniałem o tym że pierwsze co to wyłączyłem buforowanie danych z stdout :)

    setvbuf(stdout, NULL, _IONBF, 0);

    Natomiast zupełnie zapomniałem ze powinienem zrobić to samo w drugim wypadku.
    Dzieki wielkie, sam bym nad tym siedział kolejne dni szukając dziury w całym.
    Temat wyczerpany zamykam. :)
REKLAMA