i have been working with STM32 hal drivers and i noticed when they want to give a value to a register , they use some code like this :
#define __IO volatile
typedef struct
{
__IO uint32_t CR1; /*!< USART Control register 1, Address offset: 0x00 */
__IO uint32_t CR2; /*!< USART Control register 2, Address offset: 0x04 */
__IO uint32_t CR3; /*!< USART Control register 3, Address offset: 0x08 */
__IO uint32_t BRR; /*!< USART Baud rate register, Address offset: 0x0C */
__IO uint32_t GTPR; /*!< USART Guard time and prescaler register, Address offset: 0x10 */
__IO uint32_t RTOR; /*!< USART Receiver Time Out register, Address offset: 0x14 */
__IO uint32_t RQR; /*!< USART Request register, Address offset: 0x18 */
__IO uint32_t ISR; /*!< USART Interrupt and status register, Address offset: 0x1C */
__IO uint32_t ICR; /*!< USART Interrupt flag Clear register, Address offset: 0x20 */
__IO uint32_t RDR; /*!< USART Receive Data register, Address offset: 0x24 */
__IO uint32_t TDR; /*!< USART Transmit Data register, Address offset: 0x28 */
__IO uint32_t PRESC; /*!< USART clock Prescaler register, Address offset: 0x2C */
} USART_TypeDef;
#define D2_APB1PERIPH_BASE (0x40000000UL)
#define UART4_BASE (D2_APB1PERIPH_BASE 0x4C00UL)
#define UART4 ((USART_TypeDef *) UART4_BASE)
UART4->CR = whatever!
so i tried to test on computer with C but i got a little confused , the program below is the one i wrote :
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define startaddress ((mytype*) (0x6d9ff93b))
typedef struct
{
volatile uint32_t myTypeValue;
}mytype;
int main()
{
mytype* inst;
inst = startaddress;
inst->myTypeValue = 0x10;
printf("address is : %x \n",inst);
return 0;
}
output :
Process finished with exit code -1073741819 (0xC0000005)
the program will crash at inst->myTypeValue = 0x10;
. otherwise it will show the address which has been assign to it . for example this is the output :
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#define startaddress ((mytype*) (0x6d9ff93b))
typedef struct
{
volatile uint32_t myTypeValue;
}mytype;
int main()
{
mytype* inst;
inst = startaddress;
// inst->myTypeValue = 0x10;
printf("address is : %x \n",inst);
return 0;
}
output :
address is : 6d9ff93b
Process finished with exit code 0
now i have some question , dose the stm32 library works because the address is a register and not the SRAM ? because i remember when i use SDRAM on FMC i can do the same at address 0xC0000000 and it works perfectly.
if the assignment is wrong why does the compiler works on second example and only crashes when i am trying to use the variable inside the struct ? why not crash at the assignment inst = startaddress;
it self ?
CodePudding user response:
Those addresses in STM32 are defined and they reference memory-mapped hardware registers.
Your code is different. To be equivalent to the STM one it has to be:
#define inst ((mytype*) (0x6d9ff93b))
typedef struct
{
volatile uint32_t myTypeValue;
}mytype;
int main()
{
inst -> mytepevalue = 10;
.....
dose the stm32 library works because the address is a register and not the SRAM ?
Yes. Those addresses you see in the STM CMSIS headers (not the library!!!!) are defined by the manufacturer and are hardware related.
because i remember when i use SDRAM on FMC i can do the same at address 0xC0000000 and it works perfectly.
It is because one of banks of memory managed by the Flexible Memory Controller is exposed to the core at this address. The chip manufacturer also defines those addresses.
if the assignment is wrong why does the compiler works on second example and only crashes when i am trying to use the variable inside the struct ? why not crash at the assignment inst = startaddress; it self ?
Because you define a pointer and assign it with value and it is OK. But this pointer contains an invalid reference and when you try to dereference it - the system fails.
I think you need to reread the pointers chapter in your favourite C book as your understanding of pointers is rather limited. It is quite important knowledge if you want to bare-metal program uCs