mercoledì 6 marzo 2019

Differenza FreeRTOs su Arduino AVR e SAMD21 e ESP-Wroom-32

La principale differenza nell'implementazione di FreeRTOs in ESP32 ed in Arduino Uno (ovvero AVR ATMega328) e' il fatto che Esp32 e' un processore dual core. FreeRTOs riesce a distribuire il carico del lavoro tra i core. Nell'esempio sottostante (ripreso da qui), fatto girare su Esp-Wroom-32, si vede che il main loop ed il task vengono eseguiti su due core differente in modo parallelo


Viene creato un task generico che fa un solo loop e poi si autodistrugge (vTaskDelete(NULL)) mentre il loop principale continua a rimanere in esecuzione.
-------------------------------------------------------------------------
void setup() {

  Serial.begin(9600);
  delay(1000);

  Serial.print("Setup: Executing on core ");
  Serial.println(xPortGetCoreID());

  xTaskCreate(
                    genericTask,       /* Task function. */
                    "genericTask",     /* String with name of task. */
                    10000,             /* Stack size in words. */
                    NULL,              /* Parameter passed as input of the task */
                    2,                 /* Priority of the task. */
                    NULL);             /* Task handle. */
 delay(2000); 

}

void loop() {
  Serial.print("Main Loop: Executing on core ");
  Serial.println(xPortGetCoreID());
  delay(1000);
}

void genericTask( void * parameter ){
    Serial.print("Created task: Executing on core ");
    Serial.println(xPortGetCoreID());
    vTaskDelete(NULL);
}

-----------------------------------------------------------------------------------------
Setup: Executing on core 1
Created task: Executing on core 0
Main Loop: Executing on core 1
Main Loop: Executing on core 1

Main Loop: Executing on core 1


 Se si usa #include <Arduino_FreeRTOS.h> si vedra' che non esiste nemmeno la funzione xprtoGetCoreID perche' ATMega328 e' un processore single core...i task vengono eseguiti su un unico core dividendo i tick del processore tra i vari task come un time sharing

Le cose non cambiano con la serie Arduino MKR che montano SAM D21 Cortex M0-+ (solo alcuni  Cortex di fascia alta sono multi core) 

martedì 5 marzo 2019

Blink con FreeRTOs

Questo e' il classico di Blink del pin 13 pero' compilato usando un task di FreeRTOS.
Questa configurazione permette di lanciare il task e poi di addormentare il processore.
Il classico esempio blink "consuma" circa 45 mA mentre con questo codice circa 20 mA

Un altro aspetto non trascurabile e' si puo' impostare il tempo di lampeggio sopra gli 8 secondi

Con il codice normale di Arduino l'unico metodo di risvegliare il processore e' quello derivante da un interrupt derivante dal watchdog (impostabile al massimo ad 8 secondi) oppure si deve utilizzare un interrupt esterno derivante da un RTC esterno

--------------------------------------------------------------------------------------
#include <Arduino_FreeRTOS.h>
#include <avr/sleep.h>  
#include <avr/power.h>  



void TaskBlink( void *pvParameters );

void setup() {
  xTaskCreate(TaskBlink,(const portCHAR *)"Blink",128 ,NULL,2,NULL);
}

void loop()
{
power_adc_disable(); //ADC
power_spi_disable(); //SPI
power_twi_disable(); //I2C


//set_sleep_mode( SLEEP_MODE_PWR_DOWN ); 
set_sleep_mode( SLEEP_MODE_EXT_STANDBY); 

portENTER_CRITICAL();
sleep_enable();

#if defined(BODS) && defined(BODSE)
sleep_bod_disable();
#endif

portEXIT_CRITICAL();

sleep_cpu(); 

sleep_reset();
}

void TaskBlink(void *pvParameters)  // This is a task.
{
  (void) pvParameters;

  pinMode(LED_BUILTIN, OUTPUT);

  for (;;) 
  {
    digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
    vTaskDelay( 1000 / portTICK_PERIOD_MS ); // wait for one second
    digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
    vTaskDelay( 7000 / portTICK_PERIOD_MS ); // wait for one second
  }
}

