When I declare a function that accepts const char*
and I pass a string literal, I get a
Warning: [2066] type qualifier mismatch in assignment
because string literals are rom const char*
. It's the same the other way around.
Though the PIC is Harvard architecture, the memory is mapped into one contiguous address space, so theoretically it should be possible to support both ram and rom pointers the same way. Probably I have to use rom pointers because they are 24 bit while ram pointers are 16 bit.
However, just casting a const char*
to a const rom char*
does not work.
Unfortunately, this is an inherent limitation of the Microchip C18 compiler. A pointer in C18 can point to either ROM or RAM, but not both.
This is why you will find duplicated functions for ROM and RAM operations in e.g. the Microchip Application Libraries:
BYTE* TCPPutString(TCP_SOCKET hTCP, BYTE* Data);
ROM BYTE* TCPPutROMString(TCP_SOCKET hTCP, ROM BYTE* Data);
The Hi-Tech PICC-18 compiler has the appropriate address space determined at runtime, which allows for more flexible pointer usage. This is one of the reasons I ditched C18 in favour of PICC-18.
See the answers to this question and John Temples' Comparison of Hi-Tech PICC-18 and MPLAB C18 for more insight.
Adding to the answer of mizo (I'm unable to comment, as I primarily answer on Arduino.SE and EE.SE)
The XC8 compiler also has the feature to determine the appropriate address space at runtime.
So yes, Hi-Tech PICC-18 does this, but is not the only compiler to do so.
Though I could understand if switching compiler might be impossible at the moment.
For that reason, you might want to use the following functions in string.h
/** @name memcpypgm2ram
* The {\bf memcpypgm2ram} function performs a {\bf memcpy} where
* {\bf s1} points to data memory and {\bf s2} points to program
* memory.
* @param s1 pointer to destination in data memory
* @param s2 pointer to source in program memory
* @param n number of characters to copy
*/
void *memcpypgm2ram (auto void *s1, auto const MEM_MODEL rom void *s2, auto sizeram_t n);
/** @name memcpyram2pgm
* The {\bf memcpyram2pgm} function performs a {\bf memcpy} where {\bf s1}
* points to program memory and {\bf s2} point to data memory.
* @param s1 pointer to destination in program memory
* @param s2 pointer to source in data memory
* @param n number of characters to copy
*/
MEM_MODEL rom void *memcpyram2pgm (auto MEM_MODEL rom void *s1, auto const void *s2, auto sizeram_t n);
And you could make your function like:
void YourStringFunction(ramstring);
void YourStringFunctionAccpetingRom(romstring){
YourStringFunction(memcpypgm2ram(romstring));
}
^This isn't actual code, more psuedo code. Also, I'm not sure if it's efficient.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With