16F873, Výpočet rychlosti RS232

Zdravím všechny, potřebuji poradit s následujícím výpočtem.
PIC16F873 20MHz bude přijímat z PC přes RS232 data a ukládat je do eeprom 25LC256.

Popis funkce:
PIC čeká na přerušení od RS232, vyzvedne data z RCREG, vloží je do SSPBUF a zase čeká na přerušení.
V tomto režimu nic jiného nedělá.

Jakou rychlost přenosu RS232 mohu nastavit aby se přijatý byte stačil zapsat do eeprom než nastane další přerušení.

budou ty data se posílat nonstop zasebou nebo v nějakých intervalech a nebo nějak náhodně?

Data se budou posílat jednorázově najednou zasebou, odhad asi tak 3 - 5 tisíc bytů.
Na době, jakou se data budou přenášet nezáleží, jen to nechci zbytečně zdržovat pomalou rychlostí přenosu.

Pro zápis jednoho byte do eeprom je potřeba 32 taktů CLK
8 bitů příkaz, 16 bitů adresa a 8 bitů data

nejsem moc na výpočty ale asi bych to nějak vypočet takto.

spočet bych jak dlouho trvá zápis do eeprom. podle toho bych vybral rychlost kerá bude mít čas příjmu jednoho bajtu delší než je ten zápis do eeprom, a to protože, jestli si dobře pamatuju tak přerušení se vyvolá až po dokončení příjmu bajtu. takže postup programu by asi vypadal následovně, prijmu první bajt a pak se vyvolá přerušení, tím začnu zapisovat do eeprom a pri tom zápisu už se mi přijímá další bajt, než se přijme tak se dokončí zápis do eeprom a pak se dokončí příjem druhého bajtu, vyvolá se přerušení atak dokola.

nejsem profi programátor a toto je jen moje teoretická myšlenka. zapisovat do eeprom zároveň s příjmem na sériové lince sem ještě nedělal, takže doufám že sem vám nějak nezamotal hlavu :slight_smile:

Jo, přesně tak to funguje, už to mám spočítané. Díky.

né že bych byl nějak moc zvědavej :smiley: ale mohu se zeptat jak dlouho trvá zápis do eeprom a jakou jste nastavil rychlost? já jen tak informativně, kdybych se k tomuto případu také někdy dostal.

No, spíš mě šlo o to, jestli mohu použít rychlost 9600bd a nemusel ji snižovat.
Při této rychlosti je jeden datový bit dlouhý 104us, celý přenášený datový rámec má celkem 10 bitů. Čas potřebný pro přenesení bude tedy 10x104us = 1,04 ms.

Nastavením hodin v SPI modulu na Fosc / 4 bude jeden takt trvat 200ns (20MHz krystal).
Pro zápis 1 byte do eeprom je potřeba 32 taktů hodin, 32x200ns = 6,4us.

Já jen doufám že je to správně.

Tak eeprom 25LC256 se mě nepodařilo nikde sehnat, budu muset použít 24LC256, jsem zase na začátku a ještě k tomu ta komunikace, nemám ji rád.

Musí to být ten konkrétní typ? Paměti 25xxx jsou vcelku běžně k dostání. I microchip vyrábí spi eeprom.
Jinak také 93Cxx jsou sériové ne-i2c. Nevím jesli všechny, ale atmelácké AT93C56 umějí i 8bit režim.

Nemusí, ale i ta největší 93LC86 má pouze 16K a to je málo. Potřebuji minimálně 256K paměti. Proto jsem zvolil 25LC256, ale tu zase nikde nemají. Takže zbývá 24LC256, ty běžne jsou k dostání, ale…

Zkus TME, 25LC256-I/P DIP8 kusovka 49,66 Kč a 25LC256-I/SN SO8 kusovka 41,64 Kč

Moment… to chcete robit tak, ze prijmete jeden bajt z RS232, potom ho zapisete do EEPROM a potom cakate na zapis tohto jedneho bajtu?
To Vam spadne komunikacna rychlost na stovky baudov, pretoze zapis do EEPROM, ci je to SPI alebo IIC trva zhruba 5ms. To znamena, ze sa sekundu ich zapisete prinajlepsom 200, fakt len 200B/s. Teda mozete to tlacit rychlostou povedzme 150 baudov, pri kontinualnom, neustalom zapise.

