Sběrnice SPI - synchronizace prvního bitu

Zdravím. Mám dvě zařízení, disponující rozhraním SPI (nebo jeho odvozenině, prostě synchronní sériová sběrnice) a řeším následující problém:
Zařízení A, master, zařízení B, Slave.
Obě jsou to samostatné krabičky, které se propojují kabelem, u obou se zapíná napájení zvlášť, tedy ne současně. Dokonce kabel se může připojovat kdykoliv.
Jde mi o to, že při připojení kabelu, se do posuvného registru nasouká prostě několik “falešných” bitů, třeba díky tomu, že při zapojování konektoru se objeví nějaké zákmity na vstupu interface a podobně.
Tímpádem do posuvného registru je “naclockováno” několik nesmyslných bitů, a když potom zařízenní A do B se snaží poslat svých 8 bitů, mělo by dojít k jejich správnému usazení - posuvný registr se prostě posune 8x, tedy se vymění všech 8 pozic, na správné log. hodnoty.
Mikrokontrolér si ale přesto správnou hodnotu nepřečte:
Řekněme, že po přijetí 8mi bitů (naplnění bufferu) se vyvolá přerušení.
Při připojování zařízení se díky chybě do bufferu zapíšou tři bity (nesoucí nesmyslnou informaci), a při následném pokusu o poslání 8mice správných bitů dojde k získání nesmyslu, jelikož po přijetí 5ti )z 8mi) bitů se vyvolá zmíněné přerušení, a následně se do bufferu znovu umístí 3 zbývající bity.
Komunikace se tedy nachází mimo synchronizace, je posunutá o několik bitů.
Zajímalo by mě, jak je možné tuhle opravdu pitomou situaci vyřešit, existuje-li vůbec nějaké řešení.

Díky za návrhy možných řešení.

PS: Přidání dalšího komunikačního vodiče (kromě MOSI, MISO a SCK) nelze provést.

Nijak zvlášť jsem nad tím nepřemejšlel, ale například mít spi vypnutý. Každý uzel by na vysílacím pinu držel 0 a na přijímacím měl aktivní pull-up. Jakmile by na příjmu uviděli 0, lze aktivovat spi.

Tohle řešení úplně nechápu. Jak když je tam nula, je možné aktivovat SPI? jak se pak pozná, co je jen bordel ze zakmitávání a co jsou právě data?
Tohle podle mě nepůjde… nebo si nedovedu představit, jak by šlo.

Edit: Vlastně by to nešlo vůbec, protože na každém uzlu jsou diferenční budiče sběrnic, takže by musel pull-up být na driveru. Na procesoru by nepomohl, tam je stav stále definovaný tím, co leze z toho převodníku.

//PS: SPI honím 100 metrovým kabelem (diferenciálně, 3 kroucené páry)

Předpokládám, že už jsi někdy použil tlačítko. Taky je tam pull-up. Když není stisknuto, je tam “1”, když je stisknuto tak “0”. Tohle je úplně stejný. Při vypnutym spi jsou piny běžné IO. Jakmile se připojí protějšek, změní stav. Pokud bude změněný stav chvíli trvat, je stabilně připojen. Přestaneš s pinem zacházet jako s tlačítkem, a zapneš spi. To převezme kontrolu nad portem.
S budičem problém není, přednastav budič pro požadovanou úroveň.

Tak mi to nedalo a otevřel jsem datasheet(m8 )…
SS Pin Functionality(Slave Mode):

Stačí cuknout /SSkem a slejvovo spi se resetuje.
Do mastera se nic nenakmitá když nevysílá hodiny.

Mě furt někdo okřikuje, že se mám naučit číst.
říkám, že mám dráty jen tři (respektive tři kroucené páry), je to hodněné skrz RS485/422 budiče (75176 a 75179). Měnit nebo změnit to NELZE.
Master je implementovaný softwarově, slave je tiny26, SS vývod nemá, SPI nemá, má jen USI. (jednodušší SPI).
Do slejva se toho nakmitá dost. Ruční připojování konektorů se bez zašramocení signálů neobejde.

S tím pull-upem je to sice zajímavé řešení, ale… k MCU je připojený 75176/9. Klidovou výstupní úroveň definuje terminační odpor na vstupu. Takže klidový stav definovaný je. Řešení podobné zákmitům tlačítka ale značně kulhá v tom, že spoléhá že četnost dat je menší než ty zákmity. Protože pokud bude master (již připojený ke kabelu) chrlit data, dpcházelo by ke kolizi toho ochranného mechanismu s daty a podobně. Nepřipadá mi to jako moc spolehlivé řešení.

celé odpoledne jsme přemýšlel a přišel na další řešení, které mi můžete nyní zdrbat jako já to vaše:

Odesílané datové packety doplňovat například CRC, nebo jiným způsobem zajistit odlišování platných/neplatných přijatých dat. Program v přijímací straně pokud by se neshodovalo CRC, vynuloval by čítač USI hodinových pulzů. Tím pádem by po chvilce mělo dojít k synchronizaci komunikace.
Nejjednodušší způsob kontroly platnosti přijatých dat mě napadl třeba každý packet začínat číslem třeba $AB. Po přijetí prvních 8 bitů pokud by to nebylo tohle číslo resetovat čítač (od kterého je odvíjen příznak přijatých dat) Zde to ale kulhá taky v ne úplné spolehlivosti.
Lepší by bylo udělat opravdové CRC, ale to už by od předchozího neměl být takový problém.

Zítra to zkusím s tím “číslem před packetem”, pak to upgraduju na skutečné CRC.

Jeden z kritických faktorů téhle mojí šílenosti je i to, že zařízení A (master), hlídá stavy určitých míst připojených na B (slave), a reakční doba řetězce nesmí být delší než asi 10ms, přinejhorším 20.

//PS: Jak já tu SPI nemám rád… Už minule jsem se s ní pral - někteří pamatují. Zlatá RS232… bohužel MCU v zařízení A jí nedispouje. Jiank bych to snadno převedl na RS422 a bylo by po problémech.

Komunikace na takovou vzdálenost musí být zabezpečená, to je bez debat. Jak moc (jesli je třeba CRC nebo stačí XOR) je jiná věc. Ten úvodní byte pomůže. Taky timeout se občas hodí (byte nebo zpráva musí dojít do určitého času po první hraně hodin, jinak reset).

Ke kolizi ochranného mechanismu by nedocházelo, protože by měl být aktivní pouze do doby, než “uvidí” stabilně připojený protějšek nebo poté, co by přestal odpovídat.

Že nemáš /SS jsem přehlédl, pardon.

Čo takto synchronizácia na medzeru: Master medzi paketmi urobí medzeru napr. 10ms počas ktorej nebude vysielať,
Slave bude nastavený tak že ak neprijme počas 8ms žiadne dáta tak zresetuje USI.

Robit zpoždění mezi pakety si nebudu. Už tak to mám na háku, jelikož master je (bude) pomalý (SW implementace).
Pokud mezera mezi platnými daty bude větší než třeba několik ms, zresetuj čítač - ano, to by šlo, napadlo mě to hend jako první. Ale myslím si o tom, že je to také značně nespolehlivé, především kvůli tomu, že by mohlo dojít k nechtěnému resetu v průběhu již správně synchronizované komunikace. Potom by mohlo dojít i ke stavu, že třeba frekvence odesílání packetů by vyšla ně nějaký násobek té resetovací frekvence, a už by se to z problému nevyhrabalo. Při každém pokusu o odeslání dalších pár dat by se to mohlo nechtěně resetovat v nevhodnou chvíli.

Podle mě, nejlepší zabezpečení (nejen kvůli synchronizaci) ale také jak bylo správně připomenuto délka vedení, bude nějaký kontrolní součet, a ještě na vrch ten identifikační byte. Tím se přijetí nechtěných dat vyloučí na nejnižší možnou úroveň.

Až se teď vydýchám ze školy, začnu to programovat. Zatím totiž ani nevěřím tomu, že by to vůbec po těch 100m byť diferenciálně proudovou smyčkou šlo. :confused:

Pokud nemužeš dělat zásah do HW, tak jsi v nezáviděníhodné situaci. Sběrnice SPI je konstruovaná pro propojováni IO na téže desce a je 4vodičová. Chybějící SS nebo někde označovaný jako CSN, slouží k synchronicazi rámců. Architektura SPI nepředpokládá porušení dat ani hran během přenosu, nemá tutéž výbavu, jako UART, který jednotlivé bity vzorkuje 3x. Použití SPI na dlouhé vzdálenosti, kde se předpokládá jisté rušení, je nemožné.

