[C++] Cortex M4 - Function execution stoppen

Pagina: 1
Acties:

Vraag


Acties:
  • 0 Henk 'm!

  • diondokter
  • Registratie: Augustus 2011
  • Laatst online: 11:20

diondokter

Dum spiro, spero

Topicstarter
Hallo mede-tweakers!

De situatie is als volgt:
Er is een potentieel langlopende functie die aangeroepen moet worden. (Ga ervan uit dat die functie niet aangepast kan worden en dat deze veilig op elk moment gestopt zou kunnen worden.)
Deze functie mag maximaal een X aantal seconden duren. Als die tijd overschreden wordt, dan zal de executie van de functie moeten stoppen en zal de caller moeten kunnen zien dat de functie timed out is.

De huidige concept setup:
- Start de Watchdog Timer met een timeout op X seconden.
- Call de functie.
- Disable de Watchdog Timer.

De watchdog timer zal na een interrupt gegeven te hebben de MCU resetten als hij niet gedisabled is voordat de X seconden voorbij zijn gegaan.

Dit voldoet dus niet aan de beoogde situatie omdat de hele MCU wordt gereset als de execution te lang duurt terwijl ik wil dat ik gewoon verder kan gaan.

Mijn ideeën:
1. Voer de functie uit als een soort thread. Laadt de instructies beetje bij beetje in, in plaats van als heel blok. Dan wanneer de WDT zijn interrupt geeft, stop met het uitvoeren van de thread.
2. Bij het returnen uit de interrupt, pas de stack en registers zo aan dat de execution niet terug gaat naar de functie, maar naar de caller.

Limitaties:
1. Te weinig kennis over de exacte interne werking van de MCU om mijn ideeën uit te voeren.
2. De code netjes houden is belangrijker dan deze feature.
3. Heel weinig ROM en RAM waardoor exceptions en grote libraries niet mogelijk zijn.

Gebruikte omgeving:
De MCU betreft de ATSAM4ls2b, dit is een Cortex M4 ARM chip zonder FPU.
De programmeeromgeving is Atmel Studio en de daarbij inbegrepen GCC compiler.
Dit betekent dus dat er geen OS is en dat alle memory management zelf beheerd kan en moet worden.

Slot:
Het doel is dus om een extra stukje veiligheid in te bouwen voor als de function niet optijd returnt.

Bedankt voor het lezen en meedenken. Hopelijk heeft iemand een goed idee hoe dit aangepakt kan worden.

Dion Dokter

[ Voor 0% gewijzigd door diondokter op 29-08-2018 19:30 . Reden: Tikfout correctie ]

Beste antwoord (via diondokter op 30-08-2018 11:55)


Verwijderd

Even over hele andere boeg:

Je huidige opzet van een WDT gewoon gebruiken. Als je klant een functie schrijft die blokeert dan is dat een design fout, niet een run-time fout. Idealiter wil je dan informeren dat er een watchdog timeout plaatsvond als gevolg van de klantfunctie. Nog fijner als er een een stackdump bij zit.

Vervang je de watchdog reset door een watchdog interrupt dan kan je deze stackdump wegschrijven naar een log en daarna vanuit de watchdog interrupt een reset forceren.

Vervolgens is het aan de klant om zijn functie te fixen zodat deze geen hackup meer veroorzaakt.

Alle reacties


Acties:
  • 0 Henk 'm!

Verwijderd

Met een RTOS (Real-Time OS) ga je je probleem niet oplossen; je functie zal namelijk gewoon door lopen tot deze klaar is.

Wat je kan proberen is om te identificeren waar de functie veel tijd kwijt is, en daarin een check bouwen voor de timeout.

Meestal zien dergelijke lange functies er ongeveer zo uit:
code:
1
2
3
4
5
6
7
8
9
functie()
{
  setup();
  while(conditie)
  {
    doe_iets();
  }
  cleanup();
}

meestal is het niet doe_iets() dat lang duurt, maar conditie die lang true blijft. Door daar conditie && !timeout van te maken kan je de functie vroewgtijdig afbreken.

Als het wel doe_iets() is dat lang duurt dan moet je kijken waarom dat het geval is. Bijvoorbeeld een SD card schrijfactie die maar niet afgerond raakt. Dan zal je in de SD schrijf routine moeten kijken hoe je deze instrueert om te stoppen op een timeout, of deze moeten aanpassen om een timeout te gebruiken.

