Úvod
Sériové periferní rozhraní (Serial Peripheral Interface) je protokol, kterým mohou komunikovat dvě nebo více zařízení. Je plně duplexní, což znamená, že můžete odesílat a přijímat data současně. Ve skutečnosti, jak uvidíme, musíte data odesílat, abyste je mohli přijímat. Pro komunikaci se používají 3 vodiče – jeden, který přenáší data z hlavního do sekundárního zařízení, druhý, který přenáší data ze sekundárního do hlavního, a hodinová linka, která tyto přenosy synchronizuje. Sekundární zařízení jsou adresována pomocí výběru čipu – čtvrtého vodiče, který samostatně připojuje každý sekundární vodič k hlavnímu. Celkem tedy 4 vodiče plus zem.
SPI je rychlé a optimalizované pro komunikaci mezi zařízeními, která jsou velmi blízko sebe (tj. na stejné desce plošných spojů).
Zapojení hardwaru
Zapojení SPI systému je velmi jednoduché. Obrázek znázorňuje propojení mezi hlavním zařízením (obvykle mikrokontrolérem) a několika sekundárními zařízeními (periferiemi). Vidíte, že všechna sekundární zařízení sdílejí společnou hodinovou linku, která vychází z hlavního zařízení. Také vidíte, že obě datové linky jsou sdíleny všemi sekundárními zařízeními. Ty jsou označeny MOSI (Main Out Secondary In) – která odesílá data z hlavního zařízení do sekundárního – a MISO (Main In Seconary Out), která odesílá data ze sekundárního zařízení do hlavního.
SCLK jsou hodiny, které synchonizují obě zařízení.
Pouze jedno zařízení může generovat hodinový signál na lince SCLK. Toto zařízení (jehož úlohou je generovat hodiny SPI) se nazývá Master nebo Centrální uzel (na obrázku SPI Main). Všechna ostatní zařízení se v tomto okamžiku chovají jako periferní (nebo podřízené) uzly. Pro fungování SPI je potřeba alespoň jeden centrální uzel a jeden periferní uzel. Dva periferní uzly propojené navzájem nebudou fungovat, protože žádná zařízení nemohou generovat hodiny. MISO, MOSI a SCLK linky jsou společné pro všechna zařízení (centrální a periferní uzly). Když chce centrální uzel odesílat/přijímat nějaká data, může na lince generovat hodiny se specifickou frekvencí na lince SCLK a aplikovat data na MOSI linku. Než to ale udělá, musí centrální uzel určit, které zařízení má tato data přijmout. To se provede tak, že se CS linka odpovídajícího periferního zařízení stáhne na nízkou úroveň, zatímco všechny ostatní CS linky se nastaví na vysokou úroveň.
Protože pouze centrální uzel může generovat hodiny, může pouze centrální uzel iniciovat přenos dat. Proto musí komunikace SPI využívat schéma příkaz-odezva. Centrální uzel může nastavit CS pin uzlu na nízkou úroveň a poté na něj odeslat nějaký příkaz. Po přijetí příkazu začne periferní uzel odesílat data odpovědi. Centrální uzel musí udržovat hodinový signál po dobu, kdy periferní zařízení odesílá data.

Jednou z trochu nepříjemných věcí na SPI je, že různí výrobci používají pro tyto linky různé názvy. Proto si musíte přečíst datový list, abyste se ujistili, že zapojujete správné piny mezi Pico a pariferii.
-
Místo MOSI (Master Out Slave In) se například může objevit COPI (Controller Out Peripheral In), SDO (SPI Data Out), nebo jen DO, nebo SO.
-
Místo MISO (Master In Slave Out) se může objevit CIPO (Controller In Peripheral Out), SDI nebo SI.
Musíte si přečíst datový list a podívat se na časové diagramy (na jeden se podíváme za chvíli), abyste si ověřili funkčnost každé datové linky.
Mimochodem, uvidíte také různé označení pro chipselect (výběr periferie).
-
Můžete vidět označení CS, nebo CSn, nebo SS, nebo CS
Všechny znamenají totéž.
Ale jak vidíte, zapojení je naprosto jednoduché. K jednomu hlavnímu obvodu můžete připojit mnoho sekundárních obvodů, omezujícím zdrojem se často stává dostatek vstupních a výstupních linek pro výběr čipu. Vzhledem k tomu, že tyto datové linky jsou sdíleny, můžete usoudit, že není dobrý nápad spouštět výběr čipu na dvou zařízeních současně.
Popis na vysoké úrovni
Během přenosu přes SPI se data přesouvají mezi dvěma posuvnými registry. Jeden z těchto posuvných registrů se nachází na hlavním obvodu a druhý na sekundárním. Jak velké jsou tyto posuvné registry? Budete si muset přečíst datový list pro konkrétní sekundární obvod, se kterým komunikujete. Může mít 8 bitů, 16 bitů nebo 32 bitů. Tyto dva posuvné registry tvoří mezičipovou kruhovou vyrovnávací paměť.
Když hlavní registr načte vysílací registr, začne přenos. Data jsou současně a synchronně odesílána z hlavního do sekundárního a ze sekundárního do hlavního registru přes linky MOSI/MISO. Synchronně znamená, že každý bit je vysílán synchronně s hodinami (možná na každé náběžné nebo sestupné hraně - to je konfigurovatelné, jak uvidíme). Současně znamená, že spodní část hlavního posuvného registru je současně posunuta do horní části sekundárního posuvného registru. Každý je pak samozřejmě posunut dolů a přenese se dalších 7 bitů, dokud se hodnoty v těchto dvou registrech nevymění.

