Jak umístit proměnnou na absolutní adresu v AVR+GCC ?

Nějak mi to nejde, poradí někdo jak na to ? Mám třeba pole 32 bajtů a ty bych chtěl mít v RAM třeba od adresy 0x0050. Potom bych chtěl mít třeba proměnou dvoubajtovou a tu bych chtěl mít třeba v RAM na adrese 0x0040. Předpokládám, že mám procesor, který má dostatečnou kapacitu RAM.
pyrin

Jaký by to mělo smysl?

Můžeš to zkusit nadeklarovat jako periférii.

Smysl to má v tom, že pokud kouknu třeba sériovou linkou do oblasti, kde předpokládám, že ta proměnná je, tak tam taky je a nemusím jí hledat. A mám jí pořád na stejném místě.
pyrin

K tomu nevidím žádný důvod. Jesli ti jde o ladění, tak to se dá zařídit i bez toho a na všechno ostatní(určitě včetně DMA na xmeze) stačej pointery nebo globální proměnná.

Mno pokud v tom nevidíš důvod, tak já ano. Protože pokud mám stovky různých aplikací a v nich mám určité proměnné, které jsou pro všechny aplikace stejné a potom proměnné, které jsou svázány pouze s danou aplikací, tak proč bych měl hledat ty stejné proměnné na různých místech ? Hlavně jde o to, že mám pro sériovou linku aplikaci na PC a pokud tedy obsluha chce změnit třeba žádanou teplotu, tak jak to té aplikaci v procesoru řeknu ? Dnes mám v aplikaci, že žádaná hodnota je na určité adrese a fidli basta. Může k tomu přjít kdejakej Pepík nebo Jarin a klepne na talčítko a má hodnotu. Pokud budu mít proměnnou v každé aplikaci jinde, tak toho jednoduše nedosáhnu. Navíc mám třeba pole, kde mám nasázené teploty a to se periodicky vyčítá pro kalibraci. Kalibrační konstanty se zapisují též na absolutní adresu ale do EEPROM. Potom bych vždy musel jít do překladače, podívat se kam mi to šoupne a adresu zapsat do PC a následně překalibrovat. Nebo naopak, potřebuji se podívat, proč mi to špatně měří a tak kouknu na kalibrační konstanty, protože jsou pořád na svém stejném místě a to ve všech aplikacích, tak nemusím jít do linkru a hledat, kde jsou. Tak proto. pyrin

Taky to moc nechapu…
Z PC posilas do uC po seriovem portu retezec “SET SP_TEMP1 22.5” a uC si to prechrousta jak chce. Potom posles retezec “GET TEMP1” a uC ti to posle. Nevidim nikde problem s vycitanim nejake adresu. Pokud to mas dobre udelane funguje to pro jakykoliv uC, staci jenom prelozit program pro prislusny porcesor.

Podle me na to nejdes nejstastnejsim zpusobem. Drbani levou rukou za pravych uchem :slight_smile: Pokud komunikujes softwarem z PC pres seriak, tak je lepsi mit nejaky komunikacni protokol. PC nejdriv zasle pozadavek co chce a mcu mu vrati vysledek at lezi kdekoli. PC nemusi o umisteni promenne nic vedet, dokonce ani jestli lezi v ram nebo eeprom. Napr. prvni byte z pc znamena zadost o kalibracni hodnotu a druhy specifikuje kterou (jeji poradove cislo, nazev a pod.). Nebo textove retezce viz. predchozi prispevek. Pak uz si mcu vytahne spravnou hodnotu a posle ji zpet. Pak tenhle protokol musi umet mcu i pc samozrejme.

Kdysi dávno jsem se o to samé také pokoušel,
ale taktéž bezvýsledně.
GCC prostě tyto “triky” nepodporuje.

OPRAVA!!!

Podařilo, ale stejně mi to bylo houby platné.
Můžeš definovat kam umístíš celý blok (funkci),
nikoliv samostatnou proměnnou.

Postup je jednoduchý.
Někam za globální proměnné musíš deklarovat funkci následujícím způsobem:

void MyBoot(void) BOOTLOADER_SECTION;

BOOTLOADER_SECTION pochází z knihovny boot.h,
takže si to můžeš najít.