Druha moznost je poziit prijimaci buffer. Data budete prijimat do bufferu, povedzme 32-bytoveho a ked sa ich nazbiera 32, tak ich zapisete do EEPROM - totiz kazda EEPROM umoznuje page write, teda za dobu jedneho zapisu (5ms) sa zapise viac bytov naraz. Podmienkou je, aby data boli v rozsahu jednej stranky, ale o tom viac v datasheete.
No a pokial by sa to robilo tak, ze sa data zbieraju do buffera, potom sa prenesu do EEPROM a spusti zapis, tak pocas zapisu sa moze cakat na znovunaplnenie buffera (prijimanie musi byt samozrejme riesene cez prerusenia).
Teda pocas zapisu (5ms) moze prijat cely buffer dat (32byte), to je 200 krat za sekundu 32 byte, cize 6400B/s. To je adekvatna rychlost na prenos 57600 baudov - na kontinualny zapis.
A mozete ten buffer zvacsovat az do velkosti 64bytov, lebo 25LC256 ma velkost stranky 64 bytov, cim sa rychlost posunie na hranicu 115200 baudov.

Realne mam s takymto buffrovanim skusenosti napriklad z nahravania zvuku do EEPROM. 128KB EEPROM je zapisana za 12s, co je rychlost asi 10kB/s.

Tam jsem koukal taky, na skladě 0.

jaromír:

Popsal jsi to hezky, jen mě vysvětli jak se dopočítám k tomu, že zápis bude trvat 5ms, mě vyšlo něco jiného, tak abych věděl kde mám chybu, viz o kousek nahoře.
Jinak ano, stránka u této paměti je 64B, dal by se použít zásobník 64B.

ww1.microchip.com/downloads/en/D … 21822F.pdf
strana 4, parameter 20, Twc - internal write cycle time, typicky 5ms. Teda musite zhodit CS dolu, naclockovat vsetky data, vyhodit CS hore - a potom zacina zapis do EEPROM. Ten trva max. 5ms, typicky o nieco menej. Stav zapisu sa kontroluje bitom WIP v STATUS registri (strana 10).
To nasypanie dat cez SPI trva zanedbatelne kratko oproti Twc (Vam to vyslo na 6,4us), takze som to zaokruhlil na 5ms, lebo rozdiel medzi 5ms a 5,0064ms je zanedbatelny.

No preto som pisal aj to, ze zapis typu
1, bajt z RS232
2, zapis do EEPROM
3, cakanie na zapis
4 chod na 1
by fungoval pre baudove rychlosti maximalne tak 200 baudov. Ak vyuzijete buffer, tak do tej EEPROMky mozete zapisovat rychlejsie (viac bajtov naraz), dajme tomu 57k6 alebo 115k2 - to vsetko preto, ze cas zapisu je rovnaky bez ohladu na to, ci zapisujete jeden bajt alebo celu stranku.

Samozrejme, bavime sa o tom, ze data sa kontinualne “sypu”.

Jaromire děkuji za vysvětlení. S tím 5ms vlastním zápisem jsem nepočítal a abych se přiznal, ani jsem o něm nevěděl. Doposud jsem paměti používal jen ke čtení textů pro znakový LCD, které jsem si tam předem nahrál přes programátor, takže zápisem do eeprom jsem se nikdy nezabýval, až teď.
Vytvořím tedy 64B zásobník a budu zapisovat po stránkách. Předpokládám že když použiji 24LC256, bude to něco podobného.
Ještě jednou díky za objasnění.

Ano, v tomto pripade ich vykon bude zhruba rovnaky, pretoze cas zapisu bude prevadajucim faktorom - nie rychlost zbernice, ktora u IIC moze byt mimochodom 400kHz. U SPI je to trosku jednoduchsie (vyssie rychlosti zbernice, radovo MHz), ale aj s IIC sa da v tejto aplikacii pekne pohrat.

Nemate za co, rad som pomohol.

Jaromíre mám ještě takovou prosbu o ujasnění jak by to mělo správně fungovat.

Dám příklad:
Po 232 budu přijímat data a zapisovat do zásobníku. Po naplnění celý zásobník přepíšu do eeprom, ale kam mám mezi tím zapisovat další přijatá data od 232, přenos nejde pozastavit.

