PaulS:
The question is why do you need to store the data in EEPROM, instead of, say an SD card?
I have got the shield, and have run a couple of the example sketches. I just need to spend some more time with it. I'll likely need it for another part of the program I may or may not be able to implement. I'm a little concerned about the speeds but I'll need to do some testing to see if those concerns are valid.
If have come across detailed tutorials for using sd, I would love to see. What I breezed over in the playground left me a little blurry. Maybe I'll take a closer look latter today.
26 is fine, maybe even 52 would be fine (adding capital letters). It is adding numbers, symbols, synonymous chord values and then combining this with the main program body where memory usage is going to get hairy.
I should have disclaimed that the crashes I got were with arrays of 128 ints which are much bigger not just a little. I really thought with 2k of ram the arduino would have been able to even handle that, but apparently there is a bit of over head and with the bits and bobs of my example program, it choked.(what little serial debugging I was doing stopped midway and could get further depending on array size) Could have been my code, however If things were getting hairy in an example/test program I would expect there to be issues with much more code to be added, so since then I've become conscious of memory usage.
PeterH:
It would be a good idea for you to describe the data you're trying to persist more clearly.
Is it all predefined and constant, or will it be modified at runtime? How much data is there? What is the structure? How is it accessed? How will it be modified?
I guess the gotcha to this whole thing is that the data needs to be modified during run time. The main body of code "guesses" what letter the user is trying to type and assigns it. It needs to interpret the chord, make the "educational guess" and the assign the chord with in at least a 50ms time window to be responsive (as far as I understand, might be more or less wiggle room)
I'm fairly new to programming so structure and access are all experimental to me. An int array seems like a good middle of the road approach since using a struct is too much. As far as access goes I'm just using for loops to iterate through the data till I find what I want.
There are probably better strategies for doing this I'm just not aware yet.
PeterH:
I have no idea how you're doing that - are you using some sort of lookup table, or something?
Assume I have no idea what your sketch does - what's the structure of your data, how is it accessed and which parts of it are modified at runtime?
the "guess" right now, isn't vary intelligent yet. Currently just a for loop that goes through unassigned letters (i.e. chordValue==0) alphabetically, then it prints the letter and assigns the value it was tested against (the chordValue coming from the user). This is the write during run time and it need to be keep persistently unless the user deletes that letter which signals that the letter was unwanted for that assignment in which case it goes back to zero. Representing another write situation during runtime
i would post code but its really too messy for anyone to make sense of yet.
So it sounds like you have a 'letter' identifying the chord which is assigned by choosing the first unassigned letter when the chord is first encountered, and a 'chordValue' which somehow specifies the chord. What data type is 'chordValue'?
PeterH:
So it sounds like you have a 'letter' identifying the chord which is assigned by choosing the first unassigned letter when the chord is first encountered, and a 'chordValue' which somehow specifies the chord. What data type is 'chordValue'?
an int, I tried a byte which should have theoretically been sufficient but it proved difficult.
I had to divide the unique value aka chordValue that the user created to fit into a 255 value range. The removing of the fractional value along the way, made me account for slight discrepancy thus reducing the value space of a byte by around a third.
I need to rewrite how the chordValue is derived to make the necessary action feel more consistent to the user, so what the values will be are still up in the air, but I think its safe to say at this point that its out of the range of a byte and within the range of an int.
I think ive come up with away to check the value without making an array.
char checkAlt(int chordValue, int modifier)//untested
{
int startAddress;
int endAddress;
if (modifier==96)
//lower case letters
{
startAddress=1;
endAddress=27;
}
if (modifier==38)
//Capital letters
{
startAddress=27;
endAddress=53;
}
//add more modifier definitions here, for symbols
for(int i=startAddress;i>endAddress;i++)
{
int address=i*2-1;
//this should assure a unique address for an int, given values are correct
//probably could have incremented by 2, but the same vars would still need definitions
int tempChord=EEPROM.readInt(address);
if(tempChord==chordValue)
{
lastLetter=char(i+modifier);
return lastLetter;
}
}
}
Still doesn't negate the "maximum write" problem, in fact It could make it worst, but it does take care of the issue of size. I just need to write an assignment function now.
I'm going to have to look into it more, but since I'm modifying so many of the variables during run time its hard for me to see where to use progmem yet, A quick example with some of the code I've be throwing around would be great
the only string literals i can think are the debugging messages at the moment.. am I being too narrow?
wait a sec... are the debug messages in the library being loaded into ram?... That would explain the crashes..
So I think your data consists of an array of ints; the index into the array is the 'chord index' and the value is the chordValue associated with that index.
If you want to associate each chord with a letter then I'd add 'a' to the chord index to get the chord letter (so 'a' becomes 0, 'b' becomes 1 and so on). I guess that when you encounter a chord you would first check against the existing known chord, and if none matched you'd allocate the next available index and store the chord value in it.
It would be easy enough to access the chord values in EEPROM by providing read and write access functions that handled the translation between the int array your application is dealing with, and the byte array that the EEPROM interface presents.
PeterH:
So I think your data consists of an array of ints; the index into the array is the 'chord index' and the value is the chordValue associated with that index.
Right on, chord index gets converted to the letter that the chordValue is associated with.
now stay with me on this one, going to take a turn into the weeds...
Because the function, EEPROM.readBlock<int>(address, array, size);
requires bringing the whole array into ram, I run into issues when I want a larger array,
this is why I built the checkAlt( ) function I posted recently.
You have to kinda imagine the index as the iterations that the for loop is going though.
the index values get converted to address space in eeprom, (basically skipping every other byte as an int is 2 bytes)
the "modifier" helps reduce interations by selectively searching address space
This makes things more complex but gives the needed flexibility
The assignment function was a little more of a puzzle then expected, heres a part of it.
keep in mind the letter coming in will actually be the ascii number associated with it, see here http://web.cs.mun.ca/~michael/c/ascii-table.html
int assignAlt(int chordValue, int letterNum)
//returns overwritten value... just in case
{
if(letterNum>ALPHA && letterNum<123)
{
int startAddress=1;
int endAddress=27;
int modifier=96;
for(int i=startAddress;i<endAdress;i++)
{
if(letterNum==i+96)
{
int address=i*2-1;
int lastValue=EEPROM.readInt(address, chordValue);
EEPROM.writeInt(address);
return lastValue;
}
}
}
if(letterNum>64 && letterNum<59)
{
address=;
}
}
Wondering if this is possible with out the for loop, gathering the address from an equation?
I would start the problem from the bottom up. Assuming that the chords will be held in EEPROM as an array of ints starting at a known position within the EEPROM, you need to be able to read and write to the int values within that array. An API to do that could be:
// incomplete, untested
const int CHORD_BASE = 0;
const int CHORD_COUNT = 26;
const int UNDEFINED_CHORD = -1;
// read a chord from the store (returns UNDEFINED_CHORD if no value stored)
int readChord(byte chordNumber)
{
// pull two bytes out of EEPROM at the appropriate position and make an int out of them
return word(EEPROM.read(CHORD_BASE+(2*chordNumber)), EEPROM.read(CHORD_BASE+(2*chordNumber)+1));
}
// write a chord to the store
void writeChord(byte chordNumber, int chordValue)
{
// split the int into two bytes and write them to EEPROM at the appropriate position
EEPROM.write(CHORD_BASE+(2*chordNumber), highByte(chordValue);
EEPROM.write(CHORD_BASE+(2*chordNumber)+1, lowByte(chordValue);
}
Then you would build the allocation/lookup functions on top of that:
// incomplete, untested
// return the chord number associated with this chord value, allocating it if necessary
byte getChordNumber(chordValue)
{
// walk through the array of chords until a matching value is found, append to the array if no match found
for(byte i = 0; i < CHORD_COUNT; i++)
{
int val = readChord(i);
if(val == chordValue)
{
// this element holds the chord we're looking for
return i;
}
else if (val == UNDEFINED_CHORD)
{
// this element is empty so store the new chord here
writeChord(i, chordValue);
return i;
}
}
// we failed to identify an existing chord and also failed to find space for a new chord
return 0; // consider returning some other value to indicate an error condition, but make sure you calling code handles it
}
I'd also suggest that you do the chord number to chord letter conversion at the interface, and represent them as numbers internally. All you need to do is a range check to confirm it's a character in the correct range 'a'-'z', and subtract 'a' from it.
Perfect, now I see the light at the end of the tunnel, definitely shows this can be done without the library. I'll put a proof of concept together tomorrow.
I didn't even know these functions existed
word(byte, byte);//syntax is kind quirky for what it seems to do
//can it handle other variable types?
highByte(int);
lowByte(int);
Now I do,.. learn something new everyday
Thank you Peter, for taking the time to draft that out.
Success!! Well at least for me, anyone concerned with the issue the op stated is still SOL
The solution to me is the library is unnecessary
Though I do applude its effort and intention
Wear leveling is the only thing that I'm missing out on now, but I can afford to figure that out later
Anyhow here is the example code I came up with tested and working
feel free to try it out and do what you want with it, only requires the uno.
/*eepromtest
*test character layout building functions using eeprom
*prints actions to serial monitor
*
*/
#include <EEPROM.h>
byte key=22; // change to be able to do a second write, between 1-255
void setup()
{
Serial.begin(9600);
delay(2000);//give some time to pull up the serial monitor and see the write
if (session(512,key))//session will read false in the case the key is different
//the session function helps reduce accidental/unnessiary writes
{
clearPROM(0,254);
randAssignment(97,123,0);//lowercase storage, addressspace=letter
EEPROM.write(512,key);//set key so assignment only happens once/change to rewrite
}
//the goes through an iteration of most of the positive int value space to check if the values stored
for (int chord = 1; chord<32000; chord++)
{
byte letteR=check(chord);
if (letteR > 0)
{
Serial.print(F(" read data equals "));
Serial.print(chord);
Serial.print(F(" and its value is equal to-> "));
Serial.println(char(letteR));
}
//else{Serial.print(letteR);};
}
}
void loop()
{
}
int assign(int letter, int chordValue)
{
int modifier=0;
int storedVal=word(EEPROM.read(letter*2), EEPROM.read(letter*2+1));
//allow letters to posibily have more then one value
if(storedVal>0)
{
if (letter>96 && letter<123)
{
modifier=-95;
}
storedVal=word(EEPROM.read(letter*2+modifier), EEPROM.read(letter*2+1+modifier));
}
EEPROM.write(letter*2+modifier, highByte(chordValue));
delay(5);
EEPROM.write(letter*2+1+modifier, lowByte(chordValue));
delay(5);
return storedVal;
}
//Checking
byte check(int chordValue)
{
byte letter=0;
for(int address=2;address<254;address=address+2)//full address range
{
int reading=word(EEPROM.read(address), EEPROM.read(address+1));
if(reading == chordValue)
{
if(address>65)
{
letter=address/2;//luckly we are just dealing with even numbers
return letter;
}
if(address<65)
//synonymous chords
{
letter=address/2+95;
return letter;
}
}
}
return letter;
}
//---------------------------------------------------------make assignments
void randAssignment(byte startL, byte endL, byte modifier)
{//random assignment
for (int makeLetter=startL;makeLetter<endL;makeLetter++)
{
int data=random(1,32000);
assign(makeLetter, data);
//debuging info
int modifiedL=makeLetter-modifier;
char makeLetterChar = char(modifiedL);
Serial.print(data);
Serial.print(F(" was assigned to "));
Serial.println(makeLetterChar);
}
Serial.println(F("Assignment made"));
}
//-----------------------------check for persistent key
boolean session(int address, byte code)
{//establishes if source has been run by checkig is a key/code has been written
byte potentialCode=EEPROM.read(address);
if(code==potentialCode){
return false;
}
else{return true;};
}
//--------------------clear EEPROM
void clearPROM(int start, int finish)
{
for(int i=start;i<finish;i++)
{
EEPROM.write(i,0);
delay(6);//again percautionary, not sure is this is nessisary
}
}
Keep in mind there is some extra kruft in here that is meant for the main program, regardless it proves the concept
I don't understand how checkEX could, itself, lead to that error message.
I'm looking at the library, and that message comes from EEPROMEx.isWriteOK - but checkEX is only reading, not writing, and is only doing so through the normal EEPROM library, not EEPROMex. Something isn't adding up here.
That said, 33000 is very close to 32768, which is when integers roll over - if the point at which things start going wrong is there, I'll bet money that that's the cutoff when things break. But I don;t know why they would.