pyrin: Vymýšlíš s prominutím nesmysly. Ty z PC posíláš adresu do RAM a hodnotu pro zapsání??? Tobě asi moc o funkčnost programu nejde, jinak si to nedovedu vysvětlit. PC se v žádném případě nemá co vrtat v prostředcích mcu. To je takový problém z pc poslat příkaz “nastav teplotu” a v mcu, když ten příkaz přijmeš, nastavit hodnotu proměnné “teplota”? Konstrukce, kterou popisuješ, je velmi nevhodná a může být pro HW(pokud né pro životy lidí) velmi nebezpečná. Právě z toho důvodu, že “přijde pepík…” povrtá ti něco v ram a v lepším případě hw pouze skolabuje. Navíc pokud jsi vymyslel řešení tohoto typu, tak nečekám ani žádné kvalitní zabezpečení přenosu proti chybám.

Pokud trváš na určité formě adresace, tak si vytvoř pole a posílej si pouze indexy do něho, né adresy do RAM.

Co se týká přístupu do eeprom, je to úplně stejné. MCU ví, kde data má. PCéčku do toho ale vůbec nic není. Prostě pošli balík dat a mcu si s nima musí poradit sám. Tedy přesněji programátor musí zařídit aby si poradil.

Přímý přístup do paměti má jediné ospravedlnění pokud vím. Tím je ladění programu.

Nemá k tomu důvod stejně tak jako jiné překladače.

Ani to ladenie nieje dovod. Ak treba tak potom JTAG alebo nieco podobne.
Kto (programator) ma ako strazit aby KAZDA premenna bola na konkretnej adrese?

Na prenos je vhodny napriklad protokol MODBUS.
Alebo hociaky iny, kde na zaciatku bude 1B prikaz (RD/WR) potom 2B subadresa (index do pola udajov) a 1B pocet prenasanych bajtov. Na konci spravy urcite daj aspon jednouchu kontrolnu sumu z dvoch bajtov. Niektore indexy mozu byt v RAM, ine indexy v EEPROM a niektore ine zase vo Flash, PC to nemusi vobec rozlisovat. Alebo si to rozlisuj v prvom bajte kde prenasas info ci RD alebo WR. Este tam je 7 bitov volnych.
Aj teraz predsa musis mcu povedat, z akej adresy a kolko bajtov sa ma posielat.
protokoly typu “POSLI_TEPLOTU1” Ti z celeho srdca neodporucam. Su velmi pomale, a text nenesie absolutne ziadnu pridanu hodnotu, akurat Ti komplikuje dekodovanie prijatej spravy velmi zlozitym parserovanim. Ak si spravis dalsie zariadenie musis v nom dorobit aj dalsiu cast parseru a dekodovanie dalsich vyziev k zapisu alebo k nacitaniu. Index do pola je jednoduchy a prakticky.

Subadresa je index do pola. Pole si pavidelne refresujes a tak vidis (napr. pole o velkosti 128B mozes do PC posielat castejsie ako 80x za sekundu 115200Bd, to uz zmeny hodnot pomaly ani ludske oko nezachyti), co sa Ti v systeme deje. Do pola si mozes kludne kopirovat na Tebou vybrane indexy aj obsah HW registrov.

No a este si mozes cisto do Flash ulozit tabulku kde prvy stlpec bude nazov premennej (napr. pevne 16B pole), v druhom bude jej index a v tretom bude atribut, ci PC moze na dany index aj zapisovat, alebo iba z neho citat. Potom Tvoj sw v PC moze automaticky zobrazit hodnoty a priradit im texty. Lebo ved ked Jozko/Janko/Ferko k programu sadne, odkial ma vediet na ktorom mieste je co?

Po spusteni SW sa tento najpr spyta na nazvy premennych a potom ich pravidelne nacitava a zobrazuje. K takemu sw do PC sa lahko spravi nejaky subor INI, v ktorom bude definovane, co sa ma na obrazovke kde zobrazovat.

