I'm trying to implement some code in an Atmel datasheet. I have directly copied it from the datasheet below.
(unsigned int) (*IAP_Function)(unsigned long);
void main (void)
{
unsigned long FlashSectorNum = 200; //
unsigned long flash_cmd = 0;
unsigned long flash_status = 0;
unsigned long EFCIndex = 0; // 0:EEFC0, 1: EEFC1
/* Initialize the function pointer (retrieve function address from NMI vecto*/
IAP_Function = ((unsigned long) (*)(unsigned long))0x00800008;
/* Send your data to the sector here */
/* build the command to send to EEFC */
flash_cmd = (0x5A << 24) | (FlashSectorNum << 8) | AT91C_MC_FCMD_EWP;
/* Call the IAP function with appropriate command */
flash_status = IAP_Function (EFCIndex, flash_cmd);
}
This enables me to call a function in ROM to program the flash that runs the code in the micro.
I'm using the gcc for ARM Cortex and get an error for the first line:
expected identifier or ‘(’ before ‘unsigned’
Now, I just changed that to:
unsigned int (*IAP_Function)(unsigned long);
As it looked wrong (not sure why the return value from a function should be in brwackets) and that error went away.
However, this line:
IAP_Function = ((unsigned long) (*)(unsigned long))0x00800008;
Throws up the error:
expected expression before ‘)’ token
With the cursor being by the ) next to the *.
Unsurprisingly, I also get the error:
too many arguments to function ‘IAP_Function’
For the line:
flash_status = IAP_Function (EFCIndex, flash_cmd);
I suspect the datasheet has been poorly written in terms of that last error and, indeed, the first error.
However, the line:
IAP_Function = ((unsigned long) (*)(unsigned long))0x00800008;
I do not understand. I believe, it is trying to get the contents of 0x00800008, and use that as the pointer to the function. If that is correct, how should I write that line?
Also, are my other assumptions correct in terms of ignoring the brackets around unsigned int in the first line for the value returned from the function? Also, I assume I should just change that first line to be:
unsigned int (*IAP_Function)(unsigned long, unsigned long);
As the function call needs two values?
Many thanks :)
Line IAP_Function = ((unsigned long) (*)(unsigned long))0x00800008; casts integer to a function pointer address and assigns it to IAP_Function. Cast is required, because any self-respecting compiler should throw warning if you try to assign integer to pointer without a cast.
But as you noted return type doesn't match and for some reason there are parenthesis around it. So proper cast would look like:
IAP_Function = (unsigned int (*)(unsigned long))0x00800008;
And if you need another parameter, do add that also. Datasheet code examples are often lies, so do read carefully what manual says about the function parameters.
You should consider declaring typedef of function pointer to make sense out of this madness:
typedef unsigned (*FuncType)(unsigned long, unsigned long);
FuncType IAP_Function;
...
IAP_Function = (FuncType)0x00800008; // Nice and simple
Actually, IAP_Function = ((unsigned long) (*)(unsigned long))0x00800008; doesn't uses content of 0x00800008 as a pointer to function. It uses 0x00800008 as the address itself.
In your definition you declared IAP_Function as a function that returns unsigned int, however, when you're casting you cast to function that returns unsigned long.
Also, function takes just one argument and you're passing two. You should either change your cast and function declaration or pass only one argument.
To match the call at the bottom, the function pointer declaration at the top should be
unsigned long (*IAP_Function)(unsigned long, unsigned long);
However, the correct thing to do depends on the function that is assigned to the pointer, which you have not described.
It is out of the primary topic, but I report my result, as I found first this page for my original problem with the IAP_Function() in question.
After some tries I successfully used the IAP_Function() (a clear GPNVM Bit operation) with SAM3A8C, in the following way. The address in not 0x00800008, but 0x00100008 (I found this tip elsewhere), and IAP_Function() takes only one long argument, as described in chapter 20.5.2 of the Atmel manual. I don't know if the 0x00800008 address works similarly, but with two arguments (with EFCIndex), or these are mistypings in the manual.
Related
today I've catched quite unfamiliar situation with my code. I've changed type of variable passed as parameter to function - from unsigned char to unsigned short and...there was no warning! On the debug I saw that variable's value is truncated and rest of the functio happily play with half of value without any problem....what the heck?!
Below short code snippet:
void func1(unsigned char param)
{
if(param == 0x02) //even if passed parameter is 0x0102, truncated data fits and enter branch
{
__asm("nop"); //just anything to avoid optimization
}
}
void func2(void)
{
unsigned short param_test = 0x0102;
unsigned char test2;
test2 = param_test; //completely fine for compiler, "test2" stores 0x02 value
(void)test2; //to avoid compiler warning of not used variable
func1(param_test);
}
IAR compiler doesn't see any problem to not inform programmer that something may not work as intended...
Windows C compiler is VS at least return warning C4244: "conversion from unsigned short to unsigned char, possible loss of data". Is there any flag for IAR as well? I couldn't find it yet...
From the Annex I of the ISO/IEC 9899:1999 C Language Specification:
An implementation may generate warnings in many situations, none of which are
specified as part of this International Standard. The following are a few of the more common situations.
[...]
An implicit narrowing conversion is encountered, such as the assignment of a long int or a double to an int, or a pointer to void to a pointer to any type other than a character type (6.3).
[...]
Meaning that, according to the standard, the char type is not "generally" entitled for warning.
One potential solution, based on this particular question, is to pass the parameter as a pointer in the func1() function:
#include <stdbool.h>
bool func1(unsigned char *param);
bool func1(unsigned char *param)
{
return (*param == 0x02);
}
Under such situation, the compiler will generate a compile time error when trying to pass a pointer to a short:
func1(¶m_test);
will fail with Error[Pe167]: argument of type "unsigned short *" is incompatible with parameter of "unsigned char *".
In general, such practice can help to catch bugs at compile time with a potentially good side effect of saving some cycles.
I wasn't exactly exactly sure what title I should use for this question, but I'll try to clarify through an explanation:
So the long and short of it is that I want a functions argument to accept both an array AND an integer for the same argument. Not too difficult, just use a pointer right? So I have this:
#define BIT0 (unsigned char){0b00000001}
void foo (unsigned char *ptr_bar)
{
printf("%x", *ptr_bar);
}
void main (void)
{
foo(&BIT0);
}
Works all fine and dandy for a regular value, but in my case I need to be able to inverse the value, so I figured this would work:
#define BIT0 (unsigned char){0b00000001}
void foo (unsigned char *ptr_bar)
{
printf("%x", *ptr_bar);
}
void main (void)
{
foo(&~BIT0);
}
Just invert the value with a bitwise NOT (~) when passing it. No biggie right? Well I get the error
error: lvalue required as unary '&' operand
If I rewrite it as:
#define BIT0 (unsigned char){0b00000001}
void foo (unsigned char *ptr_bar)
{
printf("%x", *ptr_bar);
}
void main (void)
{
foo(&(unsigned char){~BIT0});
}
First off, this is a super ugly solution, and I really don't want to have to use it in my code. It doesn't feel intuitive at all.
Second, It works as I wanted it to work initially, but what I believe that this is telling me is that the '~' operator is promoting the unsigned char to an unsigned int. So I have to cast it back to an unsigned char for the function to be able to accept the address. But the error message doesn't really match up with that which is confusing me.
What's going on here? How do I work around this to get the behavior that I want?
The reason for the error is that some operators (like unary *) return a so-called modifiable lvalue, meaning a reference to an object that you can change. Most operators don't do this however and ~ is such an operator. All you get from it is a temporary read-only value. It does indeed also promote the operand to signed int, which is often problematic but not the reason for the error.
As for how to solve the problem, it's in how you use these macros. If BIT0 is a compound literal with bit 0 set, then for the sake of consistently one would probably create a similar macro:
#define BITS1_7 (unsigned char){0xFE}
(Note that binary literals aren't standard C.)
But I wouldn't do that either. The root of the problem is overengineering and insisting on using compound literals in strange ways. Instead apply the KISS principle. If you have a function accepting either a single byte or an array, then the most readable way to write the program would be:
#define BIT0 (1u << 0) // industry de facto standard way to write a bit mask
...
uint8_t tmp = BIT0;
foo(&tmp);
alternatively
uint8_t tmp = ~BIT0;
This code can be read and understood by all C programmers.
Learning C and having some issues with pointers/arrays.
Using MPLAB X and a PIC24FJ128GB204 as target device, but I don't really think it matters for this question.
The answer might be obvious, but without much background in C (yet), it is difficult to find a similar question that I understand enough to draw conclusions.
I have written an I2C library with the following function:
int I2C1_Write(char DeviceAddress, unsigned char SubAddress, unsigned char *Payload, char ByteCnt){
int PayloadByte = 0;
int ReturnValue = 0;
char SlaveWriteAddr;
// send start
if(I2C1_Start() < 0){
I2C1_Bus_SetDirty;
return I2C1_Err_CommunicationFail;
}
// address slave
SlaveWriteAddr = (DeviceAddress << 1) & ~0x1; // shift left, AND with 0xFE to keep bit0 clear
ReturnValue = I2C1_WriteSingleByte(SlaveWriteAddr);
switch (ReturnValue){
case I2C1_OK:
break;
case I2C1_Err_NAK:
I2C1_Stop();
I2C1_Bus_SetDirty;
return I2C1_Err_BadAddress;
default:
I2C1_Stop();
I2C1_Bus_SetDirty;
return I2C1_Err_CommunicationFail;
}
// part deleted for brevity
// and finally payload
for(PayloadByte = 0; PayloadByte < ByteCnt; PayloadByte++){
// send byte one by one
if(I2C1_WriteSingleByte(Payload[PayloadByte]) != I2C1_ACK){
I2C1_Stop();
I2C1_Bus_SetDirty;
return I2C1_Err_CommunicationFail;
}
}
return I2C1_OK;
}
I want to call this function from another one, using a predefined const:
const unsigned char CMD_SingleShot[3] = {2, 0x2C, 0x06};
This has the length of the command as first byte, then the command bytes.
The calling function is:
int SHT31_GetData(unsigned char MeasurementData[]){
// address device and start measurement
if(I2C1_Write(SHT31_Address,
0xFF,
CMD_SingleShot[1], // this is where the error message is given
CMD_SingleShot[0])
< 1){
return -1;
}
//code omitted for brevity
return 1;
}
The error message:
../Sensirion_SHT31.c:40:17: warning: passing argument 3 of 'I2C1_Write' makes pointer from integer without a cast
../I2C1.h:66:5: note: expected 'unsigned char *' but argument is of type 'unsigned char'
The problem is clearly
(unsigned char)CMD_SingleShot[1] where I try to give a pointer to the second byte of the unsigned char array.
I have tried:
reading up on pointers and arrays and trying to understand
searching for similar functions
given up on understanding and trying random thing hoping the error messages would lead me to the correct way of doing this. Things like:
CMD_SingleShot[1]
&CMD_SingleShot[1]
(unsigned char)CMD_SingleShot + 1
this just gave other error messages.
My questions:
given the I2C1_Write function as is (expecting a unsigned char *) (for instance, if that was not my code and I couldn't change that), how would I pass the pointer to the second byte in the cont unsigned char array? My understanding is that an array is a pointer, so
since this is my code, is there a better way to do this altogether?
First, don't do casting unless you know better than the compiler what is going on. Which, in your case, you don't. This is nothing to be ashamed of.
Doing &CMD_SingleShot[1] is a step in the right direction. The problem is that CMD_SingleShot[1] is of type const unsigned char and therefore taking the address of that gives you a pointer of type const unsigned char *. This cannot be passed to the Payload parameter since it expects a pointer of unsigned char *. Luckily you don't modify whatever Payload points to, so there is no reason for that to be non-const. Just change the definition of Payload to const unsigned char * and the compiler should be happy.
And by the way, in c, &Foo[n] is the same as Foo + n. Whatever you write is a matter of taste.
Edit:
Sometimes you don't have access to the library source code, and because of bad library design you are forced to cast. In that case, it is up to you to get things right. The compiler will happily shoot you in the foot if you ask it to.
In your case, the correct cast would be (unsigned char *)&CMD_SingleShot[1] and NOT (unsigned char *)CMD_SingleShot[1]. The first case interprets a pointer of one type as a pointer of different type. The second case interprets an unsigned character as a pointer, which is very bad.
Passing the address of the second byte of your command is done with either
&CMD_SingleShot[1]
or
CMD_SingleShot+1
But then you will run into an invalid conversion error since your command is defined as const unsigned char and then &CMD_SingleShot[1] is of type const unsigned char* but your function expects unsigned char*.
What you can do is either change the argument of your function:
int I2C1_Write(char DeviceAddress, unsigned char SubAddress, const unsigned char *Payload, char ByteCnt)
or cast your passing argument:
I2C1_Write(SHT31_Address, 0xFF, (unsigned char*)&CMD_SingleShot[1], CMD_SingleShot[0])
In the latter case be aware that casting away const'ness might result in undefined behaviour when changing it afterwards.
The function call is mostly correct, but since the 3rd parameter of the function is a pointer, you must pass an address to an array accordingly, not a single character. Thus &CMD_SingleShot[1] rather than CMD_SingleShot[1].
if(I2C1_Write(SHT31_Address,
0xFF,
&CMD_SingleShot[1],
CMD_SingleShot[0])
< 1)
However when you do this, you claim that you get "discards qualifiers from pointer target" which is a remark about const correctness - apparently CMD_SingleShot is const (since it's a flash variable or some such?).
That compiler error in turn simply means that the function is incorrectly designed - an I2C write function should clearly not modify the data, just send it. So the most correct fix is to change the function to take const unsigned char *Payload. Study const correctness - if a function does not modify data passed to it by a pointer, then that pointer should be declared as const type*, "pointer to read-only data of type".
If it wouldn't be possible to change the function because you are stuck with an API written by someone else, then you'd have to copy the data into a read/write buffer before passing it to the function. "Casting away" const is almost never correct (though most often works in practice, but without guarantees).
Other concerns:
When programming C in general, and embedded C in particular, you should use stdint.h instead of the default types of C, that are problematic since they have variable sizes.
Never use char (without unsigned) for anything else but actual strings. It has implementation-defined signedness and is generally dangerous - never use it for storing raw data.
When programming an 8 bit MCU, always use uint8_t/int8_t when you know in advance that the variable won't hold any larger values than 8 bits. There are plenty of cases where the compiler simply can't optimize 16 bit values down to 8 bit.
Never use signed or potentially signed operands to the bitwise operators. Code such as (DeviceAddress << 1) & ~0x1 is wildly dangerous. Not only is DeviceAddress potentially signed and could end up negative, it gets implicitly promoted to int. Similarly, 0x1 is of type int and so on 2's complement PIC ~0x1 actually boils down to -2 which is not what you want.
Instead try to u suffix all integer constants and study Implicit type promotion rules.
Maybe I don't find other functions, but all functions that deals with endianness that I find accept only unsigned variable. My question is why (or are there functions that deals with endianness and accept signed variable) ?
List of functions I find : here and here.
Maybe solution is to use these macro ? What is the difference between macro and above function ?
Since endianness is implementation defined, it is safe to assume that you are talking about an implementation and not C standard. Looking at the links you have sent, I think you refer to Linux and GNU C compiler.
Then under this implementation it is safe to first type pun the signed int to unsigned int, change the endianness and type pun it back.
Following is one way of doing it
union signed_unsigned {
signed long a;
unsinged long b;
} converter;
signed long to_convert = .... //whatever value
converter.a = to_convert;
converter.b = htonl(converted.b);
to_convert = converter.a;
You can make this into a macro or a function as you see fit.
As suggested by #underscore_d, the other way to type pun a signed long to unsigned long (and back) is using pointer cast. That is valid in both C and C++ (although in C++ you should use reinterpret_cast rather than C style pointer casts).
You can use the following way to achieve the same.
signed long to_convert = .... //whatever value
unsigned long temp = *(unsinged long*)&to_convert;
temp = htonl(temp);
to_convert = *(signed long*)&temp;
do you know what does this code mean?
#define StartEsub (unsigned short (**) (unsigned short \
AnalogConfigReg, \
unsigned short \
AnalogClockMask)) 0x00502501
Get rid of the messy macro and you get
(unsigned short (**) (unsigned short AnalogConfigReg,
unsigned short AnalogClockMask)) 0x00502501
Which is a cast from an integer, representing an address, into a pointer to a function pointer. How a pointer to a function pointer is meaningful for your specific case, I have no idea.
A much better and more readable way to write the same would be:
typedef unsigned short func_t (unsigned short AnalogConfigReg,
unsigned short AnalogClockMask);
(func_t**) 0x00502501
It seems to be defining a hard-coded vector address for a function (a pointer to a function pointer). It will be specific to your particular embedded target, so you might want to add details about the system where this code is being used.
In more detail - there is apparently a function somewhere that looks like this:
unsigned short foo (unsigned short AnalogConfigReg,
unsigned short AnalogClockMask)
and a pointer to this function is stored at the address 0x00502501.
This kind of thing is sometimes known as a "hook", and it probably allows a user-defined function to be installed by modifying this hook address.