Vlákno názorů k článku Dokončení software digitálního termostatu od SB - Nebylo by jednodušší si vést nextRun místo jeho...

  • Článek je starý, nové názory již nelze přidávat.
  • 25. 6. 2015 16:21

    SB (neregistrovaný)

    Nebylo by jednodušší si vést nextRun místo jeho neustálého dopočítávání přes lastRun?
    Nebylo by koncepčnější si vést task, který je ve zpracování první další, a čekat jen na něj místo opakovaného procházení celého pole tasků?

  • 25. 6. 2015 16:48

    Petr Stehlík
    Zlatý podporovatel

    Nevím, který task bude další, protože nevím, jak dlouho bude trvat task současný. Klidně mi pošlete pull request, podívám se, jestli bude váš kód rychlejší, kratší nebo aspoň čitelnější při zachování současné funkčnosti.

  • 26. 6. 2015 8:59

    SB (neregistrovaný)

    Zdroják vám nepošlu, Cčko moc neovládám.

    Myšlenka je jednoduchá: Vložení (setRepeated), smazání a dokončení tasku (loop) provede vždy výpočet následujícího (= jediný průchod polem), pak už se jen čeká na nextRun (testován primitivním porovnáním s okamžitým millis()) uvedený v dopočteném tasku, nebo nastaví přerušení na uvedený čas.

  • 26. 6. 2015 13:00

    Petr M (neregistrovaný)

    To ale vyjde podstatně hůř.

    - Polem se musí procházet vždycky, aby se zjistilo, co spustit.
    - Porovnat dvě čísla znamená odečíst je a testovat zero flag (CMP nebo SUB). INC a DEC taky ovlivní zero flag. Nic na tom neušetřím.
    - Countdown nevyžaduje předpočítání dalšího startu.
    - Pokud se vejdu s dalším spuštěním tasku do 250 ticků systému, stačí u countdownu 8b, u porovnání času je potřeba 16-32b (sestřelí osmibit až hrůza).
    - U countdownu nepotřebuju přepočet před startem.
    - U countdownu, pokud není potřeba logování nebo real time, můžu tick count vyhodit úplně.
    - Tick count by musel být volatile (mění se v přerušení timeru a i v průběhu té funkce), static (aby se nesmazal po vyskočení z té porovnávací funkce) a register (aby se ušetřila polovina přístupu do RAM) současně. U 32b tick counteru a 8b CPU znamená obětování čtyř registrů.

    Na jednočipu, víc než kde jinde, musí být Occamova břitva pěkně ostrá. Nesjou zdroje nazbyt.

  • 26. 6. 2015 13:43

    lojza (neregistrovaný)

    při porovnání dvou čísel se nic neodečítá, ale porovnává se po bytech. Tedy při předpočítání dalšího spuštění v každym kroku 1x sada lds (předpočítané nextRun) a pak sada cp/cpc vůči now, bez předpočítání 2x sada lds (lastRun + interval), sada sub/sbc a sada cp/cpc vůči now. Problém při počítání nextRun by byl možná spíš při přetečení při dlouhodobém provozu

  • 26. 6. 2015 14:43

    Petr M (neregistrovaný)

    Citation needed.

    Odečítají se právě ty byte při tom porovnání. Algoritmus porovnání vícbytovýho čísla do puntíku sedí s rozdílem dvou čísel až na to, že se výsledek zahodí.

    Při porovnání se stav vždycky musí dostat do flagů. Tzn. nějaká "porovnávací" instrukce, ze které vypadne "rovno", "menší", "větší". Ve druhé je podmíněný skok, který testuje flagy.

    Jasně, šlo by na čip zadrátovsat něco ve smyslu 7485, ale proč? Znamenalo by to přivedení dvou sběrnic od registrů jako u ALU, drátovat výstupy do řadiče, další flagy, podmíněný skoky s dalšíma podmínkama pro tytyo flagy a podobný nesmysly.

    Pokud ALU podporuje ADD a SUB, tak není potřeba vymýšlet opičárny navíc. Sběrnice ze dvou registrů tam jsou (zadarmo), odpadne blok komparátoru, SUB/SBC nastaví Z flag, pokud je výsledek nula (rovnost, A-B=0 <=> A=B) a N flag pokud B>A. A v dekodéru instrukcí stačí vyhradit varianty SUB a SBC bez ukládání výsledku (nepošle se write signál do cílovýho registru).

    V AVR architektuře není o komparátoru ani slovo, popis ALU taktně mlčí a v přehledu ASM je u instrukce CP popis Rd-Rr, ovlivněno Z, N, V, C, H, 1 takt. Podobně CPC a CPI, založeno na rozdílu...

    Mrkni třeba na http://www.atmel.com/Images/doc2552.pdf, tabulka na str. 369, instrukce CP, CPC, CPI

    No a je z pohledu rychlosti jedno, jestli bude

    CP R1, R2
    BREQ LaunchTask

    nebo
    DEC R1
    BREQ LaunchTask

    Jenom v prvním případě nebude asi 8b stačit a trochu to nabobtná ;)

  • 26. 6. 2015 14:53

    lojza (neregistrovaný)

    tohle generuje avr-gcc (bavíme se o konkrétní úpravě konkrétní knihovny která se tím kompiluje)
    kód s předpočtem koncové hodnoty

    if (x1 > x2) {
    190: 50 91 09 01 lds r21, 0x0109
    194: 60 91 0a 01 lds r22, 0x010A
    198: 70 91 0b 01 lds r23, 0x010B
    19c: 80 91 04 01 lds r24, 0x0104
    1a0: 90 91 05 01 lds r25, 0x0105
    1a4: a0 91 06 01 lds r26, 0x0106
    1a8: b0 91 07 01 lds r27, 0x0107
    1ac: 84 17 cp r24, r20
    1ae: 95 07 cpc r25, r21
    1b0: a6 07 cpc r26, r22
    1b2: b7 07 cpc r27, r23
    1b4: 08 f4 brcc .+2 ; 0x1b8 <main+0x2e>

    kód bez předpočtu koncové hodnoty

    if (x1 -x3 > x2) {
    1ba: 80 91 08 01 lds r24, 0x0108
    1be: 90 91 09 01 lds r25, 0x0109
    1c2: a0 91 0a 01 lds r26, 0x010A
    1c6: b0 91 0b 01 lds r27, 0x010B
    1ca: 00 91 00 01 lds r16, 0x0100
    1ce: 10 91 01 01 lds r17, 0x0101
    1d2: 20 91 02 01 lds r18, 0x0102
    1d6: 30 91 03 01 lds r19, 0x0103
    1da: 40 91 04 01 lds r20, 0x0104
    1de: 50 91 05 01 lds r21, 0x0105
    1e2: 60 91 06 01 lds r22, 0x0106
    1e6: 70 91 07 01 lds r23, 0x0107
    1ea: 80 1b sub r24, r16
    1ec: 91 0b sbc r25, r17
    1ee: a2 0b sbc r26, r18
    1f0: b3 0b sbc r27, r19
    1f2: 48 17 cp r20, r24
    1f4: 59 07 cpc r21, r25
    1f6: 6a 07 cpc r22, r26
    1f8: 7b 07 cpc r23, r27
    1fa: 08 f4 brcc .+2 ; 0x1fe <main+0x74>


    v té nepředpočítané verzi je úplně to samý co v nepředpočítané + něco navíc, takže je úplně jedno jestli alu komparátor obsahuje nebo ne, protože se volá v obou verzích stejně

  • 26. 6. 2015 16:23

    Petr Stehlík
    Zlatý podporovatel

    Jste na sebe moc přísní. Jádro původní rady bylo IMHO v tom vypočítat po změně fronty, který další task by měl být volán, a pak na něj čekat v krátké smyčce. Zatímco současná implementace nehledá další task jen po změně fronty, ale neustále, protože stejně nemá nic lepšího na práci, takže vlastně běhá v delší smyčce.

    Ve skutečnosti by to ale dle té rady fungovalo špatně, protože když bych náhodou minul ten přesný okamžik, kdy měl být spuštěn další task, tak bych pak nevěděl, který mám vlastně spustit a musel bych znovu celou frontu procházet a hledat, takže bych prd ušetřil, naopak bych to ještě zpomalil. Ta moje současná implementace prostě funguje správně (tj. tak, jak byla zamýšlena) a nemám důvod ji měnit.

  • 26. 6. 2015 16:40

    SB (neregistrovaný)

    Vůbec netuším, o čem píšete...

    Na co budu pořád ve smyčce procházet pole, když v něm je pořát to samé, dokud do něj není něco přidáno, z něj ubráno nebo změněno (což dělají 3 přesně definovaná místa), což jsou k počtu cyklů smyčky zcela ojedinělé události, nehledě na to, že varianta s procházením pole neumožňuje programování časovače na probuzení pro operaci.

    Chcete říct, že „now - t.lastRun >= t.interval“ je stejně rychlé jako „now >= t.nextRun“?

    Máte potřebu řešit bitová harakiri s tím, že to možná přeteče a možná taky ne?

    Dál nemám sílu.

    Autorovi Taskeru děkuji za ušetření mi nejhorší práce, už jen doladím.

  • 26. 6. 2015 18:36

    Petr Stehlík
    Zlatý podporovatel

    Připomínám, že některé z jiných řešení, které jsem analyzoval, už podporu pro přerušení měly. Takže můžete vzít jiné, už hotové řešení. Odkazy na všech 12 jiných projektů jsou na mém blogu (na něj je zas odkaz v článku).