Snad se Jaromír nebude zlobit, když ho předběhnu :slight_smile:
Zápis stránky je inicializován pomocí “STOP”. Mělo by tedy být možné data zapisovat průběžně bez generování stop a teprve na konci ho vytvořit.
K bufferu si tedy můžeš vytvořit 2 pointery: přijímací a vysílací. Jakmile ti paměť signalizuje ACK, můžeš do ní tlačit data. Tedy klidně hned po prvním přijatém bytu, jakmile ho zapíšeš, prostě počkáš na další (bez STOP na i2c). Až jich bude 64, vytvoříš STOP a paměť si začne data zapisovat. Mezi tím ti přicházejí nová data po uartu a přepisují buffer, ale to nevadí, protože data už máš v eeprom. Počkáš na dokončení zápisu v eeprom (při pokusu o zápis ti paměť odpoví ACK) a začneš ládovat nová data, která už máš v bufferu. Teď jen stačí pohlídat, aby vysílací pointer nepředběhl přijímací (uložil by sis stará data). Je zřejmé, že doba příjmu 64B po uartu nesmí být kratší, než doba přenosu dat do eeprom + doba interního zápisu eeprom (když si eeprom zapisuje data, neodpovídá ACK a nelze jí tedy mezi tím ládovat nová data do jejího interního bufferu).

Vyčerpávájící popis snad lze dodat že správné I2C jede sice jen o dvou drátech nicméně přijímač dat přidržuje linku na L po čas své práce tudíž lze časovat i výš než 400kHz ale nutno si linku kontrolovat - správný vysílač tak činí a proto lze linku nataktovat témněř na max rychlost přijímače ! Pokud ovšem je dodržen protokol I2C celý - to je nutno vždy skusit ale pic to hardwarově umí a většina pamnětí taky a pak není problém když data běží i 1MHz ovšem že na krátkou vzdalenost - co nejkratší

PS:omluvte pravopis dík

No, treba to robit tak, ze prijem dat bude prebiehat cez prerusenia. Popisem najjednoduchsi scenar:
V prerusovacom handleri nebude nic viac, nez len vyzdvihnutie znaku z RCREG a strcenie na koniec buffera (tam kam ukazuje nejaky ukazovatel) a kontrolovanie, ci je buffer plny - teda ci ma povedzme 64 znakov zapisanych - resp. ci je ukazovatel na konci bufferu.
Ak je plny, nastavi sa nejaky bit indikujuci, ze buffer je plny. V tejto chvili je cas prijmu jedneho RS232 znaku na to, aby sa data z bufferu odpratali a ukazovatel sa nastavil opat na nulu. Tym padom pri prijme dalsieho znaku sa interrupt handler nemusi o nic starat, len strci znak na koniec bufferu (medzicasom ukazuje opat na zaciatok bufferu) a inkrementuje ukazovatel. Otazka je, ako upratat tie data. Su v zasade dve moznosti:
1, Rychlo ich zapisat do EEPROM a vynulovat ukazovatel. Tu si treba spocitat, ci sa stiha v priebehu prijmu jedneho znaku (to je cas, kym treba odsunut data) vsetko nacvakat do EEPROM - myslim tym len cas samotheho presunu dat po zbernici. Cas zapisu po tomot presune, tych znamych 5ms nas mezaujima, lebo pocas tohoto casu sa bude plnut dalsi buffer a s EEPROM sa nebude manipulovat. Povedzme, ze IIC bezi na 400kHz, cas prenosu 9-tich bitov je asi 22us, presnos vsetkych dat (64bajtov dat + dva bajty adresa + jeden bajt adresa zariadenia = 67 bajtov) je 1522us, teda 1,5ms. Teda bude trvat asi 1,5ms kym sa data odpracu prec. To by zodpovedalo rychlosti 666 B/s. Teda nic moc. Situaciu som zjednodusil, lebo v skutocnosti nie je problem cakat aj viac, ako zodpoveda casu prijatia jedneho bajtu, pretoze zatialco je jednen znak prijaty a caka v RCREG, druhy sa moze prijmat do shitheregistra v UART-e, ale akonahle bude prijaty STOP bit, bude ho chciet UART presunut do RCREG - a tu nastane pretecenie (OERR bit). Takze, s vypnutymi preruseniami mozeme cakat dobu dvoch prijmov cez USART, co posuva situaciu na 1332 B/s.
2, Zakazat prerusenia, vynulovat ukazovatel, zacat zapisovat data do EEPROM, po zapise prveho bajtu povolit prerusenia a potom zapisat zvysok. Tu ide o to, ze ukazovatel sa vynuluje hned ako je to mozne, teda prijimanie je mozne hned, dalsi prijaty byte z USART-u sa zapise na poziciu 0. To je problem, lebo to moze prepisat data ktore sa prave idu zapisovat do EEPROM. Preto treba zakazat prerusenia, zacat zapisovat data, po presune prveho bajtu do EEPROM povolit prerusenia, aby prijimaci “stroj” mohol pokracovat ako ma. Buffer sa bude prepisovat prijimanymi datami este v dobe, ked bude prebiehat ich presun do EEPROM, ale kedze tento je rychlejsi ako prijimanie dat, moze byt ovplyvnani prinajhorsom prvy bajt - preto je treba pocas jeho presunu do EEPROM vypnut prerusenia.
Teda prerusenia budu zakazane po dobu presunu prych styroch bajtov (adresa zaraidenia, dv abajty adresy, jeden bajt dat), co znamena 4x22us pri 400kHz, to je 88us. Teda znaky z UART-u sa mozu sypat kazdych 88us, co je rychlost asi 11300 B/s, teda takmer 115k baud. Vzhladom k tomu, ze prijimac moze cakat aj o nieco dlhsie, ako som pisal hore, realne je ta prijimacia rychlost este vyssia. Pre SPI EEPROM to bude podstatne lepsie, odhadujem tak o jeden rad.

