MPLAB - prace s EEPROM
Jan Waclawek
konfera na efton.sk
Čtvrtek Leden 6 11:25:44 CET 2022
>Tak jak jsem to resil driv treba v uPascalu bylo, ze jsem mel
>nadefinovanou jednu strukturu jako promennou v RAM a z EEPROM jsem si od
>nejake pevne dane adresy nacital nejaky blok dat a pro dalsi sadu jsem
>si jen pocatecni adresu zvysil o offset dany velikosti te struktury v
>eeprom.
Presne toto iste mozes robit aj v tom C. Tu by sme mohli skoncit, ale...
> Pochopil jsem, ze kdyz chci umistit promennou do EEPROM pouziji klicove
> slovo EEMEM. Nicmene nejak nechapu jaky to ma smysl.
To nie je klucove slovo jazyka C, ale nejake jeho rozsirenie v konkretnej
implementacii, ktoru pouzivas. Neviem ktory prekladac pouzivas, ale v jeho
navode by mohol/mal byt nejaky naznak toho, co to rozsirenie presne
znamena.
Jazyk C - ako napokon vsetky existujuce vyssie programovacie jazyky -
nepredpoklada, ze by mohli existovat nejake ine formy pamati, nez jedna
uniformna suvisla RAM. Tak to napokon skutocne je u PDP-11, na ktorom
jazyk C vznikol, a tak je to aj na uplne vsetkych "velkych" pocitacoch
dodnes.
Jazyk ma zabudovany nejaky mechanizmus na to, aby pri definicii premennej
nejako tie premenne do tej pamate naukladal, a ked sa ta premenna pouzije,
tak vygeneruje instrukcie na citanie a zapis do tej pamate.
Lenze mikrokontrolery nie su obycajne pocitace a maju rozne druhy pamati -
RAM, ROM, FLASH, EEPROM, externe pripojene pamati - ktore su mapovane v
roznych pamatovych priestoroch a pristupuje sa k nim roznymi instrukciami
ci sustavami instrukcii. Niektore mcu (typicky 32-bitove) maju tendenciu
napchat vsetky interne pamate na uniformnu internu zbernicu, t.j. pamate
su v jednom adresnom priestore a obvykle sa daju aspon citat rovnakymi
instrukciami (dokonca niekde aj zapisovat, akurat ze ten zapis dlho trva a
pred nim treba urobit nejake odomknutie atd.). Este aj v tom pripade vsak
obvykle zostava problem vo forme nesuvisleho adresneho priestoru.
Mimochodom, situacia sa u mcu komplikuje este aj tym, ze aj do tej istej
pamate sa da pristupovat roznymi sposobmi; co toto presne znamena, doverne
poznaju pouzivatelia '51, ale aj trebars derivatov 6800 a vacsich
8-bitovych PICiek - tam vsade existuje relativne velka RAM, do ktorej sa
pristupuje pomerne pomalou metodou (napr. nepriamo), a pritom do casti tej
istej RAM sa da pristupovat aj rychlou metodou (priamo). Uzivatel moze
chciet. Dalsou, trocha podobnou komplikaciou su strankovane pamate. V
konecnom dosledku je teda lepsie nehovorit o adresnom priestore ale o
pamatovych triedach, pretoze k nejakej konkretnej adrese sa da pristupovat
roznymi sposobmi a uzivatel moze chciet ovplyvnit, ze ktory sposob sa
pouzije (napr. chce mat explicitnu metodu, ktorou ovplyvni alokovanie
nejakej premennej napriklad do "rychlejsie pristupovanej" pamati, a potom
moze chciet mat aj metodu, ktorou prekladacu "povie", ktory druh pristupu
sa ma pouzit).
Prekladace su obvykle nastavene tak, ze "nativne" umiestnuju/pouzivaju
premenne v RAM (ak je ich viac, obvykle sa da prepinacom pri preklade
ovplyvnit, do ktorej), tak ako v PDP11. Co so zvysnymi pamatovymi triedami?
Existuju dve moznosti - bud sa prenecha cely problem na programatora, ktory
si musi rucne rozvrhnut, kde je ktora neRAM premenna alokovana a potom pri
volani funkcii, ktore vedia tie pamate obsluhovat, pouzivat konstanty
(mozno vypocitane nejakou jednoduchou aritmetikou) pre adresy a dlzky;
alebo sa pre konkretny prekladac vytvori nejake rozsirenie jazyka, ktore
cast alebo vsetko z tohoto problemu riesia pomocou prekladaca. Treba si
uvedomit, ze sa jedna vlastne o tri skupiny problemov: 1. alokacia
premennych a metodika, ktorou su dane premenne inicializovane, 2. sposob
citania a zapisu danych premennych, 3. sposob, ktorym si prekladac interne
vedie, do ktoreho adresneho priestoru je premenna naalokovana.
Prekladace nemusia mat implementovanu kompletnu podporu v tomto duchu, a
obvykle ani nemaju. Zlozitost problemu rastie od 1 do 3, takze typicky je
implementovane len 1. Ciastocna ci plna implementacia 2. a 3. je
charakteristicky pritomna len u prekladacov, ktore nativne podporuju
(pomenovane) adresne priestory, napr. Keil C51 alebo SDCC (a asi aj ten
"omniscient" HiTech C pre PIC (dnes XC8? nepamatam sa) ale o tom viem malo
lebo nie som PICkar). Do urcitej miery su named address spaces
implementovane aj v avr-gcc, hoci asi vacsina uzivatelov (tvorena
arduinistami) o tom netusi (a v g++ to asi ani dobre alebo vobec
nefunguje). Toto je v skutocnosti velmi rozsiahla problematika na poctive
riesenie ktorej nie su ani ludia ani cas a ani peniaze.
Takze u vacsiny prekladacov je implementovane len 1., 2. je namiesto
nativneho pristupu (kde by uzivatel pouzival dane premenne uplne rovnako
ako premenne v RAM) nie je a je to odbyte implementaciou funkcii na
citanie/zapis (alebo, ako je to asi aj v tomto pripade EEPROM, je pristup
k danej pamati asymetricky, t.j. citanie je rovnake ako u normalnych
premennych kdezto zapis je prostrednictvom funkcii); a 3. by aj tak bolo
treba len v pripade plnej implementacie 2. takze na to sa da v tomto
pripade zabudnut.
1. sa da dosiahnut pomerne lahko za pouzitia linkera, t.j. casti
prekladaca, ktory ma na starosti prave alokaciu pamate a povkladanie
adries naalokovanych premennych vsade kam treba do vysledneho binaru
programu. Linker je typicky ovladany konfiguracnym suborom, ktory sa
nazyva linker script, a obvykle existuje nejaka metoda, ktorou sa v
zdrojovom texte oznaci nestandardne alokovana premenna (napr. klucove
slovo EEPROM, nech to znamena cokolvek), sucastou metody je potom interny
mechanizmus, ktorym sa toto oznacenie prenesie az do linkera, ktory tym
padom vie, ze takto oznacena premenna ma byt vlozena do nejakej konkretnej
oblasti ("section") pamate. Ze na akej adrese je dana oblast umiestnena a
ako je velka, pripadne aj nejake jej vlastnosti (napr. jej adresna
granularita, ak nie je 1, lebo su aj take pamate kde sa napriklad daju
zapisovat napriklad len cele N-bytove kusy naraz, a tak je treba potom
premenne do nej alokovat) je prave zadane linker scriptom, co umoznuje
urcitu pruznost pre uzivatela.
Tato sada vlastnosti sa vyuziva napokon aj tam, kde je k dispozicii
nesuvisla RAM, prip. RAM, ktora sice suvisla je, ale pozostava z viacerych
casti a existuju dovody na alokaciu do separatnych casti (napr. len cast
RAM je chranena hardwarovymi prostriedkami proti neziaducemu
zapisu/citaniu alebo proti chybe sposobenej ionizujucim ziarenim, alebo
cast RAM je intenzivne pouzivana nejakym rozhranim typu DMA ktore "brzdi"
procesor pristupujuci do tej istej RAM, alebo cast RAM je vyhradena pre
komunikaciu medzi procesormi vo viacjadrovom mcu, cast RAM je baterkou
zalohovana, cast RAM je fyzicky pomalsia alebo je za sustavou zbernic,
ktore pristup do nej spomaluju - vsetko toto je pomerne bezne u stredne
velkych 32-bitovych mcu) - v tomto pripade nie je problem s 2. a 3 a takto
naalokovane premenne sa pouzivaju uplne rovnako ako akekolvek ine premenne.
Dost charakteristicky sa 1. pouziva aj tam, kde je ROM/FLASH sucastou
jednotneho adresneho priestoru a cita sa rovnakou metodou ako RAM (a zapis
sa vobec neuvazuje alebo je to len velka zriedkavost). Pomerne bezne sa na
tento pristup ani nepouzivaju ziadne rozsirenia syntaxe jazyka, jednoducho
len kompilator pre vsetky premenne kvalifikovane ako const generuje
automaticky aj znacku pre linker, aby tuto premennu umiestnil v oblasti
ROM/FLASH (niekedy je
Rozdiel medzi implementaciou len 1. a "rucnou" alokaciou je (okrem toho, ze
je tym obvykle vyriesena inicializacia premennych - pri alokacii do
FLASH/EEPROM je inicializator jednoducho sucastou generovaneho binaru a
premenne sa pomerne prirodzene inicializuju sucasne s "napalovanim"
programu) v tom, ze na zadanie adresy/velkosti citanej/zapisovanej pamati
sa daju pouzit nativne prostriedky prekladaca - adresa sa da ziskat
pomocou operatora & (a naslednym pretypovanim vysledku zo smernika na cele
cislo, ci uz uzivatelom pred volanim, alebo samotnou volanou funkciou -
obe tieto operacie maju podla normy implementacne zavisly efekt, no ale
bavime sa tu o funkciach ktore prinalezia konkretnej implementacii, takze
to je v poriadku) a na velkost zapisovanej premennej sa da pouzit operator
sizeof (v oboch jeho formach, t.j. priamo aplikovany na premennu alebo
aplikovany na typ premennej). Vyhodou tiez je, ze linker automaticky
pouklada vsetky premenne alokovane do urcitej oblasti (a tie mozu byt v C
zdrojaku definovane na roznych miestach, v roznych zdrojovych .c suboroch)
pekne za seba, takze je zarucene, ze sa neprekryvaju. (Linker tiez vie
upozornit, ak by premenne "vytiekli" z danej oblasti, t.j. by ich bolo
privela). Na druhej strane, automaticke usporiadanie premennych je aj
nevyhodou, kedze sa tym ztazuje kompatibilita medzi roznymi verziami
programu (ktore by mohli chciet mat urcite premenne vzdy na tom istom
mieste). Technik, ktorymi sa docieli kompromis, je viacero, ale zavisia od
konkretneho prekladaca/linkera.
Do urcitej miery suvisiace: http://efton.sk/tmp/C_ch50.pdf
wek
----- Original Message ---------------
Subject: MPLAB - prace s EEPROM
From: Admin HWnews <hwnews na cncnet.info>
Date: Thu, 6 Jan 2022 08:39:02 +0100
To: HW-news <hw-list na list.hw.cz>
Zdravim,
snazim se zase nejak pokrocit s tim zatrolenym Cckem v MPLABu a narazil
jsem na dalsi problem..respektive netusim jak se to spravne resi.
Potrebuji ukladat nejake obsahle konfiguracni struktury - nekolik sad
techto struktur...moje predstava je, ze nadefinuji pole struktur. Jedna
cast bude ulozena normalne v kodu tedy ve flash pameti (to jsou data,
ktera jsou znama v dobe kompilace) a pak bych rad mel jeste druhou sadu,
ktera bude uzivatelsky definovatelna ...treba 10 polozek pole (podle
toho co se vejde do EEPROM). Potrebuji na zaklade pripojene periferie
najit v tech polich odpovidajici konfiguracni sadu (dle nejakeho
identifikatoru) a tu si nacist do promenne.
Pochopil jsem, ze kdyz chci umistit promennou do EEPROM pouziji klicove
slovo EEMEM. Nicmene nejak nechapu jaky to ma smysl.
Tak jak jsem to resil driv treba v uPascalu bylo, ze jsem mel
nadefinovanou jednu strukturu jako promennou v RAM a z EEPROM jsem si od
nejake pevne dane adresy nacital nejaky blok dat a pro dalsi sadu jsem
si jen pocatecni adresu zvysil o offset dany velikosti te struktury v
eeprom.
Tady ale netusim jaky vyznam ma definovat neco v EEPROM...stejne se s
tim neda primo pracovat...stejne budu muset pouzit neco takoveho:
eeprom_write_block(&DA485_par, &DA485_par_EE, sizeof(DA485_struct));
coz mi prijde v podstate uplne to same...jen teda netusim jak zajistim
to abych zapsal jen cast toho pole v EEPROM.
Budu moc vdecnej za nejake navedeni...ta filosofie tohodle jazyka mi
prijde proste silena. :-(
RV
_______________________________________________
HW-list mailing list - sponsored by www.HW.cz
Hw-list na list.hw.cz
http://list.hw.cz/mailman/listinfo/hw-list
Další informace o konferenci Hw-list