Názory k článku Přístupy k programování STM32

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

    danman (neregistrovaný)

    Super serial. Uz sa tesim na zlozitejsie temy ako casovace, prerusenia a dma a mohla by byt aj komunikacia po usb :)

  • 3. 10. 2017 9:32

    gripennn (neregistrovaný)

    USB opravdu nedám. Dělám výhradně low-level aplikace (časování, regulace, sběr dat a pod.). Nějaké tutoriály na timery mám v betaverzi zde: http://www.pd-nb.cz/avr.html

  • 3. 10. 2017 22:26

    peter (neregistrovaný)

    Ďakujem za výborne spracovené tutoriály!
    Zaujalo ma hlavne riadenie servo motorčeka pomocou PWM módu 1, keďže potrebujem podobné pulzy v blízkej dobe spraviť. Navnadili ste ma na STM32, no potreboval by som synchronizovane riadiť 6-8 kanálov. Rozmýšľal som použiť TIMery dva (trebárs TIM2 a TIM3), čím by som mohol riadiť 8 kanálov/pinov, ale problém ktorý pravdepodobne nastane, že nedokážem oba časovače spustiť naraz.
    Alternatívne som rozmýšľal o použití časovača len na generovanie prerušení a GPIO output piny by som nastavoval ručne v obsluhe prerušenia. Keďže ale potrebujem mikrokontroler externe ovládať či už cez USB CDC alebo USART, bojím sa že MCU môže začať obsluhovať prerušenia týchto periférí, čo mi vnesie nepresnosť do dĺžky mojich pulzov. Ako začiatočník s MCU (hlavne Arduino), ocením akékoľvek tipy.

  • 3. 10. 2017 22:49

    gripennn (neregistrovaný)

    Timery na STM32 lze snadno hardwarově synchronizovat. Jeden timer nakonfigurujete jako master a na interní TRGO výstup mu vyvedete událost "enable". Další timery nastavíte jako slave s tím že na příchod interního TRGI signálu má reagovat spuštěním ("trigger"). Jen je potřeba z tabulek "Internal trigger connection" vybrat slave timerům správný TRGI signál... přirozeně master timer pak musíte spustit až po konfiguraci všech slave timerů. Časem to asi k tutoriálům ( www.pd-nb.cz/avr.html ) přidám.

  • 5. 10. 2017 21:03

    peter (neregistrovaný)

    Ďakujem, naozaj to funguje!
    Našiel som doma povaľovať STM32F103 (takzvaný "blue _p.i.l.l_") a podarilo sa mi to vyklikať v CubeMX. Síce mi zopár hodín trvalo kým sa mi to podarilo rozchodiť ale výsledok je presne taký ako ste hovorili. Timery sú krásne zosynchronizované. Takto môžem generovať synchronizované pulzy presnej dĺžky na niekoľkých kanáloch, bez toho aby som sa musel báť že mi časovanie nabúrajú prerušenia napr. vyvolané komunikáciou na perifériách.
    Moje predchádzajúce riešenie, ktoré bolo postavené na arduine, som ovládal cez prerušenia vyvolané časovačom. Pre dosiahnutie presnosti som musel, vypnúť všetky ostatné prerušenia a kvôli tomu som musel obetovať riadenie cez sériový port. Toto riešenie je o dosť lepšie.

  • 5. 10. 2017 21:47

    gripennn (neregistrovaný)

    jj, je to otázka tří funkcí. Na master timeru (např TIM2) vybrat událost:

    TIM_SelectOutput­Trigger(TIM2,TIM­_TRGOSource_E­nable); // povolení/spuštění timeru vyvést na TRGO

    na slave timeru (např TIM5) vybrat zdroj signálu (dle tabulek z datasheetu) a událost jak s ním naložit:

    TIM_SelectInput­Trigger(TIM5,TIM­_TS_ITR0); // využít input ITR0 (TRGO z TIM2)
    TIM_SelectSla­veMode(TIM5,TIM_­SlaveMode_Trig­ger); // s příchodem ITR spustit/povolit timer

    pak už jen stačí spustit TIM2 a je synchronizováno (za předpokladu že strop timerů je stejný nebo alespoň soudělný). Možná vás podceňuji, ale pokud generujete PWM nezapomeňte si zapnout "preload":

    TIM_OC1Preload­Config(TIM2, TIM_OCPreload_E­nable); // preload na TIM2_CH1

    Jinak se vystavujete riziku zmršené waveformy při změně PWM hodnoty.

  • 23. 3. 2018 11:02

    Mard (neregistrovaný)

    No jen podořtknu že to je využití standard pepripherial library. Já osobně také používím SPL, protože s tím spáchám všechno. A pokud potřebuji tak si pro nový čip SPL ohnu ze staršího typu.

  • 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 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.

  • 3. 10. 2017 10:35

    MV (neregistrovaný)

    Dovolil bych si poznamenat, že implementace čekací smyčky (delay) postrádá kvalifikator volatile u iterační proměnné. Při kompilaci s optimalizací by se totiž mohl překladač rozhodnout, že to je celkem zbytečný kód, co nic nedělá a vlastně i zbytečná funkce. https://en.m.wikipedia.org/wiki/Volatile_(computer_programming)

  • 3. 10. 2017 10:52

    dustin (neregistrovaný)

    Když vidím tu smyčku - opravdu má smysl provozovat takový hardware bez více "běžících" vláken?

  • 3. 10. 2017 11:21

    Petr M (neregistrovaný)

    Na knihovnách od STM evidentně jo. Tam se tenhle způsob používá by defaut, i když si v STMCube vygeneruješ projekt s FreeRTOSem :Q :Q :Q

  • 3. 10. 2017 11:43

    gripennn (neregistrovaný)

    Pokud tím HW myslíte STM32 tak nepochybně ano. Z mého úhlu pohledu jsou STMka užitečná i když na nich neběží žádný sofistikovaný kód a to hlavně kvůli periferiím. Často dělám přesné časování (STM zvládá na jednotky až desítky ns), občas nějaký rychlejší sběr dat (tam člověk ocení DMA a slušnou RAM). Někdy je zase potřeba chrlit z DA převodníku nějaký průběh. A to všechno se schopností rychle reagovat (~1us) na nějaké vnější změny. Žádná rozumnější platforma mě nenapadá (FPGA je na spoustu věcí overkill). A to vše jde většinou ovládat relativně primitivními programy...

  • 3. 10. 2017 11:50

    trumbera (neregistrovaný)

    Ono někdy je použití HAL knihoven je už příliš náročné (jsou nabobtnalé a plné chyb), natož ještě mít něco jako jádro os na vícevláknovou podporu ... to aby jste tam pak dal ještě jeden procesor :-)

    Hodně záleží na aplikaci.

  • 3. 10. 2017 13:26

    dustin (neregistrovaný)

    Přiznám se, že prakticky to teprve budu na STM32F1 v následujících měsících řešit, zatím jsem si s tím jen celkem úspěšně hrál, ale nepředpokládám výkonové problémy s http://www.chibios.org/dokuwiki/doku.php?id=chibios:kb:timing . Bez vláken bych se do svého projektu neodvážil.

    Takováto čísla jsem při testování na Maple mini za $3 taky dostal (např. > 900tis. kontext switchů vláken/s - http://chibios.sourceforge.net/reports/STM32F103-72-GCC.txt , zdroják testu https://github.com/ChibiOS/ChibiOS/blob/master/test/rt/source/test/test_sequence_013.c#L338

  • 3. 10. 2017 15:40

    Ladislav Michl (neregistrovaný)

    Jen tak pro zajímavost, k čemu tam ta vlákna potřebujete? Procesor je jen jeden a všechny vnější události se projeví jako přerušení (i "poll style" může být přerušení časovače). "Hlavní vlákno" pak buď nedělá nic nebo zpracovává v přerušeních a DMA kanály nasbíraná data, případně řeší power management.

  • 3. 10. 2017 16:36

    dustin (neregistrovaný)

    V projektu s dost rozsáhlým GUI (touchscreen TFT) běží řada tasků:
    * příjem a zpracování zpráv z několika sériových portů - na některé se reaguje změnou GUI, některé se jen přeposílají dál na jiné porty
    * čte analogové porty a posílá zprávy na porty
    * čte touchscreen a reaguje na to - sama knihovna UGFX https://ugfx.io/ používá řadu vláken
    * GUI má řadu současně běžících časovaných prvků

    Když třeba vstupním vláknem zpracovávám message obdrženou do mailboxu od IRS sériového portu ze vstupu, mohu být klidně přerušen jiným vláknem, které se právě dočkalo v mailboxu dat od IRS AD konverze, jež vlákno zabalí do zprávy a pošle sériákem někam dál. Obě vlákna mohou mít stejnou prioritu a prohazovat se po uplynutí timeslicu - vykreslování GUI bude pomalejší, ale poběží. Nebo může mít jedno prioritu vyšší (třeba zrovna GUI kvůli plynulosti vykreslení), dle potřeby.

    Každý odchozí port má své vlákno se vstupním mailboxem. Když do něj dostane data, probudí se a zprávu odešle. Vlákna generující zprávy nemusí nic zásadního řešit, prostě zprávu pošlou do mailboxu.

    Zprávy jsou brané z předdefinovaného memory poolu, kam se po odeslání zase vrací. OS má statickou správu paměti, nemá malloc/free. Memory pooly mohou případně vlákno bloknout na nastavený čas, pokud je zrovna prázdný. Vlákno paměť buď stihne dostat, nebo má smůlu a musí se zařídit jinak (třeba zkusit to znovu). Ale to je klasika...

    Nechci vše míchat do jednoho kódu, když mohu pro jednotlivé funkčnosti vytvořit vlákna a miniOS si je sám časuje/přepíná. Vláknům lze nastavovat různé priority, pre-emptivně se přepnou dle potřeby (přijde interrupt od periférie, "vyprší" softwarový timer od scheduleru, přijdou očekávaná data do mailboxu atd.).

    Samozřejmě to vyžaduje správně pracovat se zamykáním, ale to je normální, to samé musím řešit v pythonním prototypu celého řešení (několik STM32 + PC), na kterém zatím dělám.

  • 3. 10. 2017 17:24

    Sten (neregistrovaný)

    Nešlo by to řešit kooperativním multitaskingem založeným na message loop, případně korutinách? To žádná vlákna nepotřebuje. IMO plnohodnotný pre-emptivní multitasking je na takovém procesoru overkill.

  • 3. 10. 2017 17:37

    dustin (neregistrovaný)

    Proč bych si komplikoval práci loopem, když mohu použít OS přímo určený pro STM32, pro jehož výrobce jeho autor pracuje? U takto rozsáhlého programu by mi z loopu hráblo...

  • 3. 10. 2017 20:49

    Ladislav Michl (neregistrovaný)

    Co jste popsal výše vlákna zcela určitě nepotřebuje a nezbývá než popřát, aby Vám nehráblo později, až budete v tom "OS přímo určeném pro STM32" hledat nějaké podivné chování, které se projevuje pouze u zákazníka. STM32F103 a "rozsáhlý program" se tak trochu vylučují, ne? ;-) Pro zajímavost potom napište, zda se zvolené řešení osvědčilo neboť moje zkušenost říká, že u podobných projektů je každá další abstrakce spíše na škodu.

  • 4. 10. 2017 8:20

    dustin (neregistrovaný)

    Každý si ve finále píše nějakou knihovnu funkcí, viz post Petra M výše o vlastním přepínání vláken. Ten "OS" je také jen sada funkcí a maker od člověka, který práci s tímhle MCU rozumí nesrovnatelně víc, než já, a ten OS dělá přes 10 let.

    Potřebuji zpracovávat paralelně běžící tasky se stejnou i různou prioritou (tj. i načasované přehazování) a nemíním to přepínání psát sám, když mohu využít něco hotového odladěného s ochotným supportem (vyzkoušeno). Do 120kB fleš se vejde už docela složitý program.

    Rád se pak podělím o zkušenosti. Zdrojáky budou stejně na githubu.

  • 4. 10. 2017 21:14

    PetrM (neregistrovaný)

    Asi takhle... Mám program s FreeRTOSem na STM32F4, kde běží 15 vláken. Dělá grafiku na TFT 800x480 s touchscreenem, komunikaci po dvou UARTech, měření pěti analogových kanálů, ovládání výstupů, správa několika rozhraní, FLASH disk v externí NOR FLASH a obsluha NFC. Sakum prdum včetně fontů, tabulek zvuků přes PWM generovaných a podobných blblin 130kB FLASH + 40kB RAM.

    A ten komfort, když všechno řeším nezávisle... Třeba audio. Přijde zpráva, vlákno se probere, vezme číslo zvuku, podívá se do tabulky, kde jsou data jako vektory významem (tón, délka), a jeden po druhým pouští do PWM a schrupne si. Mezi tím se děje něco jinýho, ale to nemusím při psaní audia řešit. Co mě zajímá je jenom fronta, do které spadne kód zvuku, jinak je to autonomní program a mimo initSound()m, playSound() a enum s předdefinovanýma zvukama o něm nevím. Je to těžce návykový.

  • 5. 10. 2017 0:29

    dustin (neregistrovaný)

    Přesně takhle to budu psát. Vlákna komunikující frontami, každé si řeší to svoje. Tu část prototypu v pythonu, která bude běžet na MCU, dělám s ohledem na možnosti a principy programování toho MCU. Zatím skoro všechno mám v chibios k dispozici, samozřejmě kromě správy paměti.

  • 5. 10. 2017 9:01

    rrrobo (neregistrovaný)

    A keby ste aj nejake ukazky toho celeho nejake zverejnil, aby sme sa aj my ostatni nieco naucili a nerobili len while(1) { ... zapni led sleep vypni led sleep }?

  • 5. 10. 2017 11:55

    Kiwi (neregistrovaný)

    Je vidět, že o tématu nemáš ani šajna. Nemáš vůbec představu o (ne)náročnosti implementace vláken, dokonce ani nevíš, jak jsou kooperativní a preemptivní multitasking implementované.
    Mimochodem, ty procesory jsou výkonnější než PDP-9, na němž vznikal Unix.

  • 5. 10. 2017 19:59

    Karel (neregistrovaný)

    "Vícevláknový systém" je široký pojem zahrnující celou řadu nástrojů s velmi různou náročností na implementaci. Podle subjektivních požadavků na tu množinu se dá trvrdit cokoliv od "to je triviální" přes "to bude hodně zatěžovat" až po "to ten procesor neumí".

    Pár z těch nástrojů:

    - context switch - snadné - vyvolá se přerušení, uloží se registry jednoho procesu, načtou se registry jiného procesu a obnoví se běh
    - ochrana paměťového prostoru - nemožné bez MMU - aby jeden proces nemohl číst a přepisovat paměť jiného procesu
    - kooperativní multitasking - triviální - svůj kód prošpikujete příkazem "yield" (SWI), což je volání systémové funkce, kterým říkáte "jestli chce běžet někdo jiný, tak teď je vhodná doba"
    - preemptivní multitasking - může být snadné i těžké - pokud obsluha periferií běží v přerušení, pak je tohle stejně snadné jak kooperativní multitasking. Pokud obsluha běží ve vlákně, tak může být problém, když procesor vlákno přeruší ve špatnou chvíli. To se pak řeší pomocí zákazů přerušení apod., což jsme ale krok zpět ke kooperativnímu multitaskingu
    - virtuální paměť - bez MMU velmi těžké - umět část paměti vlákna odsypat někam jinam a uvolnit tak paměť pro jiné vlákno
    - dynamická alokace paměti - snadné, ale - to ale je v ochraně paměťového prostoru - bez MMU je to celé o dobrovolnosti a bezchybnosti
    - překrývání paměti - bez MMU velmi těžké - to aby vlákna mohla běžet ve stejné oblasti. Paměť se musí při context switchi celá překopírovat. S MMU triviální. Pokud píšu programy relokovatelné, tak to řešit nemusím. Stejně tak když každé vlákno bude jinde
    - mezivláknová komunikace - snadné až těžké - podle toho, zda to chci jet v režii vláken (dohodnou se na semaforech) nebo v režii OS
    - dynamické zavádění programů - netriviální plus problémy uvedené výše - natáhnout kus kódu do paměti a ten spustit jako další vlákno

    Takže pokud je požadavek: mám jen jeden program, který obsahuje více vláken, která se mezi sebou dobrovolně přepínají (kooperativní multitasking), přístup ke sdíleným datům si řeší semafory ve vlastní režii a nepotřebují vyšší funkce OS jako je dynamická alokace paměti, pak se to dá napsat snadno i na STM32 a na výkonu se to nepozná. Pokud ale někdo čeká, že bude mít na SD kartě kusy kódu, které bude zavádět do paměti a spouštět, tak to už ho čeká pořádný kus práce. STM32 má Supervisor mód, takže toho dost udělat půjde. Ale nemá MMU. Na to už by byl potřeba Cortex-A.

  • 5. 10. 2017 20:10

    dustin (neregistrovaný)

    Nejsem žádný specialista, ale preemptivní přepínání v tom OS řeší přerušení od hw časovače, v němž běží kód scheduleru. Má to time slicy, příp. umí tickless režim - ví, kdy se má co probudit, tak si časovač nastaví na daný čas. Takže není potřeba, aby se vlákno vzdalo kooperativně, scheduler si je sám přehodí, pokud zrovna neběží v nějaké kritické sekci.

    MMU to samozřejmě nemá, tudíž nemůže alokovat paměť, je to celé dělané staticky.

  • 6. 10. 2017 0:30

    Kiwi (neregistrovaný)

    ad ochrana - Cortexy M0+ a M3 a výš sice nemají MMU, ale mají MPU. Je ovšem otázka, je-li to k něčemu v praxi dobré. Nejsme na desktopech, aby si BFU instalovali a spouštěli neznámé programy, obvykle přesně víme, co v daném zařízení máme a proč a selže-li daný kus softwaru, znamená to znefunkčnění celého zařízení (jinak by tam daný kus kódu vůbec nemusel být). Nějaký význam bych viděl především při ladění, ovšem psát MPU-aware kód jen kvůli tomu, aby mi při ladění vyskočil MemFault, mi připadá jako zbytečné. V embedded světě je důležité dodržovat určitou sebekázeň a zásady, které by na desktopech mohly snad působit poněkud rigidně a zbytečně, ovšem tady nepředstavují zásadní problémy, ale zásadním způsobem právě tyto možné chybové stavy omezují. Mimochodem velké procento potenciálních MemFaultů zachytí i HardFault, který je na všech Cortexech, protože chybná hodnota pointer mnohdy namíří do neobsazené paměti nebo přepíše data v zásobníku, což následně HardFault způsobí. Chce to určitý cvik, zkušenosti a intuici při ladění. Začátečníci z toho mohou mít noční můry, ale po nějakém čase už člověk pozná, odkud vždycky vítr vane.

    ad kooperativní - na první pohled triviální, na druhý méně. Yield je jen vyvolání plánovače, které v preemptivním případě neřeším, zatímco v kooperativním to řešit musím já místo nějaké obsluhy časovače. I v kooperativním multitaskingu musím mít plánovač, který naplánuje další proces k běhu, i zde musím mít rutinu pro přepnutí kontextu. Z hlediska jádra OS je rozdíl minimální, z hlediska aplikačního vývojáře je kooperativní multitasking náročnější. Sice se zjednoduší kritické sekce, ale za to se zkomplikuje vše ostatní, protože aby to celé fungovalo, musí kooperovat každý z procesů, nejen ty, co vzájemně sdílejí nějaké prostředky, jako tomu je u preemptivního multitaskingu. Kooperativní multitasking má IMHO smysl jedině na platformách, kde chybí systém přerušení nebo časovač, což jsou v dnešní době prakticky jen případy různých zákaznických chipů obsahujících procesorová jádra v nějaké minimalističtější variantě.

    ad virtuální paměť - na mikrořadičích mi tato věc připadá poněkud perverzní, nicméně i to je řešitelné čistě programovými prostředky pomocí různých memory poolů apod., pokud by bez toho někdo nemohl žít

    ad dynamická alokace - na MCU je vše otázkou dobrovolnosti a bezchybnost. Je to opravdu úplně jiný svět oproti desktopům a přenášení některých (zlo)zvyků z desktopového prostředí na mikrořadiče je cesta do pekel. Na MCU se obvykle toto nedělá a profi standardy dynamickou alokaci paměti mnohdy explicitně zakazují, což přispívá k předvídatelnosti a testovatelnosti daného řešení. Nicméně i malloc() a free() jsou otázkou dobrovolnosti a bezchybnosti, pokud chceme, aby náš desktopový program fungoval. U mikrořadičů je třeba vnímat to celé en bloc jako jeden program - mikrořadičem něco řídím a nefunguje-li nějaká část jeho programového vybavení, tak to zařízení zkrátka nebude fungovat správně - a tedy stručněji: nebude fungovat. Správně navržený a fungující program ale zase nepotřebuje ochrany paměti.

    ad překrývání - ve skutečnosti to je ještě těžší. Nestačí překopírovat, je třeba mít i nějaký GOT. Dost záleží na překladači, zda-li vůbec umí generovat takový kód. Obecně platí co v minulých bodech - jsme na MCU, ne na desktopech, ergo má-li někdo nutkání toto potřebovat, asi přemýšlí nějak špatně. Jinak sdílení kódu více vlákny je samozřejmě triviální - stačí nemít žádná statická data.

    ad komunikace - ta je snadná tak i tak

    ad dynamické zavádění - viz předchozí body, nicméně někdy se i v tomto světě dynamické zavádění vyžaduje, pak záleží spíš na bezpečnostních standardech, bude-li to náročné nebo jednoduché (viz např. instalace appletů na smart karty dle ETSI).

    MMU v embedded světě je poměrně zbytečná věc; lidé z desktopů všeobecně mají velmi zkreslené představy o tom, jak se dá co řešit, protože na desktopech se dané věci musejí řešit velmi univerzálně a tedy komplikovaně, aby byly dostatečně robustní, a pro aplikační vývojáře jsou to obvykle jen jakési černé skříňky, nebo spíše obrovské černé skříně. Proto si pod stejnými pojmy představí tyto černé skříně i v embedded světě, nechápou, jak je možné navrhnout řešení, které dostane certifikát bezpečnosti, který by Linux nikdy nedostal, přestože daná platforma nemá žádnou MMU apod. Je to dané vysokou specifičností a úzkým záběrem, který dané řešení musí obsáhnout. Díky tomu v embedded řešení spousta kódu vůbec nemusí být přítomna a kód, který neexistuje, nemůže být zabuggovaný, ani ho nelze exploitovat. V tom to celé vězí. V jednoduchosti je krása.

  • 6. 10. 2017 13:37

    Sten (neregistrovaný)

    I v kooperativním multitaskingu musím mít plánovač, který naplánuje další proces k běhu, i zde musím mít rutinu pro přepnutí kontextu. Z hlediska jádra OS je rozdíl minimální, z hlediska aplikačního vývojáře je kooperativní multitasking náročnější.

    Ten plánovač v kooperativním multitaskingu je mnohem jednodušší, protože nemusí řešit čekání na podmíněné proměnné či čekající mutexy.

    Sice se zjednoduší kritické sekce, ale za to se zkomplikuje vše ostatní, protože aby to celé fungovalo, musí kooperovat každý z procesů, nejen ty, co vzájemně sdílejí nějaké prostředky, jako tomu je u preemptivního multitaskingu.

    Jenže správné zamykání je hodně komplikované a náchylné na vážné a velmi obtížně laditelné chyby (třeba různé Heisenbugy), zatímco kooperaci lze velmi snadno vyřešit třeba smyčkou zpráv, a protože je synchronní, nemění debugging její chování. Navíc bez MMU stejně musí procesy kooperovat a, jak sám uvádíte, „mikrořadičem něco řídím a nefunguje-li nějaká část jeho programového vybavení, tak to zařízení zkrátka nebude fungovat správně“.

    Kooperativní multitasking má IMHO smysl jedině na platformách, kde chybí systém přerušení nebo časovač, což jsou v dnešní době prakticky jen případy různých zákaznických chipů obsahujících procesorová jádra v nějaké minimalističtější variantě.

    Přerušení a časovač má i Arduino, přesto se tam preemptivní multitasking nepoužívá.

  • 6. 10. 2017 14:18

    Kiwi (neregistrovaný)

    > Ten plánovač v kooperativním multitaskingu je mnohem jednodušší, protože nemusí řešit čekání na podmíněné proměnné či čekající mutexy.

    Plánovač se zabývá jen procesy připravenými k běhu a procesem běžícím. Ostatní pro něj neexistují, takže ve skutečnosti vůbec žádný rozdíl mezi kooperativním a preemptivním plánovačem není.

    > Jenže správné zamykání je hodně komplikované a náchylné na vážné a velmi obtížně laditelné chyby

    Je-li třeba v prostředí kooperativního multitaskingu dodržovat nějaké časování, např. kvůli síťové komunikaci nebo periodickému měření, stejně se kritickým sekcím obvykle nelze vyhnout - yield se prostě zavolat musí, nikoli protože už to s klidným srdcem lze, ale protože čas si hlídám sám místo chybějícího přerušení časovače. Dalším případem je reentrance - typicky u různých event handlerů, operujících nad statickými objekty.

    > Přerušení a časovač má i Arduino, přesto se tam preemptivní multitasking nepoužívá.

    Arduino je především amatérský hobbybastl, dětská hračka. Stejně tak odrážedlo pro děti taky nemá převodovku.

  • 6. 10. 2017 8:07

    Petr M (neregistrovaný)

    No kdysi jsem si zkoušel napsat OS core na MSP430. Vyšlo to na cca 350B FLASH + 20+(počet vláken * 4)B RAM + kousek zásobníku + 1x timer. Fakt primtivní. I bez MPU a podobných kravin.

    Překrývání paměti nepotřebuješ. Co chceš překrývat ve třeba 64kB RAM? Dynalická alokace se taky omezuje na nějaký pool (třeba widgety a texty na displeji, který s novou obrazovkou mažeš). A na vytvoření dál statických struktur jako thread, fronta, mutex,... při initu a ani to není povinný.

    Předávání dat je taky easy. Pokud je to jednosměrně z jednoho vlákna, tak stačí volatile proměnná. Když se má vlákno probudit a nebloudit ve smyčce, tak event (jako signalizace pro scheduler, že má zařadit vlákno na seznam) nebo semafor nebo mailbox. Když má vlákno nižší prioritu a může tam být těch dat víc, tak fronta.

    Pokud něco sdílím (třeba společnou EEPROM s konfigurací několika modulů a současný přístup by vedl k problémům, zamknu si to mutexem<a>.

    No a pokud mám vláknu říct, že má pokračovat (třeba se čeká na přerušení od DMA), zařídí to semafor.

    No a víc vlastně většinou ani člověk nevyužije...

  • 3. 10. 2017 15:30

    me (neregistrovaný)

    Super serial. Blikani LED je sice zajimave, presto se uz ted tesim na clanek, ktery objasni, jak pouzit FLASH pamet k emulaci chybejici EEPROM... Nebo bude lepsi pridat externi EEPROM chip?

  • 3. 10. 2017 21:14

    mrazík (neregistrovaný)

    Tohle je zajímavé téma. STM knihovny údajně byly napsány tak obecně, aby umožňovaly snadnou migraci na jinou rodinu MCU. Rutiny pro zápis do flash obsahují, ale abyste je mohli použít, je třeba o tom něco vědět. Například že u některých typů tyto rutiny mohou klidně běžet v jiné oblasti flash a nic dramatického se neděje (maximálně se zakoktá nějaká periferie), u jiných musí běžet v ram, jinak to zhavaruje. Možná to někde v komentářích je, ale hledat to nebudu, ty knihovny taky nepoužívám. Periferie těchto obvodů jsou sice složité, ale pro běžné fungování stačí zapsat do registrů několik málo bitů a je nastaveno. Zkoumat všechny možnosti je nad síly běžného člověka, takže to studuje až když to opravdu potřebuje.

  • 23. 3. 2018 12:31

    Mard (neregistrovaný)

    Používám oboje, podle účelu. Když zapisuji třeba konfigurační bajty, které se až tak často nemění, tak klidně využiji flash. Ale pokud mám nějaké měření třeba (měřič strojového času, který musí vždy zapisovat poslední čas, kdy ještě byl naživu), tak raději použiji sériovou eeprom, které stojí pár kaček a připojí se dvěma dráty. Stejně tak použiji sériovou eeprom pro větší množství zaznamenávaných dat (datalogger). A pro obrovské objemy dat (třeba snímání fotek přes ccd kameru) je asi nejlepší použít levnou SD kartu s filesystémem.

  • 4. 10. 2017 8:27

    Petr M (neregistrovaný)

    Na aktuálním projektu (STM32F4xx) je zálohovaný RTC a k němu 4kB zálohované SRAMky. Stačí povolit v registrech, definovat sekci v ldscriptu a je hotovo... Mrkni do datasheetu.

    FLASH má obrovskou nevýhodu v tom, že je třeba mazat třeba celý 16kB blok...

    Btw, 24Cxx stojí tolik, co baterka a pokud nepotřebuješ RTC, vyjde to mnohem líp.

  • 4. 10. 2017 0:53

    Kiwi (neregistrovaný)

    Nevim, no.. Když to tak pročítám... Nechtěli byste někteří raději zůstat u "programování" webů? Ta Gaussova křivka je holt nemilosrdná a málokdo je ochoten si přiznat, že je v té levé části.