Acties:
  • 0 Henk 'm!

  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

De enige nette optie voor je probleem is je functie wijzigen en checks inbouwen danwel opdelen in kleinere kortlopende blokken of states. Al het andere is inferieur.

Eventueel kun je gaan kijken naar longjmp en setjmp. Die doen ongeveer wat je voorstelt om.het normale.executiepad te doorbreken. Maar deze in een interrupt gebruiken is vragen om problemen, als het al werkt. Interrupts worden vaak uitgevoerd in een bepaalde processor modes en daarnaast moeten er interrupt flags etc gereset worden, wat normaalgesproken bij het returnen uit de interrupt gedaan wordt.

In het kort: wat je wilt kan niet netjes als het überhaupt al kan.

Acties:
  • 0 Henk 'm!

  • Josk79
  • Registratie: September 2013
  • Laatst online: 06-10 21:43
Ik ben geen expert op het gebied, maar misschien een idee:

Kun je misschien van buitenaf een exception forceren in de functie? Bijv. door een gebruikte resource te sluiten?

Acties:
  • 0 Henk 'm!

  • 3V3RT
  • Registratie: Januari 2004
  • Laatst online: 16-08 22:30
Ipv een watchdog timer kan je een van de drie 16-bit timers in dat ding gebruiken en dan een approach met register/pc saving proberen (e.g. context switching) proberen, maar dan ben je al vrij gauw een bare-scheduler aan het schrijven en je trekt een doos van pandora open als je niet veel ervaring met deze specifieke mcu hebt.

Ik zou gewoon zoals @EddoH zegt de functie opdelen en checks invoeren (bijvoorbeeld met behulp van een timer die je checkt). Ik weet niet hoe precies die timeout moet zijn, en hoelang je langste "atomische" functie duurt, maar dan zou je zo dus een vrij accurate timeout kunnen verkrijgen.

Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 27-09 13:03
De enige nette oplossing is een RTOS gebruiken en deze taak op een lagere proriteit zetten dan de caller.

In de "caller taak" ga je wachten met timeout X op een waitable object, die normaal gesproken "actief" wordt door de long running taak in geval van op tijd klaar.

Als de timeout afloopt kun je vanuit de caller taak de background taak verwijderen/stoppen.
Met een RTOS (Real-Time OS) ga je je probleem niet oplossen; je functie zal namelijk gewoon door lopen tot deze klaar is.
Ehm nee. Als er een taak met hogere prioriteit runnable is zal deze op de scheduler tick actief gezet worden en zal deze taak worden gepauzeerd. Hij komt weer aan de beurt als de taak met hogere prioriteit gaat slapen.

[ Voor 74% gewijzigd door farlane op 29-08-2018 22:59 ]

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

farlane schreef op woensdag 29 augustus 2018 @ 22:52:
De enige nette oplossing is een RTOS gebruiken en deze taak op een lagere proriteit zetten dan de caller.
Hoewel ik het helemaal met je eens bent is het natuurlijk niet echt een oplossing als er geen (RT)OS mogelijk of voorhanden is...

  • diondokter
  • Registratie: Augustus 2011
  • Laatst online: 11:20

diondokter

Dum spiro, spero

Topicstarter
Dank jullie wel voor de snelle reacties.

Ik had dit soort antwoorden al wel verwacht.
Josk79 schreef op woensdag 29 augustus 2018 @ 21:28:
Kun je misschien van buitenaf een exception forceren in de functie? Bijv. door een gebruikte resource te sluiten?
We hebben geen exceptions omdat dat te veel geheugen kost. Ook is vooraf niet bekend welke functie het is, aangezien er gebruik wordt gemaakt van dependency injection. Elke keer kan het weer een andere zijn.
EddoH schreef op donderdag 30 augustus 2018 @ 07:02:
[...]