Časový diagram
Zde je příklad 8bitového přenosu do/z SPI zařízení. Vidíte, že pro zahájení transakce je linka pro výběr čipu přivedena na nízkou úroveň hlavním zařízením. Když sekundární zařízení zjistí, že tato linka je na nízké úrovni, ví, že má očekávat (v tomto případě) 8 hodinových impulsů. Mezi ukončením výběru čipu a spuštěním hodin může být určité zpoždění, podívejte se do datového listu.
Hodiny poté začnou vysílat impulsy. V tomto diagramu jsou hodiny v klidu na nízké úrovni a v aktivní vysoké úrovni. Svislé červené čáry jednoduše označují náběžné hrany každého hodinového impulsu. Vidíte, že data jsou platná na náběžných hranách a že se data mění na sestupných hranách každého hodinového impulsu. I toto je konfigurovatelné a budete si muset přečíst datový list sekundárního zařízení, abyste zkontrolovali, co je správné.
Na základě tohoto diagramu můžete odvodit, že existují 4 různé režimy SPI. Dva stupně volnosti, které se mění pro každý režim, jsou polarita hodin a fáze hodin.
Na diagramu je polarita 0 a fáze 0. To znamená, že hodiny jsou v klidu na nízkém signálu a aktivní na vysokém signálu a data jsou platná na náběžných hranách.
Některá zařízení však budou mít fázi 1, což znamená, že data jsou platná na sestupných hranách a hodnota dat se mění na náběžných hranách.
Některá mohou mít fázi 0 a polaritu 1, což znamená, že hodiny jsou v klidu na vysokém a jsou aktivní nízkém signálu.
A konečně, můžete mít polaritu 1 a fázi 1, což znamená, že hodiny jsou v klidu na vysokém signálu a aktivním na nízkém signálu a data jsou platná na sestupných hranách.
Jak poznáte, který z nich je správný? Přečtete si datový list!! (Nebo často provedete vyčerpávající vyhledávání. Ne, to není nejpřesnější metoda, ale 4 není příliš velké číslo na to, abychom jen zkoušeli režimy, dokud nebudou fungovat).
Pico SPI rozhraní
SPI hardware na Picu

