I have an array of a lot of numbers (1 and 0) but i can't store them since arduino does not have enough space. How can i save an array of example 00110 in PROGMEM, then read from PROGMEM and set x to be equal lets say, third int in the array?
-
How many is "a lot", and how wasteful is the datatype you have chosen? – Majenko Sep 11 '15 at 20:14
-
4000 elements and each element is a number like 1 or 0 to set a pin high or low. – Arduino Sep 11 '15 at 20:23
-
Stored as `int` variables (as you seem to suggest) that's a massive 8KB. Packed into individual bits of a byte that's a mere 500 bytes. – Majenko Sep 11 '15 at 20:25
-
I can store it in PROGMEM – Arduino Sep 11 '15 at 20:28
-
I would also suggest you change your name before the mods blacklist you... – Majenko Sep 11 '15 at 20:34
-
The Arduino website tells you all about how to use PROGMEM. Have you considered reading that? https://www.arduino.cc/en/Reference/PROGMEM – Majenko Sep 11 '15 at 20:39
-
Yes i didn't understand it well i need a code for my case – Arduino Sep 11 '15 at 20:41
-
There is suitable code right there on the page for you. What more do you need? – Majenko Sep 11 '15 at 20:42
-
Can you please send me the part of the code for storing an Array of 1's and 0's and then setting a variable as a value from that array? – Arduino Sep 11 '15 at 20:46
-
Look at the bits of that code pertaining to the variable "charSet" - it has everything you need. – Majenko Sep 11 '15 at 20:47
-
It's not about storing array but declaring *const char PROGMEM myarray[50] = {0x45, 0x47};* in source code , etc. It's elementar task appearing in many examples. – TMa Sep 11 '15 at 20:50
-
After i store the array in PROGMEM how do i set a variable to have a value of a element inside that array? – Arduino Sep 11 '15 at 20:57
3 Answers
Store them with const byte PROGMEM with bit 0 as MSb and bit 7 as LSb per byte. E.g. 011100100101001010101011 would become const byte[] var PROGMEM {0x72, 0x52, 0xab}
Use the following macro to retrieve them (untested):
#define loadbit(mem, pos) ((pgm_read_byte(&(mem[pos / 8])) >> (7 - (pos % 8))) & 0x01)
So if you had const byte[] data PROGMEM {0x72, 0x52, 0xab}; you would call loadbit(data, 3) and it would return bit 3 starting with 0 on the left, i.e. 1.
Naturally if you needed more than one bit at a time there are probably situation-specific routines that could be used, but without knowing anything about the actual program the above will work.
- 17,583
- 1
- 26
- 32
-
What data type is that? 0x72? Is that hex? And how do i convert big data chunks of binary into that data type? – Arduino Sep 11 '15 at 21:23
-
1
-
@Arduino I usually write a Perl or PHP script (depending on what the source of the data is) to convert it into C source code. – Majenko Sep 11 '15 at 21:52
As noted in Ignacio's answer, you can pack your bits of data into bytes and access them via pgm_read_byte() calls. If (for coding convenience, not for efficiency) you prefer to pack the bits into larger units, you can use word and dword access functions, as listed in AVR pgmspace.h documentation. The _near and _far suffixes denote 16 or 32 bit pointers, respectively; for an Uno with its 32K flash memory, _near is always suitable. See PROGMEM documentation at arduino.cc for further discussion.
Here's an example program that accesses and prints data from program memory in 16-bit chunks:
void setup() {
Serial.begin(115200); // initialize serial port
}
int k=0;
const uint16_t fnums[] PROGMEM {191, 272, 353, 434, 515, 646, 767, 888};
void loop() {
uint16_t b = pgm_read_word_near(fnums+k);
Serial.print(k); Serial.print(" ");
Serial.print(b); Serial.println();
k = (k+1)%8;
delay(1000);
}
To pack your 4000 bits of data in the first place, write a C or Python program that runs on a host computer and writes out array definitions that you can cut and paste into a sketch. Here's an example (in Python) that packs bits into bytes:
data = [1,1,0,0,0,1,0,1,0,0,1,0,1,0,1,1,0,0,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,1,0,1,1,1,1,1,1,0,0,0,1,0,1,0,0,0,1,1,1,1,0,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,1,1,0,1,1,0,1,0,0,0,1,1,1,0,1,0,1,0,0,1,1,0,0,0,0,1,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,1]
first = 1; byt = 0
for i, b in enumerate(data):
if i%8==0:
if first:
print 'const uint8_t fnums[] PROGMEM {',
first = 0
else:
print '{},'.format(byt),
byt = 0
byt = (byt<<1) | b # add bit into byte being built
print byt<<(8-i%8), '};'
Here is what the program produces:
const uint8_t fnums[] PROGMEM { 197, 43, 32, 200, 47, 197, 30, 119, 153, 37, 180, 117, 48, 218, 214, 212, 170, 262 };
If you want that code to instead pack bits into 16-bit words, change 8 to 16 in four places. Note, the code stores bits in the “bit 0 as MSb and bit 7 as LSb” order mentioned in Ignacio's answer. Thus, data[0] is stored in the high bit of fnums[0], data[8] is stored in the high bit of fnums[1] , and so forth.
- 8,800
- 3
- 16
- 32
-
The thing is that `(E)LPM` only loads a single byte at a time regardless, so using larger types causes the program to do more work for no gain. – Ignacio Vazquez-Abrams Sep 11 '15 at 21:47
-
Yes, I meant to mention that byte access uses fewer instructions. However, for some kinds of data (not necessarily this data), coding convenience rather than efficiency may be important. Added a note to answer. – James Waldby - jwpat7 Sep 11 '15 at 21:50
-
-
@Arduino, see edit. Also, upvote answers you find useful – James Waldby - jwpat7 Sep 12 '15 at 06:03
Building on the excellent other answers by jwpat7 and Ignacio Vazquez-Abrams, you could conceivably convert your bits into a table using Lua:
data = { 1,1,0,0,0,1,0,1,0,0,1,0,1,0,1,1,0,0,1,0,0,0,0,0,1,1,0,0,1,
0,0,0,0,0,1,0,1,1,1,1,1,1,0,0,0,1,0,1,0,0,0,1,1,1,1,0,0,1,
1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,1,1,0,1,1,0,1,0,
0,0,1,1,1,0,1,0,1,0,0,1,1,0,0,0,0,1,1,0,1,1,0,1,0,1,1,0,1,
0,1,1,0,1,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,1 }
output = 0
bit = 0
for _, num in ipairs (data) do
assert (num == 0 or num == 1, "Number must be 0 or 1")
output = (output * 2) + num
bit = bit + 1
if bit >= 8 then
io.write (output .. ", ")
output = 0
bit = 0
end -- if
end --for
print ""
Output from above:
197, 43, 32, 200, 47, 197, 30, 119, 153, 37, 180, 117, 48, 218, 214, 212, 170, 131,
Now you can make a simple function to pull a particular bit out of PROGMEM:
const byte myTable [] PROGMEM = {
197, 43, 32, 200, 47, 197, 30, 119, 153, 37, 180, 117, 48, 218, 214, 212, 170, 131,
};
bool getBit (const unsigned int which)
{
const unsigned int whichByte = which / 8;
const byte whichBit = which & 0x07;
return bitRead (pgm_read_byte (&myTable [whichByte]), 7 - whichBit);
} // end of getBit
void setup ()
{
Serial.begin (115200);
Serial.println ("Starting");
for (int i = 0; i < sizeof (myTable) * 8; i++)
{
Serial.print (int (getBit (i)));
Serial.print (", ");
}
Serial.println ();
} // end of setup
void loop ()
{
} // end of loop
Output from above:
Starting
1,1,0,0,0,1,0,1,0,0,1,0,1,0,1,1,0,0,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,1,0,1,1,1,1,1,1,0,0,0,1,0,1,0,0,0,1,1,1,1,0,0,1,1,1,0,1,1,1,1,0,0,1,1,0,0,1,0,0,1,0,0,1,0,1,1,0,1,1,0,1,0,0,0,1,1,1,0,1,0,1,0,0,1,1,0,0,0,0,1,1,0,1,1,0,1,0,1,1,0,1,0,1,1,0,1,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,0,0,0,0,1,1,
- 35,792
- 12
- 63
- 121