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

Sekcje programu gdzie właściwie sie znajdują?

Jakub17 28 Lut 2018 16:27 669 14
  • #1 28 Lut 2018 16:27
    Jakub17
    Poziom 6  

    Witam

    Tak jak w temacie, mam problem ze zrozumieniem gdzie właściwie poszczególne sekcje programu. Czy wszystkie sekcje znajdują się w pamięci RAM, a przy starcie programu są wypełniane zawartością lub adresami innych rodzajów pamięci jak np. FLASH? I program przez adresy umieszczone w tych sekcjach skacze do odpowiednich rodzajów pamięci?
    Kiedy np. tworzę zmienną EEMEM to znajduje się ona w sekcji eeprom, ale czy sama sekcja znajduje się w RAM i przechowuje adres zmiennej z pamięci eeprom, czy może cała sekcja jest w eeprom?
    Gdzie znajdują się sekcje .data i .bss?

    0 14
  • Pomocny post
    #2 28 Lut 2018 17:50
    grko
    Poziom 32  

    Twoje pytanie jest dość ogólne ponieważ wszystko o czym mówisz jest definiowane w skrypcie linkera. Ale zazwyczaj jest tak, że:
    - sekcja .text jest umieszczana w pamięci flash
    - sekcja .data jest umieszczana w pamięci RAM (kopiowana z pamięci flash w rozbiegówce)
    - sekcja .bss jest umieszczana w pamięci RAM (ustawiana na wartość zero w rozbiegówce)

    Jak tworzysz zmienną EEMEM to jest ona umieszczana pod rzeczywistym adresem pamięci EEPROM (w AVR wszystkie rodzaje pamięci są w odrębnej przestrzeni adresowej zaczynającej się od 0) ale i tak musisz się odwoływać do tych zmiennych poprzez odpowiednie API z avrlibc. Tego typu zmienne są umieszczane w sekcji eeprom i możesz sobie zaprogramować pamięć EEPROM mając tylko plik *.elf. Program readelf może wyświetlić wszystkie sekcje z pliku *.elf:

    Kod: bash
    Zaloguj się, aby zobaczyć kod

    0
  • #3 28 Lut 2018 20:36
    Jakub17
    Poziom 6  

    grko napisał:

    - sekcja .data jest umieszczana w pamięci RAM (kopiowana z pamięci flash w rozbiegówce)

    Czy to znaczy, że zmienne statyczne czyli zadeklarowane ze słowem static i zmienne globalne znajdują się w pamięci FLASH i są później kopiowane do RAM?

    grko napisał:

    Jak tworzysz zmienną EEMEM to jest ona umieszczana pod rzeczywistym adresem pamięci EEPROM (w AVR wszystkie rodzaje pamięci są w odrębnej przestrzeni adresowej zaczynającej się od 0) ale i tak musisz się odwoływać do tych zmiennych poprzez odpowiednie API z avrlibc. Tego typu zmienne są umieszczane w sekcji eeprom i możesz sobie zaprogramować pamięć EEPROM mając tylko plik *.elf. Program readelf może wyświetlić wszystkie sekcje z pliku *.elf:
    [/syntax]

    Gdybym hipotetycznie utworzył wskaźnik w main() i chciał mu przypisać początkowy adres pamięci EEPROM np. adres 0 to skąd będzie wiadomo o adresowanie jakiej pamięci chodzi skoro wszystkie rodzaje pamięci zaczynają się od adresu 0. Musi chyba istnieć jakaś wzajemna korelacja między tymi pamięciami pozwalająca jednocześnie na wzajemne ich odróżnienie... Czytałem gdzieś kiedyś na forum, że np. adres zerowy np. pamięci EEPROM wcale nie ma wartości 0 tylko ma jakiś offset pozwalający odróżnić go od innych rodzajów pamięci, czyli tak jakby wszystkie pamięci traktowane były jako jedna przestrzeń adresowa. To prawda?

    0
  • Pomocny post
    #4 28 Lut 2018 22:18
    grko
    Poziom 32  

    Jakub17 napisał:

    Czy to znaczy, że zmienne statyczne czyli zadeklarowane ze słowem static i zmienne globalne znajdują się w pamięci FLASH i są później kopiowane do RAM?


    Dotyczy to tylko zmiennych globalnych (statycznych w scope funkcji), które są zainicjalizowane. Zmienne globalne niezanicjalizowane są umieszczane w sekcji .bss i inicjalizowane wartością 0.

    Jakub17 napisał:

    Gdybym hipotetycznie utworzył wskaźnik w main() i chciał mu przypisać początkowy adres pamięci EEPROM np. adres 0 to skąd będzie wiadomo o adresowanie jakiej pamięci chodzi skoro wszystkie rodzaje pamięci zaczynają się od adresu 0. Musi chyba istnieć jakaś wzajemna korelacja między tymi pamięciami pozwalająca jednocześnie na wzajemne ich odróżnienie...


    No właśnie nie ma rozróżnienia. Dlatego przy dostępie do pamięci EEPROM musisz używać API z avrlibc.

    Jakub17 napisał:

    Czytałem gdzieś kiedyś na forum, że np. adres zerowy np. pamięci EEPROM wcale nie ma wartości 0 tylko ma jakiś offset pozwalający odróżnić go od innych rodzajów pamięci, czyli tak jakby wszystkie pamięci traktowane były jako jedna przestrzeń adresowa. To prawda?


    IMO nieprawda. Funkcje z avrlibc pobierają jako adres zwykłe o ile się nie mylę 16 bitowe wskaźniki.

    https://www.nongnu.org/avr-libc/user-manual/group__avr__eeprom.html

    0
  • #5 28 Lut 2018 23:31
    2675900
    Użytkownik usunął konto  
  • #6 01 Mar 2018 07:02
    Jakub17
    Poziom 6  

    grko napisał:


    IMO nieprawda. Funkcje z avrlibc pobierają jako adres zwykłe o ile się nie mylę 16 bitowe wskaźniki.

    https://www.nongnu.org/avr-libc/user-manual/group__avr__eeprom.html



    Pytanie moje było raczej ogólne, nie chodziło mi tylko o pamięć EEPROM. Z kolei funkcje z avrlibc do EEPROM ktoś musiał napisać zatem wewnątrz ich ciała pamięć musi być jakoś "ręcznie adresowana" a nie przez kolejne funkcje... Jeżeli wszystkie rodzaje pamięci są traktowane jako wspólna przestrzeń adresowa, to wydaje mi się że adresy początków tych pamięci muszą się jakoś odróżniać żeby na siebie nie nachodziły tzn. np. zerowy adres pamięci EEPROM ma tak naprawdę adres 0x8000 we wspólnej przestrzeni adresowej. A jeżeli nie ma wspólnej przestrzeni adresowej to może istnieją specjalne instrukcje do odwoływania się do różnych rodzajów pamięci?
    Zależy mi na tym by to zrozumieć, bo gdybym podłączył zewnętrzną pamięć EEPROM czy FLASH to nie wiedziałbym jak ją adresować. Najpierw chciałbym zrozumieć jak to zachodzi niskopoziomow a pozniej będę używał funkcji bibliotecznych.

    0
  • #7 01 Mar 2018 08:43
    2675900
    Użytkownik usunął konto  
  • #8 01 Mar 2018 09:52
    Jakub17
    Poziom 6  

    Wiem, że w niektórych uC występuje interfejs XMEM, który obsługuje pamięci zewnętrzne. Moje pytanie dotyczy tylko tego czy jest możliwość odwoływania się do różnych rodzajów pamięci (zewnętrznych lub wewnętrznych) poprzez podanie odpowiedniej wartości wskaźnika czy jednak trzeba użyć jakiś specjalnych instrukcji asemblerowych. Wiem że dla pamięci FLASH i RAM są odpowiednie instrukcje asemblera, ale czy tak jest też w pamięci EEPROM i rownież w przypadku różnego rodzaju pamięci zewnętrznych?

    Dodano po 58 [minuty]:

    Odnośnie sekcji ale trochę innych:

    Kod: c
    Zaloguj się, aby zobaczyć kod


    Oczywiscie wiem, że w tych sekcjach nie powinno sie używać tak rozwlekłego kodu jak wypisywanie tekstu na ekran LCD ale funkcja jest do testów.
    Nie rozumiem, dlaczego utworzenie zmiennej lokalnej tab powoduje, że kompilator sypie mało jasnym błędem: in store_field, at expr.c:6661. W sekcji .init5 na pewno jest już zainicjalizowany stos oraz zmienne globalne, także umieszczenie takiej tablicy na stosie powinno być możliwe. Natomiast użycie zmiennych statycznych z sekcji .data jak literał "Tekst" czy statyczna tablica tab nie powoduje już błędu. Nie rozumiem takiego zachowania programu...
    Funkcja "pierwsza funkcja" jest z atrybutem naked ponieważ nie będzie już nigdzie wywoływana w main() ani nie pobiera argumentów, więc prolog i epilog jest nie potrzebny.

    0
  • Pomocny post
    #9 01 Mar 2018 12:22
    tmf
    Moderator Mikrokontrolery Projektowanie

    Piotrus_999 napisał:
    grko napisał:
    IMO nieprawda

    a czy Xmegi przypadkiem nie mapuja przypadkiem eepromu do data memory ?


    Tak, w tym przypadku można włączyć mapowanie EEPROM do SRAM, co ma też tą zaletę, że można programować EEPROM stronami (co bywa nawet 32x szybsze niż programowanie komórka, po komórce).

    Jakub17 napisał:
    Wiem, że w niektórych uC występuje interfejs XMEM, który obsługuje pamięci zewnętrzne. Moje pytanie dotyczy tylko tego czy jest możliwość odwoływania się do różnych rodzajów pamięci (zewnętrznych lub wewnętrznych) poprzez podanie odpowiedniej wartości wskaźnika czy jednak trzeba użyć jakiś specjalnych instrukcji asemblerowych. Wiem że dla pamięci FLASH i RAM są odpowiednie instrukcje asemblera, ale czy tak jest też w pamięci EEPROM i rownież w przypadku różnego rodzaju pamięci zewnętrznych?


    Programując w C musisz kompilatorowi w jakiś sposób przekazać na co wskazuje wskaźnik. W AVR używasz do tego PROGMEM, lub _flash lub _memx. Kompilator taki wskaźnik będzie traktował jako wskaźnik do FLASH lub do FLASH i SRAM (dla _memx) i wygeneruje odpowiednie instrukcje asemblera. W przypadku EEPROM sprawa jest bardziej skomplikowana, gdyż AVRy różnią się sposobem dostępu do tej pamięci. W efekcie póki co nikt nie zaimplementował osobnej przestrzeni adresowej dla EEPROM i trzeba korzystać z funkcji udostępnionych w nagłówku eeprom.h. Generują one odpowiednie instrukcje umożliwiające dostęp do tej pamięci - EEPROM jest dostępny przez rejestry układów IO, a nie oddzielne instrukcje asemblera. Podobnie pamięci zewnętrzne - zazwyczaj są łączone poprzez jakiś interfejs, np. SPI lub I2C, więc dostęp do nich musisz załatwić we własnym zakresie. Wyjątkiem jest pamięć podłączona przez XMEM - wtedy wystarczy tylko ew. zmienić skrypt linkera, lub odpowiednio skonfigurować Atmel Studio. Dostęp do tej pamięci z poziomu asemblera wygląda identycznie jak do SRAM.

    Jakub17 napisał:
    Funkcja "pierwsza funkcja" jest z atrybutem naked ponieważ nie będzie już nigdzie wywoływana w main() ani nie pobiera argumentów, więc prolog i epilog jest nie potrzebny.


    To nie wystarczy. ABI kompilatora czyni pewne założenia co do zawartości rejestrów. Jeśli powyższa funkcja je zmieni, co jest prawie pewne, to dalszy kod ma spore szanse się posypać. naked ma sens stosować tylko dla funkcji, które kończą program, w efekcie co dalej jest bez znaczenia, ew. dla funkcji które nie zmieniają rejestrów traktowanych jako zachowywane przez funkcję. Ew. dla funkcji napisanych w asemblerze, dla których to programista np. zadbał o przywrócenie kontekstu.

    0
  • Pomocny post
    #10 01 Mar 2018 12:36
    2675900
    Użytkownik usunął konto  
  • #11 01 Mar 2018 17:55
    Jakub17
    Poziom 6  

    tmf napisał:


    To nie wystarczy. ABI kompilatora czyni pewne założenia co do zawartości rejestrów. Jeśli powyższa funkcja je zmieni, co jest prawie pewne, to dalszy kod ma spore szanse się posypać. naked ma sens stosować tylko dla funkcji, które kończą program, w efekcie co dalej jest bez znaczenia, ew. dla funkcji które nie zmieniają rejestrów traktowanych jako zachowywane przez funkcję. Ew. dla funkcji napisanych w asemblerze, dla których to programista np. zadbał o przywrócenie kontekstu.


    Dzięki za szczegółowe wyjaśnienia :) Skoro pojawił się wątek atrybutu naked to dopytam: Czyli użycie normalnej funkcji spowoduje zapisanie stanu rejestrów podczas prologu a naked już tego nie robi, tak? Czyli wystarczy się pozbyć atrybutu naked i będzie w porządku? No bo gdy deklaruje powyższą funkcję bez atrybutu naked to cały program zapętla się na tej funkcji i nie wchodzi nawet w main(). A jeśli chodzi o modyfikacje rejestrów to mówisz o rejestrach R1-R31 czy jakich?

    1
  • #12 01 Mar 2018 18:22
    2675900
    Użytkownik usunął konto  
  • #13 01 Mar 2018 18:43
    Jakub17
    Poziom 6  

    Piotrus_999 napisał:
    Musisz jednak pamiętać że zero_reg niekoniecznie musi być zero (a to zakłada kompilator) a zależne jest to od tego co się wykonywało poprzednio.

    Możesz rozwinąć trochę myśl? Nie rozumiem tego zdania. Wychodzi na to, że bez naked sie nie obedzie bo program się zapętla jeszcze przed main() ale dlaczego?

    Dodano po 17 [minuty]:

    Dodatkowo nie panuje jeszcze nad jedną rzeczą:
    Utworzyłem własną sekcje:
    Kod: c
    Zaloguj się, aby zobaczyć kod

    I przekazałem informację do linkera z poziomu interfejsu Atmel Studio w zakładce SRAM:
    .moja_sekcja = 0x150
    Zrobiłem do wedle wskazówek zamieszczonych w samym Atmel Studio:
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Problem w tym, że pod wskazanym przeze mnie adresem nie ma łańcucha "tekst". Sprawdzałem to w podglądzie pamięci Atmel studio podczas debugowania. Dodatkowo pliki .lss i .map poświadczają, że sekcja została utworzona i zajmuje odpowiednią ilość pamięci. Co jest nie tak?

    0
  • Pomocny post
    #14 01 Mar 2018 18:52
    2675900
    Użytkownik usunął konto