This recipe illustrates a version of addTwoNums
that uses the machine storage classes, int32_t
and uint8_t
. We explain why it is advantageous for embedded applications to define and use these as opposed to the primitive types that are provided by the C language.
To define and use machine storage classes, please follow the outlined steps:
addTwoNums_v2
by cloning the previous project.addTwoNums.c
file from the previous recipe to the folder and modify it as follows:int main (void) { int32_t input; uint8_t num1, num2, res; HAL_Init (); /* Init Hardware Abstraction Layer */ SystemClock_Config (); /* Config Clocks */ SER_Init(); for (;;) { /* Loop forever */ printf("Enter First Number: "); scanf("%d", &input); num1 = (uint8_t) input; printf("Enter Second Number: "); scanf("%d", &input); num2 = (uint8_t) input; res = num1 + num2; printf("Result = %d ", res); } }
Serial.c
, Serial.h
, Retarget.c
and addTwoNums.c
files to the project.Invoke PuTTY and configure the port as we did in Chapter 2, C Language Programming.
The size of signed and unsigned integers that a microprocessor can manipulate is determined by its low-level architecture. The Cortex-M3 and -M4 microcontrollers are based on the ARMv7-M architecture (refer to ARMv7-M Architecture Application Level Reference Manual). Part A of the manual details the application-level architecture and programmers' model, and it begins by summarizing the core data types and arithmetic operations. ARMv7-M processors support the following data types in memory:
Byte |
8-bit |
Halfword |
16-bit |
Word |
32-bit |
The manual explains that processor registers are 32 bits in size, and the instruction set supports the following data types:
It also describes the binary format that is used to store these quantities and provides a pseudo-code description of how addition and subtraction are performed. This description is consistent with the results that we got with the recipe, addTwoNums_c3_v0
. The pseudo-code uses the terms zero-extended and sign-extended to describe how 8- and 16-bit numbers are stored in the 32-bit registers of the Cortex-M architecture. This is important as the processor status-register bits reflect the result of 32-bit arithmetic, and so, 8- and 16-bit values must be appropriately extended to fill the whole 32-bit register so that the sign and overflow bits correctly reflect the result of operations on shorter word lengths.
Implementations of C standard data types, such as char, short int, int, long int, and so on, depend on the (machine-specific) compiler implementation. You may recall that the C standard only specifies they must be at least a certain size. Apply italics to (at least). This can be a problem for embedded system programs that need to be ported between architectures with particular sizes of storage. Luckily, C provides a mechanism called typedef
to create new types that are aliases of existing types. The C Standard Library includes stdint.h
, containing C type definitions that can be customized for the different target architectures. The stdint.h
header is included in stm32F4xx_hal.h
, so there is no need to include it again in our program. A typedef
keyword in the stdint.h
header defines the following machine storage classes:
/* exact-width signed integer types */ typedef signed char int8_t; typedef signed short int int16_t; typedef signed int int32_t; typedef signed __int64 int64_t; /* exact-width unsigned integer types */ typedef unsigned char uint8_t; typedef unsigned short int uint16_t; typedef unsigned int uint32_t; typedef unsigned int64 uint64_t;
If we require that an integer be represented in exactly N bits, then we use one of the following types:
signed: |
int8_t |
int16_t |
int32_t |
int64_t |
unsigned: |
uint8_t |
uint16_t |
uint32_t |
uint64_t |
3.139.105.159