ARM EEPROM on Teensy 3

Status
Not open for further replies.

LC475

Member
Hello Forums!

I'm so sorry to bother you, but I recently bought three Teensy 3.0 boards. I have a sketch which compiles fine and works on Teensy 2.0, but when I try to compile it for Teensy 3.0, it won't work. I am using it with the latest Teensyuino version, and Arduino 1.0.5.

Here is the error info the Arduino software provides:

Aug_22_2013_GOOD.cpp.o: In function `readFloat(int)':
C:\Program Files (x86)\Arduino/Aug_22_2013_GOOD.ino:396: undefined reference to `eeprom_read_block'
Aug_22_2013_GOOD.cpp.o: In function `writeFloat(float, int)':
C:\Program Files (x86)\Arduino/Aug_22_2013_GOOD.ino:401: undefined reference to `eeprom_write_block'
collect2.exe: error: ld returned 1 exit status

I wish I was experienced enough at this to handle this myself, but sadly I am new and in over my head. I do notice that in my sketch is this line:

#include <avr/EEPROM.h>

And there is no "avr" folder in libraries. However, changing the line does not fix the problem. I think it must be including the EEPROM library buried in subfolders for AVR. So, the problem must be something to do with the new 32-bit chip, right?

Sketch is attached below. I hope the problem is reproducible. Any ideas?

View attachment Aug_22_2013_GOOD.ino
 
Here is all it's doing with the EEPROM, by the way, so you don't have to wade through all the other irrelevant code in the sketch:

Code:
// These are addresses into EEPROM memory.  The values to be stores are floats which
// need 4 bytes each.  Thus 0,4,8,12,...
#define PGAIN_ADR 0
#define IGAIN_ADR 4
#define DGAIN_ADR 8




// Simple extension to the EEPROM library
// Tim Hirzel
// All code released under
// Creative Commons Attribution-Noncommercial-Share Alike 3.0

#include <avr/EEPROM.h>

float readFloat(int address) {
  float out;
  eeprom_read_block((void *) &out, (unsigned char *) address ,4 );
  return out;
}

void writeFloat(float value, int address) {
  eeprom_write_block((void *) &value, (unsigned char *) address ,4);
}

// END EEPROM Float

That's it. Then there's serial input and output to change the values, but I think that's all that the sketch does directly concerning EEPROM. Arduino compiles this sketch fine for Teensy 2.0, and in fact for all the Teensy versions except for 3.0.
 
The basic AVR EEPROM functions exist but not eeprom_read_block and eeprom_write_block.
Try these changes. Use:
Code:
#include <EEPROM.h>

and add these two functions :
Code:
void eeprom_read_block(unsigned char *o, int a, int n)
{
  for(int i = 0;i < n;i++) {
    *o++ = EEPROM.read(a++);
  }  
}

void eeprom_write_block(unsigned char *o, int a, int n)
{
  for(int i = 0;i < n;i++) {
    EEPROM.write(a++,*o++);
  }  
}

Pete
 
El Supremo,

Thank you so much! It is so kind of you to reply. I am extremely dismayed to report, however, that I have been unable to get it working, as of yet. I have added the functions -- outside of void setup() and void loop()'s brackets, just as (I think!) is the correct way -- but it still tells me

undefined reference to 'eeprom_read_block'
undefined reference to 'eeprom_write_block'

But I did define them, thanks to you! Hmm...

Maybe it's something in the *o, a, and n? I have no idea what those are.
 
Given the error messages, I assume eeprom_read_block and eeprom_write_block need to be defined as C functions instead of C++, so you might try wrapping the two functions in extern "C" { ... }:

Code:
extern "C" {
void eeprom_read_block(unsigned char *o, int a, int n)
{
  for(int i = 0;i < n;i++) {
    *o++ = EEPROM.read(a++);
  }  
}

void eeprom_write_block(unsigned char *o, int a, int n)
{
  for(int i = 0;i < n;i++) {
    EEPROM.write(a++,*o++);
  }  
}
}
 
