Dear Forum,
I have searched all of Keil's website, manuals and the internet about this issue and have found nothing that can eliminate this compiler warning in my "C" source code.
I am getting a warning throughout my code showing a symbol that appears as an explanation point inside a yellow triangle in the left shaded source column that when I pass the cursor over reads: "warning: implicit truncation from 'int' to bitfield changes value from 3 to -1". The related statements are: GPIOE->GPIO_MODER.P03 = GPIO_OUTPUT; // PE03 - SCOPE1 GPIOE->GPIO_OTYPER.P03 = GPIO_PUSHPULL; GPIOE->GPIO_OSPEEDR.P03 = GPIO_HIGH; where the third line is flagged with this warning.
Although the compiler does generate the proper assembly statements to correctly implement my statement, these warnings are all over, but only flagged on certain statements. I haven't gotten these warnings in prior Keil versions. It appears to only occur, in this example, if GPIO_FAST or GPIO_HIGH are used in which for these two bits, the higher bit being set causes the warning as if the 2-bit field is "signed".
using FAST: "warning: implicit truncation from 'int' to bitfield changes value from 2 to -2" using HIGH: "warning: implicit truncation from 'int' to bitfield changes value from 3 to -1"
The compiler setting "Enum Container always int" is checked. I also have defined my "u32" as "typedef unsigned long u32;" and been using this with Keil since before the "uint32_t" came out, plus it's shorter.
I have replaced STM's difficult to read, use and prone to bugs register definitions that use "#define xxxx" with typedefs of bitfields, structs and enums so that the compiler verifies all read and write terms into the registers. This particular warning is related to my GPIO register definitions (in order as written):
typedef enum // gpio speeds { GPIO_LOW = 0, // low speed (2MHz) (reset state) GPIO_MED = 1, // medium speed (25MHz) GPIO_FAST = 2, // fast speed (50MHz) GPIO_HIGH = 3 // high speed (100MHz) } gpio_ospeed_e;
typedef struct // port speed selects { gpio_ospeed_e P00 : 2; // portx.0 gpio_ospeed_e P01 : 2; // portx.1 gpio_ospeed_e P02 : 2; // portx.2 gpio_ospeed_e P03 : 2; // portx.3 gpio_ospeed_e P04 : 2; // portx.4 gpio_ospeed_e P05 : 2; // portx.5 gpio_ospeed_e P06 : 2; // portx.6 gpio_ospeed_e P07 : 2; // portx.7 gpio_ospeed_e P08 : 2; // portx.8 gpio_ospeed_e P09 : 2; // portx.9 gpio_ospeed_e P10 : 2; // portx.10 gpio_ospeed_e P11 : 2; // portx.11 gpio_ospeed_e P12 : 2; // portx.12 gpio_ospeed_e P13 : 2; // portx.13 gpio_ospeed_e P14 : 2; // portx.14 gpio_ospeed_e P15 : 2; // portx.15 } gpio_ospeed_b;
typedef struct // STM32FF429 GPIO REGISTERS { __IO gpio_mode_b GPIO_MODER; // MODE [PA = 0xA8000000] // [PB = 0x00000280] // [PC-PD = 0] __IO gpio_otype_b GPIO_OTYPER; // OUTPUT TYPE [0] __IO gpio_ospeed_b GPIO_OSPEEDR; // OUTPUT SPEED [0] __IO gpio_pupd_b GPIO_PUPDR; // PULL-UP/DN [PA = 0x64000000] // [PB = 0x00000100] // [PC-PD = 0] __I gpio_dr_u GPIO_IDR; // INPUT DATA (R) [0] __O gpio_dr_u GPIO_ODR; // OUTPUT DATA [0] __O gpio_bsrr_b GPIO_BSRR; // BIT SET/CLEAR (W) [0] __IO u32 GPIO_LCKR; // LOCK [0] __O gpio_afrl_b GPIO_AFRL; // ALT FUNCTION LOW [0] __O gpio_afrh_b GPIO_AFRH; // ALT FUNCTION HIGH [0] } gpio_reg_t;
#define GPIOE_BASE (0x40021000) #define GPIOE ((gpio_reg_t *)GPIOE_BASE)
I appreciate any feedback on how force the compiler to ignore or eliminate this warning.
Sincerely, Robbie
It isn't the enum that is wrong.
But when declaring bit fields, the normal way is to write "unsigned" or "unsigned int" instead of "int".
A one-bit "int" bit field can only store -1 and 0. A two-bit "int" bit field can only store -2, -1, 0 and 1.
Another thing - if you want to post code, it's best if you read the posting instructions directly above the message input box.
Then you can post code that looks like:
int my_function(int a,int b) { return 2*a + b; }
Much easier to read...
Sorry the code did't display well - it was when I entered it and when I sent it then Keil's website mushed it all together into a single line. Now I understand what the strange instructions such as <bracket>text</bracket> is about. This is my very first posting anywhere.
In reply, I have no "int" in the program. In fact all these registers are defined as 32-bit unsigned. What I have done is create enumerated typedefs for a bit field's various values. This typedef enum is then assigned as a particular "named" bit field's "type". As with most processors, registers are collections of single and multi-bit sized bit fields. For instance, a two bit field has 4 different enumerated values that can be placed in it. Then each of these single or multi-bit fields are defined to create the 32-bit register which is itself also typedef'd as shown in the following hopefully easier to read example.
//---- define timing register ---- typedef enum // values of the 2-bit trig field's contents { TRIG_OFF = 0, // trigger off TRIG_RISING, = 1, // trigger on rising edge TRIG_FALLING, = 2, // trigger on falling edge TRIG_BOTH = 3 // trigger on both edges } trig_e; // "_e" for enumerated type typedef struct // 32-bit trigger register { trig_e trig : 2; // edge state of trigger uint32_t device_num : 6: // device number uint32_t unused_bits : 24; // (reserved) } trig_reg_b; // "_b" for bit type typedef struct // timing 32-bit registers { volatile trig_reg_b TRIG; // edge detection volatile uint32_t CLOCKS; // number of clocks to sense } timing_regs_t; #define TIMING_BASE (0X40012000) #define TIMING_REGS ((timing_regs_t *)TIMING_BASE //---- now the code that accesses these registers ---- TIMING_REGS->TRIG.trig = TRIG_OFF; // no warning TIMING_REGS->TRIG.trig = TRIG_RISING; // no warning TIMING_REGS->TRIG.trig = TRIG_FALLING; // has warning as follows: "warning: implicit truncation from "int" to bitfield from 2 to -2" TIMING_REGS->TRIG.trig = TRIG_BOTH; // has warning as follows: "warning: implicit truncation from "int" to bitfield from 3 to -1"
So it appears that any enumerated type of a register's values where the upper-most bit is a '1' the compiler believes that this entity is a "signed" value rather than "unsigned". This also probably has to do that a "normal" enumeration is "signed" and you can set Keil's compiler for either "Enum Container always int" or not. The problem is that when this is option is unchecked, the assembly code that accesses these registers does so with 8-bit instructions instead of the 32-bit instructions and wrongly loads the registers. Thus when this option is checked, it uses the proper 32-bit access instructions, but shows warnings on each line where the enum value highest bit is '1'. This issue has never come up in Keil previously nor with any of the other IDSs that I've used over the decades. Perhaps the issue is that in addition to Keil's option using 32-bit enumerations, it forces them to always be "signed" rather than "unsigned" as the "int" word in the option says. However, from what I understand, enumerations can be made "unsigned", but I haven't found any Keil option to force this nor to disable the wrongly assummed warnings.
In fact all these registers are defined as 32-bit unsigned.
But your data definitions are not, and that's precisely your problem:
typedef struct // 32-bit trigger register { trig_e trig : 2; // edge state of trigger uint32_t device_num : 6: // device number uint32_t unused_bits : 24; // (reserved) } trig_reg_b; // "_b" for bit type
trig_e is an enum, not an uint32_t. Neither is the enum's underlying integer type uint32_t.
Making bitfiels of enums is generally a shaky proposition. The problem with it is that the underlying type of an enum is picked by the compiler, and the compiler's behaviour in this regards is very rarely as fully controllable as this method would require it to be.
In the case at hand, you would need a compiler flag that makes the compiler pick exactly uint32_t, as the underlying integer type of this particular enum (or possibly all of them). Well, I don't think that's happening.