Představa, že použiju kontrolní součet nebo samoopravné kódy, je poněkud lichá, protože vycházi z představy, že se na trase poruší jen data a SCK nikoli. Jakékoli porušení SCK má za následek posunutí přijímaných dat. Data jsou rozhozena i na zpáteční cestě, takže i zpráva o chybném kontrolním součtu je nečitelná.

Pokud by byla zajištěna bezchybnost přenosu dat, je možné signál SS na straně slave odvodit z SCK pomocí monostabilního KO typu 74HC123. S náběžnou hranou se KO nahodí a generuje aktivní SS. Spádová hran SCK pak provede zápis bitu do USIDR. Po přenesení X byte by musel být SCK na nějakou dobu v klidu, aby MKO stihl deaktivovat SS a ukončit tak rámec. Pro kontrolu přenesených dat, lze použít loop-back. Co master odvysílá, musí se mu v neporušené podobě vrátit zpět.

Podíval jsem se do DS ATtiny26 a skutečně nemá HW SS. Musí se řešit porgramem. To mě přivádí na myšlenku, že by ten MKO tam nemusel být fyziky, mohl by ho nahradit nějaký algoritmus spojeny s timerem. U MCU typu tiny = hubený asi nelze předpokládat komunikaci bez intervence procesoru. V DS je také zmínka, že se dá USI naprogramovat jako UART. Možná, že to bude někde popsáno v AN na stránkách Atmelu.

blbost blbost blbost
USI je sběrnice třívodičová. tiny26 čtvrtý vývod nepřiděláš. Leda softwarově.
Představa CRC je sudá. Pokud přijímací straně se nebude shodovat CRC, zresetuje bitový čítač, tedy se pokusí o znovu navázání synchronizace. Tedy se ošéfuje i vadný SCK signál. Občasné ztráty packetů a nutnost vyslání nových dotazů na data mému konstrukčnímu účelu příliš nevadí.
K signálu SS jsme ti řekl své. Lidi naučte se sakra číst.
Jasně, že USI se dá použít jako UART. Ale kdyby jsi nebyl líný číst, věděl bys, že na druhé straně UART nemám k dispozici. A věřž, že kdybych měl, skončil bych na RS422 a měl bych po problémech.
(To SPI mi leze na nervy, příště tam asi naštvaně vrazím 8251 a udělám si UART další :smiley: )

Když už jsme u toho čtení, tak Technik v souvislosti s /SS nepíše o USI, ale SPI, které je opravdu 4 vodičové. USI(Universal Serial Interface) není žádná sběrnice, ale hw prostředek umožňující snazší implementaci sériových přenosů.
Co se týká CRC, tak samo o sobě ti je opravdu k ničemu. Co ti bude platné resetovat čítač, když se budeš nacházet uprostřed přenosu a z pohledu usi tedy okamžitě začne přenos nový a opět blbě. Bez implementace timeoutů se ve tvé nezáviděníhodné situaci obejdeš asi celkem složitě.

Navrhnout ti uart mě sice napadlo také, ale zároveň jsem si domyslel, že kdybys ho měl u mastera k dispozici, tak bys tu nesoptil :slight_smile:
I2C by nebylo přijatelné? SW master je bez problému a USI je na I2C stavěné(má hw detekci start podmínky, což je pro sw slejva bez této fičurky značný problém). Ani bys nemusel dodržovat I2C protokol. Taková vlastní modifikace ve stylu 1. byte je od mastera a 2. od slejva, na nějaký adresy a R/W bity hodit bobek by mohla celkem fungovat. Navíc bys měl plonkovej drát.
Ono by ve skutečnosti stačilo upravit přenos na jakoukoli formu poloduplexu. 1 drát data, 2. hodiny a 3. můžeš použít pro bytovou/rámcovou synchronizaci.

I2C na masterovi je taky obsazená, takže osrávání nepřichází v úvahu.
Druhak, jak chceš hnát i2c po 100m kabelu?
Za třetí, HW měnit nelze, ten je daný (master). Já to mám jen naprogramovat.

Nápad synchronizovat detekcí start condition stejně jako u i2c se mi zdá celkem dobrý. Popřemýšlím o tom, jak by se to dalo implementovat na obou stranách.