Hoewel ik het helemaal met je eens bent is het natuurlijk niet echt een oplossing als er geen (RT)OS mogelijk of voorhanden is...
RTOS is wel beschikbaar voor deze MCU, maar ons project is er niet op gebouwd. Dit is mogelijk nog wel interessant voor in de toekomst, maar is op korte termijn niet mogelijk om te gebruiken. Ik ben het er namelijk ook mee eens dat dat een van de mooiere oplossingen is.
3V3RT schreef op woensdag 29 augustus 2018 @ 21:42:
Ipv een watchdog timer kan je een van de drie 16-bit timers in dat ding gebruiken en dan een approach met register/pc saving proberen (e.g. context switching) proberen, maar dan ben je al vrij gauw een bare-scheduler aan het schrijven en je trekt een doos van pandora open als je niet veel ervaring met deze specifieke mcu hebt.
Als dit een hobby project was, dan had ik dat meteen gedaan >:)
Maar binnen een bedrijf is dat niet goed te verantwoorden en zal waarschijnlijk te veel tijd kosten. O-)

Als iemand nog suggesties heeft, dan hoor ik die graag, maar ik ben bang dat ik die system reset maar moet accepteren en daar wat op moet verzinnen.

Acties:
  • +1 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 27-09 13:03
diondokter schreef op donderdag 30 augustus 2018 @ 08:22:
Als dit een hobby project was, dan had ik dat meteen gedaan >:)
Maar binnen een bedrijf is dat niet goed te verantwoorden en zal waarschijnlijk te veel tijd kosten. O-)

Als iemand nog suggesties heeft, dan hoor ik die graag, maar ik ben bang dat ik die system reset maar moet accepteren en daar wat op moet verzinnen.
Ik voorspel je dat je langer bezig gaat zijn om het enigzins goed te krijgen met je puist en pleister constructie dan met het porten van je applicatie van bare-metal naar RTOS based.

Er is een grote kans dat je chip door bv FreeRTOS al standaard wordt ondersteund; kort door de bocht kun je je huidige code in een taak plempen en werkt het.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Verwijderd

farlane schreef op woensdag 29 augustus 2018 @ 22:52:
Als er een taak met hogere prioriteit runnable is zal deze op de scheduler tick actief gezet worden en zal deze taak worden gepauzeerd. Hij komt weer aan de beurt als de taak met hogere prioriteit gaat slapen.
Klopt, maar dat is niet wat TS vroeg. Hij vroeg hoe de lange functie te stoppen was, niet hoe deze gepauzeerd kon worden. Als hij dat laatste had gevraagd had ik hetzelfde antwoord gegeven.
Er is een grote kans dat je chip door bv FreeRTOS al standaard wordt ondersteund; kort door de bocht kun je je huidige code in een taak plempen en werkt het.
In ST CubeMX kan je letterlijk aanvinken dat je je configuratie wilt maken voor FreeRTOS.

Het blijft natuurlijk een beetje gis werk gezien TS ons niet verteld hoe zijn functie eruit ziet an waarom deze zo lang duurt. In de regel duurt een functie lang omdat:
  • Er een dure, zware berekening uitgevoerd wordt
  • Er een blocking wait in zit
In het eerste geval moet je je afvragen waarom je deze zou willen afbreken. In het tweede geval moet je je afvragen waarom je denkt dat een blocking wait nodig is.

[ Voor 40% gewijzigd door Verwijderd op 30-08-2018 10:19 ]


  • EddoH
  • Registratie: Maart 2009
  • Niet online

EddoH

Backpfeifengesicht

Verwijderd schreef op donderdag 30 augustus 2018 @ 10:14:
[...]

Klopt, maar dat is niet wat TS vroeg. Hij vroeg hoe de lange functie te stoppen was, niet hoe deze gepauzeerd kon worden. Als hij dat laatste had gevraagd had ik hetzelfde antwoord gegeven.
Hoewel lelijk (vooral ivm met memory management), kun je met vTaskDelete gewoon je je taak direct verwijderen vanuit een taak met hogere prioriteit. Dit doet toch precies wat de TS zoekt?

Overigens ben ik het eens met het feit dat de functie zelf aangepast moet worden. Er is, ook met een RTOS, niet een 100% mooie manier dit op te lossen zonder de functie zelf aan te raken.
Ik ben dan ook benieuwd waarom @diondokter dit niet wil/kan.

[ Voor 22% gewijzigd door EddoH op 30-08-2018 10:34 ]


  • diondokter
  • Registratie: Augustus 2011
  • Laatst online: 11:20

diondokter

Dum spiro, spero

