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

PGM SPACE w C, jak czytać dane powyżej 64kB?

mas24 15 Cze 2015 07:47 2184 33
  • #1 14771813
    mas24
    Poziom 16  
    Witam,

    Zdecydowałem się na opisanie mojego problemu z w nowym wątku. Otóż w poprzednim Kolega Michałko zapodał kod, który nieźle działał, mimo warningów, ale tylko do 64kB. Jak dodałem więcej danych, zamiast przebiegu odczytany został jakiś szum. Dla przypomnienia podaję Link do tego wątku.

    Tym razem spróbowałem czegoś innego, by ominąć ograniczenie do 64kB:

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


    lecz dostaję jeszcze więcej warningów:

    ../main.c:83:10: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
    ../main.c:83:8: warning: assignment makes pointer from integer without a cast [enabled by default]

    O co chodzi z "castowaniem", jak to rozumieć?
  • #2 14771957
    tmf
    VIP Zasłużony dla elektroda
    Widzę, że z tamtego wątku nie wyciągnąłeś żadnych wniosków...
    W powyższym kodzie - zastanów się jak przy pomocy 16-bitowego adresu (bo taki mają standardowo etykiety w avr-gcc) określić położenie w przestrzeni większej niż 64 kB? Raczej trzeba pobrać adres co najmniej 24 bitowy, prawda? Zobacz do czego rozwijane jest (uint_farptr_t * ) - nie jest to to co potrzebujesz. Zamiast tak kombinować już trzeci raz ci napiszę - przekształć te tablice do obiektów binarnych i użyj do nich dostępu przez _memx, lub napisz własną wstawkę asemblerową do odczytu pamięci spod 24-bitowego adresu.
    Poza tym w kodzie:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    tab1 wskazuje raczej na tablicę leżącą poza granicą 64 kB, prawda? A więc odczyt jej elementów powinien odbywać się przez pgm_read_word_far. Wylko po co się cofać o 4 lata, skoro obecnie robi to jak należy kompilator.
  • #3 14771976
    mas24
    Poziom 16  
    Czyli rozumiem,że PGM Space powyżej 64kB nie zadziała nigdy i lepiej sobie tym w ogóle głowy nie zawracać?

    Planowałem na samych wskaźnikach. Pobrać adres pierwszej tablicy, i potem "ręcznie" zwiększać go co 2048, by odczytać następną tablicę, ale to wymuszałoby znów użycie pgm_read_word(_far). Co z kolei, jak piszesz także nie jest tym, co potrzebuję.

    No dobra, jak ma wyglądać taka tablica binarna 16-bitowych elementów? Mógłbyś podać przykład chociaż 5-elementowej takiej tablicy?

    O _memx gdzie mogę poczytać?
  • #4 14771998
    tmf
    VIP Zasłużony dla elektroda
    Oczywiście, że PGM zadziała powyżej 64 kB, tylko musisz używać konsekwentnie wersji FAR i pobierać adresy 24 bitowe. Standardowo avr-gcc zwraca ci adresy 16 bitowe. Abe to zmienić musisz stosować makro zwracające 24 bitowy adres (jest w pgmspace), lub używać przestrzeni __memx, która też wymusza pobieranie 24 bitowego adresu. Wszystkie odpoweiedzi na pytania uzyskałeś już w poprzednim wątku, nie ma sensu tego dublować.
  • #5 14772191
    mas24
    Poziom 16  
    Sorki, że obstaję jeszcze przy tym PGM Space, ale chcę to zrozumieć, zanim zabiorę się za _memx i inne metody.

    Próba czytania:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    kończy się odczytaniem wartości 0 i nic nie jest generowane. Według mnie wszędzie dałem wskaźniki powiej 16 bit i nie wiem, dlaczego to nie działa?

    no i krzyczy cały czas:
    ../main.c:32:21: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
    ../main.c:32:21: warning: initialization makes pointer from integer without a cast [enabled by default]
  • #6 14772218
    tmf
    VIP Zasłużony dla elektroda
    Tak jak pisałem operator & zwraca w avr-gcc adres 16-bitowy, a ty potrzebujesz 24-bitowy. Samo użycie funkcji far nic nie da. Czyli adres musisz pobierać nie przy pomocy & lecz makra GET_FAR_ADDRESS lub właśnie zastosować przestrzeń __memx, gdyż kompilator jest na tyle sprytny, że dla tej przestrzeni zwracany jest 24-bitowy adres, czyli żadnych makr nie musisz stosować.
  • #7 14772469
    mas24
    Poziom 16  
    Szukając po necie, jak się tego GET_ADDRESS_FAR używa dowiedziałem się, ze jest to oddzielne makro, więc znalazłem coś takiego:

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


    lecz krzyczy mi, że nie ma rejestrów r26 i r30, w dodatku nigdzie tutaj to nie jest pokazane. Dotarłem nawet do paczki z plikami Carlosa Lamasa, a po wgraniu tego do projektu, krzyczy o jakis jeszcze plik. Nie wiem już, co robić?
  • #9 14772599
    mas24
    Poziom 16  
    i wali dokładnie te same błędy:

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

    błędy:
    Kod: Text
    Zaloguj się, aby zobaczyć kod
  • #11 14772662
    mas24
    Poziom 16  
    Mam Atmel Toolchain 3.4.2.1573 a programuję w Eclipse Luna na procku Xmega128A4U-U.
  • #12 14772703
    michalko12
    Specjalista - Mikrokontrolery
    Problemem jest to, że kompilator w makrze GET_FAR_ADDRESS() potrzebuje znać adres zmiennej już na etapie kompilacji. Musisz tym makrem pobrać do zmiennej adres całej tablicy a potem tą zmienną zmodyfikowaną indeksem użyć jako argument dla funkcji pgm_read_word_far() .


    Sprawdź czy Ci coś takiego przejdzie:

    Kod: C / C++
    Zaloguj się, aby zobaczyć kod
  • #13 14772812
    mas24
    Poziom 16  
    Podany przez Ciebie kod skompilował się, ale zamiast generowanego przebiegu mam kaszane na ekranie oscyloskopu, jakiś niezdefiniowany przebieg naprzemiennie z innym. Dziwna sprawa.

    Zmienna "numer" to numer kolejnej tablicy z danymi (nie ze wskaźnikami), którą inkrementuję przyciskiem przechodząc do generowania następnego przebiegu.

    Ale metoda bez pętli, tylko poprzez memcopy jest warta uwagi!
  • #14 14772819
    michalko12
    Specjalista - Mikrokontrolery
    Poprawiłem.


    Spróbuj wersję z __memx
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    Może pojawić się warning "cast from pointer to integer of different size" - zignoruj go.
  • #15 14773958
    mas24
    Poziom 16  
    Wow, dzięki z góry. Mam kilka pytań:
    1. Tam gdzie napisałeś "FILL" wstawić dane z przebiegu? W jakiej postaci?
    2. Jednak tablica wskaźników także tutaj obowiązuje?
    3. Tablica VCOTAB chyba może mieć 2048 elementów? (MAXPOINT=2048)
    4. Do czego służy pętla "for" w pętli głównej? Przepisuje kolejne przebiegi z FLASH do SRAM? Jeśli tak, to ja to zrobię sobie wybór za pomocą przycisku(ów).
    5. Ten warning pojawia mi się dość często, o co tu chodzi? Co to znaczy "cast" w tym przypadku?
  • #16 14773993
    michalko12
    Specjalista - Mikrokontrolery
    mas24 napisał:
    1. Tam gdzie napisałeś "FILL" wstawić dane z przebiegu? W jakiej postaci?

    Tak jak się wypełnia każde inne tablice:
    0x0000, 0x0001...
    mas24 napisał:
    2. Jednak tablica wskaźników także tutaj obowiązuje?

    To upraszcza kod.
    mas24 napisał:
    3. Tablica VCOTAB chyba może mieć 2048 elementów? (MAXPOINT=2048)

    Ja Ci dałem tylko przykład do wzorowania się jak stosować __memx, wykorzystaj go do swoich potrzeb.
    mas24 napisał:
    4.

    Do czego służy pętla "for" w pętli głównej? Przepisuje kolejne przebiegi z FLASH do SRAM? Jeśli tak, to ja to zrobię sobie wybór za pomocą przycisku(ów).

    Do niczego, to jest tylko pod potrzeby przykładu.

    Oczywiście nie testowałem tego kodu.
  • #17 14774007
    mas24
    Poziom 16  
    Dzięki, jutro to sprawdzę, gdy będę miał dostęp do oscyloskopu i sprawdzę generowane przebiegi.

    Powinienem sobie poradzić z adaptacją tego kodu do moich potrzeb.
  • #18 14774950
    mas24
    Poziom 16  
    Niestety wywala błąd przy definicji każdej z tablic, np.

    /Przeb_2048x16b.c:85:23: error: conflicting named address spaces (__memx vs generic) for 'SINUS1'
  • #19 14775026
    michalko12
    Specjalista - Mikrokontrolery
    U mnie to co Ci podałem kompilowało się z tylko jednym warningiem.
    Cytat:
    avr-gcc -g1 -Wall -Os -mmcu=atmega168p -DF_CPU=16000000UL -c -o main.o main.c
    main.c: In function 'generuj_VCO':
    main.c:79:29: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
    memcpy_PF( (void *)VCOTAB, (uint_farptr_t)TABPS[numer], sizeof(uint16_t)*1000);
    ^
    avr-gcc -g1 -Wall -Os -mmcu=atmega168p -DF_CPU=16000000UL -Wl,-Map,main.map -o main.elf main.o
    avr-objdump -h -S main.elf > main.lst
    avr-objcopy -j .text -j .data -O ihex main.elf main.hex
    avr-objcopy -j .text -j .data -O binary main.elf main.bin
    avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex main.elf main_eeprom.hex


    Cytat:
    avr-gcc --version
    avr-gcc.exe (AVR_8_bit_GNU_Toolchain_3.4.3_1072) 4.8.1
  • #20 14775033
    mas24
    Poziom 16  
    OK, poradziłem sobie z błędami kompilacji, ale generowane przebiegi nadal są nieprawidłowe, z wyjątkiem prostokąta. Reszta to jakieś bohomazy. Tak w ogóle to te tablice mam w oddzielnym pliku, a kod jest taki:

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


    a w pliku głównym:

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


    próbowałem jeszcze z "__flash", ale efekt jest taki sam.

    działa!!!
    wyszedł taki szkopuł, że podczas kopiowania tablic "na piechotę" za pomocą pętli FOR, skalowałem dane z 16 bit na 12 dla DAC, a po zastosowaniu "memcpy" to skalowanie gdzieś uciekło. Zastosowałem w innym miejscu, przy wpisywaniu do przetwornika DAC
  • #21 14775093
    michalko12
    Specjalista - Mikrokontrolery
    W pierwszym poście masz jeszcze jakieś przesuwanie bitów
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod

    To nie ma znaczenia?
  • #22 14775095
    mas24
    Poziom 16  
    No właśnie na to wpadłem i dopisałem w poprzednim poście :)

    Na razie przetestowałem metodę z PGM Space i Get ADres Far, zaraz zrobię i z _memx
  • Pomocny post
    #23 14775120
    michalko12
    Specjalista - Mikrokontrolery
    mas24 napisał:
    Zastosowałem w innym miejscu, przy wpisywaniu do przetwornika DAC

    To nie jest zbyt dobre rozwiązanie. Po przekopiowaniu tablicy z FLASH do RAM przeskaluj dane w pętli, a w ogóle to najlepiej byłoby gdybyś już we FLASHu takie dane umieścił.
  • #24 14775150
    mas24
    Poziom 16  
    Wszystko da się zrobić, także wygenerować dane 12-bitowe, zamiast 16-bitowych. Niezależnie od tego, oba przykłady działają, i zamieszczam je tu dla potomnych.
    Dziękuje Ci Michałko za pomoc, dzięki Tobie rozwiązałem ten problem i to w dwóch wersjach :)

    Teraz kody:
    Wersja PGM_SPACE:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    procedura odczytu w programie głównym:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    a teraz wersja z __memx
    plik z danymi:
    Kod: C / C++
    Zaloguj się, aby zobaczyć kod


    a teraz procedura odczytu w programie głównym:

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


    Dodano po 1 [godziny] 22 [minuty]:

    Wpisałem aż 22 przebiegi, i zauważyłem coś dziwnego: otóż nie generuje mi kilku przebiegów zdefiniowanych na początku, tylko te górne, jakby powyżej 64kB? Chodzi o sposób z __memx

    Jak temu zaradzić?
  • #25 14775334
    michalko12
    Specjalista - Mikrokontrolery
    Sprawdź w pliku map lub lst jakie są adresy tych tablic z których przebiegi są złe.
  • #26 14775345
    mas24
    Poziom 16  
    jest takie coś:
    Kod: Text
    Zaloguj się, aby zobaczyć kod


    w ogóle są nie po kolei. RAMPUP i RAMPDOWN są zdefiniowane na początku,a tu wylądowały na końcu i m. in. tych nie generuje, tak jakby ich w ogóle nie było.[/syntax]
  • #27 14775363
    michalko12
    Specjalista - Mikrokontrolery
    No dobra, ale działa coś z adresu powyżej 0x10000? Jaki dokładnie procesor używasz?
  • #28 14775565
    mas24
    Poziom 16  
    Właśnie wszystkie powyżej tego adresu nie działają. Co ciekawe, są zdefiniowane na samym początku.
    Procek to Xmega128A4U-U

    Co ciekawe, w metodzie z Progmem jest dokładnie to samo.
  • #29 14775620
    michalko12
    Specjalista - Mikrokontrolery
    A masz ustawiony dobry typ procesora w opcjach (atxmega128a4u) ?

    Pokaż listingi funkcji memcpy_PF i __xload_3. jeśli masz źle zdefiniowany procesor to te funkcje będą używały instrukcji LPM zamiast ELPM.

    Kod: AVR assembler
    Zaloguj się, aby zobaczyć kod
  • #30 14775623
    mas24
    Poziom 16  
    Tak, inaczej nie zaprogramowałby mi Eclipse procka. Na początku miałem omyłkowo ustawione na Xmega64A4U, ale wtedy napisał, że sygnatury się nie zgadzają, a teraz programuje, wiec ten sam procek jest.

    Ja się zastanawiam, czy to memcpy obsługuje adresy powyżej 64kB?

    Właśnie mam wrażenie, że to memcpy kuleje. Wpisałem kilka adresów na twardo (przepisane z pliku MAP) i jest to samo, zaraz sprawdzę.

    Kod: AVR assembler
    Zaloguj się, aby zobaczyć kod


    Kod: AVR assembler
    Zaloguj się, aby zobaczyć kod


    mam za to takie informacje od kompilatora;
    Kod: Text
    Zaloguj się, aby zobaczyć kod
REKLAMA