Given the error messages, I assume eeprom_read_block and eeprom_write_block need to be defined as C functions instead of C++, so you might try wrapping the two functions in extern "C" { ... }:
Sounds good. Did it.

Got some errors about conflicting with some existing eeprom_read_block functions in EEPROM.h and avr_functions.h. Namely this, BTW:

Code:
sketch_oct04a.ino: In function 'void eeprom_read_block(unsigned char*, int, int)':
sketch_oct04a:34: error: declaration of C function 'void eeprom_read_block(unsigned char*, int, int)' conflicts with
In file included from C:\Program Files (x86)\Arduino\libraries\EEPROM/EEPROM.h:26:0,
                 from sketch_oct04a.ino:1:
C:\Program Files (x86)\Arduino\hardware\teensy\cores\teensy3/avr_functions.h:45:6: error: previous declaration 'void eeprom_read_block(void*, const void*, uint32_t)' here
sketch_oct04a.ino: In function 'void eeprom_write_block(unsigned char*, int, int)':
sketch_oct04a:41: error: declaration of C function 'void eeprom_write_block(unsigned char*, int, int)' conflicts with
In file included from C:\Program Files (x86)\Arduino\libraries\EEPROM/EEPROM.h:26:0,
                 from sketch_oct04a.ino:1:
C:\Program Files (x86)\Arduino\hardware\teensy\cores\teensy3/avr_functions.h:50:6: error: previous declaration 'void eeprom_write_block(const void*, void*, uint32_t)' here

So, I just renamed the functions to eeprom_read_block2 and eeprom_write_block2.

Now, we are still having the exact same problem as all along. "eeprom_read_block2 / eeprom_write_block2 Not declared in this scope"

Here I've stripped out everything from the code except the EEPROM stuff. Maybe that will help to figure it out. I might just be doing something horribly obvious wrong. Here is the entire sketch.

Code:
#include <EEPROM.h>

// These are addresses into EEPROM memory.  The values to be stores are floats which
// need 4 bytes each.  Thus 0,4,8,12,...
#define PGAIN_ADR 0
#define IGAIN_ADR 4
#define DGAIN_ADR 8


void setup()
{
}


void loop()
{  
}



float readFloat(int address) {
  float out;
  eeprom_read_block2((void *) &out, (unsigned char *) address ,4 );
  return out;
}

void writeFloat(float value, int address) {
  eeprom_write_block2((void *) &value, (unsigned char *) address ,4);
}



extern "C" {
void eeprom_read_block2(unsigned char *o, int a, int n)
{
  for(int i = 0;i < n;i++) {
    *o++ = EEPROM.read(a++);
  }  
}

void eeprom_write_block2(unsigned char *o, int a, int n)
{
  for(int i = 0;i < n;i++) {
    EEPROM.write(a++,*o++);
  }  
}
}
 
Actually, wait, that's not the same! Before it was undefined reference, now it's not declared in this scope.

And actually, if I take off the extra 2 so it's just eeprom_read_block and eeprom_write_block again, and totally remove all the extern "C" stuff, the sketch compiles successfully! But not in the full sketch. I wonder what would be messing it up.
 
I wonder what would be messing it up.

OK, what is "messing it up" is that as long as the function isn't ever actually called in setup or loop, nothing happens with it and so the compiler apparently could care less what is going on inside of it.

But then in setup when the program tells the Teensy to:

targetTemp = readFloat(ESPRESSO_TEMP_ADDRESS);

it tries to do it, and fails horribly.

I am a bit confused as to why I got the conflict with the extern "C" stuff referring to a function that already exists in eeprom.h. I thought you guys said that the eeprom_read_block and eeprom_write_block wasn't included in the Teensy 3.0.

I am picking this stuff up, step by step, but maybe what it comes down to is that the Teensy 3.0 cannot do simple things like read blocks of EEPROM larger than 1 byte and I should just return them?

Maybe the Arduino Micro would be a better choice for a neophyte like me.

