What happen when you store something greater than 32 bits on STM32?
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:

0x00000001_00000003


If the variable is stored at address 0x20017000, the bytes will be:

+------------+------------+
|  Address   | Byte value |
+------------+------------+
| 0x20017000 | 0x03       |
| 0x20017001 | 0x00       |
| 0x20017002 | 0x00       |
| 0x20017003 | 0x00       |
| 0x20017004 | 0x01       |
| 0x20017005 | 0x00       |
| 0x20017006 | 0x00       |
| 0x20017007 | 0x00       |
+------------+------------+


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:

0x01634578_5D8A0000

+------------+------------+
|  Address   | Byte value |
+------------+------------+
| 0x20017000 | 0x00       |
| 0x20017001 | 0x00       |
| 0x20017002 | 0x8a       |
| 0x20017003 | 0x5d       |
| 0x20017004 | 0x78       |
| 0x20017005 | 0x45       |
| 0x20017006 | 0x63       |
| 0x20017007 | 0x01       |
+------------+------------+


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:

0x01634578_5D8A0000

+------------+------------+
|  Address   | Byte value |
+------------+------------+
| 0x20017000 | 0x5d       |
| 0x20017001 | 0x8a       |
| 0x20017002 | 0x00       |
| 0x20017003 | 0x00       |
| 0x20017004 | 0x01       |
| 0x20017005 | 0x63       |
| 0x20017006 | 0x45       |
| 0x20017007 | 0x78       |
+------------+------------+


A fully big-endian 64-bit value (big-endian byte order and word order) would go like this:

0x01634578_5D8A0000

+------------+------------+
|  Address   | Byte value |
+------------+------------+
| 0x20017000 | 0x01       |
| 0x20017001 | 0x63       |
| 0x20017002 | 0x45       |
| 0x20017003 | 0x78       |
| 0x20017004 | 0x5d       |
| 0x20017005 | 0x8a       |
| 0x20017006 | 0x00       |
+------------+------------+


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:

uint32_t b = (uint32_t)a;


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:

uint32_t *addr = (uint32_t *)&amp;a;
uint32_t w0 = a[0];  // == *a
uint32_t w1 = a[1];  // == *(a + 1)


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:

uint8_t *addr = (uint8_t *)&amp;a; //If this is 0x20017000...
uint32_t b0 = addr[0]; //address 0x20017000
uint32_t b1 = addr[1]; //address 0x20017001
uint32_t b2 = addr[2]; //address 0x20017002
uint32_t b3 = addr[3]; //address 0x20017003
uint32_t b0 = addr[4]; //address 0x20017004
uint32_t b1 = addr[5]; //address 0x20017005
uint32_t b2 = addr[6]; //address 0x20017006
uint32_t b3 = addr[7]; //address 0x20017007


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 &amp;a + 1 is 32 bits (4 bytes) later in memory. If it's a uint8_t, then &amp;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.)