Mikrokontrolér RP2040, který se nachází na desce Raspberry Pi Pico, má uvnitř dva identické SPI řadiče. SPI řadiče jsou založeny na synchronním sériovém portu (SSP) PrimeCell od společnosti ARM. Každý SPI řadič má následující funkce.
-
Režimy Master nebo Slave
-
Rozhraní kompatibilní s Motorola SPI
-
Synchronní sériové rozhraní Texas Instruments
-
Rozhraní National Semiconductor Microwire
-
8 hlubokých Tx a Rx FIFO
-
Generování přerušení pro obsluhu FIFO nebo indikaci chybových stavů
-
Lze řídit z DMA
-
Programovatelná taktovací frekvence
-
Programovatelná velikost dat 4–16 bitů
FIFO paměti RX i TX (First In First Out, vyrovnávací paměť pro ukládání dat) mají šířku 16 bitů, což umožňuje přímý zápis 16bitových dat. FIFO paměti mají hloubku 8 pozic, což znamená celkem 32 bajtů. Piny obou SPI regulátorů lze přiřadit k více pinům GPIO pomocí bloku GPIO Mux čipu RP2040. Každý SPI blok může mít maximálně 8 signálových linek, jak je popsáno níže.
| Jméno | Směr | Popis |
|---|---|---|
SSPFSSOUT |
výstup |
Ekvivalen výstupu CS z centrálního uzlu |
SSPCLKOUT |
výstup |
Výstup hodin (SCLK) z centrálního uzlu |
SSPRXD |
vstup |
Linka pro příjem dat (MISO) pro centrální uzel |
SSPTXD |
výstup |
Linka pro vysílání dat (MOSI) pro centrální uzel |
nSSPCTLOE |
výstup |
Řídí *SSPCLKOUT signál. Aktivní je nízko. 1 = periférie, 0 = centrální uzel |
SSPFSSIN |
vstup |
Ekvivalent vstupu CS pro periférii |
SSPCLKIN |
vstup |
Hodinový vstup pro periférii |
nSSPOE |
výstup |
Řídí linku SSPTXD, Aktivní je nízko. 1 = TX výstup je vypnut, 0 = TX výstup je zapnut. |
To je více než čtyři signály, o kterých jsme hovořili dříve. Ale nebojte se. V závislosti na roli SPI rozhraní (centrální nebo periferní) budou tyto signály směrovány na příslušné piny. Pico C/C++ SDK má API (Application Programming Interface) pro ovládání a konfiguraci SPI řadičů, jak uvidíme později. Jedna věc, kterou musíte mít na paměti, je, že SPI řadič RP2040 nemůže dynamicky přepínat mezi rolí Centrální a Periferní. Uživatel musí režim deinicializovat a ručně znovu inicializovat SPI v jiném režimu. Datový list RP2040 na straně 501 obsahuje podrobný popis jeho SPI řadiče a souvisejících registrů.
Detaily lze nalézt na About the ARM PrimeCell SSP (PL022)
Programování SPI na Picu
Programátoři Raspberry Pi Pico mají k dispozici dva SPI řadiče, SPI0 a SPI1, které mohou fungovat v režimu nadřízený (master) nebo podřízený (slave).
Zapojení obou řadičů může být směrováno k různým pinům.
| řadič | funkce | sada 1 | sada 2 | sada 3 | sada 4 |
|---|---|---|---|---|---|
SPI0 |
MISO |
GP0 |
GP4 |
GP16 |
GP20 |
CSn |
GP1 |
GP5 |
GP17 |
GP21 |
|
SCLK |
GP2 |
GP6 |
GP18 |
GP22 |
|
MOSI |
GP3 |
GP7 |
GP19 |
GP23 |
|
SPI1 |
MISO |
GP8 |
GP12 |
GP24 |
GP28 |
CSn |
GP9 |
GP13 |
GP25 |
GP29 |
|
SCLK |
GP10 |
GP14 |
GP26 |
||
MOSI |
GP11 |
GP15 |
GP27 |
Pokud budeme pracovat se SPI sběrnicí nesmíme zapomenout do našeho programu vložit
#include "hardware/spi.h"
a do CMakeLists.txt dodat knihovnu hardware_spi
target_link_libraries( nas_projekt pico_stdlib hardware_spi )
Výběr pinu, aby pracoval v rámci SPI sběrnice se provádí funkcí:
gpio_set_function( pin, GPIO_FUNC_SPI );
kde pin musí odpovídat příslušnému rozhraní spi0 nebo spi1 podle výše uvedené tabulky.
Takže například pro spi0 v implicitním nastavení to bude:
gpio_set_function( 16, GPIO_FUNC_SPI);
gpio_set_function( 17, GPIO_FUNC_SPI);
gpio_set_function( 18, GPIO_FUNC_SPI);
gpio_set_function( 19, GPIO_FUNC_SPI);
Dá se to zaprat i takto:
gpio_set_function (PICO_DEFAULT_SPI_RX_PIN, GPIO_FUNC_SPI);
gpio_set_function (PICO_DEFAULT_SPI_SCK_PIN, GPIO_FUNC_SPI);
gpio_set_function (PICO_DEFAULT_SPI_TX_PIN, GPIO_FUNC_SPI);
gpio_set_function (PICO_DEFAULT_SPI_CSN_PIN, GPIO_FUNC_SPI);
SPI funkce
SPI funkce v Pico C SDK lze rozdělit do tří kategorií. Na inicializaci, konfiguraci a na přenos dat. Podíváme se na ně. Všechny podrobnosti jsou v dokumentaci k SDK zde.
Inicializace
K zapnutí nebo vypnutí SPI sběrnice používáme funkce:
uint spi_init( spi_inst_t *spi, uint baudrate ); // zapnutí
void spi_deinit( spi_inst_t *spi); // vypnutí
Funkcí spi_init nastavujeme rychlost rozhraní v baudech, což je to samé jako nastavení tikání hodin v Hertzích.
Parametr spi typu spi_inst_t je ukazatel na hardwarovou adresu SPI řadiče a není to index 0 nebo 1, jak jsme zvyklí.
Je však k dispozici užitečná makra, kterými si vybereme, zda budeme pracovat se SPI0 nebo SPI1, místo zadávání hardwarové adresy.
#define spi0 ((spi_inst_t *)spi0_hw)
#define spi1 ((spi_inst_t *)spi1_hw)
K získání indexu se dá použít funkce:
static uint spi_get_index( spi_inst_t *spi);
která konvertuje hardwarovou adresu na index 0 nebo 1.
Konfigurace
Nejlepším způsobem, jak nastavit rychlost SPi rozhraní je použít funkci spi_set_baudrate, protože nám vrátí nastvenou hadnotu, kte je nejblíže skutečné rychlosti hodin.
uint spi_set_baudrate( spi_inst_t *spi, uint baudrate );
Funkce spi_set_slave určuje, zda bude Pico fungovat jako řídící (master) nebo podřízený (slave) na sběrnici.
Parametr slave roven false — Pico je řídící, slave rovno true — Pico je podřízené.
static void spi_set_slave( spi_inst_t *spi, bool slave );
Pokud nepoužijete funkci spi_set_slave, tak bude SPI funkcí spi_init nastaveno do režimu master.
Nejdůležitější funkcí je spi_set_format, která nastavuje polaritu a fázi hodin, počet datových bitů přenosu a SPI režim (Big-Endian nebo Little-Endian), což není nic jiného než způsob přenášení bitů (nejdříve MSB nebo nejdříve LSB).
static void spi_set_format( spi_inst_t *spi, uint data_bits, spi_cpol_t cpol, spi_cpha_t cpha, __unused spi_order_t order);
Parametry:
-
spi— příslušná instance buďspi0nebospi1 -
data_bits— počet přenesených bitů během transakce, hodnoty v rozsahu4..16. -
cpol— polarita hodinSSPCLKOUT. Musí býtSPI_CPOL_0pro polaritu 0 neboSPI_CPOL_1pro polaritu 1. Viz obrázky výše o polaritě a fázi. -
cpha— fáze hodinSSPCLKOUT. Musí býtSPI_CPHA_0pro fázi 0 neboSPI_CPHA_1pro fázi 1. Viz obrázky výše o polaritě a fázi. -
order-- pořadí přenášení bitů, musí býtSPI_MSB_FIRSTna PL022.
Funkce pro přenos dat
SPI sběrnice komunikuje obousměrně. Kvůli tomu je implementace komunikačních funkcí trochu jiná než u jiných sběrnic. Základní funkcí, kterou budeme používat je:
int spi_write16_read16_blocking( spi_inst_t *spi, const uint16_t *src, uint16_t *dst, size_t len );
Pole src a dst mají stejou velikost, která je v parametru len. Pole src se používá pro vysílaná data a pole dst je pro data přijímaná zpět.
Obě pole mají prvky o velikost 16 bitů, avšak posílá se jenom počet bitů, který je zadán v konfiguraci instance SPI.
To znamená, že pokud například nastavíme data_bits funkcí spi_set_format na velikost 8, bude se přenášet jenom vrchních 8 bitů z každého prvku pole src a dst.
Funkce vrací počet zapsaných nebo přečtených bajtů.
Tady vzniká velmi zajímavá situace, funkce nám může vrátit nenulové číslo, přestože podřízené zařízení nekomunikuje a neposílá nám žádná data.
Můžeme si to ověřit pokusem.
Nemůžeme spoléhat podle návratové hodnoty na to, že počet přenesených dat podřízené zařízení skutečně obdrželo. Stejně tak nemůžeme spoléhat na to, že nadřízené zařízení skutečně přečetlo data z podřízeného zařízení.
V případě poruchy podřízeného zažízení obdržíme v *dst nuly.
|
Pokud potřebujete data jenom zapisovat nebo jenom číst, tak použijte funkce:
int spi_write16_blocking( spi_inst_t *spi, const uint16_t *src, size_t len );
int spi_read16_blocking( spi_inst_t *spi, uint16_t *repeated_tx_data, uint16_t *dst, size_t len );
Funkce spi_write16_blocking přijatá data jednoduše zahazuje.
Funkce spi_read16_blocking má zvláštní parametr repeated_tx_data, kde jsou obvykle samé nuly, ale některé periferie vyžadují, aby tam bylo něco jiného.
Obě tyto funkce jsou jenom zjednodušením funkce spi_write16_read16_blocking.
Dají se používat i obdobné osmibitové verze těchto funkcí:
int spi_write_read_blocking( spi_inst_t *spi, const uint8_t *src, uint8_t *dst, size_t len );
int spi_write_blocking( spi_inst_t *spi, const uint8_t *src, size_t len );
int spi_read_blocking( spi_inst_t *spi, uint8_t repeated_tx_data, uint8_t *dst, size_t len );
Jsou to jednodušší verze funkce spi_write16_read16_blocking, které používají 8bitové pole místo 16bitových.
Je tady ještě jedna malá komplikace, kterou můžete téměř ignorovat. SPI hardware má buffery MISO a MOSI linky mají na sobě frontu FIFO 8 prvků dlouhou a to znamená, že můžete posílat a přijímat data rychleji, poku není fronta plná nebo prázdná. Stav této fronty lze zjistit funkcí:
static size_t spi_is_readable( spi_inst_t *spi);
která vrací nenulovou hodnotu, pokud jsou ve frontě nepřečtená data. A obdobně funkce:
static size_t spi_is_writable( spi_inst_t *spi );
vrací nenulovou hodnotu, pokud je ve frontě nějaké místo. Tyto funkce mužete použít, pokud chcete minimalizovat čekání při použití blokujících I/O funkcí.
Použití přenosových funkcí
Základní funkce pro přenos dat spi_write16_read16_blocking ukazuje jak se používá obousměrný přenos.
uint16_t wBuff[] = {'A', 'B', 'C'};
uint16_t rBuff[3];
int n = spi_write16_read16_blocking( spi0, wBuff, rBuff, 3);
Pošle tři prvky z wBuff a přijme zpět tři prvky do rBuff.
Data v příjmovém bufferu rBuff budou mít nějaký význam tehdy, pokud periferie pošle něco smysluplného, co nás zajímá.
Nemají-li data pro nás význam nebo je nepořebujeme, naprogramujeme to raději takto:
uint16_t wBuff[] = {'A', 'B', 'C'};
int n = spi_write16_blocking( spi0, wBuff, 3);
U 8bitového přenosu to uděláme takto:
uint8_t wBuff[] = {'A', 'B', 'C'};
spi_write_blocking( spi0, wBuff, 3);
Podobně když nás nezajímají data poslaná na periferii a chceme jenom číst, napíšeme:
uint16_t wBuff = {0};
uint16_t rBuff[3];
int n = spi_write16_read16_blocking( spi0, wBuff, rBuff, 3);
nebo
uint16_t rBuff[3];
int n = spi_read16_blocking( spi0, rBuff, 3);
Pro 8bitový přenos to bude:
uint8_t rBuff[3];
spi_read_blocking( spi0, rBuff, 3);
Nyní jeden detail. Jaký je rozdíl mezi přenosem několika bajtů najednou a přenosem několika bajtů individuálně mnohonásobným voláním funkce spi_write16_read16_blocking()?
// přenos 3 bajtů najednou
uint16_t wBuff[] = {'A', 'B', 'C'};
uint16_t rBuff[3];
// CS se bude aktivovat
int n = spi_write16_read16_blocking( spi0, wBuff, rBuff, 3);
// CS se deaktivuje
// přenos 3 bajtů po prvcích
uint16_t wBuff[] = {'A', 'B', 'C'};
uint16_t rBuff[3];
// CS se bude aktivovat
int n = spi_write16_read16_blocking( spi0, wBuff, rBuff, 1);
// CS se deaktivuje
// CS se bude aktivovat
n = spi_write16_read16_blocking( spi0, wBuff+1, rBuff+1, 1);
// CS se deaktivuje
// CS se bude aktivovat
n = spi_write16_read16_blocking( spi0, wBuff+2, rBuff+2, 1);
// CS se deaktivuje
Před každým přenosem se aktivuje linku CS, potom se přenášejí data a potom se linka CS deaktivuje. Při přenášení několika bajtů najednou je linka CS aktivní po celou dobu přenosu, to znamená, že CS nemusíme deaktivovat mezi jednotlivými bajty. Někdy tento rozdíl v přenosu není důležitý a můžete přenos dělat třeba 3 bajty najednou nebo 3 bajty po jednom. Avšak některé periferie přeruší operaci přenosu, pokud je CS deaktivováno uprostřed přenosu (tj. přenášíme po jednotlivých bajtech). Protože Pico vyžaduje, abychom CS aktivovali a deaktivovali sami, je na vás, jak to uděláte.
Je důležité vědět, že přenos vždy probíhá tak, že jakmile je první prvek vyslán, tak je současně i první prvek přijat. Druhý prvek je vyslán a současně je druhý prvek přijmut, třetí prvek vyslán a současně třetí prvek přijmut a tak dále. To je zcela jiný přístup než u ostatních protokolů a pokud tomu neporozumíte, tak to může vést k některým opravdu zajímavým chybám.
Komunikace dvou Raspberry Pi Pico pomocí SPI sběrnice
Zkusíme rozchodit nejprve jednosměrnou komunikaci mezi dvěma RPi Pico. K tomu si založíme dva projekty.
Projekt pro RPi Pico, které bude řídící, umístíme do adresáře master.
Projekt pro RPi Pico, které bude podřízené, umístíme do adresáře slave.

