Pamięć at89c2051

Ciąg dalszy eksperymentów z antycznymi mikrokontrolerami. :)

Trafiłem na taką oto dziwną sytuację (zawartość pliku .mem wklejona na końcu wiadomości). Z jakiegoś powodu kilkanaście bajtów na początku pamięci zostało wyłączonych z użytku przez kompilator sdcc. Ktoś ma pomysł dlaczego tak się stało i co mogę z tym zrobić? Może mam coś źle ustawione w makefile albo powinienem deklarować zmienne w jakiś specyficzny sposób?

Druga sprawa: wykonałem kilka eksperymentów i z tego co widzę umieszczenie w kodzie tablicy znaków zdefiniowanej jako const char[] nie powoduje zwiększenia zużycia RAM-u. Mam rozumieć, że 8051/sdcc potrafi odwoływać się do danych umieszczonych w pamięci programu bezpośrednio, bez potrzeby kombinowania z jakimś odpowiednikiem AVR-owskiego pgmspace.h?

Internal RAM layout: 0 1 2 3 4 5 6 7 8 9 A B C D E F

0x00:|0|0|0|0|0|0|0|0|a|a|a|a|Q| | | | 0x10:| | | | | | | | | | | | | | | | | 0x20:|B|b|b|b|b|b|b|b|b|b|b|b|b|b|b|b| 0x30:|b|b|b|b|b|b|b|b|b|b|b|b|b|b|b|b| 0x40:|b|b|b|b|b|b|b|b|b|b|b|b|b|b|b|S| 0x50:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S| 0x60:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S| 0x70:|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S|S| 0x80:| | | | | | | | | | | | | | | | | 0x90:| | | | | | | | | | | | | | | | | 0xa0:| | | | | | | | | | | | | | | | | 0xb0:| | | | | | | | | | | | | | | | | 0xc0:| | | | | | | | | | | | | | | | | 0xd0:| | | | | | | | | | | | | | | | | 0xe0:| | | | | | | | | | | | | | | | | 0xf0:| | | | | | | | | | | | | | | | | 0-3:Reg Banks, T:Bit regs, a-z:Data, B:Bits, Q:Overlay, I:iData, S:Stack, A:Absolute

Stack starts at: 0x4f (sp set to 0x4e) with 49 bytes available.

Other memory: Name Start End Size Max ---------------- -------- -------- -------- -------- PAGED EXT. RAM 0 256 EXTERNAL RAM 0 1024 ROM/EPROM/FLASH 0x0000 0x0327 808 2048

Reply to
Atlantis
Loading thread data ...

-- Wiadomość oryginalna (wysłana 21.03.2017 09:09) --

Pamięć: Zapewne obszar zmiennych jednego modułu (jednego pliku .c) musi być ciągły, a obszar "bbbb" jest za duży, aby się zmieścił od 0x0D do 0x1F. Używasz też zmiennych bitowych, które zaczynają się zawsze od 0x20. Rozwiązanie: rozdziel zmienne modułu "bbbb" na dwa moduły.

Dane we FLASH: Jak najbardziej, całe kombinowanie to dyrektywa const lub code.

Pozdrowienia, MKi

Reply to
MKi

W dniu 2017-03-21 o 09:09, Atlantis pisze:

to jest antyczny? spróbuj 8049, 8085, a dla hardcorów - 8080.

Zapoznać się z mapą pamięci?

a w asemblera bym może zajrzał... podpowiedź: "architektura Harvard" oraz "instrukcja MOVC"

a.

Reply to
Miller Artur

Użytkownik "Atlantis" napisał w wiadomości grup dyskusyjnych:58d0dfa8$0$651$ snipped-for-privacy@news.neostrada.pl...

Poczatek RAM to sa rejestry R0-R7. 4 banki takich rejestrow sa, ktore mozna sobie przelaczac ... albo uzywac jako normalna pamiec, jesli nie przelaczasz. Kompilator z tego co widac ominal tylko jeden bank.

8051 potrafi, ale wymaga takiego samego kombinowania. Widac w tym komplitatorze pisze sie const char :-)