Queue con FreeRTOS su Arduino Uno

Le Queue, code, di FreeRTOs sono metodi per scambiare dati tra due task. In questo esempio una coda monodirezionale (un task invia dati e l'altro li riceve)


-----------------------------------------------------------------
#include <Arduino_FreeRTOS.h>
#include <queue.h>  

QueueHandle_t coda;
int codasize = 10;

void sender( void *pvParameters );
void receiver( void *pvParameters );

void setup() {

  Serial.begin(9600);
  coda = xQueueCreate(codasize,sizeof(int));
  
  if ( coda == NULL )   {
     Serial.println("Errore nella creazione");
  }

  xTaskCreate(sender,(const portCHAR *)"Sender",128,NULL,3,NULL);
  xTaskCreate(receiver,(const portCHAR *)"Receiver",128,NULL,2,NULL);

}

void loop()
{
}



void sender( void *pvParameters __attribute__((unused)) )  // This is a Task.
{
  for (;;)
  {
    for (int t=0;t<5;t++){
      xQueueSend(coda,&t,portMAX_DELAY);
    }
    vTaskDelay( 1000 / portTICK_PERIOD_MS );

  }
}


void receiver( void *pvParameters __attribute__((unused)) )  
{
  int elemento;
  for (;;)
  {
    for (int t=0;t<codasize;t++){
      xQueueReceive(coda,&elemento,portMAX_DELAY);
      Serial.print(elemento);
      Serial.print("|");
    }
    Serial.println();

    vTaskDelay( 1000 / portTICK_PERIOD_MS );
  }
}

Semafori binari in FreeRTOS con Arduino

I semafori binari (o Mutex) sono metodi per stabilire per un task per capire se una risorsa condivisa e' occupata da un altro task (e quindi non utilizzabile) oppure e' disponibile

In questo esempio sono creati due task che ogni 5 secondi si sovrappongono e cercano entrambi di scrivere sulla porta seriale.
----------------------------------------------------------------------------------

#include <Arduino_FreeRTOS.h>
#include <semphr.h>  
SemaphoreHandle_t semaforo;

void blink_even( void *pvParameters );
void blink_odd( void *pvParameters );

void setup() {

  Serial.begin(9600);


  if ( semaforo == NULL )   {
    semaforo = xSemaphoreCreateMutex();  
    if ((semaforo) != NULL)
      xSemaphoreGive((semaforo));  
  }

// crea i due task
  xTaskCreate(blink_even,(const portCHAR *)"BlinkEven",128,NULL,3,NULL);
  xTaskCreate(blink_odd,(const portCHAR *)"BlinkOdd",128,NULL,2,NULL);

}

void loop()
{
}



void blink_even( void *pvParameters __attribute__((unused)) )  
{
  for (;;)
  {// qui viene testato se il semaforo e' settato, se la risorsa e'occupata riprova per 5 tick ..in caso la risorsa
   // rimanga occupata abbandona
    if (xSemaphoreTake(semaforo, ( TickType_t ) 5 ) == pdTRUE )
    {
      Serial.println("Even");
      xSemaphoreGive(semaforo);
    }
    vTaskDelay( 5000 / portTICK_PERIOD_MS );

  }
}


void blink_odd( void *pvParameters __attribute__((unused)) )  
{
  for (;;)
  {
    if (xSemaphoreTake(semaforo, ( TickType_t ) 5 ) == pdTRUE )
    {
      Serial.println("Odd");
      xSemaphoreGive(semaforo);
    }
    vTaskDelay( 1000 / portTICK_PERIOD_MS );
  }
}

Diventare amministratore della macchinetta del caffe'

Per motivi non meglio spiegati (sarebbe interessante scoprire il metodo) la macchinetta del caffe' dell'ufficio e' andata in crisi lasciando aperta una bella shell di amministrazione ...ops menu' di configurazione con cui poter fare qualunque cosa


Per interagire con il menu si possono usare Zucchero - e Zucchero + per andare indietro ed avanti, Caffe' e cioccolato per selezionare (Ok) e Caffe' al gingseng per andare indietro nel menu (i pusalnti sono illuminati in modalita' di amministrazione) 


Si puo' fare di tutto, dal cambiare il prezzo delle varie bevande ad avere le statistiche. Peraltro sembra che la macchinetta possa trasmettere i dati in remoto (non credo invece che possa essere controllata in remoto altrimenti sarebbe gia' stata resettata)



.....e no, non ne ho approfittato..nemmeno un caffe'

lunedì 4 marzo 2019

Mongoose OS ed ESP-Wroom-32

Un paio di indicazioni:
1) Mongoose OS non e' legato a MongoDB e Node.JS...maledetta fantasia nel mettere i nomi
2) in estrema sintesi Mongoose OS e' molto simile al cloud di Particle con la differenza che quest'ultimo e' legato a doppio filo con l'hardware di Particle (Electron, Photon) mentre Mongoose OS puo' essere usato con hardware ESP32 ed STM32



