A couple of questions regarding the word size:
STM32 series have 32-bit wide words.
-
Considering that, what happens when we try to store something more than 32 bits or even
uint64_t
for instance? I gave it a try and defineduint64_t a = 4294967299;
and what I see in the memory is00000003
. What does that mean? Is it truncating? -
an address stores 32 bits, isn't it? then why do I see in the resultant bytes (
0x00000003
) stored at&a
different addresses every byte? so from MSB,0x00
is at0x20017FE8
, the second byte0x00
is at0x20017FE9
, … and the last0x3
is at0x20017FEA
.
Shouldn't each set of 32 bits have a distinct address?
Edit:
a side question: SRAM is a part of the MCU (which contains the cortex Mx processor). Is little/big endian related to the processor or the memory? The value that I see in memory seems to be big endian but according to the RM, it's little endian
Tried this code out to test the endianness:
uint64_t a = 0x00008a5d78456301;
uint32_t b = (uint32_t) a; // 0x78456301
shouldn't b
store the first 32 bits (from smallest address) instead of the latter 32?
Any visuals would help a lot.
Best Answer
Memory addresses are byte addresses. A word is made up of multiple bytes. An STM32 can (with some caveats) read 4 bytes (32 bits) at once, but each of those bytes has a separate address.
When you declare a uint64_t, you get an 8-byte (64-bit) variable. You're only looking at the lower four bytes, so what you see is correct. 4,294,967,299 in hexadecimal is:
If the variable is stored at address 0x20017000, the bytes will be:
This is for a little-endian CPU. If you add 1 to your uint64_t, it should increment the first byte (the one at 0x20017000).
If you try a larger number like 10^17, you should get:
If you do a 32-bit read from address 0x20017000, you'll see 0x5D8A0000. This is expected and intentional -- the CPU doesn't know what you're storing in that memory!
Endianness is a property of the CPU. (The SRAM probably doesn't do byte addressing at all -- it reads and writes whole memory words at a time.) Cortex-Ms don't load or store more than 32 bits in once access, so it would be up to the compiler how to order the two halves of the 64-bit value in SRAM. You might have a big-endian CPU (although those are pretty rare), but the compiler could still put the lower 32 bits first in memory. In that case, you might see something like:
A fully big-endian 64-bit value (big-endian byte order and word order) would go like this:
Note that, while the CPU can do byte addressing just fine, JTAG debuggers may handle it poorly. If you're looking at a memory window in an IDE, the IDE is probably doing 32-bit reads and manually splitting up the bytes afterward. Try having the CPU store each byte in a separate 32-bit variable, then look at those variables in the memory window to see what's really going on.
EDIT: Your code is wrong. This:
casts
a
to a uint32_t, which just truncates it to 32 bits. If you want to see what's in memory, you can do:This will read 32 bits from the address of
a
(let's say it's 0x20017000), and 32 bits from the word after that in memory (0x20017004). If you want to read the bytes, the simplest way is:Remember, when you do pointer arithmetic in C, the size of the data type is taken into account. So if
a
is a uint32_t, then&a + 1
is 32 bits (4 bytes) later in memory. If it's a uint8_t, then&a + 1
is 8 bits (1 byte) later in memory.As for why your CPU uses byte addresses instead of word addresses... By definition, a byte is the smallest addressable unit of memory. If each memory address held 32 bits, then a byte would be 32 bits on that system. Bytes are 8 bits for historical reasons (meaning software compatibility). To simplify: because that way each byte could hold one character of (English) text.
(There are still some DSPs with 16-bit or 32-bit bytes, but those are special-purpose processors.)