It can be written it like this (but see below for a beeter idea):
uint32_t *addr = 0X0801F000;
uint32_t read_value = *addr;
If you cast addr as an unsigned char * like you do in your second example, then, when you dereference the unsigned char pointer, you get an unsigned char:
uint32_t* addr = 0X0801F000;
unsigned char read_value = *(unsigned char *)addr;
So that's not what you want because then you only read one character. Then, there is one other thing you should remember, you need volatile if you want the compiler to read the memory address every single time you dereference the pointer. Otherwise, the compile could skip that if it already knows that the value is. Then you would have to write it like this:
volatile uint32_t *addr = 0X0801F000;
uint32_t read_value = *addr;
Or if you put it all on one line (like you did in your comment):
uint32_t read_value = (*((volatile uint32_t*)(0x0801F000)));
uint32_t *addr = 0X0801F000; read_value = *addr;Notice that you missed the star in the declaration of addr.uint32_t *addrthen accessing*addrwill give you a 32 bit number.volatile uint32_t *addr(volatile tells the compiler that it MUST read and write to the memory and it can't optimize it away even if it knows what is in the memory location.)read_value = (*((volatile uint32_t*)(0x0801F000)));?