Topicstarter
Verwijderd schreef op donderdag 30 augustus 2018 @ 10:14:
Het blijft natuurlijk een beetje gis werk gezien TS ons niet verteld hoe zijn functie eruit ziet an waarom deze zo lang duurt. In de regel duurt een functie lang omdat:
  • Er een dure, zware berekening uitgevoerd wordt
  • Er een blocking wait in zit
In het eerste geval moet je je afvragen waarom je deze zou willen afbreken. In het tweede geval moet je je afvragen waarom je denkt dat een blocking wait nodig is.
EddoH schreef op donderdag 30 augustus 2018 @ 10:29:
[...]
Overigens ben ik het eens met het feit dat de functie zelf aangepast moet worden. Er is, ook met een RTOS, niet een 100% mooie manier dit op te lossen zonder de functie zelf aan te raken.
Ik ben dan ook benieuwd waarom @diondokter dit niet wil/kan.
Misschien dan een vollediger verhaal:
We hebben verschillende klanten/projecten waarbij voornamelijk data verzameld en verzonden wordt. We gebruiken altijd een basis programma waarin we de klant-specifieke code kunnen injecteren. De functie in dit geval is een van die injecties. Daardoor weet het basis programma niet wat die uitvoert.

De basis is goed getest, maar de klant code is vaak nieuw geschreven en kan bugs bevatten. In het verleden is het vaker gebeurt dat het programma op is gehouden in die klant functie, waarschijnlijk door een oneindige loop of door ergens op te wachten wat nooit komt.

Daarbij komt dat we binnenkort nieuwe stagiairs krijgen die ook zulke functies gaan schrijven en we verwachten niet dat ze hele hoge kwaliteit code gaan leveren. Dus als fallback wilden we deze nieuwe functionaliteit hebben. Van een stilgevallen apparaat kun je niks zeggen. De batterij kan te snel leeg zijn gegaan of hardware kan stuk zijn. Maar een apparaat dat weet te melden dat de klant functie er te lang over heeft gedaan, zegt al zoveel meer.

Natuurlijk is het belangrijk om de geschreven code te checken, maar de feature zou dan ook voornamelijk als noodrem dienen en als het goed is nooit gebruikt worden.
Verwijderd schreef op woensdag 29 augustus 2018 @ 17:06:
code:
1
2
3
4
5
6
7
8
9
functie()
{
  setup();
  while(conditie)
  {
    doe_iets();
  }
  cleanup();
}
Code als dit is natuurlijk het beste, maar dan moet er wel secuur aan vast worden gehouden.

Edit:
Als ontwikkelaar van de basis moet ik er voor zorgen dat alles zo soepel mogelijk verloopt.
Als ik vanuit de basis een bepaalde stijl voor die functie zou kunnen enforcen, dan zou ik daarmee het doel ook kunnen bereiken.

[ Voor 4% gewijzigd door diondokter op 30-08-2018 11:07 ]


Acties:
  • Beste antwoord
  • +1 Henk 'm!

Verwijderd

Even over hele andere boeg:

Je huidige opzet van een WDT gewoon gebruiken. Als je klant een functie schrijft die blokeert dan is dat een design fout, niet een run-time fout. Idealiter wil je dan informeren dat er een watchdog timeout plaatsvond als gevolg van de klantfunctie. Nog fijner als er een een stackdump bij zit.

Vervang je de watchdog reset door een watchdog interrupt dan kan je deze stackdump wegschrijven naar een log en daarna vanuit de watchdog interrupt een reset forceren.

Vervolgens is het aan de klant om zijn functie te fixen zodat deze geen hackup meer veroorzaakt.

  • diondokter
  • Registratie: Augustus 2011
  • Laatst online: 11:20

diondokter

Dum spiro, spero

Topicstarter
Ik denk dat dat misschien wel het beste is.

En ik zal ook op de agenda zetten om een keer RTOS te onderzoeken.

Bedankt in ieder geval voor de reacties!

Acties:
  • 0 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 27-09 13:03
diondokter schreef op donderdag 30 augustus 2018 @ 11:57:
En ik zal ook op de agenda zetten om een keer RTOS te onderzoeken.
Beter eerder dan later zou ik adviseren.

In feite is de Cortex-M core ontworpen voor een (RT)OS; het verbaast me eerlijk gezegd dat er mensen zijn die die optie nog niet hebben onderzocht.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.


