Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 17 of 17

Thread: ARM EEPROM on Teensy 3

  1. #1

    ARM EEPROM on Teensy 3

    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?

    Aug_22_2013_GOOD.ino

  2. #2
    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.

  3. #3
    Senior Member
    Join Date
    Nov 2012
    Posts
    1,546
    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

  4. #4
    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.

  5. #5
    Senior Member+ MichaelMeissner's Avatar
    Join Date
    Nov 2012
    Location
    Ayer Massachussetts
    Posts
    3,981
    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++);
      }  
    }
    }

  6. #6
    Quote Originally Posted by MichaelMeissner View Post
    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++);
      }  
    }
    }

  7. #7
    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.

  8. #8
    Quote Originally Posted by LC475 View Post
    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?

  9. #9
    Senior Member
    Join Date
    Jan 2013
    Posts
    843
    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.

  10. #10
    Quote Originally Posted by tni View Post
    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!

  11. #11
    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_function s.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?

  12. #12
    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?

  13. #13
    Senior Member
    Join Date
    Jan 2013
    Posts
    966
    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.

  14. #14
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    23,789
    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.

  15. #15
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    23,789
    Here are updated files. These go into hardware/teensy/cores/teensy3.
    Attached Files Attached Files

  16. #16
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    23,789
    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?

  17. #17
    Quote Originally Posted by PaulStoffregen View Post
    Here are updated files. These go into hardware/teensy/cores/teensy3.
    Ha-HA! It works!

    Thank you so very, very much, Paul. Your reputation for wonderful support is clearly well deserved.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •