Aktyw Forum

Zarejestruj się na forum.ep.com.pl i zgłoś swój akces do Aktywu Forum. Jeśli jesteś już zarejestrowany wystarczy, że się zalogujesz.

Sprawdź punkty Zarejestruj się

Umieszczenie tablicyuint w pamieci flash w AVR-GCC

Sławek5
-
-
Posty:485
Rejestracja:15 sie 2003, o 16:40
Lokalizacja:Szczecin
Kontaktowanie:
Umieszczenie tablicyuint w pamieci flash w AVR-GCC

Postautor: Sławek5 » 2 lis 2006, o 06:43

Cześć.
Możecie mi powiedzeć jak a AVR-GCC umiescic tablice w pamieci flash a nastepnie odczytac ją. Dane są w w formacie Unsgned int z zkresem od 0 do 34000.
Może pytanie jest banalne ale natknąłem się na pewne trudności i proszę Was o pomoc.
Spotkałem kilka mozliwości zapisu i nie wiem czym sie różnią.

Sławek.

P.S.
Przy okazji jeszcze chciałbym sie spytać jak to jest np w przypadku np. obsługi lcd. Zwyke tworzy się sie dwie funkcje wyswietlajace tekst jedna dla danych odczytywanych z RAM a druga z flash.
Czy możecie mi powiedzieć dlaczego dwie i jak powinny wyglądać.
Jest to tylko kwestią przypomnienia bo troche sie zamieszałem, więc pytanie może się wydawac dziwne, ale proszę o pomoc.

Jurek Szczesiul
-
-
Posty:175
Rejestracja:10 paź 2003, o 20:44
Lokalizacja:Białystok
Kontaktowanie:

Re: Umieszczenie tablicyuint w pamieci flash w AVR-GCC

Postautor: Jurek Szczesiul » 2 lis 2006, o 10:58

Możecie mi powiedzeć jak a AVR-GCC umiescic tablice w pamieci flash a nastepnie odczytac ją.
Np. tak :

Kod: Zaznacz cały

#include <avr/pgmspace.h> ............... uint Tablica[] PROGMEM = {0,100,1000,10000,30000}; uint Element; ................. Element=pgm_read_word(&Tablica[3]);
Pozdrowienia Jurek S.

Sławek5
-
-
Posty:485
Rejestracja:15 sie 2003, o 16:40
Lokalizacja:Szczecin
Kontaktowanie:

Postautor: Sławek5 » 2 lis 2006, o 11:46

Ja spotkałem jeszcze takie coś

Kod: Zaznacz cały

pgm_uint16_t tablica[10];
Próbowałem też odczytać poprzez podstawienie elementu tablicy do danej i nie powstał błąd kompilacji tzn

Kod: Zaznacz cały

uint16_t dana; prog_uint16_t talica[10]; dana=tablica[1];

Nie wygenerował błędu?
a co oznacza

Kod: Zaznacz cały

pgm_read_word
A mogę prosić o to co pytałem o lcd.

Jurek Szczesiul
-
-
Posty:175
Rejestracja:10 paź 2003, o 20:44
Lokalizacja:Białystok
Kontaktowanie:

Postautor: Jurek Szczesiul » 2 lis 2006, o 13:15

Próbowałem też odczytać poprzez podstawienie elementu tablicy do danej i nie powstał błąd kompilacji tzn

Kod: Zaznacz cały

uint16_t dana; prog_uint16_t talica[10]; dana=tablica[1];

Nie wygenerował błędu?
a co oznacza

Kod: Zaznacz cały

pgm_read_word
A mogę prosić o to co pytałem o lcd.
Proponuję jednak zajrzeć do manuala avr-libc -> Library reference ->
avr/pgmspace.h Program Space String Utilities.

Nie wszystko będzie od razu jasne ale przynajmniej obejrzysz czym
dysponują biblioteki.
Tam od razu sprawdzisz, że typ prog_uint16_t jest dokładnie tym samym
co uint16_t PROGMEM - utworzonym poprzez typedef.
Jeśli masz ochotę - tworzysz sobie zupełnie własny ( z nazwy, ale
identyczny w działaniu ) typ np.
typedef uint PROGMEM Calkowita_bez_znaku_w_pamieci_flash;
i zamiennie go używasz :
Calkowita_bez_znaku_w_pamieci_flash Tablica2[] = {20,120,1200,12000,34000};

