I am writing some embedded code to interface with an external device over SPI. The device has several registers of varying length and to help keep things straight I have defined the following structure
typedef struct
{
uint16_t Signed :1; // Register is signed or unsigned
uint16_t CommLengthBytes :3; // The width of the register in bytes
uint16_t Address :12; // Register address
}ts_register;
I have then defined each register in my sources as follows
static const ts_register SAGCYC = {0, 1, 0x000};
static const ts_register DISNOLOAD = {0, 1, 0x001};
static const ts_register LCYCMODE = {0, 1, 0x004};
static const ts_register IRMSA = {0, 4, 0x31A};
static const ts_register IRMSB = {0, 4, 0x31B};
static const ts_register VRMS = {0, 4, 0x31C};
etc.
I have a function that will take a pointer to an array of ts_registers and queue up the SPI transfers required to read all of the registers in the array and call a callback function to handle the reply
My issue comes when I try to make the array of ts_registers that I want to read as follows:
ts_register regs_to_read[3] = {VRMS, IRMSA, IRMSB};
This generates the error: "expression must have a constant value" 3 times (once per array element).
Since they are defined as constants, what have I overlooked?
Unfortunately constant variables cannot be used in constant expressions. They are considered to be variables that cannot change, but not constants that can be determined at compile time.
Unfortunately, C makes a difference between integer constant expressions and " const qualified" variables. (C and C++ are different here.) This means that the initializer of your cfg variable must be an integer constant (for example 1 ), an enum or a #define value, or an expression formed by such operands.
4 All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals. 2 A constant expression can be evaluated during translation rather than runtime, and accordingly may be used in any place that a constant may be.
2 A constant expression can be evaluated during translation rather than runtime, and accordingly may be used in any place that a constant may be. 7 More latitude is permitted for constant expressions in initializers.
Since they are defined as constants, what have I overlooked?
In C objects declared with the const
modifier aren't true constants. A better name for const would probably be readonly
- what it really means is that the compiler won't let you change it. And you need true constants to initialize objects with static storage (I suspect regs_to_read
is global).
You could try assigning regs_to_read
in a function called before anything else uses that array.
const doesn't make them constants at compile time. Make them #defines and the compiler will be happy.
I think this may be a compiler issue, and it would be helpful to know your platform and how you are building this code. I just took most of your code, doctored it up to compile it, and compiled on Linux using gcc. There were no warnings.
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
typedef struct
{
uint16_t Signed :1; // Register is signed or unsigned
uint16_t CommLengthBytes :3; // The width of the register in bytes
uint16_t Address :12; // Register address
}ts_register;
int main(int argc, char **argv) {
static const ts_register SAGCYC = {0, 1, 0x000};
static const ts_register DISNOLOAD = {0, 1, 0x001};
static const ts_register LCYCMODE = {0, 1, 0x004};
static const ts_register IRMSA = {0, 4, 0x31A};
static const ts_register IRMSB = {0, 4, 0x31B};
static const ts_register VRMS = {0, 4, 0x31C};
ts_register regs_to_read[3] = {VRMS, IRMSA, IRMSB};
return(0);
}
Have you tried casting the values? It's not always the best thing to do, but will get you around the error.
Have you considered creating #define entries?
Also, please be aware consts take a bit of getting used to in C. They do not always behave the way you might expect.
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