Arduino Multitasking

Salve a tutti, sto lavorando ad un piccolo progetto, e mi servirebbe implementare il multitasking... purtroppo l'arduino permette solo di lavorare in modo sequenziale e a me non serve! con la funzione millis() non mi piace... mi servirebbe un sistema di multitasking robusto, del tipo round-robin, ho cercato in giro ma tutti usano la funzione millis... Mi servirebbe lavorare con gli interrupt su tutti i pin digitali (Possego un Arduino mega 2560 e uno) mi potete aiutare? Thanks! :-)

Devi passare a microcontrollori più potenti come il SAM3X montato sulla Arduino Due. Vedi qui --> http://forum.arduino.cc/index.php/topic,170177.0.html

per quanto riguarda gli interrupt?

PS: avevo provato AVR-OS su Arduino uno e funziona, nel 2560 no... mi si resetta sempre....

Prova a guardare se QUESTO oppure QUESTO può esserti utile ... :roll_eyes:

Guglielmo

P.S. : Ricorda sempre che NON stai su un PC, ma su una piccola MCU che ha ben poca SRAM, quindi ....

Si, so che non è un pc... però mi suona strano... sul'' Arduino uno funziona alla perfezione, sul 2560 non funziona mi si resetta sempre... e confrontando i datasheet dell' Atmega2560 e Atmega328 il 2560 è superiore... quei schedulatori usano entrambi la funzione mills() e non mi è molto utile... Grazie :)

GalaxyHD96: Si, so che non è un pc... però mi suona strano... sul'' Arduino uno funziona alla perfezione, sul 2560 non funziona mi si resetta sempre... e confrontando i datasheet dell' Atmega2560 e Atmega328 il 2560 è superiore... quei schedulatori usano entrambi la funzione mills() e non mi è molto utile... Grazie :)

  1. E come credi che faccia un S.O. a gestire più task se non usando la divisione del tempo basandosi su un tickcounter tipo millis? 2 .A me pare strano che su Uno ti funziona mentre su Mega hai problemi. Se magari posti il codice magari scopriamo l'arcano. ;)

Bene, sto usando “AVR-OS” il codice (è quello di esempio) l’ho caricato nell’ UNO e funziona, nel 2560 no… ho provato a cambiare i 3 timer {0,1,2} ma con nessuno dei tre funziona sul 2560

#include <Arduino.h>
#include <LiquidCrystal.h>

#include <util/delay.h>

extern "C" {
    #include <os.h>
}

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

spinlock_t testLock;

void kernel_task(void *arg) {
    while(1) {
        spinlock_acquire(&testLock);
        lcd.setCursor(0, 0);
        lcd.print("kernel: " + String((long)os_get_uptime()));
        spinlock_release(&testLock);
        os_sleep(1000);
    }
}

void user_task(void *arg) {
    int x = 0;
    while(1) {
        spinlock_acquire(&testLock);
        lcd.setCursor(0, 1);
        lcd.print("user_task: " + String(x++));
        spinlock_release(&testLock);
        os_sleep(5000);
    }
}

void setup() {
    os_init();
    lcd.begin(16, 2);
    lcd.print("Starting up...");
}

void loop() {
    spinlock_init(&testLock);

    os_schedule_task(kernel_task, NULL, 0);
    os_schedule_task(user_task, NULL, 0);
    lcd.clear();
    os_loop(); 
}

Per me ti vuoi complicare la vita inutilmente …
… AVR-OS non fa altro che usare l’interrupt generato da un timer … e millis() cosa pensi che faccia ??? ]:smiley:

Impara piuttosto ad usare BENE millis() che su Arduino è la soluzione più efficiente … :roll_eyes:

Guglielmo

Va bene :) userò millis :) per gli interrupt su tutti i pin come si fa? in oltre vorrei sapere se si possono usare altri timer :)

Sulla Mega hai più int veri (legati nativamente ad un singolo pin) della uno e trovi le specifiche nella attachInterrup() e poi puoi usare l'interrupt sugli altri pin grazie alla libreria PinChangeInt ... studiati entrambe ed avrai tutte le possibilità.

Relativamente hai timer, certo che si possono usare ... basta studiarsi come nel datasheet ... da pag. 118 in poi ... ;)

Ricorda comunque che, toccando i Timers, sulla mega influenzi :

Timer0
Usato per il PWM sui pin 4 e 13
fast hardware pwm

Timer1
Usato per il PWM sui pin 11 e 12
8-bit phase correct pwm mode

Timer2
Usato per il PWM sui pin 9 e 10
8-bit phase correct pwm mode

Timer3
Usato per il PWM sui pin 2, 3 e 5
8-bit phase correct pwm mode

Timer4
Usato per il PWM sui pin 6, 7 e 8
8-bit phase correct pwm mode

Timer5
usato per il PWM sui pin 45 e 46
8-bit phase correct pwm mode
Pin 47 è usato per il “pulse counting”
Pin 48 è usato per il “input capture”

Guglielmo

No, gli output PWM non li uso... al massimo userò gli RX/TX per comunicare tra arduini... per quanto riguarda i timer, potresti gentilmente postarmi del codice spiegato? sinceramente non ho mai capito le istruzioni per inizializzare, avviare e utilizzare sti timer thanks :)

Guarda ... bisogna proprio che te li studi sul datasheet perché possono essere programmati in tanti modi ... ...se poi cerchi tra le varie librerie di Leo ... sicuramente ce ne sono tante che usano i Timers e li programmano ;)

Guglielmo

... poi ... guarda anche QUI :grin: :grin: :grin:

qui https://github.com/chrismoos/avr-os dice che per compilare la versione 2560 devi eseguire il build con:

make DEVICE=arduino_mega2560