Komunikace dvou Raspberry Pi Pico pomocí SPI
Pico řídící
master/master.c
|
Pico podřízené
slave/slave.c
|
Protože podřízené Pico je v režimu slave, je nutné na něm prohodit drátky SPI0 TX a SPI0 RX oproti řídícímu Pico v režimu master.
Při zapojování jiných periférií, které fungují v režimu podřízený se to nedělá.
|
| Pico řídící | barva drátu | Pico podřízené |
|---|---|---|
GPIO17 (SPI0 CSN) |
zelená |
GPIO17 (SPI0 CSn) |
GPIO18 (SPI0 SCK) |
modrá |
GPIO18 (SPI0 CSn |
GPIO19 (SPI0 TX) |
čevená |
GPIO16 (SPI0 RX) |
GPIO16 (SPI0 RX) |
žlutá |
GPIO19 (SPI0 TX) |
GND |
černá |
GND |

Výstup minicomu
Pico řídící
minicom -b 115200 -D /dev/ttyACM0
|
Pico podřízené
minicom -b 115200 -D /dev/ttyACM1
|
CMakeLists.txt pro naše dva projekty
Pico řídící
master/CMakeLists.txt
|
Pico podřízené
slave/CMakeLists.txt
|
Problémy tohoto software jsou dva:
-
Komunikace je jednosměrná.
-
Ani jedno Pico neví o případné poruše druhého Pica.
Obousměrná komunikace
Udělat synchronní obousměrnou komunikaci je celkem jednoduché, stačí na obou RPi Pico používat funkci spi_write_read_blocking().
Komunikace obou strojků se zasynchronizuje automaticky.
Obousměrná komunikace
Pico řídící
master_sync/master_sync.c
|
Pico podřízené
slave_sync/slave_sync.c
|
Sestavení programů je stejné a CMakeLists.txt u obou částí jsou podobné, jako u předchozího programu.
Nevyřešeným problémem zůstává to, že pokud bude mít jedno Pico poruchu, tak druhé Pico uvidí při komunikaci jenom nulu, která však patří do množiny platných dat.
Obousměrná komunikace s ošetřením chyby komunikace
Pokud do komunikačního protokolu mezi Picy přidám k přenášenému bajtu ještě jeho bitovou negaci, tak bude snadné zjistit poruchu komunikace. Při správné komunikaci se nejprve přenese datový bajt a potom jeho negace. Porovnáním přeneseného datového bajtu a jeho přenesené bitové negace se na druhé straně zjistí chyba.
Při poruše obdrží protější Pico 0 jako datový bajt a také 0 jako bitovou negaci datového bajtu, což je špatně, protože bitová negace 0 je 255.
Tak poznám chybu.
Obousměrná komunikace s ošetřením chyby komunikace
Pico řídící
master_sync2/master_sync.c
|
Pico podřízené
slave_sync2/slave_sync.c
|