Thoughts?
 
Do some reading on function declaration vs. definition.
eeprom_read_block is declared as a 'C' function in:
arduino-1.0.5/hardware/teensy/cores/teensy3/avr_functions.h
void eeprom_read_block(void *buf, const void *addr, uint32_t len); // TODO: implement

But the implementation is missing. That's why the linker error: "undefined reference to `eeprom_read_block'".

Your eeprom_read_block function signature:
void eeprom_read_block(unsigned char *o, int a, int n)
doesn't match the original signature/isn't a C function. With C++, you have function overloading. That's why the linker error didn't go away without the extern "C" (the C function with the original signature is being called and your C++ version doesn't match).

When you add the extern "C", you make your function a C function and C doesn't support overloading. That's why the conflict error - the signatures must match.
 
Do some reading on function declaration vs. definition.
eeprom_read_block is declared as a 'C' function in:
arduino-1.0.5/hardware/teensy/cores/teensy3/avr_functions.h
void eeprom_read_block(void *buf, const void *addr, uint32_t len); // TODO: implement

But the implementation is missing. That's why the linker error: "undefined reference to `eeprom_read_block'".

Your eeprom_read_block function signature:
void eeprom_read_block(unsigned char *o, int a, int n)
doesn't match the original signature/isn't a C function. With C++, you have function overloading. That's why the linker error didn't go away without the extern "C" (the C function with the original signature is being called and your C++ version doesn't match).

When you add the extern "C", you make your function a C function and C doesn't support overloading. That's why the conflict error - the signatures must match.
THANK YOU! Wow, you are a genius. Thank you for looking at my little problem here and applying your brilliance to it. I knew that it must be conflicting with some code somewhere (the error message said as much), but I didn't know where that code would be. So, what would the solution be? Can I just delete or comment out the line:

// void eeprom_read_block(void *buf, const void *addr, uint32_t len);[/I][/B]

in avr_functions.h? Will that cause any other problems? Anyway, I am going to try it and see. Wish me luck!
 
OK, I've tried a ton of different things, modifying files far and wide. Could anyone walk me through exactly what I'm supposed to add and where? Should I indeed switch from
#include <avr/EEPROM.h>
to
#include <EEPROM.h>

as Pete suggested? Where should I put the code he suggested? In Arduino\hardware\tools\avr\avr\include\avr\eeprom.h? Or Arduino\hardware\teensy\cores\teensy3\avr_functions.h? Or Arduino\libraries\EEPROM\EEPROM.h? Should a wrap it in the extern C command, or not?

In my trying various things one interesting error I was able to get was about "invalid conversion from 'void*' to 'unsigned char*' -fpermissive". I don't know what that means. Of course. Because I don't know much of anything.

I did read up on function declaration vs. definition as you suggested, tni, and so now I understand that somewhat.

In your last post, tni, were you saying that what I'm trying to do is impossible?

If so, is there any hope of eeprom being implemented by PJRC someday soon?
 
Bump.

So, is what I am trying to do impossible?

And if so, is there any hope of eeprom being fully implemented by PJRC someday soon?

Or is my only solution to return the 3.0s for a refund?
 
No, I don't believe that's impossible. These error messages are pretty cyptic ;-)
Wht the compiler is telling you that you are trying to convert one data type - 'void*' - into another - 'unsigned char*' and it cannot do that because these data types are incompatible.
The next thing to read up on is type casting in C++ which seems to be the problem.
 
I'm looking into this now.....

Edit: oh, looks like I left this for "later", due to the thorny 32/16/8 data size alignment issues.
 
Here are updated files. These go into hardware/teensy/cores/teensy3.
 

Attachments

  • avr_functions.h
    4.3 KB · Views: 252
  • eeprom.c
    8.4 KB · Views: 290
Did these new files resolve the problem?

I tested here with several cases. I'm planning to release these in version 1.17, unless I hear any report of trouble?
 
Status
Not open for further replies.
Back
Top