A ktomu CRC - představme si, že se snažím odeslat a správně přijmout jediný byte, třeba číslo 123. Pokaždé, když slave pochytá 8 bitů a nebude se to shodovat se 123, dojde k resetu čítače bitů.
číslo 123 odpovídá 0b01111011
slave má už v bufferu naprděné 3 bity, dejme tomu 010. Po pokusu nasypat do něj číslo 123 v něm dojde k vyvolání přerušení, při obsahu bufferu (shiftujeme od LSB k MSB) “11011.010” (tečku jsme umístil mezi bordýlek a část správné skupiny bitů). Dojde tedy k přijetí nesmyslu. T9m se spustí restovací mechanismus. Kdyby došlo k nulování čítače bitů ihned, došlo by k tomu, že zbývající tři bity které se ještě stále nenasypaly do bufferu se tam nasypou již do čerstvě nulovaného, a zase tam bude posun o ty tři byty jako prve. Je tam tedy nutný nějaký delay před tím nulováním. Jelikož to hodlám hnát těmi dráty parní rychlsotí (co dovolí SW implementace a kabel vs. spolehlivost), ten delay bude stačit malý, a nebude vadit účelu zařízení.

Připadá mi, že by to mohlo takto fungovat, ale jako řešení mi nepřipadá zdaleka nejhezčí. Piityy navrhuje synchronizovat podobně jako i2c. Tenhle nápad se mi líbí. Cosi jako Start Condition (dále jen SC) se softw. implementací v masterovi bude generovat snadno. Jak funguje USI v tiny26 při i2c režimu se podívám. Domnívám se, že neobsahuje USI žádný obvod jako dekodér adresy, takže na tohle se můžu taky vykandit (jak navhuje taktéž piityy). Jediné, v čem tu vidím zradu je to, jestli jde u USI spustit SC detektor aniž by se piny USI nastavily na režim i2c. K přenosu totiž potřebuju dráty 3, a ne dva a ke všemu s otevřenými kolektory
Kouknu na to USI, pak dám vědět, co jsme objevil.
PS: Díky za nápad

Edit:
Tak jsem se na to mrknul do DS:

Tedy smůlu mám. Jedině si detekci SC naprogramovat softwarovou. TO by taky mohlo jít, zas budu muset popřemýšlet.

Samozřejmě jsem předpokládal mastera sw a nechtěl jsem to hnát přímo, ale přes drivery. Jen mi zas nedoteklo, že USI na tiny pojede s otevřenejma kolektorama :frowning:. To je vopruz. SW detekce startu na i2c je problém (tedy alespoň pokud má mcu dělat i něco jinýho). Ale jelikož to budeš psát sám a specifikace I2C tě nemusejí zajímat, tak by to měla bejt schůdná cesta.

Když už zmiňuješ ten opruz, tak opruz je celé to SPI, protože se na danou aplikaci prostě nehodí. Proč soudruzi nemohou dát dva UARTy ani do m644 ?! (ta je v masterovi)

Už mám napsanou vysílací procedůrku v masterovi. Nyní napsat tu přijímací ve slave.

Nu dobrá, tak si tedy USI nastavím do 3-wire mode.
Odesílání byte provádím obdobně jako po i2c. Klidový stav sběrnice je H na CLOCK i MOSI. Ve slave potřebuju nějak vhodně dělat detekci SC. SC mám naprogramované pomocí CLOCK a MOSI stejně jako má i2c, tedy že první se objeví L na MOSI a pak na CLOCK. Vzorkování dat ve slave by mělo proběhnout na náběžné hraně.

slave má pouze na starosti ten 100m kabel a měl by fungovat pouze “na dotaz”, tedy master se ho může zeptat na stavy nějakých vstupů, popřípadě požádat o zápis do nějakých výstupů. Tedy se může věnovat spousty času jen té komunikaci.

Jsou tedy nějaké nápady, jak na SW detekci SC ?

Je teda potřeba nejprve detekovat správn SC a následně vynulovat 4b counter.
Potom spolykat 8 bitů, zpracovat přijatá data a vrátit se na začátek.

PS: USI jsem nastavil tedy do 3-wire modu, shift registr posunuje na positive edge a ten 4b čítač reaguje na obě hrany CLK signálu.