Per inziare ho scaricato il pacchetto generico per Linux

curl -fsSL https://mongoose-os.com/downloads/mos/install.sh | /bin/bash mos

e si lancia il programma in $HOME/.mos/bin/mos

si aprira' il browser di default all'indirizzo http://127.0.0.1:1992/
Le istruzioni dicono di premere CTRL+N per creare una nuova app ma su Chrome per Linux questa combinazione apre una nuova scheda del browser. Si puo' pero' usare la barra in basso allo schermo (vicino all'icona arancione che si trova nell'angolo in basso a destra) per digitare 

mos clone https://github.com/mongoose-os-apps/demo-js app1
a seguire (la compilazione avviente completamente sul cloud...i risultati saranno nella sottodirectory build)

mos build
mos flash 

Per avere la possibilita' di interagire in remoto ed effettuare anche degli OTA update (Over the air) si puo' configurare la connessione con l'access point con 

mos wifi WIFI_NETWORK_NAME WIFI_PASSWORD

Una volta ottenuta la connessione si rete si puo' impostare la connessione al cloud.Ci si collega a  https://dash.mongoose-os.com/ e si crea un nuovo dispositivo (con il profilo gratuito se ne possono creare fino a 3)

si copia il token (basta andare sopra al token) e da http://127.0.0.1:1992/ si digita

mos config-set dash.enable=true dash.token=xxxxxxxxdc08

se tutto e' andato bene il dispositivo comparira' on line nel cloud
Dall'interfaccia Web si puo' impostare il comando remoto tramite Mobile (si tratta di un link)
Si puo' accendere o spengere una porta digitale. Con il modulo ESP-Wroom-32 il pin preimpostato e' il numero 13 (IO13 a destra di GND)

La programmazione successiva puo' avvenire mediante C o Javascript. In generale, leggendo anche il forum, si tratta di un progetto piuttosto immaturo con un supporto ancora scarso con l'hardware (nonostante sia comunque presente la possibilita' di convertire le librerie Arduino nei progetti Mongoose)



venerdì 1 marzo 2019

Impostazione ProtonVPN su Debian 9

Questo e' un promemoria perche' regolarmente mi scordo come si fa ad impostare ProtonVPN su Debian

per prima si installano i pacchetti per openvpn in Network Manager

apt-get install openvpn network-manager-openvpn network-manager-openvpn-gnome


Da Account si copia OpenVPN/IKEv2 Username



e da Download si scaricano i file .ovpn relativi ai server (free nel mio caso) 


Fatto cio' si apre Network Manager/VPN/VPN Settings e si aggiunge il nuovo server importando il file .ovpn ed inserendo come username il precedente OpenVPN/IKEv2 Username e la password


Debugger integrato ESP32S3

Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede  nell'ID USB della porta Jtag. Nel modulo...