So I’m a little confused with this code I am wading through. It’s the CMSIS level for the 32-bit zero gecko from Silabs.
Basically they have a series of defines, for the base address of each peripheral. Followed by a macro, which contains a pointer to a struct of ***_TypeDef as the first parameter (these typedef structs are declared in repsective peripheral header files), and then the defined base addresses as a second paramater. Defines as follows:
Code:
#defineAES_BASE (0x400E0000UL) /**<AES base address */
#defineDMA_BASE (0x400C2000UL) /**<DMA base address */
#defineMSC_BASE (0x400C0000UL) /**<MSC base address */
#defineEMU_BASE (0x400C6000UL) /**<EMU base address */
#defineRMU_BASE (0x400CA000UL) /**<RMU base address */
#defineCMU_BASE (0x400C8000UL) /**<CMU base address */
#defineTIMER0_BASE (0x40010000UL) /**<TIMER0 base address */
#defineTIMER1_BASE (0x40010400UL) /**<TIMER1 base address */
#defineACMP0_BASE (0x40001000UL) /**<ACMP0 base address */
#defineUSART1_BASE (0x4000C400UL) /**<USART1 base address */
#definePRS_BASE (0x400CC000UL) /**<PRS base address */
#defineIDAC0_BASE (0x40004000UL) /**<IDAC0 base address */
#defineGPIO_BASE (0x40006000UL) /**<GPIO base address */
#defineVCMP_BASE (0x40000000UL) /**<VCMP base address */
#defineADC0_BASE (0x40002000UL) /**<ADC0 base address */
#defineLEUART0_BASE (0x40084000UL) /**<LEUART0 base address */
#definePCNT0_BASE (0x40086000UL) /**<PCNT0 base address */
#defineI2C0_BASE (0x4000A000UL) /**<I2C0 base address */
#defineRTC_BASE (0x40080000UL) /**<RTC base address */
#defineWDOG_BASE (0x40088000UL) /**<WDOG base address */
#defineCALIBRATE_BASE (0x0FE08000UL) /**<CALIBRATE base address */
#defineDEVINFO_BASE (0x0FE081B0UL) /**<DEVINFO base address */
#defineROMTABLE_BASE (0xF00FFFD0UL) /**<ROMTABLE base address */
#defineLOCKBITS_BASE (0x0FE04000UL) /**<Lock-bits page base address */
#defineUSERDATA_BASE (0x0FE00000UL) /**<User data page base address */
/**@} End of group EFM32ZG222F32_Peripheral_Base */
/**************************************************************************//***@defgroup EFM32ZG222F32_Peripheral_Declaration EFM32ZG222F32Peripheral Declarations* @{*****************************************************************************/
#defineAES ((AES_TypeDef *) AES_BASE) /**<AES base pointer */
#defineDMA ((DMA_TypeDef *) DMA_BASE) /**<DMA base pointer */
#defineMSC ((MSC_TypeDef *) MSC_BASE) /**<MSC base pointer */
#defineEMU ((EMU_TypeDef *) EMU_BASE) /**<EMU base pointer */
#defineRMU ((RMU_TypeDef *) RMU_BASE) /**<RMU base pointer */
#defineCMU ((CMU_TypeDef *) CMU_BASE) /**<CMU base pointer */
#defineTIMER0 ((TIMER_TypeDef *) TIMER0_BASE) /**<TIMER0 base pointer */
#defineTIMER1 ((TIMER_TypeDef *) TIMER1_BASE) /**<TIMER1 base pointer */
#defineACMP0 ((ACMP_TypeDef *) ACMP0_BASE) /**<ACMP0 base pointer */
#defineUSART1 ((USART_TypeDef *) USART1_BASE) /**<USART1 base pointer */
#definePRS ((PRS_TypeDef *) PRS_BASE) /**<PRS base pointer */
#defineIDAC0 ((IDAC_TypeDef *) IDAC0_BASE) /**<IDAC0 base pointer */
#defineGPIO ((GPIO_TypeDef *) GPIO_BASE) /**<GPIO base pointer */
#defineVCMP ((VCMP_TypeDef *) VCMP_BASE) /**<VCMP base pointer */
#defineADC0 ((ADC_TypeDef *) ADC0_BASE) /**<ADC0 base pointer */
#defineLEUART0 ((LEUART_TypeDef *) LEUART0_BASE) /**<LEUART0 base pointer */
#definePCNT0 ((PCNT_TypeDef *) PCNT0_BASE) /**<PCNT0 base pointer */
#defineI2C0 ((I2C_TypeDef *) I2C0_BASE) /**<I2C0 base pointer */
#defineRTC ((RTC_TypeDef *) RTC_BASE) /**<RTC base pointer */
#defineWDOG ((WDOG_TypeDef *) WDOG_BASE) /**<WDOG base pointer */
#defineCALIBRATE ((CALIBRATE_TypeDef *) CALIBRATE_BASE) /**<CALIBRATE base pointer */
#defineDEVINFO ((DEVINFO_TypeDef *) DEVINFO_BASE) /**<DEVINFO base pointer */
#defineROMTABLE ((ROMTABLE_TypeDef *) ROMTABLE_BASE) /**<ROMTABLE base pointer */
The respective structs all look something like this:
Code:
typedefstruct
{ __IOMuint32_tCTRL;/**<Control Register */
__IOMuint32_tFRAME;/**<USART Frame Format Register */
__IOMuint32_tTRIGCTRL;/**<USART Trigger Control register */
__IOMuint32_tCMD;/**<Command Register */
__IMuint32_tSTATUS;/**<USART Status Register */
__IOMuint32_tCLKDIV;/**<Clock Control Register */
__IMuint32_tRXDATAX;/**<RX Buffer Data Extended Register */
__IMuint32_tRXDATA;/**<RX Buffer Data Register */
__IMuint32_tRXDOUBLEX;/**<RX Buffer Double Data Extended Register */
__IMuint32_tRXDOUBLE;/**<RX FIFO Double Data Register */
__IMuint32_tRXDATAXP;/**<RX Buffer Data Extended Peek Register */
__IMuint32_tRXDOUBLEXP;/**<RX Buffer Double Data Extended Peek Register */
__IOMuint32_tTXDATAX;/**<TX Buffer Data Extended Register */
__IOMuint32_tTXDATA;/**<TX Buffer Data Register */
__IOMuint32_tTXDOUBLEX;/**<TX Buffer Double Data Extended Register */
__IOMuint32_tTXDOUBLE;/**<TX Buffer Double Data Register */
__IMuint32_tIF;/**<Interrupt Flag Register */
__IOMuint32_tIFS;/**<Interrupt Flag Set Register */
__IOMuint32_tIFC;/**<Interrupt Flag Clear Register */
__IOMuint32_tIEN;/**<Interrupt Enable Register */
__IOMuint32_tIRCTRL;/**<IrDA Control Register */
__IOMuint32_tROUTE;/**<I/O Routing Register */
__IOMuint32_tINPUT;/**<USART Input Register */
__IOMuint32_tI2SCTRL;/**<I2S Control Register */
}USART_TypeDef;/**@} */
First a little bit of context:
At the start of my learning, this was naturally all a bit confusing. (I made a post earlier in the year about these structs. It was made clear to me that the size of each register and thus the calculated offset, was defined by size of the data type. Very cool!)
Then after having stumbled upon the syntax for writing to a register i.e.
Code:
USART1→ROUTE (= / |= / &=) PREDEFINED_MASK_EXAMPLE;
I then learned about the arrow operator (something I personally feel should be called the deference [not de-reference] operator) and why we use it as opposed to the dot operator: because I am accessing a member of a struct via a pointer. Again, very cool. Woot.
So all of that makes sense. I call a macro, access a member via a pointer and the base address is passed to the macro. Then magic.
What doesn’t make sense is two things:
1. In the macros, how does the second parameter i.e. base address, actually become associated with the struct. Is this something that is inherent to macros??
2. The same question plays out, in a slightly different form, in the following function which is defined in the silabs api for this chip.
Code:
uint8_t USART_SpiTransfer(USART_TypeDef *usart, uint8_t data)
<<<<<<<<----------
{
while (!(usart->STATUS & USART_STATUS_TXBL))
;
usart->TXDATA = (uint32_t)data;
<<<<<<<<<<<<--------------------------------
while (!(usart->STATUS & USART_STATUS_TXC))
;
return (uint8_t)usart->RXDATA;<<<<<<<<<<------------
}
I understand that the first parameter is a pointer to a struct of USART_TypeDef and that we are writing to an instance of that struct.
What I am struggling to see is where the appropriate peripheral base addresses are being passed to this instance of said struct. For all I can see it’s merely a random instance of a struct, just like any other struct, without association to any real address space register.
Again, even here:
Code:
#defineUSART1 ((USART_TypeDef *) USART1_BASE) /**<USART1 base pointer */
The passing of the struct as the first parameter (and base address as second parameter), to the macro is only relevant when I call that macro directly.. yes?
Again,how does this base address become associated with the struct inside the macro and how then does the same thing happen to the instance of the struct, that is created inside the above mentioned function?
Thanks Salem and everyone in advance! haha