Acties:
  • 0 Henk 'm!

  • Sissors
  • Registratie: Mei 2005
  • Niet online
Zoals dan? Oké je hebt een SysTick erin zitten, maar dat lijkt me niet echt genoeg reden om te stellen dat hij ontworpen is voor een OS. En die zit voor zover ik weet ook op de M0s met 1kB geheugen. Daar zou ik toch echt geen (RT)OS op willen draaien.

Vooral als je veel verschillende functies door elkaar draait is een RTOS natuurlijk aantrekkelijk, maar het kan afhankelijk van je use case en device ook een behoorlijke impact hebben. Memory management wordt er bijvoorbeeld ook niet makkelijker op (iig niet in degene die ik heb gebruikt, omdat je zelf moest bedenken hoeveel geheugen een thread nodig gaat hebben, tenzij je alles op de heap gooit).

Acties:
  • 0 Henk 'm!

  • BastiaanCM
  • Registratie: Juni 2008
  • Laatst online: 08:30
nvm, suggestie was al gegeven en op gereageerd

[ Voor 66% gewijzigd door BastiaanCM op 31-08-2018 12:08 ]


Acties:
  • 0 Henk 'm!

  • diondokter
  • Registratie: Augustus 2011
  • Laatst online: 11:20

diondokter

Dum spiro, spero

Topicstarter
Top prioriteit is bij ons ook stroomverbruik.
Verzamel data -> verstuur -> slaap.

We hoeven daarbij ook maar weinig 'tegelijk' te doen. Wat dat betreft is RTOS zeker niet nodig.

Met de interrupt hoeft het idd niet per definitie de watchdog timer te zijn. Maar dit is zo'n beetje het enige wat de WDT kan. De andere timers hebben ook meer functies, dus het is handig om die vrij te laten voor de toekomst.

Acties:
  • +1 Henk 'm!

  • farlane
  • Registratie: Maart 2000
  • Laatst online: 27-09 13:03
Sissors schreef op vrijdag 31 augustus 2018 @ 12:02:
Zoals dan? Oké je hebt een SysTick erin zitten, maar dat lijkt me niet echt genoeg reden om te stellen dat hij ontworpen is voor een OS. En die zit voor zover ik weet ook op de M0s met 1kB geheugen. Daar zou ik toch echt geen (RT)OS op willen draaien.
SysTick, SVCall exception, PendSV exception, de (optionele, maar vaak aanwezig) MPU; al die dingen zijn er op gericht om het implementeren van een OS op Cortex-M zo makkelijk mogelijk te maken.

Een RTOS heeft over het algemeen erg weinig RAM/ROM nodig, dus zelfs op een M0 met 1kB (RAM/ROM) zou het makkelijk kunnen. Aan de andere kant, als je een chip kiest die zo weinig resources heeft heb je waarschijnlijk al vastgesteld dat een RTOS niet veel waarde toevoegt en dus niet gebruikt gaat worden.
Vooral als je veel verschillende functies door elkaar draait is een RTOS natuurlijk aantrekkelijk, maar het kan afhankelijk van je use case en device ook een behoorlijke impact hebben.
Zoals bij de TS het geval is dus. De oplossing voor het probleem dat hij heeft is *precies* dat waar zo een OS voor is bedacht.
Memory management wordt er bijvoorbeeld ook niet makkelijker op (iig niet in degene die ik heb gebruikt, omdat je zelf moest bedenken hoeveel geheugen een thread nodig gaat hebben, tenzij je alles op de heap gooit).
Bedenken hoeveel geheugen je gaat gebruiken (stack danwel heap) hoeft niet in een bare metal situatie?
diondokter schreef op vrijdag 31 augustus 2018 @ 12:09:
Top prioriteit is bij ons ook stroomverbruik.
Verzamel data -> verstuur -> slaap.

We hoeven daarbij ook maar weinig 'tegelijk' te doen. Wat dat betreft is RTOS zeker niet nodig.
Een taak die wacht op een object gebruikt geen processortijd, en dus geen energie. Daarnaast, als energieverbruik echt paramount is kent bv FreeRTOS kent ook een tickless idle mode waarin er niet gescheduled wordt als de processor slaapt.

Somniferous whisperings of scarlet fields. Sleep calling me and in my dreams i wander. My reality is abandoned (I traverse afar). Not a care if I never everwake.

Pagina: 1