We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
Subject says it all. I want to place some tag into flash and than compare it with the data in my SRAM. I know that it is simple but it is hard to start. Please advise. Thanks.
I believe that you two are not on the same page.
We are developing using the Keil MCB1700 evaluation board and trying to modify the example code contained in the RTX_Blinky example from the code-size limited evaluation toll chain, which is located in C:\Keil\ARM\Boards\Keil\MCB1700\RTX_Blinky\ directory. Per, you should have access to this code, correct?
Task 6 of Blinky.c contains the function call GLCD_DisplayString(1, 0, __FI, " RTX Blinky "); The function prototype is contained in GLCD.h I believe that the body of the function is located in GLCD_SPI_LPC1700.c The prototype specifies an unsigned character pointer to the string to be displayed. I believe that this string is NULL terminated.
Boris would like to store this string in flash memory, which in the NXP1768 would have to be in program space. He also would like to not have to modify the Keil provided function body.
Just declaring the string to be a constant character array does not necessarily force the string into program space, but, in this case, it does generate the error: #167: argument of type "const unsigned char " is incompatible with parameter of type "unsigned char ". Is this because of just the type mismatch between const unsigned char and unsigned char or does the tool chain know that the const unsigned char array is in program space and an unsigned char array is in data space, and hence the incompatibility? If this is indeed that case, then is there a function in which we can copy a string from program space into data space, whether or not you think that it makes sense to do so? Or is there another source of this error? Explicitly casting the const unsigned char * to unsigned char * does not resolve the error.
Please note that we are getting to know this tool chain and this effort is an experiment to understand the compiler and linker chain. Even if we do have source code for every function, we would rather understand the tool chain and use the existing functions as they are written rather than edit every function used for each and every particular application of those functions.
Does this make sense?
Thank you.
"Is this because of just the type mismatch between const unsigned char and unsigned char or does the tool chain know that the const unsigned char array is in program space and an unsigned char array is in data space, and hence the incompatibility?"
As I already wrote in my previous post: "There is nothing magic about reading a string that is stored in flash, when using a processor architecture that have a unified memory space."
"If this is indeed that case, then is there a function in which we can copy a string from program space into data space, whether or not you think that it makes sense to do so?" Of course there is. Standard C has great abilities to copy arrays of characters or other data types from one location to another, as long as the first location has read access and the second location have write access. strcpy() might complain because of "unsigned" - solved with type casts but if typecasts are used then they are way better spent on that GLCD_DisplayString() call... - but memcpy() or memmove() will not care if the characters are signed or unsigned.
Data in flash or data in RAM doesn't matter for the C code, as long as the data is used read-only. So any function that takes as input parameter a string and don't try to change that string should specify it as const, just to make sure that a user don't get into troubles later on when having a const string and trying to send it as a parameter.
Yes, I have that example. And the code in question looks like:
void GLCD_DisplayString (unsigned int ln, unsigned int col, unsigned char *s) { GLCD_WindowMax(); while (*s) { GLCD_DisplayChar(ln, col++, *s++); } }
As can be seen, the function does not try to modify any data. So the string is only used in read-only mode. That makes it very stupid to copy the string into RAM before calling the above function. So suggesting the use of
The remaining choices then are: - Fix the function. Takes several seconds and there are zero reason to treat it as magic code just because it was supplied by Keil. It would have been a completely different issue if the source code hadn't been available - especially if the supplied binary had been built as C++ and so had name-mangling for type-safe linking. - Call Keil support and tell them exactly how stupid they are to not properly use the const keyword. Ask them to look at strlen() and a number of other functions in the CRTL and ponder exactly why there is this little 'const' used here and there on input parameters. - Add a typecast that should never have been needed, just to mute the compiler.
I say that copying the data into RAM is stupid. I say it for the very simple reason that it really is stupid. You make sure you have your variables in RAM if the goal is to modify them. There are no such goal here. So zero (!) reason to suggest code for copying the string into RAM.
So with that solution a non-contender, there are just the three I have suggested. Why are you considering them as non-contenders? Because you think Keil-supplied code is written by gods and must never be changed by a mere mortal?
"Explicitly casting the const unsigned char * to unsigned char * does not resolve the error." You sure your cast was correct? And at the correct place?
The CRTL is part of a language standard. So if unhappy with a CRTL function, the way to solve the issue is to write a new function that does what is wanted. CRTL functions should never be touched unless they really are buggy.
The GLCD code is not part of any language standard. There are very weak reasons to treat it as magic. But there are reasons to tell Keil that they should consider good coding practices. While waiting (potentially an infinite time), that example code could very quickly be fixed.
"Even if we do have source code for every function, we would rather understand the tool chain and use the existing functions as they are written rather than edit every function used for each and every particular application of those functions." It has not anything with "every particular application of those functions" to do. A function that specifies it takes a const string will be just as happy receiving a non-const string. That const keyword is a contract - an agreement - where the function promises to not try to abuse the pointer and write to the memory. Any function that takes characters for printing and do not try to write to the specified memory really should specify "const".
The GLCD_DisplayChar() and its missing const has nothing with learning the tool chain to do. The rules would be the same for a C program on a PC. The PC program can store the strings write-protected inside the 'text' segment of the PC program. Writing to that region will kill the program (unless tried all the way back at 16-bit MS-DOS). And the contract fine print the compiler would like to find when sending a const array to a function is that promise from the function that it will not try to modify the array. Hence the introduction of that const keyword - a keyword the language have had for a very, very long time for a very good reason.
Using Keil or an LPC17xx chip makes no difference. Standard C is still standard C. Bugs or bad code needs to be fixed. So fix, and move on.
The way I'm understanding this whole thread is that some people are trying to learn new stuff and asking for help while other person has difficulties to understand what the goal is and instead of helping are making the issue more complex!
Does anyone care what the function GLCD is what parameters it has and how god or bad it was written? I don't think so.
Is this stupid function is used only for the reason to provide visual output? My guess is that is the case!
Is the root of the problem that attempts to provide this function with some string located in the flash are failing? I bet!
Wasn't that problem requested the desire to use memcpy()? I have no doubt about it!
Isn't all of the above is caused by the lack off KEIL's tool chain online documentation and examples? Shame on them!
Hey, KEIL, where are you?!
How is a type cast making it more complex?
How is a duplication of a string into RAM _not_ making it more complex?
How is understanding the meaning of the "const" keyword not relevant to learning new tools?
The GLCD function may be 100% totally irrelevant. But anyone who wants to store a string in flash are likely to want to use that string without modifying it. So that someone are then doing well realizing that a copy into RAM is the wrong solution when a const/non-const conflict is caused by the "const" keyword not being used where it should have been used.
Next thing - Keils documentation aren't part of any shame here. It isn't up to Keils documentation to cover basic knowledge of the C programming language. If I sell a stereo, I should supply a manual how to connect the cables to it and how to operate it - I shouldn't have to write a manual on how to decide what music to like. Or how to understand the difference between opera and rock music.
In the end, the addition of a const keyword to that GLCD function is very much in line with what the OP have to consider doing when writing own code, if the OP do want to make use of write-protected arrays stored in flash.
The OP did say "please advice". And the advice is that the data must be copied into RAM if it is going to be modified. It can be used directly where it is, if it shouldn't be modified. But then the OP need to make sure that the code is "const"-correct. Either by making sure every pointer really have the correct type. Or by confusing the code by adding type casts.
So in the end - the answers given are exactly in line with what is requested. The problem is that the OP have assumed that the answers given should sound differently. But why give wrong answers just to make the OP happy?
When the OP have a specific case where copying of data from flash into RAM is meaningful, then - and first then - would it be meaningful to discuss such copying. But on the other hand, such copying would still be a trivial operation since the ARM chip don't care if the source is in flash or in RAM. It only cares that the source is readable and that the target allows writes. So standard C applies with zero embedded-specific or Keil-specific magic.
And shouted a mute man to a deaf one...
Der Mohr hat seine Schuldigkeit getan; der Mohrkann gehen
while other person has difficulties to understand what the goal is and instead of helping are making the issue more complex!
I think you got it absolutely right.
I have an old version of this RTX_Blinky. I did some tests.
Modified Blinky.c =>
/*---------------------------------------------------------------------------- * Task 6 'lcd': LCD Control task *---------------------------------------------------------------------------*/ __task void lcd (void) { const unsigned char hello[] = "Hello"; for (;;) { os_mut_wait(mut_GLCD, 0xffff); GLCD_SetBackColor(Blue); /* Set the Text Color */ GLCD_SetTextColor(White); /* Set the Text Color */ GLCD_DisplayString(0, 0, " MCB1700 RL-ARM "); GLCD_DisplayString(1, 0, " RTX Blinky "); GLCD_DisplayString(2, 0, " http://www.keil.com "); GLCD_DisplayString(2, 0, hello); os_mut_release(mut_GLCD); os_dly_wait (400); os_mut_wait(mut_GLCD, 0xffff); GLCD_SetBackColor(Blue); /* Set the Text Color */ GLCD_SetTextColor(Red); /* Set the Text Color */ GLCD_DisplayString(0, 0, " MCB1700 RL-ARM "); GLCD_DisplayString(1, 0, " RTX Blinky "); GLCD_DisplayString(2, 0, " http://www.keil.com "); os_mut_release(mut_GLCD); os_dly_wait (400); } }
KEIL toolchain says: -> Blinky.c(142): error: #167: argument of type "const unsigned char *" is incompatible with -> parameter of type "unsigned char *"
Modified Blinky.c, added a casting =>
__task void lcd (void) { const unsigned char hello[] = "Hello"; for (;;) { os_mut_wait(mut_GLCD, 0xffff); GLCD_SetBackColor(Blue); /* Set the Text Color */ GLCD_SetTextColor(White); /* Set the Text Color */ GLCD_DisplayString(0, 0, " MCB1700 RL-ARM "); GLCD_DisplayString(1, 0, " RTX Blinky "); GLCD_DisplayString(2, 0, " http://www.keil.com "); GLCD_DisplayString(2, 0, (unsigned char *)hello); os_mut_release(mut_GLCD); os_dly_wait (400);
KEIL toolchain says: -> ".\Obj\Blinky.axf" - 0 Error(s), 0 Warning(s).
-- I have learnt a lot from Per Westermark's articles. His articles are very detailed and well organized. I can understand that, some people just don't like/need so much details. But, to me, those are very valuable information. I would like to take this opportunity to thank Per Westermark again.
If one would ask: “What is the weather forecast for today?" And another one would provide extended "answer" including historical data and definitions of units and bunch of other very helpful and useful information; I won't consider this imaginary conversation as a question and answer. When the question about the weather has been asked the other person should probably at least ask: “Weather where?" Without this tiny detail the OP question could not be answered. That is actually all my point. Thank you for listening :)