#define statement for address of memory - c

What does this #define statement do? It is used to define an address of memory. But I don't understand the (uint32_t *) part
#define GPxDAT (uint32_t *) 0x6FC0

It is usually used to access hardware registers mapped into the address space, or some particular memory addresses
Hardware registers should be defined as volatile as registers can change without any program activity (as they are changed by the hardware).
#define GPIOREGA ((volatile uint32_t *) 0x6FC0)
then you can assign or read this memory location (*GPIOREGA = something; something = *GPIOREGA )
Sometimes much more complex data structures are used this way (example from the STM32 headers)
#define __IO volatile
typedef struct
{
__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
__IO uint32_t BSRR; /*!< GPIO port bit set/reset register, Address offset: 0x18 */
__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
} GPIO_TypeDef;
#define PERIPH_BASE 0x40000000U /*!< Peripheral base address in the alias region */
#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000U)
#define GPIOA_BASE (AHB1PERIPH_BASE + 0x0000U)
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
And you can use it is as any normal pointer
GPIOA -> MODER |= (1 << 15);

The (uint32_t *) part is what is called a cast, it converts the integer number 0x6FC0 to a pointer(an address) to an unsigned integer, 32bits wide (which is what the uint32_t type represents.) Basically a type conversion to a pointer to an unsigned integer. In my opinion, the expression is not completely safe. While the cast operator is high precedence, it should be written as:
#define GPxDAT ((uint32_t *) 0x6FC0)
rounding the whole expression in parenthesis, so it will not fail, wherever you put it.
Writing this kind of defines, you can access GPxDAT[0] as a 32bit unsigned integer at the address 0x6fc0, GPxDAT[1] as the next 32bit address (above the previous one) all of them based at the address represented by the number.

Related

give specific address to variable in Computer and STM32

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 ?
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

STM32F446xx Peripheral Register Access Difference Between Using Dereferenced Pointers and Structs