uC musi te dane odczytywac innym rozkazem (MOVC), wiec kompilator musi wiedziec, ze to jest inna pamiec, i ze trzeba uzyc innego rozkazu.

Nie mozesz sobie napisac funkcji np void funkcja(char * ptr) {...} i przekazywac jej adresy do roznych obszarow

(Wyjatkiem byl tu Keil, ale to bylo obciazone gorsza wydajnoscia).

Atlantisie - przeczytaj jakas ksiazke o 8051, albo go wyrzuc, szkoda zycia.

J.

Reply to
J.F.

-- Wiadomość oryginalna (wysłana 21.03.2017 11:16) --

Ale można! SDCC tworzy trzybajtowy wskaźnik, w pierwszym bajcie jest informacja, na jaki obszar pamięci wskazują pozostałe dwa bajty. Chyba tak samo, jak w Keil.

Oczywiście wydajniej będzie kwalifikować jawnie wskaźnik.

Pozdrowienia, MKi

Reply to
MKi

bezpośrednio,

Tak, wystarczy deklaracja const. Dodatkowo sdcc nie odróżnia wskaźników do flash/ram (z pkt. widzenia programisty oczywiście). Można je zamiennie stosować np. jako argumenty standardowych funkcji z libc. Niestety na tym chyba się kończą zalety sdcc...

Reply to
Marek

no pięknie rodzi się na grupie nowa nauka, co za maniane zrobi/ł kompilator...

Reply to
invalid unparseable

W dniu 2017-03-21 o 11:52, Marek pisze:

Ok, wielkie dzięki. :) Jeszcze jedno pytanie. Ktoś z was ma pomysł jak debugować niedziałającego UART-a w at89c2051?

Software'owy UART działa ok. Hardware'owego nie mogę odpalić, chociaż mogłoby się to wydawać banalnym zadaniem.

Procedura inicjująca wygląda następująco:

void uart_init (void) { TMOD &= ~0xF0; TMOD |= 0x20; SCON = 0x50; TH1 = 0xFD; TL1 = 0xFD; ES = 1; TR1 = 1; }

a w pętli głównej umieściłem następujący zestaw instrukcji:

if (RI) { RI = 0; c = SBUF; SBUF = c; }

Niestety, znaki wysyłane na przejściówkę USB-UART nie wracają do komputera. Analizator stanów logicznych też nie widzi żadnego ruchu na linii TX MCU.

Kierunki linii chyba też są ustawione właściwie we wstępnej konfiguracji (P3 = 0x01;).

Może coś jeszcze przeoczyłem?

Reply to
Atlantis

Użytkownik "Atlantis" napisał:

To nie kierunki, tylko ustawiłeś 0 do wszystkich linii portu P3, oprócz RXD to jak ma działać?

Alojzy

Reply to
invalid unparseable

W dniu 2017-03-22 o 18:39, Alojzy pisze:

Chwilę, a to przypadkiem nie jest tak. że jeśli ustawię 0, to tam jest dosłownie 0 - pin jest na poziomie masy i nawet jeśli podłączyłbym zewnętrznego pull-upa, to i tak po stronie pinu będzie on na potencjale masy i próba odczytania czegokolwiek da zawsze 0. Natomiast jeśli wpiszę 1, to włącza się słaby, wewnętrzny pull-up. Przy odczycie normalnie będzie zwracało jedynkę - chyba, że coś z zewnątrz zewrze pin z masą - wtedy będzie zero.

Dokładnie tak, jak w przypadku PCF8574.

Czyżbym nie miał racji?

Reply to
Atlantis

Dnia Wed, 22 Mar 2017 21:55:45 +0100, Atlantis napisał(a):

Jesli chodzi o piny dzielone, to nie. Tzn opis powyzszy jest prawdziwy, ale taka np TxD/P3.1: Jesli do P3.1 wpiszesz 0, to pin bedzie zawsze w stanie 0. Jesli wpiszesz 1, to UART bedzie sterowal pinem.

Gdzies tam w srodku jest bramka OR, laczaca rejestr portu i funkcje specjalna.

J.