Inou moznostou je pouzitie viac ako jedneho bufferu - tu su opat dve moznosti:
1, Po prijati celeho bufferu v preruseni sa tento buffer prenesie do pomocneho buffera, z ktoreho sa potom v hlavnej slucke svojim tempom zapise do EEPROM. Kedze presun z buffera do buffera (dva buffery v RAM) je rychly, netreba ani zakazovat prerusenia - prenos sa da pri 20MHz PIC16 zvladnut za nejakych 25us (64 bajtov), co bohato na baudove rychlosti ~0,4Mbaud.
2, Ping-pong buffering: teda zapisuje sa do bufferu 1, po jeho zaplneni sa pokracuje v zapise do bufferu 2, v hlavnej slucke zacne zapis do EEPROM z buffera 1, po zaplneni buffera 2 sa zacne zapis do buffera 1 a zacne sa zapis do EEPROM z buffera 2 atd… Teda zapisuje sa vzdy do ineho buffera nez ten, z ktoreho sa cita a posuva do EEPROM a tento atribut sa prepina z jedneho buffera na druhy - preto ten ping-pong.

Resume:
Osobne by som Vam pre zaciatok radil pouzit metodu 1 s dvomi buffermi, je to asi najjednoduchsie na napisanie a odladenie, pre rychlost 9600 - ak si dobre spominam - je to uplne trivialne.
Odhadujem, ze ani nebude treba velkost buffera 64B, stacilo by aj 32B, takze sa Vam oba buffery zmestia do jednej banky RAM. Potom to bude pomerne jednoduche. V preruseni sa zapisuje do buffera a inkrementuje sa ukazovatel. Ked sa buffera zaplni, bude to indikovane nejakym flagom. Ten sa strazi v hlavnej slucke. Ked sa zisti, ze flag je nastaveny, zakazu sa prerusenia, buffer sa rychlo prekopiruje do pomocneho buffera, vynuluje sa ukazovatel, povolia sa prerusenia - aby prijimanie mohlo pokracovat dalej. Potom sa v hlavnej slucke zacne zapis do EEPROM (ten trva tych povedzme 6ms, ale pocas jeho priebehu sa prijem do bufferu deje cez prerusenia), po skonceni zapisu sa opat bude cakat na flag indikujuci zaplnenie hlavneho buffera…

Este dodatok - pre 32 B buffery (z horeuvedenych dovodv) a 6ms zapis vychadza priepustnost systemu asi na 5,3kB/s, teda asi 53000baudov. Ak zapocitame rezervy, tak do 38400 baudov je to uplne v pohode. Predtym som cital, ze chcete 9600 baudov, takze ste este vo velkej rezerve.