I'm trying to simply light up an external LED (wired to my STM32F446RE's Port C Pin 10). I'm using the gcc-arm-none-eabi 8-2019-q3-update for windows for my compiler and Keil uVision5 IDE for flashing/debugging the board (the Keil IDE also handles compilation with the GCC compiler).
In the following code when using structs to reference the GPIO and RCC peripheral registers (the second "section" of main) everything works perfectly. The RCC->AHB1ENR and GPIOC->MODER write lines properly update the values at the associated memory addresses and the LED does light up.
However, when using dereferenced pointers (the first "section" of main) the LED does not light. When debugging this issue, the memory locations for all of the registers are NOT being written to after executing the *GPIOC_MODER and *RCC_AHB1ENR lines.
What is the difference between these two approaches and why does one work and not the other? I've triple checked the addresses with the STM32F446xx data sheet (https://www.st.com/content/ccc/resource/technical/document/reference_manual/4d/ed/bc/89/b5/70/40/dc/DM00135183.pdf/files/DM00135183.pdf/jcr:content/translations/en.DM00135183.pdf) and even if the addresses were incorrect, the struct-based approach shouldn't work.
#include <stdint.h>
/* General Purpose Input Output Registers, Address Range 0x4002 0000 - 0x4002 1FFF */
typedef struct
{
uint32_t volatile MODER; /* Offset: 0x00 (R/W) Mode Register */
uint32_t volatile OTYPER; /* Offset: 0x04 (R/W) Output Type Register */
uint32_t volatile OSPEEDR; /* Offset: 0x08 (R/W) Output Speed Register */
uint32_t volatile PUPDR; /* Offset: 0x0C (R/W) Pull-up/Pull-down Register */
uint32_t volatile IDR; /* Offset: 0x10 (R/W) Input Data Register */
uint32_t volatile ODR; /* Offset: 0x14 (R/W) Output Data Register */
uint32_t volatile BSRR; /* Offset: 0x18 (R/W) Bit Set/Reset Register */
uint32_t volatile LCKR; /* Offset: 0x1C (R/W) Configuration Lock Register */
uint32_t volatile AFRL; /* Offset: 0x20 (R/W) Alternate Function Low Register */
uint32_t volatile AFRH; /* Offset: 0x24 (R/W) Alternate Function High Register */
} GPIO_t;
#define GPIOA ((GPIO_t *)0x40020000)
#define GPIOB ((GPIO_t *)0x40020400)
#define GPIOC ((GPIO_t *)0x40020800)
#define GPIOD ((GPIO_t *)0x40020C00)
#define GPIOE ((GPIO_t *)0x40021000)
#define GPIOF ((GPIO_t *)0x40021400)
#define GPIOG ((GPIO_t *)0x40021800)
#define GPIOH ((GPIO_t *)0x40021C00)
/* Reset and Clock Control Registers (RCC), Address Range: 0x4002 3800 - 0x4002 3BFF */
typedef struct
{
uint32_t volatile CR; /* Offset: 0x00 (R/W) Clock Control Register */
uint32_t volatile PLLCFGR; /* Offset: 0x04 (R/W) PLL Configuration Register */
uint32_t volatile CFGR; /* Offset: 0x08 (R/W) Clock Configuration Register */
uint32_t volatile CIR; /* Offset: 0x0C (R/W) Clock Interrupt Register */
uint32_t volatile AHB1RSTR; /* Offset: 0x10 (R/W) AHB1 Peripheral Reset Register */
uint32_t volatile AHB2RSTR; /* Offset: 0x14 (R/W) AHB2 Peripheral Reset Register */
uint32_t volatile AHB3RSTR; /* Offset: 0x18 (R/W) AHB3 Peripheral Reset Register */
uint32_t volatile reserved0;
uint32_t volatile APB1RSTR; /* Offset: 0x20 (R/W) APB1 Peripheral Reset Register */
uint32_t volatile APB2RSTR; /* Offset: 0x24 (R/W) APB2 Peripheral Reset Register */
uint32_t reserved1[2];
uint32_t volatile AHB1ENR; /* Offset: 0x30 (R/W) AHB1 Peripheral Clock Enable Register */
uint32_t volatile AHB2ENR; /* Offset: 0x34 (R/W) AHB2 Peripheral Clock Enable Register */
uint32_t volatile AHB3ENR; /* Offset: 0x38 (R/W) AHB3 Peripheral Clock Enable Register */
uint32_t reserved2;
uint32_t volatile APB1ENR; /* Offset: 0x40 (R/W) APB1 Peripheral Clock Enable Register */
uint32_t volatile APB2ENR; /* Offset: 0x44 (R/W) APB1 Peripheral Clock Enable Register */
uint32_t reserved3[2];
uint32_t volatile AHB1LPENR; /* Offset: 0x50 (R/W) AHB1 Peripheral Clock Enable Lower Power Mode Register */
uint32_t volatile AHB2LPENR; /* Offset: 0x54 (R/W) AHB2 Peripheral Clock Enable Lower Power Mode Register */
uint32_t volatile AHB3LPENR; /* Offset: 0x58 (R/W) AHB3 Peripheral Clock Enable Lower Power Mode Register */
uint32_t reserved4;
uint32_t volatile APB1LPENR; /* Offset: 0x60 (R/W) APB1 Peripheral Clock Enable Lower Power Mode Register */
uint32_t volatile APB2LPENR; /* Offset: 0x64 (R/W) APB2 Peripheral Clock Enable Lower Power Mode Register */
uint32_t reserved5[2];
uint32_t volatile BDCR; /* Offset: 0x70 (R/W) Backup Domain Control Register */
uint32_t volatile CSR; /* Offset: 0x74 (R/W) Clock Control & Status Register */
uint32_t reserved6[2];
uint32_t volatile SSCGR; /* Offset: 0x80 (R/W) Spread Spectrum Clock Generation Register */
uint32_t volatile PLLI2SCFGR; /* Offset: 0x84 (R/W) PLLI2S Configuration Register */
uint32_t volatile PLLSAICFGR; /* Offset: 0x88 (R/W) PLLSAI Configuration Register */
uint32_t volatile DCKCFGR; /* Offset: 0x8C (R/W) Dedicated Clocks Configuration Register */
uint32_t volatile CKGATENR; /* Offset: 0x90 (R/W) Clocks Gated Enabled Register */
uint32_t volatile DCKCFGR2; /* Offset: 0x94 (R/W) Dedicated Clocks Configuration Register 2 */
} RCC_t;
#define RCC ((RCC_t *)0x40023800)
void main()
{
/* This section doesn't work */
uint32_t volatile * const GPIOC_MODER = (uint32_t *)0x40020800;
uint32_t volatile * const GPIOC_ODR = (uint32_t *)0x40020814;
uint32_t volatile * const RCC_AHB1ENR = (uint32_t *)0x40023830;
*GPIOC_MODER &= ~(0x1 << 21); //!# Enable clock to GPIO Port C
*GPIOC_MODER |= 0x1 << 20; //!# Clear bit 21 to put pin 10 into general purpose output mode
*RCC_AHB1ENR |= 0x1 << 2; //!# Set bit 20 to put pin 10 into general purpose output mode
while (1) {
*GPIOC_ODR |= 0x1 << 10; //!# Write a 1 to bit 10 (port 10) of GPIO Port C
}
/* This section does work */
RCC->AHB1ENR |= 0x1 << 2; //!# Enable clock to GPIO Port C
GPIOC->MODER &= ~(0x1 << 21); //!# Clear bit 21 to put pin 10 into general purpose output mode
GPIOC->MODER |= 0x1 << 20; //!# Set bit 20 to put pin 10 into general purpose output mode
while (1) {
GPIOC->ODR |= 0x1 << 10; //!# Write a 1 to bit 10 (port 10) of GPIO Port C
}
}
Update: So turns out, it is the ORDER of the instructions that is why one "section" was working and one "section" wasn't. The working "section" enabled the clock signal to that GPIO port and then did the memory writes whereas the not-working "section" tried to do the memory writes then enable the clock signal. I'm assuming here, but it seems like that memory region is clock gated or something where trying to read/write from/to the region when the clock to that region is not enabled will result in read-as-zero/write-ignore.
You have to enable the peripheral before you can talk to it.

How compiler knows if a pointer address in C is port mapped or RAM?

I know that port mapped IO are accessed thorugh in/out CPU instructions and memory (& memory mapped registers) are accessed through load/store CPU instructions (similar to memory). But, with a pointer in C code, how compiler knows if a address is port mapped IO register or memory and then inserts the correct CPU instructions?
Example:
uint16_t const* uart_reg = 0x8000c000;
uint16_t const* ram_addr = 0x4000c000;
*uart_reg = 0x1;
*ram_addr = 0x12;
If you have non-memory-mapped I/O, you're not going to be able to access it from C as if it were memory.
You must use some platform-specific trickery to get the proper I/O instructions. This is a pain, and might be one reason why modern hardware seems to favor memory-mapped I/O.
C compilers for platforms with port-mapped I/O had to include this, see for instance the inp() function in the old Turbo C++ for DOS.
Two steps:
Install the correct toolchain for your target hardware.
Use provided header files with all the necessary properly dome definitions
For example if you want to program ARM STM uC bare metal gcc compiler - use arm-none-eabi-gcc and tools. Use header CMSIS header files provided by STM & ARM (usually they are already included if you choose a "ready made" toolchain)
Example declarations and definitions (only for ADC1):
#define FLASH_BASE ((uint32_t)0x08000000U) /*!< FLASH base address in the alias region */
#define CCMDATARAM_BASE ((uint32_t)0x10000000U) /*!< CCM(core coupled memory) data RAM base address in the alias region */
#define SRAM_BASE ((uint32_t)0x20000000U) /*!< SRAM base address in the alias region */
#define PERIPH_BASE ((uint32_t)0x40000000U) /*!< Peripheral base address in the alias region */
#define SRAM_BB_BASE ((uint32_t)0x22000000U) /*!< SRAM base address in the bit-band region */
#define PERIPH_BB_BASE ((uint32_t)0x42000000U) /*!< Peripheral base address in the bit-band region */
#define AHB3PERIPH_BASE (PERIPH_BASE + 0x10000000U)
#define ADC1_BASE (AHB3PERIPH_BASE + 0x00000000U)
#define ADC1 ((ADC_TypeDef *) ADC1_BASE)
#ifdef __cplusplus
#define __I volatile /*!< Defines 'read only' permissions */
#else
#define __I volatile const /*!< Defines 'read only' permissions */
#endif
#define __O volatile /*!< Defines 'write only' permissions */
#define __IO volatile /*!< Defines 'read / write' permissions */
/* following defines should be used for structure members */
#define __IM volatile const /*! Defines 'read only' structure member permissions */
#define __OM volatile /*! Defines 'write only' structure member permissions */
#define __IOM volatile /*! Defines 'read / write' structure member permissions */
typedef struct
{
__IO uint32_t ISR; /*!< ADC Interrupt and Status Register, Address offset: 0x00 */
__IO uint32_t IER; /*!< ADC Interrupt Enable Register, Address offset: 0x04 */
__IO uint32_t CR; /*!< ADC control register, Address offset: 0x08 */
__IO uint32_t CFGR; /*!< ADC Configuration register, Address offset: 0x0C */
uint32_t RESERVED0; /*!< Reserved, 0x010 */
__IO uint32_t SMPR1; /*!< ADC sample time register 1, Address offset: 0x14 */
__IO uint32_t SMPR2; /*!< ADC sample time register 2, Address offset: 0x18 */
uint32_t RESERVED1; /*!< Reserved, 0x01C */
__IO uint32_t TR1; /*!< ADC watchdog threshold register 1, Address offset: 0x20 */
__IO uint32_t TR2; /*!< ADC watchdog threshold register 2, Address offset: 0x24 */
__IO uint32_t TR3; /*!< ADC watchdog threshold register 3, Address offset: 0x28 */
uint32_t RESERVED2; /*!< Reserved, 0x02C */
__IO uint32_t SQR1; /*!< ADC regular sequence register 1, Address offset: 0x30 */
__IO uint32_t SQR2; /*!< ADC regular sequence register 2, Address offset: 0x34 */
__IO uint32_t SQR3; /*!< ADC regular sequence register 3, Address offset: 0x38 */
__IO uint32_t SQR4; /*!< ADC regular sequence register 4, Address offset: 0x3C */
__IO uint32_t DR; /*!< ADC regular data register, Address offset: 0x40 */
uint32_t RESERVED3; /*!< Reserved, 0x044 */
uint32_t RESERVED4; /*!< Reserved, 0x048 */
__IO uint32_t JSQR; /*!< ADC injected sequence register, Address offset: 0x4C */
uint32_t RESERVED5[4]; /*!< Reserved, 0x050 - 0x05C */
__IO uint32_t OFR1; /*!< ADC offset register 1, Address offset: 0x60 */
__IO uint32_t OFR2; /*!< ADC offset register 2, Address offset: 0x64 */
__IO uint32_t OFR3; /*!< ADC offset register 3, Address offset: 0x68 */
__IO uint32_t OFR4; /*!< ADC offset register 4, Address offset: 0x6C */
uint32_t RESERVED6[4]; /*!< Reserved, 0x070 - 0x07C */
__IO uint32_t JDR1; /*!< ADC injected data register 1, Address offset: 0x80 */
__IO uint32_t JDR2; /*!< ADC injected data register 2, Address offset: 0x84 */
__IO uint32_t JDR3; /*!< ADC injected data register 3, Address offset: 0x88 */
__IO uint32_t JDR4; /*!< ADC injected data register 4, Address offset: 0x8C */
uint32_t RESERVED7[4]; /*!< Reserved, 0x090 - 0x09C */
__IO uint32_t AWD2CR; /*!< ADC Analog Watchdog 2 Configuration Register, Address offset: 0xA0 */
__IO uint32_t AWD3CR; /*!< ADC Analog Watchdog 3 Configuration Register, Address offset: 0xA4 */
uint32_t RESERVED8; /*!< Reserved, 0x0A8 */
uint32_t RESERVED9; /*!< Reserved, 0x0AC */
__IO uint32_t DIFSEL; /*!< ADC Differential Mode Selection Register, Address offset: 0xB0 */
__IO uint32_t CALFACT; /*!< ADC Calibration Factors, Address offset: 0xB4 */
} ADC_TypeDef;
and it expands to: ((ADC_TypeDef *) ((((uint32_t)0x40000000U) + 0x10000000U) + 0x00000000U))
It is not worth to do it manually.

Struct pointer to access register on microcontroller?

I'm trying to understand the cmsis header file included with the STM-32 Cortex-M4 microcontroller.
They have a struct that is
typedef struct
{
__IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */
__IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */
__IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */
__IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */
__IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */
__IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */
__IO uint16_t BSRRL; /*!< GPIO port bit set/reset low register, Address offset: 0x18 */
__IO uint16_t BSRRH; /*!< GPIO port bit set/reset high register, Address offset: 0x1A */
__IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */
__IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */
} GPIO_TypeDef;
Does it make sense, for example, to write:
((GPIO_TypeDef *) 0x08000) -> MODER = 0x12;
I don't get what this line is doing.
It would make more sense to me if you did
GPIO_TypeDef * td = 0x08000;
td -> MODER = 0x12;
Are these the same? Why?
The GPIO_TypeDef struct is a clever mechanism for encoding address offsets. So if we are given a pointer to the base GPIOD address and we cast that pointer to a GPIO_TypeDef struct pointer, we can use the standard C dereference operator (->) to access an address at some offset from the base GPIOD address.
So in your example, GPIOD_BASE evaluates to (AHB1PERIPH_BASE + 0x0C00) and MODER has an address offset of 0x0 from a GPIO_TypeDef struct pointer. This means that GPIOD_BASE->MODER evaluates to (AHB1PERIPH_BASE + 0x0C00) + 0x00. This is just the address of the port mode register for GPIOD.
This works for all the field defined in the GPIO_TypeDef struct. For example, GPIOD_BASE->PUPDR evaluates to(AHB1PERIPH_BASE + 0x0C00) + 0x0C. This is just the address of the pull-up/pull-down register for GPIOD.

Why pointer of type CAN_TypeDef is being used in following code?

I am trying to understand the code, my worry is why in below code "CAN_TypeDef" is being used, can I simply use pointer of type integer,what will be the adverse consequences of integer pointer ?
The below code belongs to CAN(controller area network) library code of stm32f discovery board
in Filename can.c
void CAN_setup (uint32_t ctrl) {
CAN_TypeDef *pCAN = (ctrl == 1) ? CAN1 : CAN2;
uint32_t brp;
When I went to definition of CAN_Typedef it throws me here.
typedef struct
{
__IO uint32_t MCR; /*!< CAN master control register, Address offset: 0x00 */
__IO uint32_t MSR; /*!< CAN master status register, Address offset: 0x04 */
__IO uint32_t TSR; /*!< CAN transmit status register, Address offset: 0x08 */
__IO uint32_t RF0R; /*!< CAN receive FIFO 0 register, Address offset: 0x0C */
__IO uint32_t RF1R; /*!< CAN receive FIFO 1 register, Address offset: 0x10 */
__IO uint32_t IER; /*!< CAN interrupt enable register, Address offset: 0x14 */
__IO uint32_t ESR; /*!< CAN error status register, Address offset: 0x18 */
__IO uint32_t BTR; /*!< CAN bit timing register, Address offset: 0x1C */
uint32_t RESERVED0[88]; /*!< Reserved, 0x020 - 0x17F */
CAN_TxMailBox_TypeDef sTxMailBox[3]; /*!< CAN Tx MailBox, Address offset: 0x180 - 0x1AC */
CAN_FIFOMailBox_TypeDef sFIFOMailBox[2]; /*!< CAN FIFO MailBox, Address offset: 0x1B0 - 0x1CC */
uint32_t RESERVED1[12]; /*!< Reserved, 0x1D0 - 0x1FF */
__IO uint32_t FMR; /*!< CAN filter master register, Address offset: 0x200 */
__IO uint32_t FM1R; /*!< CAN filter mode register, Address offset: 0x204 */
uint32_t RESERVED2; /*!< Reserved, 0x208 */
__IO uint32_t FS1R; /*!< CAN filter scale register, Address offset: 0x20C */
uint32_t RESERVED3; /*!< Reserved, 0x210 */
__IO uint32_t FFA1R; /*!< CAN filter FIFO assignment register, Address offset: 0x214 */
uint32_t RESERVED4; /*!< Reserved, 0x218 */
__IO uint32_t FA1R; /*!< CAN filter activation register, Address offset: 0x21C */
uint32_t RESERVED5[8]; /*!< Reserved, 0x220-0x23F */
CAN_FilterRegister_TypeDef sFilterRegister[28]; /*!< CAN Filter Register, Address offset: 0x240-0x31C */
} CAN_TypeDef;
I don't understand why typedef .. I have base address of CAN and offset of Different registers, I didn't find any relevance of above code for my purpose.
I am trying to apply this way
/*=========================CAN BASE ADDRESS=============== */
#define CAN1_BASE 0x40006800
#define CAN2_BASE 0x40006400
/==========================================================/
#define CAN1_MCR (CAN1_BASE+ 0x00)
#define CAN2_MCR (CAN2_BASE+ 0x00) // 0x00 is offset for MCR
#define DEMO(X) (*(unsigned int*)(X)) // will use this to type cast and deference ,accessing the register.
DEMO(CAN1_MCR) = (CAN_MCR_INRQ | CAN_MCR_NART ); // CAN_MCR_INRQ and CAN_MCR_NART has hexadecimal vale pointing to specific bit in MCR register
Yes... You can use an integer pointer and go ahead with the method you use.
But you will miss on "Code Readability" and "Structured Code".
With the typedef struct, it is pretty easy to access the registers and code is easy to read/understand.
Nothing else!!
The key word is reuse. Saying
#define CAN1_MCR (CAN1_BASE+ 0x00)
#define CAN2_MCR (CAN2_BASE+ 0x00)
means that you'd have to define the layout twice (with all the double maintenance problems). The structure approach allows to define it once, and use the same definition for each bus.

Resources