0

I have a project that runs on the Arduino Mega 2560 which takes up almost the complete amount of flash memory available (https://github.com/fredlcore/bsb_lan/blob/master/BSB_lan.ino). Because of this, I'm planning on migrating the project to the Arduino Due.

My main problem at the moment is to port those functions that access flash memory in the "far" memory area (>64k) for which on the one hand various _PF functions (like strncpy_PF) are provided, and on the other hand a dummy "pointer" type uint_farptr_t (which is actually uint32_t) is available.

My problems now are twofold:

  1. While the _PF functions have specific definements for the Due which under "normal" circumstances should work without changes in the code, they expect different variable types. For example, strncpy_PF takes uint_farptr_t (i.e. uint32_t) as argument for src on the Mega, it expects a const char * on the Due. Compilation thus results in lots of errors.

  2. For the Mega to be able to access char arrays (which are 16 Bit on the Mega) above 128k, I need a rather dirty workaround (see function calc_enum_offset() in the code linked above). Basically I need to take the memory address of a 16 Bit char pointer and make some calculations to get the final address from which I read the strings. On the Mega, I can do these calculations on the basis of uint_farptr_t and then read from the calculated memory address with pgm_read_byte_far() for example. On the Due, however, pgm_read_byte_far(addr) is translated to (*(const unsigned char *)(addr)). Again, the uint32_t type does not fit this.

Do you have any suggestions on how I should tackle these issues with the least amount of code?

2
  • 1
    the pointer type on Due has 32 bits so const char* is uint32_t. I would use ifdefs to skip use of far variants
    – Juraj
    Commented Dec 20, 2019 at 9:35
  • @Juraj: Hm, uint_farptr_t on the Mega is also uint32_t, and I use it to access the memory locations of the strings in flash rom (which I calculate based on the (truncated) 16-Bit char pointer. Is there a way to access the memory locations of the const char* texts on the Due in a similar way, say by getting the memory address of the const char*, make some calculations on this address and read (e.g. a character) from the resulting memory location? This may be not/less efficient, but if it would enable me to keep most of my code running on two architectures, it would be what I'm looking for.
    – fredlcore
    Commented Dec 23, 2019 at 20:31

1 Answer 1

1

The Due, being ARM, is a von Neumann architecture. That means that it has no concept of "progmem", "near" or "far" pointers, etc. There are no _P or _PF variant functions, but the Arduino core provides simple stubs as a convenience.

Instead all "flash" memory access is just simple memory accesses using const.

The best thing you can do is to use preprocessor macros to select between AVR and ARM code:

#if defined(__AVR__)
    strncpy_PF(buffer, enumstr+c, sizeof(buffer));
    buffer[sizeof(buffer)-1] = 0;
    outBufLen+=sprintf(outBuf+outBufLen,"%d - %s",val,buffer);
#else
    outBufLen += sprintf(outBuf + oufBufLen, "%d - %s", val, cmdtbl[i].enumstr);
#endif

In fact, given the huge amount of "hackiness" involved in that program with regards the cmdtbl, and the massive amounts of code that just aren't needed on the Due, it may be better to start a fresh program that is Due specific and delete the swathes of unneeded code.

3
  • Thank you for the useful example, and yes, a rewrite would certainly be the best option, but given the fact that the current user base with the Arduino Mega is several hundred users whom I would still like to provide with bugfixes without having to maintain two code-bases, that's not an option. Applying your example in varying forms to all the 100+ occurrences of the ...far... functions would make the code a complete mess. So I'm still hoping whether there is a way to solve this on the level of the functions being called and then handled there based on the respectivee architecture?
    – fredlcore
    Commented Dec 23, 2019 at 20:26
  • You could put everything into wrapper functions then supplicate those functions for each platform. Move the different platforms to different include files, then only include the right for for the current architecture.
    – Majenko
    Commented Dec 24, 2019 at 9:07
  • That sounds like a feasible plan, thank you!
    – fredlcore
    Commented Dec 24, 2019 at 9:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.