W manualu wyjaśni się też od razu, że pomocnicze funkcje pgm_read_byte
czy pgm_read_word służą do odczytania jedno- lub dwubajtowej zawartości
flash spod podanego adresu. W przypadku tablicy jako argument podajemy adres
potrzebnego elementu tablicy np. &Tablica[4] itd.

( Natomiast stała we flashu musi mieć początkowe wartości.
Zapis uint PROGMEM tablica[10]; nie ma sensu logicznego - bo co odczytasz
z zostawionego pustego miejsca we flashu ?. Zresztą u mnie kompilator tego
nie puszcza i zgłasza błąd. )

I ponieważ w avr-gcc inaczej odwołujemy się do ram ( bezpośrednio ) a
inaczej do flash ( za pomocą pomocniczych funkcji jw ) często przy
obsłudze peryferiów ( lcd, uart itd. ) pisze się dwie wersje funkcji :
jedna pobiera dane bezpośrednio z ram a druga jest przystosowana
do ściągania danych z flash. BTW to wcale nie jest konieczność. Możesz
np. przeznaczyć do współpracy z lcd oddzielny bufor ram i wtedy używasz
zawsze jednakowego sposobu wyświetlania ( pobieranie danych tylko
z tego bufora ), natomiast do bufora wcześniej ładujesz te dane skąd tylko
chcesz ( flash, eeprom, zewnętrzny DataFlash itp. )

Pozdrowienia Jurek S.

Sławek5
-
-
Posty:485
Rejestracja:15 sie 2003, o 16:40
Lokalizacja:Szczecin
Kontaktowanie:

Postautor: Sławek5 » 2 lis 2006, o 13:49

oczywiście ze zapis

Kod: Zaznacz cały

uint PROGMEM tablica[10];
nie ma sensu ja nie pisałem reszty
CZy mogę jeszcze prosć o podanie gdzie moge poczytać sobie tego manala.

A dlaczego dział takie przypisanie zwykłeczyli

Kod: Zaznacz cały

uint16_t dana; prog_uint16_t talica[10]; dana=tablica[1];
bez tego

Kod: Zaznacz cały

pgm_read_word
.

Jurek Szczesiul
-
-
Posty:175
Rejestracja:10 paź 2003, o 20:44
Lokalizacja:Białystok
Kontaktowanie:

Postautor: Jurek Szczesiul » 2 lis 2006, o 15:56

CZy mogę jeszcze prosć o podanie gdzie moge poczytać sobie tego manala.

A dlaczego dział takie przypisanie zwykłeczyli

Kod: Zaznacz cały

uint16_t dana; prog_uint16_t talica[10]; dana=tablica[1];
bez tego

Kod: Zaznacz cały

pgm_read_word
.
Manual jest w wielu miejscach, online np.
http://www.nongnu.org/avr-libc/user-man ... space.html

Można tez pościągać w różnych wersjach ( html, pdf )
http://download.savannah.gnu.org/releases/avr-libc/

Działanie powyższego kodu to "robota" optymalizatora.
Jeśli napiszesz np.

Kod: Zaznacz cały

prog_uint16_t Tablica1[] = {10,20,30,40,50};
a potem

Kod: Zaznacz cały

Element=Tablica1[2];
to wszystkie wartości i adresy są juz mozliwe do określenia
w trakcie kompilacji. Optymalizator korzysta z tego, wyciąga
spod adresu komórki tablicy wartość i ładuje ją bezpośrednio do
zmiennej bez żadnych kodów pobierania z flasha :

Kod: Zaznacz cały

Element=Tablica1[2]; ec: 8e e1 ldi r24, 0x1E ; 30 ee: 90 e0 ldi r25, 0x00 ; 0 f0: 90 93 0d 01 sts 0x010D, r25 f4: 80 93 0c 01 sts 0x010C, r24
Jeśli zamiast znanego w trakcie kompilacji konkretnego indeksu
tablicy użyjesz indeksu ustalanego programowo :

Kod: Zaznacz cały

uint Indeks; ..... Indeks=2; Element=Tablica1[Indeks];
To kompilator już tego nie łyknie i będzie się odwoływać
do obszaru ram zamiast flash ( avr-gcc tak ma - było to
wielokrotnie omawiane w różnych miejscach ). Nie będzie
zgłaszany błąd ale oczywiście program nie zadziała:

Kod: Zaznacz cały

Indeks=2; e0: 82 e0 ldi r24, 0x02 ; 2 e2: 90 e0 ldi r25, 0x00 ; 0 e4: 90 93 0b 01 sts 0x010B, r25 e8: 80 93 0a 01 sts 0x010A, r24 Element=Tablica1[Indeks]; ec: e0 91 0a 01 lds r30, 0x010A f0: f0 91 0b 01 lds r31, 0x010B f4: ee 0f add r30, r30 f6: ff 1f adc r31, r31 f8: e5 5c subi r30, 0xC5 ; 197 fa: ff 4f sbci r31, 0xFF ; 255 fc: 80 81 ld r24, Z fe: 91 81 ldd r25, Z+1 ; 0x01 100: 90 93 0d 01 sts 0x010D, r25 104: 80 93 0c 01 sts 0x010C, r24
- nigdzie nie ma instrukcji lpm pobrania z flasha.

Pozdrowienia Jurek S.

Sławek5
-
-
Posty:485
Rejestracja:15 sie 2003, o 16:40
Lokalizacja:Szczecin
Kontaktowanie:

Postautor: Sławek5 » 2 lis 2006, o 16:47

Prawda na to nie zwróciłem uwagi. Sprawdziłem w AvrStudio.

Jest tam do wyboru kilka funkcji

Kod: Zaznacz cały

pgm_read_byte_near

word dword oraz near lub fara co jam mam wybrać dla Atmega128.
Jak mam odróżnić near od far.
A czy byte word oraz dword są ze znakiem czy bez i ile wynosi dword, bo rozumiem ze word to 16 bitów.

Jurek Szczesiul
-
-
Posty:175
Rejestracja:10 paź 2003, o 20:44
Lokalizacja:Białystok
Kontaktowanie:

Postautor: Jurek Szczesiul » 2 lis 2006, o 18:05

Prawda na to nie zwróciłem uwagi. Sprawdziłem w AvrStudio.

Jest tam do wyboru kilka funkcji

Kod: Zaznacz cały

pgm_read_byte_near

word dword oraz near lub fara co jam mam wybrać dla Atmega128.
Jak mam odróżnić near od far.
A czy byte word oraz dword są ze znakiem czy bez i ile wynosi dword, bo rozumiem ze word to 16 bitów.
near obsługuje adresy do 64k a far - powyzej.
Ponieważ atrybut PROGMEM działa z załozenia tylko do 64k
- użyjemy near ( które zresztą jest zdefiniowane jako domyślne
czyli wystarczy np. pgm_read_byte )

byte = uint8_t
word=uint16_t
dword=uint32_t

Pozdrowienia Jurek S.

Sławek5
-
-
Posty:485
Rejestracja:15 sie 2003, o 16:40
Lokalizacja:Szczecin
Kontaktowanie:

Postautor: Sławek5 » 2 lis 2006, o 19:06

Nie dam spokoju i proszę o wybaczenie :)

Przecież Atmega128 ma 128k więc jest powyżej 64K to chyba nie mogę użyć near?
Czy dobrze myślę, a skąd ja mam wiedzieć czy zostanie to ulokowane na początku pamięci czy gdzieś powyżej 64K.

Jurek Szczesiul
-
-
Posty:175
Rejestracja:10 paź 2003, o 20:44
Lokalizacja:Białystok
Kontaktowanie:

Postautor: Jurek Szczesiul » 2 lis 2006, o 19:55

a skąd ja mam wiedzieć czy zostanie to ulokowane na początku pamięci czy gdzieś powyżej 64K.
Linker lokuje stałe PROGMEM zaraz na początku - po wektorach przerwań.
Tak więc near ( z instrukcjami lpm ) będzie zazwyczaj OK.
Problem może się pojawić dopiero przy jakichś wielkich ilościach (>64k) stałych.
Także jeśli zechcesz użyć stałych w kodzie bootloadera umieszczonym na końcu
flasha - tam już będą konieczne funkcje far ( z instrukcjami elpm ).

Pozdrowienia Jurek S.

Wróć do „AVR/AVR32”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 8 gości