0

I have a 2D array of uint16_t arrays (IR Remote Codes). Due to the size of this data in RAM I'm having all kinds of trouble when my array is larger than one code. Thus, I have been trying to move this whole structure into PROGMEM. Following various tutorials and this solution, I have come up with the code below for reading a single element out of the array and into a variable that I can feed to the IRLIB2 IRSendRaw function.

The variable that holds the code that is read out of PROGMEM is still huge and causing some problems. Is there a more direct way like a python list comprehension to access an arbitrary element and send it directly to the IRSender?

This PROGMEM_readAnything library looks promising, but I don't have enough C++ fu to make the mental leap to implement it in my code.

#include <IRLibSendBase.h> //We need the base code
#include <IRLib_HashRaw.h> //Only use raw sender
#define RAW_DATA_LEN 68 
const uint16_t sources[3][RAW_DATA_LEN] PROGMEM =
 {{8550, 4306, 530, 1606, 530, 566, 502, 1610, //power on/off
 530, 566, 502, 574, 506, 1630, 506, 566,
 506, 1630, 506, 566, 502, 1610, 530, 566,
 502, 1634, 506, 1606, 530, 570, 498, 1634,
 506, 570, 510, 562, 506, 566, 502, 1634,
 506, 1606, 530, 1610, 530, 562, 538, 538,
 530, 542, 538, 1598, 538, 1570, 558, 542,
 538, 538, 530, 542, 538, 1598, 530, 1578,
 558, 1578, 562, 1000},
 {8546, 4310, 558, 1578, 562, 538, 498, 1638, //source CD
 530, 542, 506, 570, 502, 1634, 502, 570,
 498, 1638, 534, 538, 498, 1638, 530, 542,
 506, 1606, 554, 1582, 558, 538, 510, 1602,
 554, 546, 506, 566, 502, 570, 510, 1602,
 554, 1582, 558, 538, 510, 566, 502, 1606,
 554, 546, 502, 1610, 558, 1574, 554, 546,
 502, 570, 510, 1602, 526, 1610, 526, 574,
 506, 1602, 526, 1000},
 {8550, 4306, 530, 1606, 534, 566, 502, 1606, //source CDR
 534, 566, 502, 570, 510, 1602, 526, 570,
 510, 1602, 534, 566, 502, 1606, 534, 566,
 506, 1602, 530, 1606, 534, 566, 502, 1610,
 530, 570, 498, 574, 506, 566, 502, 570,
 510, 1602, 526, 570, 510, 566, 502, 570,
 510, 1602, 526, 1610, 526, 1606, 534, 1602,
 534, 566, 502, 1610, 530, 1602, 534, 1602,
 526, 574, 506, 1000}};
//Create a sender
IRsendRaw mySender;
//Read out one code into a variable and send to the IR transmitter
uint16_t myCode[RAW_DATA_LEN];
for (int i = 0; i < RAW_DATA_LEN; i++) {
 myCode[i] = pgm_read_word_near(sources[0] + i); 
}
mySender.send(myCode,RAW_DATA_LEN,36);
asked Apr 4, 2019 at 19:35
4
  • you can't put a multidimensional array into PROGMEM. see "Array of Strings" in arduino.cc/reference/en/language/variables/utilities/progmem Commented Apr 4, 2019 at 19:40
  • 2
    @Juraj Sure you can. Strings are a special case though. There's no difference in memory between a 2D array, and a single large 1D array. Commented Apr 4, 2019 at 19:44
  • It is not problem to fill the rest of the flash memory of an arduino uno with progmem data. For an arduino mega 2560 it is better te keep the progmem data section below the 64k boundery. You copy the data into a buffer of 68 uint16_t, that is 136 bytes. Is that the problem? The arduino uno has 2kbyte ram. What else is using your sram? Commented Apr 4, 2019 at 19:54
  • 1
    I had problems to read a two-dimensional array from PROGMEM. now I know. for one dimension the argument to pgm_read is arr + i. it is a pointer to the element. and for two dimensions the argument to pgm_read must be arr[i] + j Commented Apr 5, 2019 at 5:39

1 Answer 1

4

The library, as it stands, doesn't support direct sending from PROGMEM. However it's not too hard to get around that - if your C++ is up to it.

The IRsendRaw class is a child class that extends the IRsendBase with a single function. You just need to do the same thing to create a new class that implements the functions in a way that can read from PROGMEM.

This is the original:

class IRsendRaw: public virtual IRsendBase {
 public:
 void send(uint16_t *buf, uint8_t len, uint8_t khz) {
 enableIROut(khz);
 for (uint8_t i = 0; i < len; i++) {
 if (i & 1) {
 space(buf[i]);
 } 
 else {
 mark(buf[i]);
 }
 }
 space(0); // Just to be sure
 }
};

You just need to make your own one of those in your sketch, called something different, and which uses the progmem functions instead of accessing buf[i]:

class IRsendRawPGM: public virtual IRsendBase {
 public:
 void send(const uint16_t *buf, uint8_t len, uint8_t khz) {
 enableIROut(khz);
 for (uint8_t i = 0; i < len; i++) {
 if (i & 1) {
 space(pgm_read_word_near(buf + i));
 } 
 else {
 mark(pgm_read_word_near(buf + i));
 }
 }
 space(0); // Just to be sure
 }
};

Now you can define your sender object as:

IRsendRawPGM mySender;

And send the data directly:

mySender.send(sources[0], RAW_DATA_LEN, 36);

(Note: this code is untested).

answered Apr 4, 2019 at 19:49
0

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.