This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Incompatible enum when using --small_enum

When I use --small_enum option, there will be many warnings like this:

warning #16027-D: object files have incompatible enumeration types ("./TimerA/TimerUtility.obj" = char/short (--small_enum), "E:\TI\Projects\AP_ED\AP\ED_2744_Grace\Debug_P1\configPkg\package\cfg\main_pe430.oe430" = integer (default))

I read some other threads, and it seems that I need to rebuild library. But How for my case?

I use grace(grace_3_00_01_59) and G2755 in my project, and I am not sure if this causes this issue.

I use --small_enum in order to reduce RAM consumption.

 

Thanks.

 

  • I'm having the same problem. Small enums are required for me to use them within packed structures.  Since they are compiled as part of the same project, I really think they should be compiled with the same options. 

    #16027-D object files have incompatible enumeration types ("./Alarm.obj" = char/short (--small_enum), "S:\Pass4G\Design\Software\workspace6\Pass4\Debug\configPkg\package\cfg\pass4g_pe430X.oe430X" = integer (default))

    I tried:

    Adding this to CCS Build->XDCTools -> Advanced Options :xdc.bld.CompileOptions.copts="--small_enum"

    and adding --small_enum to Additional compiler options. 

    Both attempts appear to be ignored. I don't understand how to trace whether these options are actually used in the make. 

    TI please help!

  • After changing this flag, all code needs to be recompiled (it won’t do automatically, since the source hasn’t changed). This also includes library code that uses enums.
    Try a clean and then a fresh build.

    However, enums are compile-time constants. Unless you assign them to variables (e.g. for a state machine), they do not consume any RAM space.

    When using the small enum switch,. enums should be unsigned char. If you declare a variable of the type of the enum and assign it a value >255, you should get a truncation warning by the compiler. No guarantee that it works, bu tit's the only way to detect it thhat comes in mind.

  • I’ve no experience with Grace, but in general the size of the Enum can be defined by;

    typedef enum myEnum {
    	enum1,
    	enum2,
    	enum3,
    	//...
    	enum99
    } myEnum;
    
    typedef struct myStruct {
    	myEnum	EnumVar		: 8 ;	// Limit size to 1 byte
    	int		SomeInteger;
    } myStruct;
    

    This doesn’t guarantee that the space used is just 1 byte, if after the enum (or char) an integer (or bigger) follows the place needs to be aligned to an even address. Therefore check in the map file or debug expressions view the place of the variables and collect single byte’s together.

  • The size of the type myEnum will still be 16 bit.
    Also, the size of the struct will be 32bit. As bitfields are 16bit too by default. Packing the bitfield may lead to a misaligned integer and 24 bit struct size. However, I don’t see how this would give any advantage.
    myEnum value = enum1; will still give a 16bit variable holding a 16bit enum value.

  • Jens-Michael Gross said:
    Also, the size of the struct will be 32bit

    Wrong!

    Jens-Michael Gross said:
    As bitfields are 16bit too by default.

    Wrong!

    Jens-Michael Gross said:
    Packing the bitfield may lead to a misaligned integer and 24 bit struct size.

    Never had any problem with that.

    Jens-Michael Gross said:
    However, I don’t see how this would give any advantage.

    The enum variable – which ranges from 0 till 255 - occupies only one byte from RAM space.

    Jens-Michael Gross said:
    myEnum value = enum1; will still give a 16bit variable holding a 16bit enum value.

    Wrong!

    Today’s compiler are much more clever and takes good care about the RAM space, pervious version certainly not and without intervention it would use a 16bit variable.

  • Leo Bosch said:
    Also, the size of the struct will be 32bit

    Wrong![/quote]

    Leo, a struct on any MSP compiler (unless you use the packed attribute) will use word alignment for all members of size int, and use padding to align the struct size to int.

    So if you had an 8bit (char) bit field (which you don’t, see below) and an int member, then the struct size will be 32 bit. With one char added as padding.

    Maybe I misinterpreted the purpose of your struct.
    If you remove the SomeInteger member from the struct, you might get (see below) a struct of size 1. Then MyStruct as well as MyStruct.EnumVar are of size 1. However, this won’t by any means define the size of myEnum itself.

     

    Leo Bosch said:
    Packing the bitfield may lead to a misaligned integer and 24 bit struct size.
    Never had any problem with that.[/quote]

    If you pack the struct, you will get a 24 bit struct with misaligned int member, which will cause highly inefficient code when accessing it (however, this might be inevitable enyway,if mapping pointers to the struct to an incoming stream, where alignment of the struct is not guaranteed)

    You might not have seen any problems, as the compiler is smart enough to replace the one-instruction 16 bit access to the struct member by a complex dual 8-bit access with shifting. However, the code is much larger and much slower then.

     

    Leo Bosch said:
    As bitfields are 16bit too by default.
    Wrong![/quote]

    ANSI/ISO specifies that bit fields must be of type int or unsigned. So on MSP, with 16 bit int/unsigned, bit fields are 16 bit.

    CCS allows breaking this standard and using any integral type, by using the --kr_compatible switch. Without this switch, using ‘myEnum’ as type for the bit field is only legal when MyEnum is of type int or unsigned. Which collides with the --small-enum switch. Using any of the two switches will make the code non-portable.

     

    Leo Bosch said:
    However, I don’t see how this would give any advantage.
    The enum variable – which ranges from 0 till 255 - occupies only one byte from RAM space.[/quote]

    As I pointed out above, the enum bitfiled may only cover a byte, if the proper switch is used, but it won’t give any advantage in the struct due to alignment and padding. One byte saved, one byte wasted. Nothing gained. Unless you also pack the struct. Lots of effort and non-portability and other penalties.

     But I agree for the last point: if myEnum is indeed a char type, by using the --small-enum switch, then a variable of type myEnum should be 8 bit in ram. However, at any point where a constant from myEnum is used, or where myEnum is passed or returned, it will make no difference and not save a single bit, immediate values or patamters areoccupying a 16 bit value anyway, even if only the lower 9 bits are used. Only global variables of type myEnum will be 1 instead of 2 bytes. And usually, you don’t have many of them, if any at all.

  • And now back, via a long loop, to the original question about a ‘small_enum’. This creates a Small Enum of 8-bits and also an 8-bit Flag, and so saving RAM space for those how needs it (I’m often);

    typedef enum myEnum {
    	myEnum1,
    	myEnum2,
    	myEnum3
    } myEnum;
    
    typedef struct FlagBits {
    	unsigned char	F1	: 1 ;
    	unsigned char	F2	: 1 ;
    	unsigned char	F3	: 1 ;
    	unsigned char	F4	: 1 ;
    	unsigned char	F5	: 1 ;
    	unsigned char	F6	: 1 ;
    	unsigned char	F7	: 1 ;
    	unsigned char	F8	: 1 ;
    } FlagBits;
    
    typedef struct FlagGroups {
    	unsigned char	G1	: 3 ;
    	unsigned char	G2	: 5 ;
    } FlagGroups;
    
    typedef union Flags {
    	unsigned char	All;
    	FlagGroups		Group;
    	FlagBits		Bit;
    } Flags;
    
    // These 4 byte's of variables will cost 6 bytes of RAM space
    typedef struct myStructA {
    	myEnum		EnumVar;
    	Flags		Flag;
    	int			SomeInteger;
    } myStructA;
    
    // These 4 byte's of variables will cost 4 bytes of RAM space
    typedef struct myStructB {
    	myEnum		EnumVar	: 8 ;
    	Flags		Flag;
    	int			SomeInteger;
    } myStructB;
    
    myStructA	sA;
    myStructB	sB;
    char		cA;
    
    /**********************************************************
     output                                  attributes/
    section   page    origin      length       input sections
    --------  ----  ----------  ----------   ----------------
    .bss       0    00000200    0000000b     UNINITIALIZED
                      00000200    00000006     (.common:sA)
                      00000206    00000004     (.common:sB)
                      0000020a    00000001     (.common:cA)
    
    ***********************************************************/
    
    void main(void) {
    	WDTCTL = WDTPW | WDTHOLD;	// Stop watchdog timer
    
    	sA.EnumVar = myEnum2;
    	sB.EnumVar = myEnum3;
    
    	cA = 10;
    
    	asm(" ");
    	asm(";	Not_Optimized! All other CCS options are Default.");
    
    	asm(";	Flag_bit:");
    	sA.Flag.Bit.F1 = 1;
    	sA.Flag.Bit.F2 = 0;
    
    	asm(";	Flag_group:");
    	sA.Flag.Group.G2 = 0x03;
    
    	asm(" ");
    }
    
    ;*****************************************************************************
    ;* FUNCTION NAME: main                                                       *
    ;*                                                                           *
    ;*   Regs Modified     : SP,SR,r15                                           *
    ;*   Regs Used         : SP,SR,r15                                           *
    ;*   Local Frame Size  : 0 Args + 0 Auto + 0 Save = 0 byte                   *
    ;*****************************************************************************
    main:
    ;* --------------------------------------------------------------------------*
            MOV.W     #23168,&WDTCTL+0      ; [] |65| 
            MOV.W     #1,&sA+0              ; [] |67| 
            MOV.B     #2,&sB+0              ; [] |68| 
            MOV.B     #10,&cA+0             ; [] |70| 
     
    ;	Not_Optimized! All other CCS options are Default.
    ;	Flag_bit:
            OR.B      #1,&sA+2              ; [] |76| 
            BIC.B     #2,&sA+2              ; [] |77| 
    ;	Flag_group:
            MOV.W     #7,r15                ; [] |80| 
            AND.B     &sA+2,r15             ; [] |80| 
            OR.B      #24,r15               ; [] |80| 
            MOV.B     r15,&sA+2             ; [] |80| 
     
            RET       ; [] 
    

  • Leo, what compiler do you use? Are you using IAR?
    What you presented in your code will (according to the docs) only work on CCS with the before mentioned --kr_compatible switch (and of course the --small-enum switch). And is not conforming to the C standard. Or the compiler works different than its documentation tells.

  • Jens-Michael,

    I’m using CCS (v6). The 8-bit enum variable works as I can remember (long long time) this way, before CCS I was using KEIL (~10 years ago) and I think it was also working there but not sure. And without any linker option.

    In the past (Flag-) Bit operations where –sometimes- wasting code but handy to use. Now I was amazed to see how efficient it works, and with increased optimize level this example will be compressed even more.

    A lot has been changed in EABI -and in the whole compiler- since the introduction of FRAM, before EABI was quite worse.

    Maybe the Compiler software has been changed faster as TI can write/update their documentation.

  • Leo, we already confirmed that the size of an enum is not specified in the standard. However, it is obvious, that the size of enums must be consistent across all code modules. So all code modules, including library code, need to be compiled with the same enum size (or at least with the common information that enums that do not need to be 16 bit by their member values are 8 bit instead). Else any call using the enum as parameter type would fail. This seemed to be the problem in the original post.

    Regarding bitfields, I agree that they are handy. However, their main use is on hardware registers where using them does most harm.
    Most people do not bother packing their data by bits in bit fields, unless they need to (which almost exclusively applies to hardware registers where the usage of individual bits is predefined).

    Today’s compilers are good enough to pack access to bitfields - unless the variable is volatile. Which all hardware registers are, for a reason.

    I totally  agree with you about outdated documentation. I know this well form my own projects. While I’m pressed to update the firmware as fast as possible, nobody cares for the required time to update the documentation too. And when there’s finally time to do it, the actual code change is only a faint memory, and often things are forgotten to be added/changed in the docs.

    Since I’m neither using IAR nor CCS, I can’t do test on them (even if I had the time) and have to rely on the docs. I appreciate your efforts with making the actual test.

     

    Btw: I see that soon you’ll join the guru league. By the time I post this answer, you’ll likely have already crossed the line. Congratulations!

  • Just wanted to say thanks to Gurus: Leo and Jens-Michael for the detailed follow up. I will not argue with the facts presented, indeed the CCS6 compiler does seem to use them efficiently.  Perhaps the IDE should know well enough that when a critical compiler option is changed, that it needs to make clean. 

    I disagree though that "Most people do not bother packing their data by bits in bit fields," in an ultra low power embedded platform using FRAM, memory is at a premium, and many static variables are used to represent state machines, for which small enums seem to be a better way than preprocessor directives. 

  • Mike Mitchell1 said:
    #16027-D object files have incompatible enumeration types ("./Alarm.obj" = char/short (--small_enum), "S:\Pass4G\Design\Software\workspace6\Pass4\Debug\configPkg\package\cfg\pass4g_pe430X.oe430X" = integer (default))

    I tried:

    Adding this to CCS Build->XDCTools -> Advanced Options :xdc.bld.CompileOptions.copts="--small_enum"

    and adding --small_enum to Additional compiler options.

    Looking at an example Grace project, the problem is that the <install_root>/grace_3_00_01_59/packages/ti/targets/msp430/rts430/lib/boot.ae430X library file doesn't get re-built with --small_enum command line option. 

    It looks like the boot.ae430X library is supplied pre-compiled, and doesn't support a RTSC target built with --small_enum.

    I think a new RTSC target would have to be created with --small_enum set as a compile option.

  • Mike, I totally agree that on an embedded system, carful use of resources should be top priority. However, most people who just entered the embedded world (or want to migrate from Arduino or similar ‘embedded’ systems with a Macrocontroller) do not care for resource usage. They don’t bother declaring bitfields when separate variables do.
    Most requests for bitfields I’ve seen here were for the hardware registers (where you are forced by the hardware to deal with sub-byte structures). And exactly with these hardware registers, where it would be most convenient, the use of bitfields is counterproductive.
    Of course using a small enum is better than using a big one :) However, using preprocessor defines doesn’t make much of a difference regarding code size and coding effort. And it is portable and works without any compiler switches if you declare the state variable as unsigned char.

  • Can you be specific how to recompile <install_root>/grace_3_00_01_59/packages/ti/targets/msp430/rts430/lib/boot.ae430X ?
    I would prefer to just compile everything from source in my project, but it is unclear to me how the dependencies work with an RTSC target.

**Attention** This is a public forum