No nic, vidím, že jedině můj názor na věc je špatný. Netvrdil jsem, že všechny proměnné chci absolutně adresované. Chci jen ty, které mně zajímají. A vím proč to chci, ne každý má dostatečné nástroje, které mu umožňují prakticky cokoliv. Nesnažím se na AVR udělat operační systém typu Win, u kterýho se člověk musí modlit, aby nemusel vědět, co kde hledat, protože mu nepomůže ani svěcená voda.
Jestliže mám stejný systém pracující na 51 KEIL bez problémů, protože každej Pepík nebo Jarin je schopen mačkat tlačítko ve vokně na PC a nezajímá ho, že to tlačítko vyprdí na sériovku žádost o konkrétní dato z konkrétní buňky, tak jen chci stejného principu dosáhnout na AVR, ale jak to vidím, s GCC to tak nepůjde.
Jinak nevidím důvod proč nemít nad aplikací absolutní kontrolu a vědět co se kam umístí. Potom si mohu dovolit do toho hrabat bez následků.
Naopak vidím dost neohrabané posílat sériovkou příkaz typu “posli mi teplotu”.
O protokolech a zabezpečení toho taky něco málo vím a modbus už jsem taky aplikoval. Nicméně právě proto, že modbus není z mého pohledu dost univerzální, tak jej nepoužívám.

Jinak nepotřebuju aby jakýkoliv uživatel věděl co na jaké adrese je, protože to má v konfiguračním souboru PC programu. A právě v tom je ta síla, že každý uživatel si může otevřít svojí aplikaci a načte se mu automaticky jeho konfiguračn soubor a zobrazí se mu právě jeho data. Konfigurák je obyčejný texťák, kde se říká o typu proměnné, adrese umístění, rozsahu, aditivní a multiplikativní konstantě a popis.
Nicméně můj názor se nemusí nutně shodovat s názory ostatních.
pyrin

Posílat jako příkaz řetězec by neohrabané bylo. Ovšem každý průměrně inteligentní bernardýn si jednotlivé příkazy nějakým způsobem označí a posílá jako identifikaci příkazu třeba jen 1 byte nebo i jen pár bitů což zajisté víš/umíš.

Když spustíš na PC program, také tě zajímá od které adresy v RAM se nachází? (Zajímat tě to může, ale k ničemu to nepotřebuješ). Když stahuješ soubor z netu, taky se server zajímá o číslo sekoru, na kterém bude soubor uložen nebo se pc zajímá o sektor na serveru?
V žádném případě. Je to totiž problém každého zařízení a jinému do toho nic není.
Jediné co potřebují komunikující stroje znát je formát dat.
Ve tvém případě je to úplně stejné.

Ale abysme vypotili alespoň něco konstruktivního když tě nepřesvědčíme o nevhodnosti tvého přístupu (nebo např. nemožnosti ho změnit z důvodu nutnosti změny pc sw).
S tvým požadavkem ti neporadím, ale můžeš tedy ty adresy použít pro identifikaci proměnné bez ohledu na to, kde se skutečně nachází.
Pokud mají všechny stejnou bitovou šířku, stačí pole a adresy po odečtení offsetu používat jako indexy.
Jesli jsou různě velké, naskládat proměnné do struktury.
Vytvořit pointer a do něho vložit adresu struktury. Potom už stejně jako u pole přičítat adresy (po odečtení offsetu) k pointeru a pracovat již s ram.
Offset: pokud jsou na x51 data např. od adresy 0x50, tak offset bude tato první adresa.

To nikto netvrdi :slight_smile:
Iba sa Ti snazime vysvetlit, ze to co potrebujes je jednoducho dosiahnutelne standartnymi postupmi. To, ze nejaky Jarin vie mackat tlacitko v PC a zaroven hovoris, ze nemusi vediet kde co je, nejako som nepochopil vyhodu absolutneho adresovania voci indexovanemu. Iba ze by bol este nejaky iny zatial utajeny dovod.

Ak uz predsa len chces vediet nastavit adresu premennej skus sa pohrat s “Project options” → “Memory settings”

Volakedy som nieco take ako Ty chces skusal a tadialto sa to nejako dalo. Ale bolo to davno a nastastie som skoro pochopil, ze tadialto cesta nie je to prave orechove. Ale asi si si na to zvykol a chyba Ti to :slight_smile:
Treba sa ale este prehrabat cez nejake headre a dalsie info o GCC. GCC Ti vie inak okrem ineho poskytnut adresu konkretneho miesta v programe pomocou ukazatela na adresu &&navestie co s vyhodou vyuzivam.

Na druhej strane sa skus inspirovat, ako su zadefinovane adresy HW registrov. Tie su na pevnych dopredu danych adresach, tak to nejako okopci a zmen si pripadne hodnoty adries.

napriklad:

#define PCMSK2	_SFR_MEM8(0x6D)

bude asi malo veci, ktore by GCC nevedelo, ale ako vidis tebou vyzadovany postup sa mnohym javi ako nie vhodny.

