<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
Některé MCU jsou na cvičení s porty i optimalizované.<br>
<br>
Třeba LPC11U68, tam udělám programem v C na pinu přes 20 MHz, tedy
blízko CLK/2. Taky jsem toho hojně využíval. Displej v paralelním
módu, data i všechny řídící signály na jednom 32b portu, pak je
rychlost komunikace taková, že doba překreslení závisí výhradně na
sw co data generuje.<br>
<br>
Ale jsou i opačná překvápka: Potřeboval jsem na AM3358 nenáročný
přístup k SPI flash a byl jsem línej rozchozovat HW SPI. Zápis šel
dle očekávání, někde v řádu 100 Mbit, ale čtení jsem si napřed
myslel, že zatuhlo ... ne, jen bylo rychlé asi jako vytáčený
internet před 25 lety:-) Přitom CLK do CPU bylo 650 MHz.<br>
<br>
PH<br>
<br>
<div class="moz-cite-prefix">Dne 27.12.2023 v 18:58 Jaroslav Buchta
napsal(a):<br>
</div>
<blockquote type="cite"
cite="mid:ac27bc56-b467-4e1a-9abd-e33aec211e8d@hascomp.cz">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<div class="moz-cite-prefix">Mam spravny pocit, ze dokonceni vsech
zapisu by mela zajistit instrukce DSB? Nebo nejaka podobna z
tech cca 3, se mi furt pletou.</div>
<div class="moz-cite-prefix">Ale asi az u novejsich.</div>
<div class="moz-cite-prefix">Mam ale vyzkouseno, ze kdyz to melo
byt rychle (simulace SPI kdyz se netrefily piny...), nasazel
jsem za sebe instrukce zapisu do 32b registru S/R, kazda menila
hodiny , kazda druha data a chodilo to jak vino maximalni
rychlosti, kdyz jsem vyhazel DSB, tak rychleji ale stale dobre.
Sbernice mely stejnou frekvenci a byl to tusim M4.<br>
</div>
<div class="moz-cite-prefix">Tak se toho asi netreba uplne bat a
cekam, ze to je nejak interne poresene.<br>
</div>
<div class="moz-cite-prefix"><br>
</div>
<div class="moz-cite-prefix">Dne 27.12.2023 v 18:06 dresler
napsal(a):<br>
</div>
<blockquote type="cite"
cite="mid:20231227170623.28915223604@alik.hw.cz">
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8">
<div dir="auto">Bavíme-li se klasických STM32, zápisy se
neztrácejí. Podle typu architektury je tam 0-1 write buffer
mezi jádrem a hlavní sběrnicí, pak (AXI-)AHB-APB bridge. Zde
je zpoždění dané tím, že se data resynchronizují mezi různými
hodinami, kde platí nejdelší zpoždění (1+ratio) a zpoždění
vnější periferie. Není tedy potřeba psát opakovaně. </div>
<div dir="auto"><br>
</div>
<div dir="auto">Aby se zajistilo, že program pokračuje po
dokončení zápisu do registru, prostě ten registr přečtěte
zpět. </div>
<div dir="auto"><br>
</div>
<div dir="auto">Tomáš </div>
<div dir="auto"><br>
</div>
<div dir="auto"><br>
</div>
<div dir="auto"><br>
</div>
<div id="composer_signature" dir="auto">
<div style="font-size:12px;color:#575757" dir="auto">Odesláno
z mého zařízení Galaxy</div>
</div>
<div dir="auto"><br>
</div>
<div><br>
</div>
<div dir="auto" style="font-size:100%;color:#000000"
align="left">
<div>-------- Původní zpráva --------</div>
<div>Od: Petr Labaj <a class="moz-txt-link-rfc2396E"
href="mailto:labaj@volny.cz" moz-do-not-send="true"><labaj@volny.cz></a>
</div>
<div>Datum: 26.12.23 22:27 (GMT+01:00) </div>
<div>Komu: <a
class="moz-txt-link-abbreviated moz-txt-link-freetext"
href="mailto:hw-list@list.hw.cz" moz-do-not-send="true">hw-list@list.hw.cz</a>
</div>
<div>Předmět: Re: Fwd: STM32F103 UART DMA </div>
<div><br>
</div>
</div>
Tak v tom případě i já pošlu odpověď, kterou jsem Vám posílal
soukromě, <br>
do konference:<br>
<br>
Hmmm.<br>
A díval jste se prosím na to, čeho se Vámi vysmívaná "rada nad
zlato" <br>
vlastně týkala?<br>
Psal jsem o prvním zápisu do nějakého registru, kdy obecně
nemusím <br>
vědět, jaký je předchozí stav daného registru.<br>
Takže pokud tam zapíšu ORem, tak tam můžou zůstat nahozené
nějaké bity, <br>
které nechci, ale byly tam v jedničce už dřív.<br>
<br>
V tomto případě přece naplatí, že by se mohl ztratit nějaký
zápis kvůli <br>
asynchronnosti přístupu na danou periferii.<br>
Jedná se o _první_ zápis na tuto periferii.<br>
Všechny případné další zápisy už samozřejmě musí být ORem,
protože jinak <br>
by zmizela předchozí konfigurace.<br>
<br>
PL<br>
<br>
*****************<br>
<br>
Dne 26.12.2023 v 22:06 František Burian napsal(a):<br>
> Omlouvám se, asi jsem to neposlal do konference ale p.
Labajovi, ale <br>
> mířilo to do konference.<br>
><br>
><br>
><br>
><br>
> Zdravíčko,<br>
><br>
> Obvykle nepřispívám ale tady musím, protože zde je
nastíněna "rada <br>
> nad zlato", která tomu, kdo se jí bude řídit způsobí mnoho
bezesných <br>
> nocí.<br>
><br>
> Nezapomínejte, že ARM je architektura mnoha sběrnic,
různých keší a <br>
> to, co napíšete do programu nikdy není to, co se provede.
Zkuste si <br>
> udělat<br>
> rychlý program, který bude pouze zapisovat do GPIO portu a
nahazovat <br>
> všechny bity na 1 a shazovat všechny bity do 0, připojte
osciloskop k <br>
> pinu<br>
> a pozorujte, co uvidíte.<br>
><br>
> Operace = je převedena do instrukce STRB která nezapisuje
na paměťové <br>
> místo, ale do cache, která to posílá na pomalejší sběrnici.
A pokud se<br>
> sejdou dva STRB do stejné paměťové pozice, je předchozí
zápis ztracen <br>
> a na pomalejší sběrnici se populuje později zapsaná
hodnota. GPIO jsou na<br>
> STMku za dvěma takovými cachemi, AHB, APB a dokážete si
představit <br>
> jakýpak krásný náhodný děj se na GPIO povede vyrobit.<br>
><br>
> Aby byly zápisy jednoznačně orderované, musí mezi nimi být
LDRB který <br>
> počká na úplnou invalidaci všech keší po cestě před další
instrukcí. <br>
> Když tedy<br>
> převedete původní sekvenci (pseudokód)<br>
><br>
> while (1) { PORTB = 0; PORTB=255; }<br>
><br>
> na<br>
><br>
> while (1) { PORTB &=0; PORTB|=255; }<br>
><br>
> dosáhnete výrazně pomalejšího programu, ale krásného
obdélníku ikdyž z <br>
> logiky věci by ty programy měly dělat totéž. Ještě
krásnější je, že<br>
> druhý příklad se může přeložit na první kvůli optimalizacím
překladače <br>
> když někdo při definici PORTB zapoměl na volatile u každého
prvku.<br>
><br>
> Toto samosemou platí pro každý přístup na jakoukoliv paměť
která má po <br>
> cestě nějakou cache (tedy je na pomalejší sběrnici). Proto
musí být<br>
> všechny přístupy k řídícím registrům které musí být vždy
sekvenční <br>
> (nejprv nastav tento bit, pak tento bit) buďto provedeny
pomocí operátorů<br>
> |= nebo &= nebo použít instrukci dmb, která ale čeká na
všechny cache, <br>
> ne jen na tu, kterou chcete zapsat, takže ještě víc
zpomalí.<br>
><br>
> Registry konfigurace periferií jsou přesně ty, které mají v
podmínkách <br>
> nejprv toto pak toto a když na tento postup nemyslíte, "ono
to nějak <br>
> funguje"<br>
> ale jednou za čas to selže a daná periferie se jeví jako
zmrzlá <br>
> protože jste nastavili bity ve stejný okamžik, ne jeden po
druhém.<br>
><br>
> Cache mezi sběrnicemi má omeznou velokost, takže pokud za
sebou <br>
> zapíšete dostatečný počet zápisů do stejné sběrnice, tak
můžete zase ten<br>
> první, protože se čeká na ostatní zápisy. Jak je cache
dlouhá je <br>
> nedokumentovaná funkce a mění se to mezi výrobními dávkami
<br>
> (odpozorováno 2-8<br>
> zápisů u stejného čipu jen z jiných dávek, dokonce jsem
nabyl dojmu že <br>
> se hloubka mění podle poměru frekvencí ale tam nemám
ověřeno) takže<br>
> nelze spoléhat na konkrétní velikost cache.<br>
><br>
> Stejný problém je když takto přistoupíte na dvě po sobě
jdoucí <br>
> paměťové místa, tak ty čipy s delší cachí zápis uvnitř keše
převedou <br>
> na jeden přístup<br>
> do paměti s delším slovem a na některých architekturách
hard fault <br>
> jako vyšitý, když ale použijete RMW, hardfault zmizí.
(Nevím jestli to <br>
> je aktuální,<br>
> takto se chovaly staré čipy)<br>
><br>
> Pokud se podíváte do implementace CMSIS, je tam vždy RMW
operace s <br>
> registry, nikdy to není čistý zápis právě kvůli tomuto
fenoménu.<br>
><br>
> S tímto jsem si při psaní vlastních rychlých knihoven užil
více než <br>
> dost. Probíralo se to i v intelektuálním klubu v Patronce,
je dobré <br>
> číst backlogy<br>
> nebo se účastnit :-)<br>
><br>
> S pozdravem a přáním pěkných svátků<br>
><br>
> František Burian<br>
><br>
><br>
> Dne 26. 12. 23 v 17:14 Petr Labaj napsal(a):<br>
>> Můžu drobnou poznámku, která je ale obecnější a s daným
problémem <br>
>> nesouvisí?<br>
>><br>
>> Vy všude používáte "orování" parametrů, které zadáváte
do řídících <br>
>> registrů.<br>
>> Např.:<br>
>> USART2->CR1 |= USART_CR1_TE | USART_CR1_RE;<br>
>> nebo<br>
>> DMA1_Channel6->CCR |= DMA_CCR_MINC | DMA_CCR_CIRC |
DMA_CCR_TCIE;<br>
>><br>
>> Ale používáte to i při prvním zápisu do daného
registru.<br>
>> Tedy jinými slovy spoléháte na to, že předtím tam byly
samé nuly.<br>
>> Což může být velice zrádné, když tu konstrukci
použijete třeba i <br>
>> někdy později, kdy už v těch registrech něco je.<br>
>><br>
>> Takže by podle mě měl první zápis vypadat takhle:<br>
>> USART2->CR1 = USART_CR1_TE | USART_CR1_RE;<br>
>> nebo<br>
>> DMA1_Channel6->CCR = DMA_CCR_MINC | DMA_CCR_CIRC |
DMA_CCR_TCIE;<br>
>><br>
>> A orování použít až když tam už dodatečně něco
přidáváte.<br>
</blockquote>
</blockquote>
</body>
</html>