Vlákno názorů k článku Přístupy k programování STM32 od Petr M - Takže popořadě. První věc, všechny knihovny od ST jsou...

  • Článek je starý, nové názory již nelze přidávat.
  • 3. 10. 2017 8:29

    Petr M (neregistrovaný)

    Takže popořadě.

    První věc, všechny knihovny od ST jsou dobrý tak pro inspiraci. Začíná to cyklickýma inkluzema v CMSIS, pokračuje nedomyšlenýma funkcionalitama v středních vrstvách (proč sakra nikdo nepočítá s tak podstatnou věcí, že na SPI mají obvody obvykle uvnitř několik registrů a je potřeba je adresovat?) konče HALem s chybějící funkcionalitou. Dál jsou tyhle funkce nekompatibilní s operačním systémem.

    Druhá věc. Jak může autor propagovat TrueStudio? Otravný, ve free verzi reklamama na sebe samo prolezlý balast, s instalací proti registraci a s aktualizací na úrovni widlí. Navíc bez registračního formuláře se člověk nedozví ani detaily o instalaci a požadavcích... :( Tfuj. Zlatý Eclipse + arm-none-eabi-gcc + gdb + Texane.

  • 3. 10. 2017 8:53

    asdasd (neregistrovaný)

    >> Jak může autor propagovat TrueStudio..
    nevidel som sice TrueStudio to bude mozno tym aky je eclipse shit co sa tyka gui. Nikdy som nedokazal eclipse nastavit tak, aby debugger nevyzeral roztahano ako na tablete. Navyse aj eclipse ma nejake problemy ked v ubuntu je stale verzia 3.x a nie najnovsia

  • 3. 10. 2017 9:37

    Petr M (neregistrovaný)

    No já mám ve Fedoře Eclipse Oxygen a GUI vypadá podstatně líp. Akorát to totálně přeházeli a na nově instalovaným stroji musím vygómat, jak to vlastně nastavit...

  • 3. 10. 2017 13:49

    Petr M (neregistrovaný)

    dnf install eclipse stlink arm-gcc-none-eabi, pokud si dobře pamatuju. Jenom to nějak poskládat v projektu... :/

  • 3. 10. 2017 9:37

    Martin K (neregistrovaný)

    Ahoj Petre,
    jaky zpusob vyvoje / knihovny tedy preferujes ty? Ja s STM32 teprve zacinam a tak nejak jsem se rozhodl pro CMSIS - prakticky zadny overhead, snad dobra prenositelnost, moznost naucit se vic o tom, jak ten chip funguje...

    Druha vec: Jako editor jsem se rozhodl pro Code::Blocks (+ arm-none-eabi-gcc a Texane), mas s nim nejakou primou zkusenost? Hodi se na to?

    Diky, Martin

  • 3. 10. 2017 9:55

    Petr M (neregistrovaný)

    No já mám momentálně knihovny vlastní, založený na CMSIS + RTOS + "objektový C". Takže nečekám ve smyčkách a mezi tím se spustí jiný vlákno (multithread je silně návykový), periferky mají z 80% stejný interface (UART, SPI a I2C jedno jest), moduly si definují závislosti,... Publikovat to ale nesmím, vzniklo to za peníze zaměstnavatele a smlouva to nedovolí.

    C::B sice tak nějak funguje, ale je to takový pěkně šišatý kolo. Vypíchl bych několik detailů pro masochsty:
    - Konfigurace má několik levelů. Globální, projekt, soubor. Nastavení se mixuje podle ne zcela zřejmých pravidel a je v tom super hokej stylem "přeložím si, jak chci".
    - V build logu jsou sice chyby a warningy, ale warningy nejdou rokliknout ve zdrojáku a ani ve zdrojáku není nikde highlight/značka, kde je něco blbě. Docela to brzdí.
    - V konfiguraci není vše, třeba tam nenastavíš hardfloat/sof­tfloat, takže hurá editovat XMLko...
    - Zobrazení paměti je super, vždycky po bytu, bez textu a ještě si můžeš volit velikost oblasti jenom jako mocninu 2. A samo, že nevidíš, co se děje kolem (takže nevidíš buffer, co ti za chvilku podteče...)
    - Lokální proměnný v debuggeru nemají možnost nastavení formátu, takže na dekadický znaky nebo hexa inty rovnou zapomeň.
    - Navigace v souborech. Nějaký ichtil tam nacpal tři stromy - source, headers, others. Fakt super, pokud v rámci modulu mám header i zdroják v jednom adresáři.
    - Navigace uvnitř souboru je nepochopitelná. Musíš vybrat kategorii (funkce, proměnná, makro) a tam teprve vidíš jejich seznam. Žádný "rozklikni si strukturu" se nekoná,...
    - Integrace GITu a SVN je naprosto bez chyby, protože když tam něco není, nemůže tam být chyba
    - ...

  • 3. 10. 2017 11:14

    Martin K (neregistrovaný)

    Napisu Krcmarovi, aby pod tvoje prispevky pridali "donate" tlacitko:)

    V tom pripade opoustim C::B a vydam se cestou Eclipse. Coz jsem uplne nechtel, je to nenazranec, ale zrovna ta integrace GITu je pro me dulezita. V aktualnim Debianu je bohuzel pouze 3.8.1, tak to budu tahat bokem...

  • 3. 10. 2017 23:13

    djmanas

    A PlatformIO jste zkoušel? Nevím jak v stable verzi, ale posledního půl roku mám develop verzi a docela se mi to prostředí začalo líbit. Mělo by podporovat i STM...

  • 3. 10. 2017 9:41

    Ladislav Michl (neregistrovaný)

    Ano, HAL v podání ST je čisté zlo, které vyplodil někdo, komu nařídili, že moderní je mít nějakou abstrakci, bez ohledu na to, jestli dává smysl. Stejný projekt (MODBus, USBTMC, nějaké SPI a I2C periferie) přepsaný s "pomocí" HAL nabobtnal o 28% a došlo z pohledu uživatele k viditelnému zpomalení. Celá akce skončila návratem k CMSIS a přímému přístupu k registrům.

  • 3. 10. 2017 10:04

    Petr M (neregistrovaný)

    No beru, že třeba handle je pointer na strukturu. Beru, že v té struktuře je uložená konfigurace periferky na nějaké úrovni abstrakce, pokud to má smysl. Ale proč u VŠECH musí být KOMPLETNÍ konfigurace jako struktura, ve které je i nastavení jednoho bitu jako uint32_t? To jako kvůli jednomu 32b registru, kde je 32 binárních flagů, musím trpět v paměti strukturu 128B? Ve světě, kde se RAM počítá na kB? Raděj tu RAMku použiju na větší FIFO u UARTu, než na uložení jednou zadané konfigurace, kterou už nebudu potřebovat...

    Samo SPI s CMSIS vs HAL 2,5kB FLASH a 130B RAM rozdíl. Funkce stejná. To samo o sobě je na pořádný kuleškub bez umrtvení.

  • 3. 10. 2017 19:11

    Houba (neregistrovaný)

    Tfujtajxl HAL pro STM32. Taky na to mám za ty leta vlastní knihovny. Včetně hezky chodícího USB CDC s DMA jako RTOS task. Ne ten humus co vyprodukuje Keil nebo STM32Cube.

    Naposledy mě požádal kamarád, že už neví co dál, že řídí nějakej ADC šváb, a když chce přečíst data co mu do něj jdou po SPI, tak to pořád nefunguje. Napsal to s HAL. Jeden by čekal, že když se chce jenom přijímat, tak to bude jenom přijímat. Použil HAL_SPI_Receive. Problém je, že tahle funkce jen využívá HAL_SPI_Transmit­Receive, a to co je v bufferu pro příjem se na SPI i vyšle. Chudák ten šváb na druhým konci. Prej Dummy Data. Třikrát si odplivnout.


    HAL_StatusTypeDef HAL_SPI_Recei­ve(SPI_Handle­TypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
    {
    .
    .
    /* Call transmit-receive function to send Dummy data on Tx line and generate clock on CLK line */
    return HAL_SPI_Transmit­Receive(hspi,pDa­ta,pData,Size,Ti­meout);
    }

    Mě kolikrát přijde, že čím novější verze těch jejich "API", tak tím větší humáč to je.

  • 3. 10. 2017 20:10

    Technik (neregistrovaný)

    Tak nevím, jestli jsem Vás správně pochopil, ale divit se, že SPI při příjmu i něco vysílá je jaksi nepochopení jeho funkce.

  • 3. 10. 2017 21:24

    Houba (neregistrovaný)

    To si nechám klidně povyprávět. V téhle konkrétní aplikaci máme ADC, který přes sestupnou hranu /DRDY signalizuje že má připravena data na SPI. Dle datasheetu STM32 musí pouze shodit /CS, a načíst 32 x 8-bit hodnot po SPI, na celkem 256 sestupných hran hodin.

    O vysílání čehokoliv tam není řeč.

    Naopak, pokud se tomu ADC pošle něco po MOSI, tak to začne dělat blbosti, protože se tomu začnou přepisovat konfigurační registry.

    Apropo, jak to souvísí s kvalitou HAL ?

  • 3. 10. 2017 21:44

    gripennn (neregistrovaný)

    Jestliže to ADC má MOSI (SDI) vstup tak bude nevyhnutelně přijímat data kdykoli na SCK poběží clock (tedy i v situaci kdy STM32 čte z ADC). A to dokonce i v případě, že by vás napadlo MOSI "nikam" nepřipojit. Pointa je poslat mu taková data, která "nic nezpůsobí" (dummy), což bude jistě zmíněno v datasheetu k ADC. Představa že vysílání a příjem jsou dvě rozdílné akce je tedy špatná.

  • 3. 10. 2017 21:54

    Houba (neregistrovaný)

    Přesně tak, takže HAL funkce pro čtení musí buď 1) na MOSI nehrabat, nebo 2) alespoň nastavit MOSI na definovanou hodnotu.

    Ale to, o čem se celou dobu bavíme milý Watsone, je fakt, že HAL pošle na MOSI obsah bufferu, do kterého se má podle dokumentace jen přijímat. Tento buffer obsahuje většinou minulá přijatá data, pokud o této zrůdnosti nevíme.

    Kdyby zcela blbě nevytvořili funkci HAL_SPI_Receive, která je vlastně HAL_SPI_Transmit­Receive, aniž by to uživatel tušil, tak by k tomu nedošlo. Přímým voláním HAL_SPI_Transmit­Receive by uživatel věděl, že má nastavit data k vyslání na dummy hodnoty.

  • 3. 10. 2017 21:05

    Wolf (neregistrovaný)

    Doporučuju si prostudovat implementaci SPI než si začnu hrát na chytrýho. Ty dummy data jsou běžná věc.

  • 3. 10. 2017 21:28

    Houba (neregistrovaný)

    Chcete mi snad vsugerovat myšlenku, že je zcela normální, že pokud je funkce označena jako ČTI, tak že data i ZAPISUJE ? A přitom v dokumentaci k této funkci není o zápisu ani řeči ?

    Upozorňuji, že se bavíme o kvalitě HAL, ne o tom, kdo ho má většího, nebo kdo je větší blbec.

    Má-li HAL funkce ČTI, ZAPIŠ_a_ČTI a ZAPIŠ, očekává prostý uživatel že funkce bude číst. Ne, že zavolá ZAPIŠ_a_ČTI když nic zapisovat nechci.

    Než mě znovu osočíte, zkuste si něco najít o periferiích, které z principu funkce NEPOTŘEBUJÍ, nebo NEMAJÍ nutnost před odesíláním dat do STM32 přijmout adresu či opcode.

  • 3. 10. 2017 21:35

    mv_

    SPI je full-duplex (aj preto sú MOSI a MISO oddelené signály). Tzn. vysielanie je príjímanie a naopak.

  • 3. 10. 2017 22:09

    Houba (neregistrovaný)

    Ale neříkejte, to by jeden nepověděl. A o tom jsem se v tom prvním příspěvku vlastně bavil. To jsem to napsal tak blbě ?

    Vždyť je to jasné - pokud chci číst, a nezmrvit data v ADC, NESMÍM hrabat na MOSI, a jen číst MISO. A přesně to byste očekával od funkce HAL_SPI_Receive. Z dokumentace:


    HAL_SPI_Receive
    Receive an amount of data in blocking mode.
    hspi: pointer to a SPI_HandleTypeDef structure that contains
    the configuration information for SPI module.
    pData: pointer to data buffer
    Size: amount of data to be received
    Timeout: Timeout duration
    HAL status

    HAL_SPI_Transmit­Receive
    Transmit and Receive an amount of data in blocking mode.
    hspi: pointer to a SPI_HandleTypeDef structure that contains
    the configuration information for SPI module.
    pTxData: pointer to transmission data buffer
    pRxData: pointer to reception data buffer
    Size: amount of data to be sent and received
    Timeout: Timeout duration
    HAL status

    Prostě očekáváte, že se pData naplní přijímanými daty, a NIC nehrabe na MOSI. Ne, že se jedná fakticky o HAL_SPI_Transmit­Receive, kde pTxData = pRxData. To tam nikde zdokumentované není.

    A o tom je celý HAL.

  • 3. 10. 2017 22:41

    gripennn (neregistrovaný)

    Nepochybuji o tom, že HAL stojí za prd a nepoužívám ho. Výraz "NIC nehrabe na MOSI" je nesmyslný. Nějaká logická hodnota tam musí být. Krom toho SPI se na STM32 dá používat klidně simplexně (tedy jenom příjem, nebo jenom vysílání). Z toho plyne, že existence obou funkcí má opodstatnění a vy jste měl tu smůlu že jste si vybral špatnou. Těžko lze ale házet vinu na autora HALu, on asi předpokládá že uživatel bude mít ponětí o tom že při duplexní konfiguraci data tečou oběma směry ...

  • 4. 10. 2017 5:46

    Houba (neregistrovaný)

    Ale to já přeci vím, proč mi pořád podsouváte že to nevím ?

    Měl jsem tam připsat velkými tiskacími "vím jak funguje SPI", a protože právě vím že funguje tak jak funguje, tak předpokládám, že mi funkce pro čtení nikam nic nepíše, protože to může rozbít věci ? A když to udělám, proč to nenapíšu do dokumentace ?

    Já se přeci celou dobu netočím na SPI a jeho použití, já se točím na té prasárně v HALu.

    Proč jste tak natvrdlý....

  • 4. 10. 2017 8:20

    gripennn (neregistrovaný)

    OK mrkněte na tyto tři situace:
    A) SPI máte nakonfigurováno v simplexním režimu v roli vysílače. STM32 tedy může pouze vysílat, linka MISO neexistuje (slave má pouze linky CS,SCK,SDI). V takovém případě voláte funkci HAL_SPI_Transmit()
    - typicky případ primitivních ADC a pod.

    B) SPI máte nakonfigurováno v simplexním režimu v roli přijímače. Linka MOSI neexistuje. Slave má pouze linky CS,SCK,SDO. V takovém případě voláte funkci HAL_SPI_Receive()
    - typický případ primitivních DAC nebo digitální potenciometrů

    C) SPI máte nakonfigurováno v duplexním režimu. Linky MOSI i MISO existují, slave má linky CS,SCK,SDO a SDI. V takovém případě voláte funkci HAL_SPI_Transmit­Receive()
    - typicky pro všechna trochu chytrá zařízení

    Co je na těchto funkcích nelogické ? Každá z nich má právě ty argumenty které ke své činnosti ve správné roli potřebuje. Vy jste si vybral špatnou a místo toho aby jste sypal popel na svou hlavu snažíte se hodit vinu za váš výběr autorům HALu. Což vám ale k ničemu nebude, protože to komunikaci s vaším ADC neopraví.

    Dalo by se to přirovnat k situaci kdy si člověk nakonfiguruje USART v 9bit režimu (neříkám že to na STM32 přímo jde), zavolá funkci USART_Transmit(u­int8_t data), která očividně žere 8bit data a pak se diví že 9.bit zprávy má jinou hodnotu než chtěl. Člověk který protokolu rozumí se pozastaví nad tím, že funkci nejde předat všechna potřebná data (9 bitů) a začne hledat tu správnou... stejně jako člověk který rozumí SPI se pozastaví nad tím, že při duplexním provozu funkci HAL_SPI_Receive() chybí klíčový argument (co odeslat na MOSI) a začne hledat správnou ...

  • 4. 10. 2017 11:06

    Karel (neregistrovaný)

    Já tomu pořád moc nerozumím. Koukám do specifikací SPI a nikde tam nevidím možnost, jak druhému zařízení říci "hele, já teď budu hejbat hodinama, ale probohe hlavně se nekoukej, co je na drátu MOSI".

    HAL má funkci "receive", která je poměrně jasně specifikovaná: načte data od slave zatímco mu pošle nedefinovaný bordel. Ta funkce má použití tam, kde to slave zařízení žádná data nečte, respektive je ignoruje. Ta funkce má výhodu v tom, že nemusíte alokovat strukturu pro odesílaná data. Ušetříte pár bajtů.

    Takže první problém je, že si nějak myslíte, že SPI umí číst bez toho, aby psalo. Neumí. A pak je tam možná problém druhý, že neumíte číst dokumentaci. Konkrétně mám na mysli zaužívanou konvenci "pokud to není definováno, tak je to nedefinované". Což v tomhle případě znamená, že nikde není definováno, co se bude odesílat - takže předjímejte, že to budou náhodné bity. Ve skutečnosti to posílá ven to, co přichází, ale to je nedokumentované chování a nesmíte se na to spolehnout. V nové verzi knihovny to může být jinak.

  • 4. 10. 2017 11:23

    Houba (neregistrovaný)

    My se přeci nebavíme o SPI jako takovém, ale o knihovně HAL. HAL = hardware abstraction layer. Já přeci samozřejmě celou dobu _vím_ že SPI, pokud obsahuje obě dvě lajny MOSI i MISO, tak je full duplex, a nejde říct zařízení ať to nepřijímá. Proboha.

    Celou dobu jde o to, že HAL definuje TŘI funkce. ČTI, ČTI_a_ZAPIŠ a ZAPIŠ. Vy píšete, že ČTI je jasně specifikovaná. NENÍ. Prostě není, i když se na hlavu postavíte. V dokumentaci se píše, že pouze čte, nepíše se tam to co píšete vy. A teď z logiky věci. HAL má být abstrakce od hardware. Když používáte HAL, tak se spoléháte, že nízkoúrovňově je to uděláno tak, že funkce odpovídají skutečnosti. Selským rozumem i dokumentací, mám-li ČTI, ČTI_a_ZAPIŠ a ZAPIŠ, tak já a další lidi tvrdí, že to má sakra dělat tohle:

    a) ČTI = čti MISO, na MOSI nešahej
    b) ČTI_a_ZAPIŠ = čti MISO a zároveň piš na MOSI
    c) ZAPIŠ = ignoruj co je na MISO, piš na MOSI

    To, co mi furt gripen podsouvá a vy nechápete je, že chcete, aby HAL (=abstrakce) fungovala takhle, a považujete to za správné:

    a) ČTI = čti MISO, na MOSI posílej náhodný bordel
    b) ČTI_a_ZAPIŠ = čti MISO a zároveň piš na MOSI
    c) ZAPIŠ = čti náhodný bordel z MISO, piš na MOSI

    Správně by HAL měl buď:

    a) definovat POUZE funkci ČTI_A_ZAPIŠ, pak by uživatel byl nucen zajistit, aby na linku nešel bordel
    nebo
    b) definovat všechny tři funkce, ale pak musí HAL zajistit, aby při pouhém zápisu nebo pouhém čtení nebyla brána v úvahu druhá linka

  • 4. 10. 2017 11:35

    gripennn (neregistrovaný)

    Požadavek aby funkce ČTI nesahala na MOSI je u duplexního SPI (váš případ) nemožný. Chcete po té funkci aby dělala něco co udělat nejde. Z čehož plyne že na tvrzení dalších lidí a na selský rozum se nelze vždy spolehnout ...

  • 5. 10. 2017 11:15

    Karel (neregistrovaný)

    Pořád píšete věci jako "piš" a "čti". Ale tam jsou dráty, ne zprávy. Zkuste pochopit, že na každém tom drátu je nějaké napětí, které reprezentuje LOW nebo HIGH. Čti nedělá nic jiného, než že si zapíše, jaké napětí na tom drátu v tu chvíli bylo. A piš má dělat co? Smysl má pouze: nastav napětí na LOW, nastav napětí na HIGH nebo tam nech napětí, co tam bylo před tím. Kterou z těch tří věcí si za "piš" představíte právě vy? Petr M tu někde zmínil, že on posílá UINT16_MAX, což jsou samé jedničky. Nechat tam poslední stav znamená posílat poslední bit z předchozí zprávy (takže buď samé nuly nebo samé jedničky, podle toho, čím to končilo). Byly by samé nuly v něčem lepší?

    A dále mě udivuje vaše víra, že HAL nějakou magií dokáže něco, o čem víte, že fyzicky není možné.

    Navíc vámi navrhované řešení A předjímá, že uživatele zajímá, co na linku posílá. Přitom v drtivé většině případů ho to nezajímá. Na SPI má připíchnuto něco, co buď jenom čte (display) nebo jenom píše (senzor). Proč by se měl doprčic zalamovat obsluhou nějakého bordelu, co na nic nemá vliv? Proč plácat paměť na ošetření něčeho, co není důvod řešit? Aby to bylo blbuvzdorné a nutilo lidi myslet? On HAL už takhle stojí za starou belu, ještě aby se tak z něj někdo snažil dělat evangelium za "vývojáři bděte".

    A vámi navrhované řešení B je právě ta víra v magii, že by to snad nějak udělat šlo. Nešlo, ten drát tam je a druhá strana si při hodinovém pulzu tu hodnotu přečte a uloží. HAL nemá jak tomu druhému zařízení říct, že nemá brát v úvahu tu druhou linku. To SPI neumí a název knihovny na tom nic nezmění.

  • 5. 10. 2017 12:21

    Petr M (neregistrovaný)

    Průšvih je v tom, že SPI je full duplex. Vždycky. Podle specifikace jsou to čtyři posuvný registry - jeden v masteru vezme paralelní data a posílá je na MOSI, kde druhý ty data převede na paralelní a naopak, třetí posílá data ze slave na MISO, kde je paralelizuje čtvrtý. Tím končí specifikace. Nikde se neříká, co ty data mají nebo nemají obsahovat.

    No a teď si představte jednoduchou periferku, třeba 4x 12b ADC, kde na vstupu je 8b slovo, ve kterým 0001xxxx je maska povolených kanálů (x povoluje/zakazuje příslušný kanál), 0010yyyy přepíná unipolární/bi­polární režim pro jednotlivý kanály,... Příkazy 0000xxxx a 1111xxxx ignoruje a příkazy se dají serializovat. To je naprosto korektní chování podle specifikace.

    Chceme číst data ze všech čtyř kanálů a nakonfigurujeme si ho. No a protože CH1 načetl poslední hodnotu 0x0012 a nějaký blb mu to teď pomocí HALu pošle zpět, tak už se CH1 nenačte, protože od teď se dojí jenom CH2 - čtyři čtení toho samýho kanálu v řadě. A protože náhodou na něm je hodnota 0x0af5, nic se na tom nezmění...

    Tímhle způsobem se obvod může překonfigurovat úplně náhodně (v závislosti na šumu vstupního signálu) a pěkně blbě se pak taková chyba hledá.

  • 4. 10. 2017 8:19

    Petr M (neregistrovaný)

    To je furt dokola...

    Ve vlastním ovladači, pokud čtu, zapisuju do Tx registru zásadně UINT16_MAX a neměním ho.

    Soudruzi z STM vezmou buffer náhodné velikosti s náhodnými daty a začnou ho blít ven. Krom toho, že to odporuje jejich vlastní specifikaci, kdyby tohle udělal IP stack a během příjmu začal blít na náhodou IP adresu poslední přijatý paket, tak by to bylo nejenom na CVE, ale i na vlastní web chyby...

  • 4. 10. 2017 10:12

    SB (neregistrovaný)

    Houba to píše správně (a to mikročipům nerozumím) - jestliže má být HAL vysokoúrovňovou vrstvou, tak v případě, že chci POUZE číst a mám na to EXTRA funkci, tak přece nebudu ještě za HAL kurva řešit, jak naplnit jakýsi buffer pro zápis sračkama, aby to fungovalo. To pak nepotřebuju HAL. Teprve až budu potřebovat zároveň zapisovat a číst, použiju na to jinou funkci. Co je na tom panu Gripenovi nejasného?

  • 4. 10. 2017 11:25

    Karel (neregistrovaný)

    Tady je problém v tom, že SPI neumí z principu věci nic jako POUZE číst. Tam je prostě pár drátů, které mají nějakou funkci. Jedním z nich jsou hodiny - když tím zahejbám, tak tím říkám druhému zařízení, že má na drátu MISO nastavit další bit a na drátu MOSI si bit načíst. Ty hodiny jsou prostě drát, kde náběžná hrana znamená "teď". Tam není žádný způsob jak druhému zařízení říci "pošli mi další bit ale sám nic nečti". Na to je to rozhraní příliš primitivní.

    Houba tvrdí, že tuhle vlastnost SPI zná. Ale tak proč se diví, že to SPI něco posílá, přestože se funkce jmenuje "Receive"? Vždyť ví, že technicky není možné na SPI jen číst nebo jen psát.

    A druhá věc je, že v dokumentaci není nikde žádné POUZE. V dokumentaci je přesně popsáno, co to funkce deklaruje, že udělá: přijme data. Nedeklaruje, co pošle. Tedy bude posílat nějaký bordel. K čemu ta funkce je dobrá? Ono řada SPI zařízení (senzory apod.) nic nečte. Kolikrát nemají ten drát zapojený, nebo prostě přijatá data nezpracovávají. Proč bych pak měl tedy plácat pamětí na alokaci výstupního bufferu? A na otázku proč neposílat jen samé 0 nebo 1 je odpověď také snadná: protože nechci mít 3 funkce. Tím, že funkce Receive a Transmit jsou jen aliasy pro TransmitReceive ušetřím docela dost paměti. Daň za to je ta, že Receive posílá to, co přijímá, a Transmit přijímá to, co vysílá. Protože ty dva pointery ukazují na stejný blok paměti.

    PS: HAL je zlo a sám bych ho nepoužil. Ale tady v tom konkrétním případě je problém mezi klávesnicí a židlí. Ten pán se diví, že HAL dělá to, co SPI z podstaty věci dělat musí. Buď neví co je SPI, nebo jen doufal, že HAL nějakou magií dokáže něco, co SPI ne.

  • 4. 10. 2017 11:26

    gripennn (neregistrovaný)

    Mě to celkem jasné je. Mýlíte se v tom, že máte EXTRA funkci sloužící ke čtení. Nemáte ji. Ta funkce slouží k něčemu jinému ! Slouží k práci s SPI v simplexním režimu. Jinak řečeno slouží k něčemu jinému než se vy domníváte. Proč nezkoušíte posílat data po SPI pomocí funkce "HAL_UART_Tran­smit()" ? No protože očividně k tomuto účelu neslouží. A stejně tak funkce "HAL_SPI_Receive()" očividně neslouží pro "příjem" po duplexním SPI.

    Pochopte laskavě, že po HALu (nebo jakékoli jiné knihovně) chcete aby provedla nemožné. Píšete že chcete POUZE číst, ale to u duplexního SPI nejde :) Prostě to není to možné. Duplexní SPI nemá nic jako "příjem" ...

    To, že se o to někdo pokouší je jen ukázka toho, že používat knihovny bez porozumění věci (v tomto případě protokolu) je rizikové...

  • 4. 10. 2017 10:03

    mv_

    Ach ... už som pochopil ... zrejme narážate na tento kúsok hneď na začiatku HAL_SPI_Receive:


    if ((hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LI­NES))
    {
    hspi->State = HAL_SPI_STATE_BU­SY_RX;
    /* Call transmit-receive function to send Dummy data on Tx line and generate clock on CLK line */
    return HAL_SPI_Transmit­Receive(hspi, pData, pData, Size, Timeout);
    }

    ... toto je fakt dosť hnus ...

  • 3. 10. 2017 21:51

    gripennn (neregistrovaný)

    Že se obsah přijímacího bufferu za určitých okolností pošle na SPI sběrnici je vcelku přirozená věc. Umožňuje vám totiž řetězit SPI slave zařízení za sebe (daisy chain). I když se to na první pohled nezdá SPI není až tak primitivní protokol a je prostě potřeba trochu opatrnosti při používání. U I2C taky člověk z ničeho nic nezavolá funkci "receive" a nezačne nadávat, že místo přijmu to začalo vysílat adresu ....

  • 3. 10. 2017 21:58

    Houba (neregistrovaný)

    O tom se přeci ale nebavíme, že ne. Odpověď viz. výše.

    A poprosil bych, kdybyste se to snažil pochopit.

  • 4. 10. 2017 20:58

    PetrM (neregistrovaný)

    Posílat náhodný blok dat z náhodné adresy ven z brouka na jakoukoliv lajnu je z principu špatně. I kdyby na to brouk na druhým konci nereagoval. Je to chyba na úrovni heartbleed a dá se takhle osciloskopem chytnout část paměti.

    Existují čtyři možnosti, jak MOSI zabít:
    a) Pollling (čekání na flag ve smyčce): po přijetí bytu hodit do vysílacího registru UINT16_MAX a odvysílat.
    b) Interrupt (obsluha přenosu v přerušení): Přerušovací rutina zajistí odvysílání UINT16_MAX
    c) DMA: vyrobím si konstantu va FLASH s hodnotou UINT16_MAX, dám pointer na ni do vysílacího kanálu DMA a přepnu do režimu "konstantní pointer".
    d) Univerzální řešení, překonfigurovat MOSI na GPIO OUT a picnout tam hodnotu natvrdo (to už je s HALem na rychlý rozhraní hodně velká drsárna, vyplnění komplet konfigurační struktury a její nahrání do portu).

    Takže opravdu není důvod tam cpát jakýkoliv buffer. Ani náhodný, ani inicializovaný. Prostě to zase nezvládli.

    A kdyby to soudruhy v ST napadlo, mohli tam do registru hodit bit BLOCK_TX který by tam ty jedničky prostě rval sám... Ale jeden bit v registru a jedno hradlo OR na výstupu shift registru by asi už nedali.

  • 4. 10. 2017 22:44

    gripennn (neregistrovaný)

    To je marná diskuze. Napřed tu stále dokola čtu, že fce "receive()" nemá na MOSI dávat nic. Po dlouhém přesvědčování vyjde najevo, že je to nesmysl protože na MOSI něco být musí. Pak aby si tu někdo nemusel přiznat, že si prostě vybral špatnou funkci, začne tvrdit, že "receive()" má na MOSI sypat jedničky. Proč proboha jedničky ? :D Proč ne nuly nebo proč ne sekvence 010101010101010101 ...

    Zkusím to naposledy, funkce receive() je určena pro SPI v simplexním režimu. Nemáte ji volat v duplexním režimu, k tomu účelu ji nikdo neprogramoval. Nemá smysl jí dávat jakékoli parametry pro MOSI, protože když ji voláte v situacích k nimž je určena, žádný MOSI vývod neexistuje :)

    Ale jestli si chcete zanadávat mám pro vás pár tipů:
    a) Vypněte timer a volejte fci "TIM_SetCompare1()" - můžete pak nadávat že na výstupu není PWM ačkoli volání fce by ji mělo přece nastavit... zase to v ST zvorali...

    b) nastavte DAC na trigrování timerem a volejte fci "DAC_Software­TriggerCmd()" - můžete nadávat že i když voláte trigger na DAC, tak on ne a ne vyhodit příslušné napětí ... zase to v ST zvorali

    a takovými ukázkami použití funkce, která nemá při dané konfiguraci periferie smysl, by se dalo pokračovat ještě dlouho. A do tohoto seznamu patří i SPI_receive() s SPI nastaveným na duplex...

  • 5. 10. 2017 9:03

    Petr M (neregistrovaný)

    1. Kde v dokumentaci je zmínka o simplexním nebo duplexním režimu?
    2. Samý jedničky odpovídají nezapojené lince s pullupem. Je to nejbezpečnější varianta a nepsaný standard pro ošetření.
    3. Obvody na SPI jsou z pohledu specifikace dlouhý shift registr a když do nich začnu nasouvat nějakou hodnotu, v okamžiku uvolnění CS se tato změna aplikuje. Pokud tam během přenosu nashiftuješ něco, co vypadá smysluplně, máš problém.
    4. Blít ven náhodný data je vždycky špatně, i pro simplex. Protože SPI se dá sdílet (několik CS na GPIO, například) a data tak můžou být vyvedený z pouzdra do jinýho brouka. A teď si představ, že je to třeba na STM32F439 (LAN + display + ext bus + crypto) a takhle ti to náhodně vybleje klíč k update firmware, který je jinak uložený interně ve FLASH. Na tohle diletantství prostě není omluva.

  • 5. 10. 2017 11:27

    Karel (neregistrovaný)

    On ale nebleje náhodně data z paměti. Ven posílá to, co přijímá. Odesílací buffer se neodkazuje na náhodné místo v paměti, ale je shodný s bufferem pro příjem. Takže po MOSI nejde nic, co nepřišlo po MISO. Nejsem si jistý, že by to bezpečnost nějak zhoršovalo, protože připojení brouci vidí MOSI i MISO. Pokud tedy nějaká periferie po MISO posílá klíč k update firmware, tak už je celkem jedno, že to master zopakuje i na MOSI. Pletu se?

  • 5. 10. 2017 11:45

    Houba (neregistrovaný)

    Pletete se. Můžou nastat dva stavy: buď budete posílat náhodná data z paměti jen při prvním čtení, nebo při každém čtení. To podle toho, jak alokujete ten buffer.

    Je to prostě prasárna, to to sakra nevidíte ?

  • 5. 10. 2017 11:41

    Houba (neregistrovaný)

    Můžu se Vás optat, kde jste přišel na to, že funkce HAL_SPI_Receive je jen pro simplexní režim ?

    Ta funkce začíná takhle, a pro master režim se provede tohle (všimněte si, SPI_MODE_MASTER a SPI_DIRECTION_2LI­NES):

    HAL_StatusTypeDef HAL_SPI_Recei­ve(SPI_Handle­TypeDef *hspi, uint8_t *pData, uint16_t Size, uint32_t Timeout)
    {
    #if (USE_SPI_CRC != 0U)
    __IO uint16_t tmpreg = 0U;
    #endif /* USE_SPI_CRC */
    uint32_t tickstart = 0U;
    HAL_StatusTypeDef errorcode = HAL_OK;
    if((hspi->Init.Mode == SPI_MODE_MASTER) && (hspi->Init.Direction == SPI_DIRECTION_2LI­NES))
    {
    hspi->State = HAL_SPI_STATE_BU­SY_RX;
    /* Call transmit-receive function to send Dummy data on Tx line and generate clock on CLK line */
    return HAL_SPI_Transmit­Receive(hspi,pDa­ta,pData,Size,Ti­meout);
    }

    Já tam naopak vidím, že funkce Receive pro dvě lajny provede tu nebetyčnou prasárnu, o které se tu celou dobu bavíme. Způsob, jakým to měli soudruzi v ST ošetřit, Vám tu podal vyčerpávajícím způsobem Petr M.

    Proč se proboha pořád snažíte obhájit _takovou_ prasečinu ?

    Vždyť je to přece totálně _naopak_, než se tu snažíte prezentovat. Každý alespoň trochu při smyslech prostě _očekává_, že MOSI je na definované úrovni, pokud jen čtu MISO, a používám na to HAL (=abstrakci). A ne, že vysypu ven buffer s pitomostma.

    Než budete pokračovat, tak nikde v dokumentaci není že ta funkce je jen pro simplex. Nikde v dokumentaci není, co ta funkce sype ven na MOSI. Naopak pohled do kódu HAL Vás usvědčuje ze lži. Kdybyste to hledal, je to version V1.7.1 ze 14-April-2017 pro STM32F4.

  • 5. 10. 2017 11:52

    cerna karkulka (neregistrovaný)

    Já bych hlavně očekával, že pro SPI na úrovni HAL nic jako funkce Transmitt() nebo Receive() nebude existovat. U SPI dává jediný smysl funkce Transceive(), u čehokoliv jinak nazvaného bych se důkladně pídil po tom, co to vlastně dělá.

  • 5. 10. 2017 19:23

    Karel (neregistrovaný)

    Ach jo. SPI simplex neumí. Takže těžko bude někdo v dokumentaci psát, že je ta funkce pro simplex. Když si přečtete váš první příspěvek, tak jste to právě vy, kdo čekal, že ta funkce simplex bude.

    Fakt, že dokumentace vůbec nepopisuje, co odesílá, neznamená, že neodesílá. Znamená jen to, že vám neslibuje, co se bude posílat.

    Co posílá vidíte sám (pData):
    return HAL_SPI_Transmit­Receive(hspi,pDa­ta,pData,Size,Ti­meout);

    Prasečina to je, to jsem nikdy nevyvracel. HAL prostě je špatně udělaný. V čem vám celou dobu oponuji je to, že vás překvapilo, co ta funkce dělá. To vás nemělo jak překvapit. Zaprvé znáte SPI, takže víte, že to (navzdory názvu) něco posílat bude. A za druhé vidíte, že v dokumentaci není popsáno co, takže je vám jasné, že to bude posílat bordel, na který nebude spoleh. Vy jste tuhle funkci prostě neměl použít - a to vám mělo být jasné už z její dokumentace, která se vůbec nezmiňuje o tom, co to posílá. Pokud víte, že to nesmí posílat bordel, tak máte sáhnout po funkci, která pošle to, co chcete.

    V textu zmiňujete "MOSI je na definované úrovni". To jste si opravdu nikdy nevšiml, že vy žádnou úroveň nedefinujete? A že ani SPI specifikace nic takového nemá? Když podle vás existuje taková definovaná úroveň, tak kde tedy přesně tu definici máte?

  • 5. 10. 2017 11:51

    Houba (neregistrovaný)

    Valná většina periferií, kromě speciálních případů, na MOSI v pull-upu na H, bude buď nereagovat, nebo reagovat nedestruktivně (=nebude třeba do paměti nebo vnitřních registrů zapisovat). Jak psal Petr M., je to nepsaný standard.

    Návrháři periferií nejsou magoři, pro to aby byl do periferie vyslán příkaz, tak je potřeba v 99 procentech případů vyslat něco jiného než je 0x00 nebo 0xFF. A to je celé jádro pudla té prasárny v HAL !!!!!

    Ta tam totiž pošle zcela náhodný buffer.

    To je to fakt tak strašně složité na pochopení ?

  • 5. 10. 2017 15:44

    gripennn (neregistrovaný)

    Ok. Funkce receive() má vysílat jedničky ... jen doufejte, že na druhém konci planety není někdo zastávající opačný názor, tedy že funkce receive() má vysílat nuly. Konec konců, běžně se programuje tak, že se člověk podívá na funkci, řekne si ... "Kdybych ji psal já tak by na MOSI cpala jedničky, v komentáři o tom nic není, takže to určitě dělá." ... a pak se funkce použije.

    Nicméně souhlasím, že by hodně lidí ocenilo funkci, která čte z MISO a na MOSI cpe volitelnou konstantu...

    Stejně tak souhlasím že fce HALu (resp LL nebo SPL) jsou málo komentované (člověk se z nich moc nedozví k jakému účelu fungují). Ale pořád je to o poznání lepší jak na ARMech od ATMELu, jejich funkce nemají vůbec žádný komentář, ani seznam maker, která mohou být argumentem ...

  • 5. 10. 2017 19:32

    Gripennn (neregistrovaný)

    Taky se v tom ztrácím. Měl jsem za to že vám vadí, že fce SPI_receive() něco vysype na MOSI. Asi jsme se nějak shodli na tom, že když je to full duplex SPI, tak to na to MOSI něco vysypat musí, protože slave chtě nechtě linku MOSI bude číst. Dál jsem vaši argumentaci pochopil tak, že když už to musí něco sypat tak ať to sype samé jedničky. Je to tak ?

    Pokud ano, pak je to funkce "naprd" protože třeba při čtení z tohoto ADC zařve
    (LTC2488) http://cds.linear.com/docs/en/datasheet/2488fb.pdf

    Pokud ne, tak co si tedy představujete, že by SPI_receive() měla při duplexním SPI udělat ?

  • 5. 10. 2017 20:33

    Houba (neregistrovaný)

    Já tomu teda dám šanci. Mě vadí to, že ta přijímací funkce blije ven náhodná data. Důraz je na to slovo náhodná. Také jsem Vám dokázal, že ta přijímací funkce není jen pro simplexní použití, ale dokonce plně počítá s duplexním provozem. Pak jsem Vám taky napsal, že by úplně stačilo, kdyby ta funkce buď vyžadovala po uživateli ten buffer co se bude vysílat (tedy nutila uživatele použít funkci pro příjem i vysílání zároveň), nebo použila pro výstup trvalou definovanou úroveň (1 nebo 0). Pak jsem Vám napsal, že návrháři periferií nejsou idioti. No a vy jste kontroval datasheetem, že když to pohrne samé jedničky tak je to k ničemu.

    No vida, a když otevřete ten datasheet, tak skutečně zjistíte, že návrhář nebyl idiot. Já tam vidím pro bajt přijatý po SPI tohle:

    1 | 0 | EN | SGL | ODD | A2 | A1 | A0

    Aby ten čip reagoval na vstup po MOSI, tak ty první dva bity musí být 10. Ne 11, a ne 00. Pokud tam tedy bude trvalá úroveň, tak ten šváb nijak reagovat nebude. Pokud se ale vyskytnou na sběrnici náhodná data, tak po detekci 10 v těch náhodných datech se Vám právě začne přepisovat registr. Vždyť tohle byl přesně ten problém, na který jsem upozorňoval v tom prvním postu.

    Vy budete argumentovat, že v tomhle případě ale použijete funkci TransmitAndReceive, tedy zapisuj a čti zároveň. Ano, v tomto případě je to vyžadováno, protože ADC nepošle žádná data na MISO, dokud mu nedojde ten jeden bajt. Jestli dobře vidím, tak posílá 4 bajty zpět. Pro řízení tohohle švába teda stačí naalokovat 4-byte buffer, do prvního bajtu hodit ten konfigurační bajt, do zbytku 0x00 nebo 0xFF protože šváb to bere jako don't care, a po provedení transferu máte v těch čtyřech bajtech výsledek. Easy, nelze tady použít špatnou funkci, protože funkce pouze pro čtení se Vám sem nehodí.

    Ale ten ADC, o kterém jsem mluvil já, nic takového neměl. Vy jste ho nakonfiguroval, pomocí TransmitAndReceive, a pak Vám zcela automaticky připravoval data pro přenos po MISO. A tam kamarád udělal onu osudnou chybu, když zcela logicky, abstraktně od hardware, použil k tomu přímo určenou funkci ČTI. Přitom by úplně stačilo, kdyby ta funkce čti držela MOSI na 0x00 nebo 0xFF. Na Váš ADC by to taky nemělo žádný vliv.

  • 5. 10. 2017 21:38

    gripennn (neregistrovaný)

    Takže jádro sporu je v tom jak by ta fce "receive()" měla vypadat. Vy navrhujete aby fce "receive()" sypala 0 nebo jedničky aniž by nad tím měl programátor kontrolu. Já říkám, že je to v podstatě stejné jako když sype náhodná data. Když má něco sypat, nechť o tom rozhoduje programátor a předá tu "dummy" hodnotu funkci jako argument.

    Ten datasheet měl poukázat právě na to, že dummy byte složený z log.1 by dělal problémy. Explicitně se tam totiž píše o první trojici bitů, že "Valid settings for these three bits are 000, 100, and 101. Other combinations should be avoided." Jinak řečeno 111 = problém.

    Když tedy bude existovat fce "receive()" bez vstupního argumentu a bude sama sypat někým zvolenou hodnotu (samé jedničky nebo samé nuly) vznikne stejný problém, jaký byl na začátku. Programátor čeká, že receive bude "pouze" číst a ona něco vysype (programátor neví co, protože si stejně jako váš kamarád neprohlídl vnitřnosti funkce). Shodou okolností si zrovna vybere slave který jedničky nebo nuly "nesnáší"(viz výše zmíněné ADC) a požár je na střeše.

    Když bude mít fce "receive()" vstupní argument jaká dummy data má sypat, nastane zase jiný problém. Programátor který má SPI nastavené v režimu "receive only" (tedy simplex) bude hledat fci "receive()" bez argumentu (on přece nic posílat nemůže ani nechce). Protože takovou fci nenajde, bude nadávat na autory HALu, že tam není.

    O tom jestli stávající "receive()" funkce je nebo není pro simplexní použití se můžeme jen přít. V dokumentaci k HALu o tom není zmínka. Já vycházím z předpokladu, že k ničemu jinému rozumně sloužit nemůže (v duplexu sype "náhodná" data), takže proč by tam jinak byla ?

  • 6. 10. 2017 7:07

    Petr M (neregistrovaný)

    "Takže jádro sporu je v tom jak by ta fce "receive()" měla vypadat."

    No konečně, o tohle jde celou dobu. Bavíme se o tom, že je sprasený HAL, ne HW.

    "Explicitně se tam totiž píše o první trojici bitů, že "Valid settings for these three bits are 000, 100, and 101. Other combinations should be avoided." Jinak řečeno 111 = problém."

    Ne, 111x xxxx bude ignorováno (avoided). Proto tam cpu UINT8_MAX nabo UINT16_MAX podle režimu, nepsaná dohoda.

    "Když tedy bude existovat fce "receive()" bez vstupního argumentu a bude sama sypat někým zvolenou hodnotu (samé jedničky nebo samé nuly) vznikne stejný problém, jaký byl na začátku."

    Na C-čku je krásný mj. to, že pokud k funkci dám míň argumentů, tak se program nepřeloží. Stačí přidat argument pro tu hodnotu a je hotovo.

    "Když bude mít fce "receive()" vstupní argument jaká dummy data má sypat, nastane zase jiný problém. Programátor který má SPI nastavené v režimu "receive only" (tedy simplex) bude hledat fci "receive()" bez argumentu (on přece nic posílat nemůže ani nechce). Protože takovou fci nenajde, bude nadávat na autory HALu, že tam není."

    Tak mu napíšu do dokomentace, ať tam střelí libovolnou hodnotu, pokud je MOSI ignorovaný. Nebo zapouzdřím funkci pomocí makra, ať to nežere tolik paměti.

    Eventuálně kdy už se periferka inicializuje vyplněním struktury, která je trvale uložena v handle, může být možnost si tam tu hodnotu předdefinovat...

    Možností, jak neudělat takovou prasárnu, je dost. Jenom myslet (ale to soudruhy od ST bolí).

    "O tom jestli stávající "receive()" funkce je nebo není pro simplexní použití se můžeme jen přít. V dokumentaci k HALu o tom není zmínka. Já vycházím z předpokladu, že k ničemu jinému rozumně sloužit nemůže (v duplexu sype "náhodná" data), takže proč by tam jinak byla ?"

    Je pro univerzální použití. Díval jsem se schválně na dema od ST a byla použita i pro paměti řady 25xx, který v simplex nemají šanci (nutnost zapsat příkaz + adresu).

    Prostě HAL je žumpa a tím bych to asi uzavřel.