San Pedro, CA.
Offline
Full Member
Karma: 2
Posts: 122
My head HURTS!!!
|
 |
« on: December 03, 2012, 10:29:30 am » |
I wrote a library for the External Memory interface module on the mega1280/2560. I wanted to incorperate templates into the library so I can pass any type as an argument to the functions. Someone suggested EEPROMWriteAnything from the Arduino Playground. I used the template parts of it in my library. My library and sketch are below. I really don't understand templates. I just copied that part into my library. I got it to compile and work, almost. In the sketch I write to external memory twice. The first time I pass a uint8_t type (20) to the write function, the second time I pass a uint16_t type (256). Then I read back the data from the same two addresses I had written to. In the case of the uint8_t type the data returns correctly (20). In the case of the uint16_t type it returns incorrectly (0). Here's the sketch: #include <ExMem.h>
void setup() { Serial.begin(115200); // Enables the interface with two sectors with the upper/lower boundry at 0x8000 and no wait-states ExMem.enable(16, 0x8000, 0, 0); uint8_t x1 = 20; uint16_t y1 = 256; ExMem.write(0, 0x0020, x1); // write to lower sector address 0x0020 ExMem.write(0, 0x0030, y1); // write to lower sector address 0x0030 // varibles to hold data read uint8_t x2; uint16_t y2; // The function places the data in the supplied variable // and returns the number of bytes read. Serial.println(ExMem.read(0, 0x0020, x2), DEC); Serial.println(x2, DEC); Serial.println(ExMem.read(0, 0x0030, y2), DEC); Serial.println(y2, DEC); }
void loop() { }
Sorry, I have to post twice, due to the size of the library.
|
|
|
|
« Last Edit: December 03, 2012, 12:31:14 pm by DigitalJohnson »
|
Logged
|
DigitalJohnson
|
|
|
|
San Pedro, CA.
Offline
Full Member
Karma: 2
Posts: 122
My head HURTS!!!
|
 |
« Reply #1 on: December 03, 2012, 10:31:25 am » |
Here's the library: #ifndef EXMEM_H #define EXMEM_H
#if (ARDUINO >= 100) #include <Arduino.h> #else #include <WProgram.h> #endif
#include <inttypes.h> #include <avr/io.h>
class exmem { public: exmem(); void enable(uint8_t addressWidth = 16, uint16_t lowerLimit = 0x0000, uint8_t upperSectorWaitState = 0x00, uint8_t lowerSectorWaitState = 0x00); void disable(void); template <class TYPE> uint16_t write(bool sector, uint16_t address, const TYPE &data); template <class TYPE> uint16_t read(bool sector, uint16_t address, TYPE &store); };
extern exmem ExMem;
static uint16_t upperSectorOffset = 0x0000; static uint16_t upperLimit = 0xFFFF; static uint16_t upperSize = 0xDE00; static uint16_t lowerSize = 0xDE00;
exmem::exmem() { }
void exmem::enable(uint8_t addressWidth, uint16_t upperSectorBoundry, uint8_t upperSectorWaitState, uint8_t lowerSectorWaitState) { switch (addressWidth) { XMCRB &= 0xF8; case 8: upperLimit = 0x00FF; XMCRB = 0x07; break; case 10: upperLimit = 0x03FF; XMCRB = 0x06; break; case 11: upperLimit = 0x07FF; XMCRB = 0x05; break; case 12: upperLimit = 0x0FFF; XMCRB = 0x04; break; case 13: upperLimit = 0x1FFF; XMCRB = 0x03; break; case 14: upperLimit = 0x3FFF; XMCRB = 0x02; break; case 15: upperLimit = 0x7FFF; XMCRB = 0x01; break; default: upperLimit = 0xFFFF; break; } uint16_t boundry; if (addressWidth < 15) { boundry = 0x0000; } else if (addressWidth < 16) { boundry = constrain(upperSectorBoundry, 0x0000, 0x6000); } else { boundry = upperSectorBoundry; } XMCRA &= 0x8F; switch (boundry) { case 0x4000: upperSectorOffset = 0x1E00; XMCRA |= 0x20; break; case 0x6000: upperSectorOffset = 0x3E00; XMCRA |= 0x30; break; case 0x8000: upperSectorOffset = 0x5E00; XMCRA |= 0x40; break; case 0xA000: upperSectorOffset = 0x7E00; XMCRA |= 0x50; break; case 0xC000: upperSectorOffset = 0x9E00; XMCRA |= 0x60; break; case 0xE000: upperSectorOffset = 0xBE00; XMCRA |= 0x70; break; default: upperSectorOffset = 0x0000; break; } if (0 < upperSectorOffset) { lowerSize = upperSectorOffset; upperSize = ((1 + upperLimit) - (0x2200 + upperSectorOffset)); } else { lowerSize = upperSize = ((1 + upperLimit) - 0x2200); } switch (upperSectorWaitState) { XMCRA &= 0xF3; case 1: XMCRA |= 0x04; break; case 2: XMCRA |= 0x08; break; case 3: XMCRA |= 0x0C; break; default: break; } switch (lowerSectorWaitState) { XMCRA &= 0xFC; case 1: XMCRA |= 0x01; break; case 2: XMCRA |= 0x02; break; case 3: XMCRA |= 0x03; break; default: break; } XMCRA |= 0x80; }
void exmem::disable(void) { XMCRA &= 0x7F; }
template <class TYPE> uint16_t exmem::write(bool sector, uint16_t address, const TYPE &data) { uint8_t *pExtMemory = reinterpret_cast <uint8_t *> (0x2200); const uint8_t *pData = (const uint8_t *)(const void *)&data; uint16_t i; i = 0; if (sector) { if (address >= upperSize) { return i; } } else { if (address >= lowerSize) { return i; } } for (; i < sizeof(data); i++) { if (sector) { uint8_t *pMemory; pMemory = (uint8_t *)(pExtMemory + upperSectorOffset + address++); *pMemory = (uint8_t)(*pData); } else { uint8_t *pMemory; pMemory = (uint8_t *)(pExtMemory + address++); *pMemory = (uint8_t)(*pData); } } return i; }
template <class TYPE> uint16_t exmem::read(bool sector, uint16_t address, TYPE &store) { uint8_t *pExtMemory = reinterpret_cast <uint8_t *> (0x2200); uint8_t *pStore = (uint8_t *)(void *)&store; uint16_t i; i = 0; if (sector) { if (address >= upperSize) { return i; } } else { if (address >= lowerSize) { return i; } } for (; i < sizeof(store); i++) { if (sector) { uint8_t *pMemory = (pExtMemory + upperSectorOffset + address++); *pStore++ = (TYPE)(*pMemory); } else { uint8_t *pMemory = (pExtMemory + address++); *pStore++ = (TYPE)(*pMemory); } } return i; }
exmem ExMem = exmem();
#endif
Can someone please tell me why the second read returns incorrectly. Thanks for your time, DJ
|
|
|
|
« Last Edit: December 03, 2012, 10:32:56 am by DigitalJohnson »
|
Logged
|
DigitalJohnson
|
|
|
|
San Pedro, CA.
Offline
Full Member
Karma: 2
Posts: 122
My head HURTS!!!
|
 |
« Reply #2 on: December 03, 2012, 10:35:10 am » |
In the serial monitor, when I run the sketch, I get 1 20 2 0 I should get 1 20 2 256 If I change the second write from uint16_t to uint8_t type it returns correctly. As I stated earlier templates are very confusing to me, but I almost have this working. Frustrating!  I really do apreciate any help on this. The functions in question are the last two in the library. The rest of the library works fine. Again thanks for your time, DJ
|
|
|
|
« Last Edit: December 03, 2012, 11:08:35 am by DigitalJohnson »
|
Logged
|
DigitalJohnson
|
|
|
|
San Pedro, CA.
Offline
Full Member
Karma: 2
Posts: 122
My head HURTS!!!
|
 |
« Reply #3 on: December 03, 2012, 11:28:36 am » |
If I break up the uint16_t type into two uint8_t types and write them seperately. It will read back in a uint16_t type as it should. So, the problem is in the write function. I've almost got it. I'll test some more and post back.
DJ
|
|
|
|
|
Logged
|
DigitalJohnson
|
|
|
|
Offline
Edison Member
Karma: 26
Posts: 1339
You do some programming to solve a problem, and some to solve it in a particular language. (CC2)
|
 |
« Reply #4 on: December 03, 2012, 12:02:18 pm » |
Not 100% sure about what's wrong here, but this line in read() *pStore++ = (TYPE)(*pMemory);
looks suspicious to me. You are "reconstructing" the type byte-by-byte, so you don't want to cast the bytes you read from the external memory to the full type. Also, I noticed in write() you don't increase pData. I suspect you're writing only the first byte of "data". Finally (this might be harmless): const uint8_t *pData = (const uint8_t *)(const void *)&data;
Why a double cast ? Disclaimer: I could have misunderstood your code... 
|
|
|
|
|
Logged
|
|
|
|
|
San Pedro, CA.
Offline
Full Member
Karma: 2
Posts: 122
My head HURTS!!!
|
 |
« Reply #5 on: December 03, 2012, 12:24:03 pm » |
@tuxduino  Thank you very much! It finally works. As for the double cast, I'm not sure. Copied it from EEPROMWriteAnything. You've been a big help. If there's anything I can do for you... Thanks again, DigitalJohnson PS. I'll share for anyone that can use it. External Memory library ExMem.h #ifndef EXMEM_H #define EXMEM_H
#if (ARDUINO >= 100) #include <Arduino.h> #else #include <WProgram.h> #endif
#include <inttypes.h> #include <avr/io.h>
class exmem { public: exmem(); void enable(uint8_t addressWidth = 16, uint16_t lowerLimit = 0x0000, uint8_t upperSectorWaitState = 0x00, uint8_t lowerSectorWaitState = 0x00); void disable(void); template <class TYPE> uint16_t write(bool sector, uint16_t address, const TYPE &data); template <class TYPE> uint16_t read(bool sector, uint16_t address, TYPE &store); };
extern exmem ExMem;
static uint16_t upperSectorOffset = 0x0000; static uint16_t upperLimit = 0xFFFF; static uint16_t upperSize = 0xDE00; static uint16_t lowerSize = 0xDE00;
exmem::exmem() { }
void exmem::enable(uint8_t addressWidth, uint16_t upperSectorBoundry, uint8_t upperSectorWaitState, uint8_t lowerSectorWaitState) { switch (addressWidth) { XMCRB &= 0xF8; case 8: upperLimit = 0x00FF; XMCRB = 0x07; break; case 10: upperLimit = 0x03FF; XMCRB = 0x06; break; case 11: upperLimit = 0x07FF; XMCRB = 0x05; break; case 12: upperLimit = 0x0FFF; XMCRB = 0x04; break; case 13: upperLimit = 0x1FFF; XMCRB = 0x03; break; case 14: upperLimit = 0x3FFF; XMCRB = 0x02; break; case 15: upperLimit = 0x7FFF; XMCRB = 0x01; break; default: upperLimit = 0xFFFF; break; } uint16_t boundry; if (addressWidth < 15) { boundry = 0x0000; } else if (addressWidth < 16) { boundry = constrain(upperSectorBoundry, 0x0000, 0x6000); } else { boundry = upperSectorBoundry; } XMCRA &= 0x8F; switch (boundry) { case 0x4000: upperSectorOffset = 0x1E00; XMCRA |= 0x20; break; case 0x6000: upperSectorOffset = 0x3E00; XMCRA |= 0x30; break; case 0x8000: upperSectorOffset = 0x5E00; XMCRA |= 0x40; break; case 0xA000: upperSectorOffset = 0x7E00; XMCRA |= 0x50; break; case 0xC000: upperSectorOffset = 0x9E00; XMCRA |= 0x60; break; case 0xE000: upperSectorOffset = 0xBE00; XMCRA |= 0x70; break; default: upperSectorOffset = 0x0000; break; } if (0 < upperSectorOffset) { lowerSize = upperSectorOffset; upperSize = ((1 + upperLimit) - (0x2200 + upperSectorOffset)); } else { lowerSize = upperSize = ((1 + upperLimit) - 0x2200); } switch (upperSectorWaitState) { XMCRA &= 0xF3; case 1: XMCRA |= 0x04; break; case 2: XMCRA |= 0x08; break; case 3: XMCRA |= 0x0C; break; default: break; } switch (lowerSectorWaitState) { XMCRA &= 0xFC; case 1: XMCRA |= 0x01; break; case 2: XMCRA |= 0x02; break; case 3: XMCRA |= 0x03; break; default: break; } XMCRA |= 0x80; }
void exmem::disable(void) { XMCRA &= 0x7F; }
template <class TYPE> uint16_t exmem::write(bool sector, uint16_t address, const TYPE &data) { uint8_t *pExtMemory = reinterpret_cast <uint8_t *> (0x2200); const uint8_t *pData = (const uint8_t *)(const void *)&data; uint16_t i; i = 0; if (sector) { if (address >= upperSize) { return i; } } else { if (address >= lowerSize) { return i; } } for (; i < sizeof(data); i++) { if (sector) { uint8_t *pMemory; pMemory = (uint8_t *)(pExtMemory + upperSectorOffset + address++); *pMemory = (uint8_t)(*pData++); } else { uint8_t *pMemory; pMemory = (uint8_t *)(pExtMemory + address++); *pMemory = (uint8_t)(*pData++); } } return i; }
template <class TYPE> uint16_t exmem::read(bool sector, uint16_t address, TYPE &store) { uint8_t *pExtMemory = reinterpret_cast <uint8_t *> (0x2200); uint8_t *pStore = (uint8_t *)(void *)&store; uint16_t i; i = 0; if (sector) { if (address >= upperSize) { return i; } } else { if (address >= lowerSize) { return i; } } for (; i < sizeof(store); i++) { if (sector) { uint8_t *pMemory = (pExtMemory + upperSectorOffset + address++); *pStore++ = (uint8_t)(*pMemory); } else { uint8_t *pMemory = (pExtMemory + address++); *pStore++ = (uint8_t)(*pMemory); } } return i; }
exmem ExMem = exmem();
#endif
|
|
|
|
« Last Edit: December 03, 2012, 12:35:15 pm by DigitalJohnson »
|
Logged
|
DigitalJohnson
|
|
|
|
San Pedro, CA.
Offline
Full Member
Karma: 2
Posts: 122
My head HURTS!!!
|
 |
« Reply #6 on: December 03, 2012, 12:36:32 pm » |
After I get all the comments back in I'll post it on google code. Enjoy.
DJ
|
|
|
|
|
Logged
|
DigitalJohnson
|
|
|
|
Offline
Edison Member
Karma: 26
Posts: 1339
You do some programming to solve a problem, and some to solve it in a particular language. (CC2)
|
 |
« Reply #7 on: December 03, 2012, 01:42:33 pm » |
I'm glad my comment helped. 
|
|
|
|
|
Logged
|
|
|
|
|
San Pedro, CA.
Offline
Full Member
Karma: 2
Posts: 122
My head HURTS!!!
|
 |
« Reply #8 on: December 03, 2012, 05:56:49 pm » |
I've found a small bug. If I pass data type char* to the write function, say char *c1 = "hello world", it will return with a value of 2, meaning it wrote 2 bytes. Then I pass the read function a variable of char*, say char *c2, and read from the same address written to. It also returns with 2, meaning it read 2 bytes. But when I use Serial.print(c2), It prints "hello world" as it should. Why is it returning a value of 2 when it clearly is more. Float returns 4, as do double, long long returns 8, and uint8_t = 1 and uint16_t = 2, all as expected. So what's with char*?
Can anyone shed some light on this?
DJ
|
|
|
|
|
Logged
|
DigitalJohnson
|
|
|
|
Seattle, WA USA
Offline
Brattain Member
Karma: 316
Posts: 35533
Seattle, WA USA
|
 |
« Reply #9 on: December 03, 2012, 06:07:13 pm » |
it will return with a value of 2, meaning it wrote 2 bytes. The value 2 means that a pointer is 2 bytes. It has NOTHING to do with the amount of data pointed to. To verify that, create an array of ints, and pass that, via a pointer, to the class. The array can have 27 elements in it, and you will still get a 2 back.
|
|
|
|
|
Logged
|
|
|
|
|
Offline
Edison Member
Karma: 26
Posts: 1339
You do some programming to solve a problem, and some to solve it in a particular language. (CC2)
|
 |
« Reply #10 on: December 03, 2012, 06:50:34 pm » |
Hmmm... *c1 = "hello world" is not quite right. Sad reality is that *c == 'h'. "hello world" is a C-string literal, meaning it's a null-terminated string. If you want to store a char* you have to work with the C-string convention that says the string ends at the first null byte. At run time, the length of a char* (i.e. the length of a C-string) must be determined with strlen() or equivalent method. Be careful to store the final null byte or the string length, otherwise at read time you won't know where to stop or how many chars to read.
|
|
|
|
|
Logged
|
|
|
|
|
San Pedro, CA.
Offline
Full Member
Karma: 2
Posts: 122
My head HURTS!!!
|
 |
« Reply #11 on: December 03, 2012, 07:57:44 pm » |
@PaulS I suspected it had to do with the pointer to the string. Thanks for the reply. @tuxduino With this library I only need to know the location of the first address of the string. The write function, or I believe the string literal variable I pass to the function already adds the terminating null for me and the function writes all of it to memory. All I have to do to read the string back is pass the read function the first address of the string and an empty string literal variable to hold it. The read function puts every byte from the first address to the null byte into the variable. I only need to know the length of the string when writing to keep track of where the next unused address is at for the next write to avoid overlap. Thanks guys, you've help me a lot, DJ BTW How can I add karma for you. Never mind, just click on karma. Duh.
|
|
|
|
« Last Edit: December 03, 2012, 08:08:35 pm by DigitalJohnson »
|
Logged
|
DigitalJohnson
|
|
|
|
Offline
Edison Member
Karma: 26
Posts: 1339
You do some programming to solve a problem, and some to solve it in a particular language. (CC2)
|
 |
« Reply #12 on: December 04, 2012, 02:24:53 am » |
I haven't tried saving strings to eeprom with EEPROMWriteAnything, but I suspect your library needs a special case for char*' data. 
|
|
|
|
|
Logged
|
|
|
|
|
San Pedro, CA.
Offline
Full Member
Karma: 2
Posts: 122
My head HURTS!!!
|
 |
« Reply #13 on: December 06, 2012, 06:33:22 am » |
@tuxduino All I need to do is e.g.: #include <ExMem.h>
void setup() { Serial.begin(115200); ExMem.enable(8, 0x0000, 0, 0); char* textToMemory = "Hello World!"; char* textFromMemory; ExMem.write(LOWER, 0x0000, textToMemory); // Will return size of pointer(2). ExMem.read(LOWER, 0x0000, textFromMemory); // Will return size of pointer(2). Serial.println(textFromMemory); }
void loop() { }
// Will print "Hello World!" to the serial monitor.
The library is on google code here: http://code.google.com/p/arduino-exmem-library/downloads/list. If anyone has the time can you please review or better yet test the library and let me know what you think. Thanks for your time, DigitalJohnson
|
|
|
|
|
Logged
|
DigitalJohnson
|
|
|
|
|