Ale on má 2 UARTy a k tomu ještě SPI a TWI a všechny mohou fungovat současně. Občas je dobrý problém vypustit a zabývat se zcela něčím jiným a pak se tomu druhý den věnovat z čistou hlavou.

Pokusím se Ti vysvětlit, jak je to s tím kontrolním součtem. Když máš n byte zabezpečených 1 kontrolním součtem (nebo XORrem), můžeš spolehlivě detekovat jen jedinou chybu v jednom bitu. Jakmile změníš kterýkoliv bit v poli 8 x n bitů včetně bitů kontrolního součtu, nebude součet souhlasit. Dojde-li k poruše např. 2 bitů, existuje X kombinací, kdy kontrolní součet vyjde správně. (viz kombinatorika ). Chceme-li, aby X bylo co nejmenší, volíme raději součet než XOR, nejlépe CRC.
Přenáším-li data po RS232, může být porušen kterýkoliv bit včetně start a stop bitu. Porušení datového bitu némá vliv na následující bity stejně tak stop bit. UART ho rozpozná (frame error). Porušení start bitu už má fatální následek v tom, že se UART odstartuje na jiný nulový bit a dojde posunu bitů. Takže nelze čekat ve výsledku jen jedinou chybu. Přesto se však UART na některém z dalších start bitů zasynchronizuje a zbytek je správně.

To neplatí u SPI či podobných protokolů. Porušením cloku dojde k porušení dat až do konce rámce a ani CRC, natož kontrolní součet, nedokáží odhalit místo, kde k tomu došlo. Ani samoopravné Hammingovy kódy s tím nic neudělají, zvláště pak, jsou-li v protokolu umístěnu na konci paketu. Pro detekci takové chyby musí být jiný algoritmus.

Z toho plynou určité zásady, jak by protokol měl vypadat. Např. uvozen znaky 0x00, 0x00, 0xFF z nichž by se rozpoznalo posunutí dat. Pokud by slave zachytil 0x0F, šlo by o posunutí o 4 bity a nasledně by to srovnal, viz. zápis do 4bit countru v USI. Vždy po X bytech (např. každý 16.) by byla značka 0x0F, na které se opět pozná porušení clocku a hlavně na konci paketu krom kontrolního součtu…

Další možností je nějak modifikovaná sběrnice TWI (I2C) jak radí piityy a využí SC. TWI sice vyžaduje 1 obousměrný vodič, ale u tiny26 by šlo jej rozdělit na 2 a po druhém zpátečním posílat acknowledge. Na základě těchto značek je u mastera v každém byte kontrolována fáze bitů, takže porušení clocku na trase se odhalí v každém byte.

Jinak režie TWI je relativně složitá a pokud Ti jde o rychlost, nezbyde Ti nic jiného, než to psát v ASM.

Technik: Řekni mi techniku, na kterých vývodech má m644 v PDIP druhý UART. Nemá.

Technik: Už jsem stopadesátkrát opakoval, že další UART není k dispozici, TWI u mastera je obsazené a SPI taktéž, HW mastera je daný, mám jej pouze k programování. (Jediný užitečný odstavec je čtvrtý. Synchronizovat dle posunu bitů úvodního znaku mě nenapadlo. Ještě zvážím, zda to taky nezkusím)

Z protokolu i2c vyplývá, že linka SDA (v mém případě MOSI) může měnit svůj stav pouze pokud je SCL (v mém případě to zančím CLOCK) v úrovni L. Pokud se změní stav na SDA (MOSI) když je SCL (CLOCK) v H, jedná se o SC. Zkusím to ještě trochu promyslet, nějak naprogramovat, třeba se pohneme z místa… snad

M644 má opravdu 2 usarty (oba na portu D a hned vedle sebe) i v DIPu.
Akorát tobě to teď nepomůže, protože ani jeden není na pinech spi.

I kdyby byl na pinech SPI, tak po stý padesátý šestý říkám, že HW mastera jsem dostal k naprogramování ne modifikování. SPI piny jsou už obsazené něčím jiným.

Stojím si za tím, že mega644 má usart jen jeden. Píšou to v DS a na portě D je USART jen jeden. (RXD0 a TXD0).

Hmm… 644PA má 2 (měl jsem ho staženej už dýl, do stejnýho ds asi koukal technik), kdežto 644 ten druhej vážně postrádá. Bordel…