Reply to
J.F.

Bardzo bym się zdziwił. To, co jest w const char[], musi być w RAM-ie nie bez powodu - te adresy muszą być dostępne dla funkcji, które operują na RAM-ie. Przykładowo jak wywołasz memcpy(), to ona zakłada, że dostała adres do RAM-u i używa instrukcji czytających z RAM-u.

8051, tak jak AVR, jest architekturą Harvardzką, co znaczy, że pamięć programu i operacyjna to dwie osobne pamięci. To, że te architektury mają instrukcje umożliwiające czytanie pamięci programu, to tzw. zmodyfikowana architektura Harvardzka.

Dla AVR to odpowiednio instrukcje LD i LPM, dla 8051 - MOV i MOVC. Funkcje operujące na pamięci muszą wiedzieć, z których instrukcji korzystać dla danego adresu.

Co do reszty - nie pomogę, dla 8051 pisałem coś ostatnio 15 lat temu :(

Reply to
Adam Wysocki

Czyli "bardzo bym się zdziwił" zmieniam na "bardzo się zdziwiłem" ;)

Reply to
Adam Wysocki

Doczytałem resztę wątku, odszczekuję :) Nie wiedziałem że SDCC robi takie sztuczki.

Reply to
Adam Wysocki

Już coraz więcej kompilatorów wychodzi z tej paranoi odróżniania wskaźników ram/flash. XC8 też już odpuszcza ten problem programiscie i sam wew. rozwiązuje ten problem.

Reply to
Marek

Jak dla mnie to dobrze - po to są języki wysokopoziomowe, żeby ukrywać szczegóły architektury platformy. Z drugiej strony nie chciałbym, żeby było to obowiązkowe, bo czasem zależy nam jednak na tym, żeby kod był tak szybki, jak to możliwe...

Reply to
Adam Wysocki

Ten problem rozwiazuje, a rodzi nowe.

Potem sie okazuje program jest wolny, oraz wielki, w pamieci sie nie miesci.

Jesli chodzi o 8051, to najlepiej po prostu o nim zapomniec. Byl, teraz jest przestarzaly, do C sie nie nadaje :-)

J.

Reply to
J.F.

W dniu 2017-03-24 o 18:14, J.F. pisze:

Nie przesadzajmy. ;) Attiny posiadające mniej zasobów programuje się w C.

Kluczową kwestią są zastosowania. Kiedyś lepszych mikrokontrolerów zwyczajnie nie było. Jeśli nie chciało się podpinać zewnętrznych pamięci RAM i EPROM przy większych projektach, trzeba było wszystko ręcznie optymalizować tak bardzo, jak to tylko możliwe.

Gdybym potrzebował więcej zasobów, wykorzystałbym nowocześniejszy mikrokontroler. Ponieważ jednak już zetknąłem się z tą platformą (napisanie nowego wsadu do instniejącego urządzenia) i mam prosty programator, a w szufladzie poniewiera się parę sztuk starych AT89C51 i AT89C2051 pewnie wykorzystam je w jakichś prostszych projektach. Właśnie takich, które wymagałyby Attiny.

Nawet konieczność wyjmowania MCU z podstawki celem jego zaprogramowania nie jest jakoś szczególne uciążliwa przy tak małych ilościach kodu.

Reply to
Atlantis

J.F. chodziło zapewne o to, że takie skamieniałości nie mają architektury przyjaznej C. Były projektowane do programowania w asamblerze. Robienie kompilatora w C do takich archtektur jest trochę na siłę, bo efekt kompilacji często nie będzie zoptymalizowany.

Reply to
Marek

W dniu 2017-03-25 o 10:17, Marek pisze:

Nie zmienia to faktu, że przy małych projektach ten argument nie ma wielkiego znaczenia. Do dużych użyję zupełnie innego MCU, tudzież jakiegoś Arduino albo nawet Raspberry Pi.

A co do optymalizacji, to darmowe wersje kompilatorów XC8/XC32 też mają ograniczone możliwości w zakresie generowania najbardziej optymalnego kodu. ;)

Reply to
Atlantis

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.