STM32 microcontroller typecast

Viewed 898

I have a question about typecasting in C language for STM32 microcontrollers. Now I'm trying to write my own libraries for controlling peripherals of a microcontroller. But I don't understand why and when should I use typecast like (uint32_t).

For example, for GPIO configuration register I saw the next example:

#define INPUT_ANALOG    ((uint32_t) 0x00)
#define INPUT_FLOATING  ((uint32_t) 0x01)
#define INPUT_PUP_PDOWN ((uint32_t) 0x02)

This information comes from the datasheet (print screen attached below). Here I don't understand why typecast (uint32_t) is used and not just 0x00 or 0.

Could I use the next code for the same purpose?

typedef enum{
    INPUT_ANALOG = 0,
    IN_FLOATING,
    IN_PULL_UP_DOWN,
}PinConfInput_t;

Should I do a typecast for this code? Could you suggest to me some study materials about typecast? Thanks

enter image description here

2 Answers

The typecast to unsigned int or the suffix u/U is needed for the values 0x00, 0x01, and 0x02 in many contexts. 0x00, 0x01 and 0x02 by themselves are constants of type int, and there are some bit twiddling things that works dubiously on ints, for example when bit shifting them to the sign position!

And that would happen if you take the value 0x02 (int) and left-shift that to the bits 31:30! So,

0x02 << 30

has undefined behaviour on machines where ints are 32 bits wide, whereas

0x02U << 30 

or

((uint32_t)0x02) << 30

would not.

The identifiers of the enum list are declared as (C11 6.7.2.2p3)

constants that have type int and may appear wherever such are permitted.

i.e. yes, they too would need the casts for those bit shifts.


Do note that the type of the enumeration constants in C need not be the type of the enumeration itself:

#include <stdio.h>


enum foo {
    bar = 42
};


int main(void) {
    printf("An enumeration constant is an %s\n",
           _Generic(bar,
                    int: "int",
                    unsigned int: "unsigned int",
                    default: "something else"));


    printf("On this implementation the enum foo is %s\n",
           _Generic((enum foo) 0,
                    int: "int",
                    unsigned int: "unsigned int",
                    default: "something else"));
}

On GCC this will print int for the enumeration constant type, and unsigned int for the type of enum foo. I.e. the constant has a different type than the actual enumeration would have.

Also, using an enumeration constant that is outside the range of an integer is a constraint violation; as 0x80000000 is not representable as an int on 32-bit systems, it cannot be used as an enumeration constant portably:

% gcc enumtest.c -std=c11 -pedantic
enumtest.c:5:11: warning: ISO C restricts enumerator values to range of ‘int’
        [-Wpedantic]
    5 |     bar = 0x80000000
      |           ^~~~~~~~~~

Finally, as the C standard says that the type of the enum itself is left to the compiler decide, some compilers might use unsigned char for short enums. Well, you might need a cast even there, because unsigned char will be promoted to a signed int, not unsigned int before arithmetic.

GCC, KEIL and IAR answer only.

There are 3 most popular compilers used in the ARM Cortex programming. ARM/Keil, IAR and gcc used by more than 99% of the ARM Cottex programmers. Statistically most STM32 programmers use gcc (STM IDE uses the gcc as its compiler). gcc is a great but non conforming C compiler and it has its own C dialect.

gcc:

KEIL enter image description here

IAR: Yuo need to define enum large enough to not fit an signed type. IAR uses any integer type (including unsigned long long) large enough to accommodate the all enum values. It automatically chooses if signed or unsigned type will be used (for example largest enum value used will be 0x80 [it is an unsigned constant] - the type will be unsigned char).

So if you compile your code using any of those 3 compilers and you do not have any negative values the type used will be unsigned int or unsigned char and no cast is needed

Related