Bohužel nevím, jak tvůj protokol vypadá. Zda obsahuje v hlavičce tu absolutní adresu a poždovaný počet byte, nebo zda se na žádost přečtou všechna důležitá data umístná na abs. adrese a PC si znich vybere jen to, co potřebuje. Nebo je to jinak?

Umísťovat proměnné na abs. adresu lze dobře v ASM (direktiva ORG), ale má to jednu velkou nevýhodu. Při rozširování počtu proměnných se následující posunou na vyšší adresy a přestane to fungovat. Tomu lze předejít jedině vkládáním rezerv mezi stávající proměnné. Pokud rezervy dojdou, situace je neřešitelná.
V céčku můžeš definovat strukturu obsahují jen ty proměnné, které máš na těch abs. adresách. Překladač si strukturu umístí na nějakou adresu, kterou snadno zjistíš. Pro zjištení se používá znak & před jménem proměnné.
V protokolu použiješ logické adresy, nikoli fyzické a budeš se na to dívat, jakoby ta struktura byla vždy umístěna na 0 adrese. Přepočet logické adresy na fyzickou se provede prachsprostým součtem logické + adresa struktury. Takže se komunikační algoritmus zkoplikuje pouze o tento součet.

A ještě něco k tomu “dovolit do toho hrabat bez následků”. Při přímém přístupu do paměti může dojít k poškození dat, nebo k chybnému čtení.
Dochází k tomu tehdy, když 2 vlákna (např. hl. program a přerušení) nesynchronně přistupují k téže vícebajtové proměnné. Např. v okamžiku čtení teploty UARTem, může dojít k obměně dat procedurou volanou z hlavní smyčky. Přečtená data budou nesmyslná, neboť 1. byte pochází ze staršího měření zatímco 2. už z novějšího.

Přístup k jednotlivým datům by měl být koordinován nějakou procedurou, která tomu zabrání a zkontroluje také rozsah (např. kalibrační konstanty). Je dobré pamatovat na to, že se programy budou rozšiřovat a počet proměnných se zvýší. Absolutní adresy jsou proto příliš rigidní. Mimochodem ani SFR není u každého AVR stejné a nikomu to nevadí.

Nenapadá mne žádný důvod proč by měla být proměnná umístěná na pevné adrese.
Když chci přečíst nebo zapsat hodnotu proměnné tak je jednodušší použít její jméno než umisťovat ji na určitou adresu a z té pak číst.
Jméno proměnné přece obsahuje její adresu.

Není třeba je hledat.
Stačí aby stejné proměnné měly stejné jméno ve všech aplikacích.
Pod tímto jménem je snadno najdu aniž bych se zajímal na jaké adrese leží.

Pro pořádek dodám, že i gcc umožňuje umístit proměnnou na pevnou adresu.

Takto vytvoříme vlastní sekci “mydata” na fixní adrese např 0x106 v RAM:
Do linker options přidáme řádek

-Wl,--section-start=.mydata=0x800106

(Ofset 0x800000 značí paměť dat)

A takto deklarujeme proměnnou v této sekci

uint16_t  prom1  __attribute__ ((section (".mydata")));

Ale pokud v této sekci umístíme více proměnných, pak ještě není zaručeno, že překladač u nich zachová stejné pořadí jako v deklaraci.
Je třeba buď pro každou proměnnou vytvořit zvláštní sekci,
nebo všechny proměnné umístit do struktury.

alebo do pola :slight_smile:, efekt je ten isty a odvolavat sa na indexy toho pola. Takze sme tam kde na zaciatku. Najdenie premennej ma predsa na starosti interpreter protokolu na strane MCU a ten moze vediet (napr. minimalne v case prekladu aplikacie) kde sa ktora adresa nachadza. Inak pyrin uvadza stovky premennych, ktore maju byt na konstatntom mieste…

ale aby sme tolko neoponovali, chcem poziadat pyrina, aby objasnil dovod, respektive sw konstrukciu komunikacie ked na jeho aplikacie modbus nie je dost univerzalny. Rad by som sa poucil, mozno sa na problem nedivam dostatocne komplexne.

