IRremote e Program Space (PGMSPACE)

In questi giorni ho avuto la necessità di simulare i comandi IR del telecomando di un decodificatore IPTV che sembra non seguire i classici standard.

Ricavate le sequenze RAW (piuttosto lunghette) mi sono posto il problema di risparmiare SRAM e di allocarle in PGMSPACE.

Girando un po' su Google ho trovato una soluzione piuttosto pulita e, dato che da una rapida ricerca qui sul forum non mi sembra di averla trovata (... ma naturalmente può essermi sfuggita ed in tal caso mi scuso anticipatamente per il duplicato), la ripropongo qui affinché possa essere magari utile a chiunque altro ha lo stesso problema.

La soluzione riguarda la creazione di un nuovo metodo nella classe IRSend che effettui direttamente l'invio delle sequenze poste in PGMSPACE senza la necessità di copiarle interamente prima in SRAM ...

1. Modifica al file IRremote.h:

Occorre aggiungere in testa la seguente #include

#include <avr/pgmspace.h>

quindi occorre scorre in basso, sino alla definizione della classe IRSend ed aggiungere tra i suoi metodi il seguente metodo (... io l'ho inserito subito dopo la "void sendRaw(....)"):

void  sendRaw_P         (PGM_VOID_P buf,      unsigned int len,  unsigned int hz) ;

2. Modifica al file irSend.cpp

Occorre aggiungere in testa la seguente #include

#include <avr/pgmspace.h>

quindi occorre scorrere in basso e, magari dopo la definizione della void sendRaw(){ ... }, aggiungere il seguete codice:

void  IRsend::sendRaw_P (PGM_VOID_P buf,  unsigned int len,  unsigned int hz)
{
    // Set IR carrier frequency
    enableIROut(hz);

    for (unsigned int i = 0;  i < len;  i++) {
      uint16_t duration = pgm_read_word_near((uint16_t)buf + sizeof(uint16_t)*i);
      if (i & 1)  space(duration) ;
      else        mark (duration) ;
    }

    space(0);  // Always end with the LED off
}

A questo punto la libreria contiene un nuovo metodo nella classe IRsend utilizzabile per inviare direttamente dal PGMSPACE le sequenze RAW.

3. Esempio:

#include <IRremote.h>

IRsend irsend;

static const unsigned char theFrequency = 36U;

static const unsigned int OKkey[] PROGMEM = {
   2616,1848,676,292,348,292,344,296,648,628,368,268,340,296,348,292,344,292,344,296,
   340,300,344,292,344,292,344,292,344,296,348,292,340,296,344,296,340,296,344,292,648,
   300,340,292,348,292,344,628,644,628,652,624,624,656,644,73730,2616,1848,676,292,344,
   296,340,296,648,620,352,292,344,296,344,292,348,292,344,292,344,296,340,300,340,296,
   344,292,344,292,344,296,344,296,344,292,344,296,340,296,648,292,348,292,344,292,344,
   632,620,652,648,628,652,624,648
};

void setup() {

}

void loop() {
    irsend.sendRaw_P(OKkey, (unsigned char) (sizeof(OKkey) / sizeof(unsigned int)), theFrequency);
    delay(1000);
}

Guglielmo

Grazie. :slight_smile:

Mi sembra ne avevamo parlato ma effettivamente l'unica soluzione trovata ai tempi era di copiare in temporaneo, sprecando memoria SRAM.
Per chi aveva in eemprom più sequenze raw, alleggeriva, ma non del tutto.

nid69ita:
Mi sembra ne avevamo parlato ma effettivamente l'unica soluzione trovata ai tempi era di copiare in temporaneo, sprecando memoria SRAM.

Infatti, da un po' di ricerche che ho fatto qui sul forum, le soluzioni trovate copiavano l'intero RAW in SRAM prima di usare la classica sendRaw() ... ::slight_smile:

Guglielmo

Grazie per la condivisione , mi potrebbe tornare utile visto che la maggior parte dei miei esperimenti con Arduino è proprio legato al mondo degli IR...

Butto lì un'idea : ho acquistato un modulo sdcard (ancora non testato) , potrei in qualche modo memorizzare li la codifica raw per avere praticamente tutto lo spazio che desidero?

può funzionare?

raffy-ree:
Butto lì un'idea : ho acquistato un modulo sdcard (ancora non testato) , potrei in qualche modo memorizzare li la codifica raw per avere praticamente tutto lo spazio che desidero? può funzionare?

NI ... ovvero, in teoria, applicando la stessa logica, SI, in pratica c'è un problema di velocità intrinseca nelle SD (... che non sono esattamente dei "fulmini") e quindi dubito che si riesca a rispettare le tempistiche (... parliamo di μSec) richieste dalla trasmissione leggendo da detti supporti.

Guglielmo

Lo immaginavo ... per ovviare a tale problema si potrebbe usare la memoria esterna per immagazinare i codici e trasferirla su arduino su di un tot di memoria lasciata libera ? Ovviamente dipende il tipo di applicazione che se ne vuole fare non sarebbe utile.. ma se ad esempio non abbiamo necessità di risposte fulminee potremmo fare così ... cosa ne pensa?

La logica sarebbe questa:

sulla scheda sd ho diciamo 100 codici raw

via seriale invio il numero 30 ad esempio

arduino lo cerca all'interno della sD

lo trasferisce sulla sram(o pgm?)

...

Visto che ancora non ho provato il modulo sd- non so che tempi impiegherebbe...

Si, averli tutti su un supporto SD è possibile, dopo di che leggi quello che ti interessa (e solo quello), lo trasferisci tutto in SRAM e, a quel punto, lo invii con la classica sendRaw().

In questo modo ti occorre uno spazio in SRAM pari al codice più lungo che devi trasmettere ... dato che usi sempre lo stesso spazio per tutti i codici.

Guglielmo

P.S.: La PGM non la puoi caricare dinamicamente, la programmi solo quando carichi il programma nella MCU.

Rimanendo in argomento, in alcune sequenze che ho dovuto inviare, le serie di dati erano intervallate da tempi superiori ai 65535 μSec, ovvero valori superiori alla capacita di un "unsigned int", che è il tipo usato dalla IRremote per i valori dei "tempi" dei vari impulsi.

Ad esempio la sequenza di un certo tasto era composta da due serie di impulsi distaccati da 73362 μSec (*μSec più, μSec meno * :grin:) e la tecnica che ho usato è stata questa (ripetibili anche per più sequenze) ...

Ho dichiarato le due sequenze in PROGMEM ed il tempo di attesa tra le due come un "unsigned long":

static const unsigned int EXITkey_1[] PROGMEM = {
   2652,1816,704,268,376,260,376,260,680,600,396,232,380,264,400,268,368,240,376,264,400,
   264,344,268,396,240,376,260,376,264,372,268,376,260,680,596,676,264,400,564,688,264,376,
   596,676,600,676,596,680,268,372,596,372
};
unsigned long tEXIT_1 = 73362;

static const unsigned int EXITkey_2[] PROGMEM = {
   2652,1816,728,272,340,268,396,240,680,596,
   372,264,376,264,372,268,372,264,372,268,372,260,376,264,376,264,372,264,396,232,384,264,
   372,264,680,600,676,264,376,596,700,240,376,600,676,596,680,596,676,268,372,596,372,
   25388,2652,1804,720,264,372,268,368,264,680,600,372,264,372,268,396,232,688,596,372,264,
   400,240,372,268,372,264,372,264,396,240,376,264,680,600,672,268,396,572,680,264,372,588,
   692,592,680,264,400,240,372,264,376,596,376
};

Dopo di che, al momento della trasmissione ho usato il seguente codice:

// Send EXITkey
irsend.sendRaw_P(EXITkey_1, (unsigned char) (sizeof(EXITkey_1) / sizeof(unsigned int)), theFrequency);
lastMicros = micros();
while (micros() - lastMicros < tEXIT_1) {}
 irsend.sendRaw_P(EXITkey_2, (unsigned char) (sizeof(EXITkey_2) / sizeof(unsigned int)), theFrequency);
//

... dove lastMicros è una variabile temporanea anche essa di tipo "unsigned long".

Ho detto μSec più, μSec meno perché, in realtà, occorrerebbe tenere conto anche del tempo impiegato dal ciclo while ... ma, con MCU a 16 MHz ... ho verificato che, su intervalli così lunghi, è realmente ininfluente.

Spero che il tutto possa essere d'aiuto a chi si trova ad avere telecomandi con sequenza RAW piuttosto complesse e con intervalli più lunghi di quanto ammesso in un "unsigned int" :wink:

Guglielmo

Grazie Guglielmo,
funziona benissimo.
Sono passato da uno sketch che usava 86% della memoria a 28%.
Grazie. :smiley:

Enzo--:
Sono passato da uno sketch che usava 86% della memoria a 28%.

Ottimo !!!

Guglielmo

Interessante.
Potresti fare una pull request
--> GitHub - Arduino-IRremote/Arduino-IRremote: Infrared remote library for Arduino: send and receive infrared signals with multiple protocols

Ciao a tutti. E se volessimo adattare questa libreria su arduino cactus, cosa bisognerebbe modificare esattamente ?
Grazie
Enzo

Enzo--:
... arduino cactus ...

... non so nemmeno di cosa stai parlando ! :o

Comunque ... la modifica è a livello della libreria NON a livello del tipo di Arduino.

Guglielmo

Ecco Arduino cactus: immagine

È un Arduino nano con il chip esp8266 integrato.

... e quindi ? Ci si può caricare e funziona la IRremote?

SE si, allora non c'è problema ad applicare la modifica che, ripeto, NON è a livello HW, ma a livello di libreria.

Guglielmo

Ho trovato questo post solo oggi. La modifica è molto utile per i codici dei condizionatori d'aria che sono molto lunghi se usati in raw.

Grazie Guglielmo! :slight_smile: