Fwd: STM32F103 UART DMA

Petr Labaj labaj na volny.cz
Úterý Prosinec 26 22:26:54 CET 2023


Tak v tom případě i já pošlu odpověď, kterou jsem Vám posílal soukromě, 
do konference:

Hmmm.
A díval jste se prosím na to, čeho se Vámi vysmívaná "rada nad zlato" 
vlastně týkala?
Psal jsem o prvním zápisu do nějakého registru, kdy obecně nemusím 
vědět, jaký je předchozí stav daného registru.
Takže pokud tam zapíšu ORem, tak tam můžou zůstat nahozené nějaké bity, 
které nechci, ale byly tam v jedničce už dřív.

V tomto případě přece naplatí, že by se mohl ztratit nějaký zápis kvůli 
asynchronnosti přístupu na danou periferii.
Jedná se o _první_ zápis na tuto periferii.
Všechny případné další zápisy už samozřejmě musí být ORem, protože jinak 
by zmizela předchozí konfigurace.

PL

*****************

Dne 26.12.2023 v 22:06 František Burian napsal(a):
> Omlouvám se, asi jsem to neposlal do konference ale p. Labajovi, ale 
> mířilo to do konference.
>
>
>
>
> Zdravíčko,
>
>   Obvykle nepřispívám ale tady musím, protože zde je nastíněna "rada 
> nad zlato", která tomu, kdo se jí bude řídit způsobí mnoho bezesných 
> nocí.
>
>   Nezapomínejte, že ARM je architektura mnoha sběrnic, různých keší a 
> to, co napíšete do programu nikdy není to, co se provede. Zkuste si 
> udělat
> rychlý program, který bude pouze zapisovat do GPIO portu a nahazovat 
> všechny bity na 1 a shazovat všechny bity do 0, připojte osciloskop k 
> pinu
> a pozorujte, co uvidíte.
>
> Operace = je převedena do instrukce STRB která nezapisuje na paměťové 
> místo, ale do cache, která to posílá na pomalejší sběrnici. A pokud se
> sejdou dva STRB do stejné paměťové pozice, je předchozí zápis ztracen 
> a na pomalejší sběrnici se populuje později zapsaná hodnota. GPIO jsou na
> STMku za dvěma takovými cachemi, AHB, APB a dokážete si představit 
> jakýpak krásný náhodný děj se na GPIO povede vyrobit.
>
> Aby byly zápisy jednoznačně orderované, musí mezi nimi být LDRB který 
> počká na úplnou invalidaci všech keší po cestě před další instrukcí. 
> Když tedy
> převedete původní sekvenci (pseudokód)
>
> while (1) { PORTB = 0; PORTB=255;  }
>
> na
>
> while (1) { PORTB &=0; PORTB|=255; }
>
> dosáhnete výrazně pomalejšího programu, ale krásného obdélníku ikdyž z 
> logiky věci by ty programy měly dělat totéž. Ještě krásnější je, že
> druhý příklad se může přeložit na první kvůli optimalizacím překladače 
> když někdo při definici PORTB zapoměl na volatile u každého prvku.
>
> Toto samosemou platí pro každý přístup na jakoukoliv paměť která má po 
> cestě nějakou cache (tedy je na pomalejší sběrnici). Proto musí být
> všechny přístupy k řídícím registrům které musí být vždy sekvenční 
> (nejprv nastav tento bit, pak tento bit) buďto provedeny pomocí operátorů
> |= nebo &= nebo použít instrukci dmb, která ale čeká na všechny cache, 
> ne jen na tu, kterou chcete zapsat, takže ještě víc zpomalí.
>
> Registry konfigurace periferií jsou přesně ty, které mají v podmínkách 
> nejprv toto pak toto a když na tento postup nemyslíte, "ono to nějak 
> funguje"
> ale jednou za čas to selže a daná periferie se jeví jako zmrzlá 
> protože jste nastavili bity ve stejný okamžik, ne jeden po druhém.
>
> Cache mezi sběrnicemi má omeznou velokost, takže pokud za sebou 
> zapíšete dostatečný počet zápisů do stejné sběrnice, tak můžete zase ten
> první, protože se čeká na ostatní zápisy. Jak je cache dlouhá je 
> nedokumentovaná funkce a mění se to mezi výrobními dávkami 
> (odpozorováno 2-8
> zápisů u stejného čipu jen z jiných dávek, dokonce jsem nabyl dojmu že 
> se hloubka mění podle poměru frekvencí ale tam nemám ověřeno) takže
> nelze spoléhat na konkrétní velikost cache.
>
> Stejný problém je když takto přistoupíte na dvě po sobě jdoucí 
> paměťové místa, tak ty čipy s delší cachí zápis uvnitř keše převedou 
> na jeden přístup
> do paměti s delším slovem a na některých architekturách hard fault 
> jako vyšitý, když ale použijete RMW, hardfault zmizí. (Nevím jestli to 
> je aktuální,
> takto se chovaly staré čipy)
>
> Pokud se podíváte do implementace CMSIS, je tam vždy RMW operace s 
> registry, nikdy to není čistý zápis právě kvůli tomuto fenoménu.
>
> S tímto jsem si při psaní vlastních rychlých knihoven užil více než 
> dost. Probíralo se to i v intelektuálním klubu v Patronce, je dobré 
> číst backlogy
> nebo se účastnit :-)
>
> S pozdravem a přáním pěkných svátků
>
>   František Burian
>
>
> Dne 26. 12. 23 v 17:14 Petr Labaj napsal(a):
>> Můžu drobnou poznámku, která je ale obecnější a s daným problémem 
>> nesouvisí?
>>
>> Vy všude používáte "orování" parametrů, které zadáváte do řídících 
>> registrů.
>> Např.:
>> USART2->CR1 |= USART_CR1_TE | USART_CR1_RE;
>> nebo
>> DMA1_Channel6->CCR |= DMA_CCR_MINC | DMA_CCR_CIRC | DMA_CCR_TCIE;
>>
>> Ale používáte to i při prvním zápisu do daného registru.
>> Tedy jinými slovy spoléháte na to, že předtím tam byly samé nuly.
>> Což může být velice zrádné, když tu konstrukci použijete třeba i 
>> někdy později, kdy už v těch registrech něco je.
>>
>> Takže by podle mě měl první zápis vypadat takhle:
>> USART2->CR1 = USART_CR1_TE | USART_CR1_RE;
>> nebo
>> DMA1_Channel6->CCR = DMA_CCR_MINC | DMA_CCR_CIRC | DMA_CCR_TCIE;
>>
>> A orování použít až když tam už dodatečně něco přidáváte.
>>
>> PL



Další informace o konferenci Hw-list