Taky jsem před nějakým časem řešil jak umístit něco na konkrétní adresu. Někomu to možná může připadat nesmyslné a možná se budete smát i tomu mému důvodu.
Chtěl jsem napsat univerzální bootloader pro své aplikace s tím, že by byla součástí bootloaderu na konci flash informace o verzi bootloaderu, typ čipu atd. FW by zase obsahoval informace o verzi programu a název aplikace. V EEPROM měl být kontrolní součet a možná nějaké další doplňkové informace. Jak bootloader, tak FW by používaly stejný komunikační protokol, jen pro aktualizaci software měly být zvláštní funkce, které by částečně fungovaly i v software.
Hlavní myšlenka je mít možnost poznat, že nahrávám něco někam kam to nepatří, případně to zakázat, a taky mít možnost připojit několik zařízení na jednu sběrnici s možností kdykoliv přehrát FW v libovolném z nich. Jak bootloader, tak FW by vracely informace o aktuálním stavu zařízení, co tam je zrovna nahrané, jaká je verze software nebo bootloaderu. Libovolné zařízení by bylo možné restartovat, uvést do bootloaderu a zase zpátky. Bootloder měl při startu spočítat kontrolní součet paměti Flash a pouze pokud je vše v pořádku spustit zbytek. Částečně to mám realizované, jen mám kvůli jednoduchosti většinu informací v EEPROM, kde si snadno zajistím pevnou počáteční adresu.
Bootloader psaný v C se mi začal nafukovat víc než jsem si přál a to mě prozatím odradilo od dokončení této časti. FW s podporou většiny věcí mám nahraný v několika procesorech a zatím využívám jiný bootloader, který je použitelný jen pro jedno zařízení spojené s PC.

Mno myslím si, že z hlediska bezpečnosti je jedno jestli zapíšu například důležitou kalibrační konstantu způsobem že pomocí interpretu příkazů pošlu špatnou hodnotu na správné místo a nebo že na správně definovanou proměnnou s absolutní adresou. Pokud bude hodnota kalibrační konstanty špatná, tak je to šumafuk.
Navíc mi připadá můj způsob jednodušší, protože si proměnné zařadím za sebou podle potřeby třeba po 16bajtech a potom jednou komunikací vyčtu všech 16 bajtů. Pokud to bude 8 dvoubajtových proměnných, tak mne čeká 8 komunikací. Netvrdím, že to je ztráta času, ale pro mně méně pohodlné. Možná mnou používaný protokol není až tak dobrý, jak si myslím, ale zabezpečení má dostačující. Stručně popíšu: Každý paket začíná a končí speciálním znakem. Pokud je tento někde v paketu, je překódován. Dále tam mám adresu master, slave, job - neboli co se bude dít . číst, zapisovat a s jakou oblastí se bude pracovat - Int.EEPROM, Ext.EEPROM, IntRAM, ExtRAM, RTC, atd., dá se rozšiřovat v rámci konfigurace 1 bajtu. Pak tam je adresa Lo, Hi a page - page je po 64k. Pak je tam pocet dat která chci přenést, vlastní data a 16bit CRC. Délka dat je do 128bajtů respektive 256. Program na PC byl původně koncipován servisně, nicméně dá se do něj udělat i vizualizace. Výhodou je, že pomocí textových souborů nakonfiguruju parametry, které může uživatel manipulovat v rámci daných mezí. Nicméně pokud si uživatel vzpomene, že by chtěl jiný parametr dostat do vizualizace, tak mu prostě pošlu textový soubor a on si ho akorát nakopíruje na ono místo. Totéž platí třeba o grafech. Stáhnu data z bafru a uživatel zjistí, že ho nezajímá rozsah -50…+150st.C, protože takové teploty asi nedosáhne, ale stačí mu od -30 do +30. Pak se mu pomocí texťáku nakonfiguruje do PC jiné měřítko, pošle se emilem. Takže když vím, kde co mám uloženo, tak mohu vytvořit textový konfigurační soubor na manipulaci s určitým parametrem a nemusím kvůli tomu jezdit až na instalaci. Předpokládám, že pokud tam proměnnou mám a neměl bych pro ní udělán v interpretu příkazů příslušnou obsluhu, tak bych musel nejdříve upravit interpret, nahrát aplikaci a pak mohu co potřebuju. Jenže dnes to udělám na 1 místě a za týden si vzpomene někdo jiný, že to chce taky a je tu nová cesta s přepálením firmware. Mým způsobem je to jen 1 konfigurační soubor. Tak to jsou moje veškeré důvody proč obhajuju umístění na absolutní adresu. pyrin