Forse è per questo che con la mega non ti funziona.

Non conoscevo avr-os, ora gli ho dato uno sguardo veloce ed è interessante. Per chi volesse saperne di più di RTOS gli consiglio di partire dal visionare il file context.h, le macro SAVE_CONTEXT e RESTORE_CONTEXT rappresentano il cuore del OS.

Comunque, una applicazione sul pc anche complessa richiede raramente uno o più thread supplementari, stessa cosa vale per le applicazioni embedded, anzi ci si deve chiedere sempre; questa cosa la possa fare senza creare un altro task? La risposta deve essere quasi sempre si, altrimenti si finisce per avere 10 task che si mangiano le risorse e il programma fa ben poco e lentamente.

Tuttavia è possibile che tu abbia proprio necessità di un RTOS, ma al momento mi sembra che tu non abbia le competenze per usarlo nel modo corretto; Il rischio è quello di cacciarsi nei guai senza sapere come ci si è finiti e tanto meno si sa come uscirne.

Un RTOS ben dotato fornisce anche funzioni per accedere all'hardware come timer, i2c, eeprom ecc svincolando il programmatore dalla conoscenza intima dell'hardware. Senza RTOS ti tocca invece studiare il datasheet e scrivere codice accessorio non strettamente legato alla applicazione.

Con arduino style è pratica comune usare millis() o micros(), non sarà bello ma funziona, comunque è possibile renderlo accettabile creando delle funzioni che operano su millis() e raramente ciò risulta insufficiente e in tal caso si può cominciare a pensare ad un RTOS.

Ciao.

Secondo me voler avere un multitasking e usare gli interrupt ti si complica solo la vita. Oltre questo stai chiedendo delle cose molto specifiche senza aver spiegato cosa devi programmare.

Ciao Uwe

Costruisci un circuito con quattro atmega328 in stand alone (anzi in questo caso stand... insiem :grin:) dove su ognuno hai il suo codice, li metti in I2C ed hai il vero multitasking.

Interessante. ;)

Propongo una modifica:

in main.cpp:

#include <Arduino.h>

int main(void)
{
	init();

#if defined(USBCON)
	USBDevice.attach();
#endif
	
	setup();
    uint8_t cicle = 1;
	while(cicle != 0) {
		cicle = loop();
		if (cicle == 2 && serialEventRun) serialEventRun();
	}
        
	return 0;
}

in Arduino.h:

uint8_t loop(void);

se si torna 0, il loop si chiude
se torna 1 continua il ciclo ma senza le seriali
se torna 2 continua con le seriali…

MauroTec: Non conoscevo avr-os, ora gli ho dato uno sguardo veloce ed è interessante. Per chi volesse saperne di più di RTOS gli consiglio di partire dal visionare il file context.h, le macro SAVE_CONTEXT e RESTORE_CONTEXT rappresentano il cuore del OS.

Non solo di Avr-Os ma di tutti gli RTOS. Il salvataggio e ripristino dello stato interno della CPU è il punto cruciale di tutti gli RTOS. Il timer è usato solo per fare il salto da un task all'altro, salvando lo stato dei registri del micro e ripristinandoli quando il task viene riesumato. Questo modo di lavorare è il multitasking senza prelazione, o preemptive. Ma è anche il più difficile da implementare perché si potrebbe fare il cambio di task mentre un task sta facendo un'operazione non interrompibile. Vedi ad esempio la lettura di un pin analogico: la conversione comporta una piccola attesa, gestita nel core dell'Arduino con un while che attende un flag che viene impostato dall'ADC quando la conversione è terminata. Metti che lo switch tra i task avvenga in quel frangente... Il dato andrebbe perso nel caso il task successivo accedesse all'ADC. E questo è solo uno dei casi. Poi ci sono quelli di gestione delle periferiche esterne: come puoi fare vero multitasking preemptive quando hai la CPU che comunica con una periferica esterna che non è nata per interrompere il suo lavoro? Metti che stai leggendo dei dati sulla seriale. Cambi task ed il task successivo non legge quei dati. I dati si accumulano nel buffer, lo riempiono e poi iniziano ad essere persi perché il buffer è circolare quindi una volta riempito continua a salvare i dati sopra ai più vecchi. Chi dice al trasmettitore di fermarsi?

Ci sono RTOS che non hanno prelazione e non c'è context switch eppure li chiamano sempre RTOS, perché anche con questi si possono scrivere applicazioni real-time, anzi qualcuno li preferisce, ma realmente si fa tanta fatica a scrivere, ha molti moltissimi task piccoli con tanti stati, insomma non è idilliaco per esperienza, ma le cose dall'altra parte mica stanno tanto meglio, c'è il vantaggio che hai effettivamente il time sharing delle risorse, ma ti devi destreggiare con semafori, lock unlock delle risorse, eventi e loro propagazione e molte code e buffer circolari, il mal di testa mi viene solo a pensarci e infatti non ci penso, prima o poi dovrò prendermi di coraggio e investire tempo in qualche RTOS Open, ma per adesso nessuno mi entusiasma più di tanto.

Qualcosa di interessante c'è, il pre-configuratore condizionale tipo linux, poi addirittura un nuovo linguaggio o qualcosa di molto simile, poi però il codice finisce per essere sempre C.

avr-os mi è sembrato semplice ed essenziale senza fronzoli, proprio come piace a me.

Aspetta, se c'è switch context allora molto probabilmente c'è lo scheduler premptive, comunque ora non sono molto vispo.

Ciao.

Sì, ci sono RTOS senza prelazione, sono quelli di tipo cooperativo. Però ci vuole sempre un minimo controllo sui task altrimenti si rischia come selle prime versioni di Win3.1 che se un task andava in crash bloccava tutto il SO.