Peripheral definition - c

Could someone please explain the following construction to a beginner:
typedef struct
{
__IO uint32_t CTRL; /**< Control Register */
__IO uint32_t CNT; /**< Counter Value Register */
__IO uint32_t COMP0; /**< Compare Value Register 0 */
__IO uint32_t COMP1; /**< Compare Value Register 1 */
__I uint32_t IF; /**< Interrupt Flag Register */
__IO uint32_t IFS; /**< Interrupt Flag Set Register */
__IO uint32_t IFC; /**< Interrupt Flag Clear Register */
__IO uint32_t IEN; /**< Interrupt Enable Register */
__IO uint32_t FREEZE; /**< Freeze Register */
__I uint32_t SYNCBUSY; /**< Synchronization Busy Register */
} RTC_TypeDef;
#define RTC_BASE (0x40080000UL)
#define RTC ((RTC_TypeDef *) RTC_BASE)
especially the last line
Why are the brackets so unusual? What does the * mean? Pointer or multiply operator ?
Thanks

Why are the brackets so unusual? What does the * mean? Pointer or
multiply operator ?
* here is a pointer not multiplication operator.
There is nothing unusual here about the macro. It is just type casting the address to be of type struct RTC_TypeDef

Whenever you will encounter a single or multiple * after a datatype (even a user defined datatype), its a pointer.
What you are calling a constructions:
typedef struct
{
__IO uint32_t CTRL; /**< Control Register */
__IO uint32_t CNT; /**< Counter Value Register */
__IO uint32_t COMP0; /**< Compare Value Register 0 */
__IO uint32_t COMP1; /**< Compare Value Register 1 */
__I uint32_t IF; /**< Interrupt Flag Register */
__IO uint32_t IFS; /**< Interrupt Flag Set Register */
__IO uint32_t IFC; /**< Interrupt Flag Clear Register */
__IO uint32_t IEN; /**< Interrupt Enable Register */
__IO uint32_t FREEZE; /**< Freeze Register */
__I uint32_t SYNCBUSY; /**< Synchronization Busy Register */
} RTC_TypeDef;
is a structure and programmatically called a struct, a user-defined datatype. struct is keyword in C. And so is typedef. To keep it simple as of now, I'll say, typedef here is specifically used to have the convenience to write RTC_TypeDef; instead of having the need to write struct stRTC for example.
RTC_BASE is a macro. So, before compilation pre-processor will replace RTC_BASE with the value (0x40080000UL), again, it is for convenience and readability.
This last line:
#define RTC ((RTC_TypeDef *) RTC_BASE)
also is a macro defined. Which is nothing but a pointer of the RTC_Typedef type, pointing to whatever is located at the address (0x40080000UL)
So, before the compilation the pre-processor will replace all instances of RTC with ((RTC_TypeDef *)0x40080000UL).
If you increment RTC pointer, it will increment by sizeof(RTC_Typedef).

The structure definition is pretty straight forward, variables are encapsulated in a structure. That structure can then be referenced as RTC_TypeDef because you use typedef.
typedef struct
{
__IO uint32_t CTRL; /**< Control Register */
__IO uint32_t CNT; /**< Counter Value Register */
__IO uint32_t COMP0; /**< Compare Value Register 0 */
__IO uint32_t COMP1; /**< Compare Value Register 1 */
__I uint32_t IF; /**< Interrupt Flag Register */
__IO uint32_t IFS; /**< Interrupt Flag Set Register */
__IO uint32_t IFC; /**< Interrupt Flag Clear Register */
__IO uint32_t IEN; /**< Interrupt Enable Register */
__IO uint32_t FREEZE; /**< Freeze Register */
__I uint32_t SYNCBUSY; /**< Synchronization Busy Register */
} RTC_TypeDef; /** #} */
The following line means every time you write RTC_BASE, the compiler will replace that line with (0x40080000UL)
#define RTC_BASE (0x40080000UL)
And finally, the following line can be broken into two parts:
(RTB_TypeDef *)RTC_BASE
Which means (RTB_TypeDef *)(0x40080000UL) - basically tells the compiler to treat memory address 0x40080000UL as a pointer to RTB_TypeDef
and the extra parenthesis are there to denote a single variable as a compund expression RTC.
From that point on, whenever the compiler sees RTC, it will replace it with (RTB_TypeDef *)(0x40080000UL), basically a convenient way to mark the beginning of this structure in memory

Related

is it possible to make a structure pointer points to another structure pointer with different types

the following structure is a structure of registers with type timer_t
typedef struct { /*!< TIMER0 Structure */
uint32_t CFG; /*!< GPTM Configuration */
uint32_t TAMR; /*!< GPTM Timer A Mode */
uint32_t TBMR; /*!< GPTM Timer B Mode */
uint32_t CTL; /*!< GPTM Control */
uint32_t SYNC; /*!< GPTM Synchronize */
uint32_t RESERVED;
uint32_t IMR; /*!< GPTM Interrupt Mask */
uint32_t RIS; /*!< GPTM Raw Interrupt Status */
uint32_t MIS; /*!< GPTM Masked Interrupt Status */
uint32_t ICR; /*!< GPTM Interrupt Clear */
uint32_t TAILR; /*!< GPTM Timer A Interval Load */
uint32_t TBILR; /*!< GPTM Timer B Interval Load */
uint32_t TBMATCHR; /*!< GPTM Timer B Match */
uint32_t TAPR; /*!< GPTM Timer A Prescale */
uint32_t TBPR; /*!< GPTM Timer B Prescale */
uint32_t TAPMR; /*!< GPTM TimerA Prescale Match */
uint32_t TBPMR; /*!< GPTM TimerB Prescale Match */
uint32_t TAR; /*!< GPTM Timer A */
uint32_t TBR; /*!< GPTM Timer B */
uint32_t TAV; /*!< GPTM Timer A Value */
uint32_t TBV; /*!< GPTM Timer B Value */
uint32_t RTCPD; /*!< GPTM RTC Predivide */
uint32_t TAPS; /*!< GPTM Timer A Prescale Snapshot */
uint32_t TBPS; /*!< GPTM Timer B Prescale Snapshot */
uint32_t TAPV; /*!< GPTM Timer A Prescale Value */
uint32_t TBPV; /*!< GPTM Timer B Prescale Value */
uint32_t RESERVED1[981];
uint32_t PP; /*!< GPTM Peripheral Properties */
}timer_t;
and this #define TIMER0 ((timer_t *) TIMER0_BASE) is used to dereference them so I can write on them as TIMER0_BASE is the base address of the used module. now I want to declare another bit field with type timerAModeBitField_t;for every register something to be like this
typedef struct timerAModeBitField{
uint32_t timerAMode : 2;
uint32_t timerACaptMode : 1;
uint32_t timeraPWMMode : 1;
uint32_t timerACountDir : 1;
uint32_t timerAMatchIntEn : 1;
uint32_t timerAWaitOnTrig : 1;
uint32_t timerASnapShotMode : 1;
uint32_t timerAIntervalLoad : 1;
}timerAModeBitField_t;
so I can directly write to their specific bits is it possible to implement something like that so I can first dereference the register and then dereference the bit field TIMER0->TAMR->timerAmode = 0x04
In portable C, the layout of bit-fields is unspecified. So you can't use bit-fields to describe a specific layout in portable C.
However, if you're writing code for a specific architecture, your C implementation may have additional guarantees. On Arm platforms, in particular, the Arm Architecture Procedure Call Standard (AAPCS) applies. It has a rule for bit-fields, and specifically for bit-fields in C and C++. If the bit-field description were provided by your vendor and the peripheral was intended to be used on an Arm processor, the AAPCS guarantees that you're both making the same assumptions on the data layout, so your code will use the intended data layout.
However using the same data layout is not sufficient! You also have to ensure that the compiler will do the right thing when a field is written in one way (say, through the uint32_t) and then read back in the other way (say, through the bit-field). C compilers are generally allowed to assume that when memory is accessed through different types, it's different memory. This allows compilers to optimize code better.
There are several exceptions which I won't go into here, but in general you can't assume that writing memory in one way and reading it back in some other way will give consistent results. Accessing the same memory in different ways is called aliasing. What is the strict aliasing rule? has a very good explanation of how this applies to C. Be careful: violating the aliasing rules can often result in code that fails only at certain levels of optimization, and only in certain contexts (e.g. depending on the number of registers that the compiler had available for a particular block of code), so this can be hard to debug. In particular, beware that casts can often get around compiler warnings, but not against aliasing bugs: casts just tell the compiler to stop complaining about broken code, they don't make the code less broken.
One way to let the compiler know that you're accessing the same memory through different types is to put those types in a union. (This is guaranteed in C11, and not officially guaranteed but widely implemented in C99.) That is:
typedef union {
uint32_t value;
timerAModeBitField bits;
} timerAModeUnion;
typedef struct {
…
timerAModeUnion TAMR;
…
} timer_t;
Then you can reliably do things like bulk-write TIMER0->TAMR.value and read a specific bit-field via TIMER0->TAMR.bits.timerAmode.
You can use the (inner) structure as the data type of an element of another (outer) structure, like this:
typedef struct timerAModeBitField {
uint32_t timerAMode : 2;
uint32_t timerACaptMode : 1;
uint32_t timeraPWMMode : 1;
uint32_t timerACountDir : 1;
uint32_t timerAMatchIntEn : 1;
uint32_t timerAWaitOnTrig : 1;
uint32_t timerASnapShotMode : 1;
uint32_t timerAIntervalLoad : 1;
uint32_t padding : 23;
} timerAModeBitField_t;
typedef struct { /*!< TIMER0 Structure */
uint32_t CFG; /*!< GPTM Configuration */
timerAModeBitField_t TAMR; /*!< GPTM Timer A Mode */
uint32_t TBMR; /*!< GPTM Timer B Mode */
uint32_t CTL; /*!< GPTM Control */
uint32_t SYNC; /*!< GPTM Synchronize */
uint32_t RESERVED;
uint32_t IMR; /*!< GPTM Interrupt Mask */
uint32_t RIS; /*!< GPTM Raw Interrupt Status */
uint32_t MIS; /*!< GPTM Masked Interrupt Status */
uint32_t ICR; /*!< GPTM Interrupt Clear */
uint32_t TAILR; /*!< GPTM Timer A Interval Load */
uint32_t TBILR; /*!< GPTM Timer B Interval Load */
uint32_t TBMATCHR; /*!< GPTM Timer B Match */
uint32_t TAPR; /*!< GPTM Timer A Prescale */
uint32_t TBPR; /*!< GPTM Timer B Prescale */
uint32_t TAPMR; /*!< GPTM TimerA Prescale Match */
uint32_t TBPMR; /*!< GPTM TimerB Prescale Match */
uint32_t TAR; /*!< GPTM Timer A */
uint32_t TBR; /*!< GPTM Timer B */
uint32_t TAV; /*!< GPTM Timer A Value */
uint32_t TBV; /*!< GPTM Timer B Value */
uint32_t RTCPD; /*!< GPTM RTC Predivide */
uint32_t TAPS; /*!< GPTM Timer A Prescale Snapshot */
uint32_t TBPS; /*!< GPTM Timer B Prescale Snapshot */
uint32_t TAPV; /*!< GPTM Timer A Prescale Value */
uint32_t TBPV; /*!< GPTM Timer B Prescale Value */
uint32_t RESERVED1[981];
uint32_t PP; /*!< GPTM Peripheral Properties */
} timer_t;
Then you can access mode bits in this way:
TIMER0->TAMR.timerAmode = 2;
Note: You should not assign 0x04 to a bitfield of width 2, the width of the value is too big. Possible values range from 0 to 3.
EDIT:
Let's minize the example:
typedef union {
struct {
unsigned int mode: 2;
unsigned int padding: 30;
};
uint32_t value;
} control_t;
typedef struct {
control_t control;
uint32_t stuff;
} module_t;
You can always obtain the address of an element of a structure:
module_t module;
control_t* mode_p = &module.control;
mode_p->mode = 3; // write only to 2 bits
uint32_t v = mode_p->value; // read all 32 bits
Via the union you can use either the complete control register or conveniently access just some bits:
module.control.value = 0x12345678;
module.control.mode = 2;
Don't fall into the trap to think too much from a machine code perspective. Use the abstraction of the higher level language to gain better source control by the compiler. Avoid casts as much as possible, since they tell the compiler to think, "The programmer is always right, who am I to doubt her?" Even in cases where your code has errors.
Caution: In fact it is not defined by the C standard how exactly bitfields are allocated. However, compilers do this in a reproducable way, it might well be documented. Make sure you guard your code with a check on the compiler you validate for your usage.
You could try this approach using unnamed members:
#include <stdint.h>
typedef struct {
...
union {
struct {
uint32_t timerAMode : 2;
uint32_t timerACaptMode : 1;
uint32_t timeraPWMMode : 1;
uint32_t timerACountDir : 1;
uint32_t timerAMatchIntEn : 1;
uint32_t timerAWaitOnTrig : 1;
uint32_t timerASnapShotMode : 1;
uint32_t timerAIntervalLoad : 1;
};
uint32_t TAMR;
};
...
} timer_t;
#define TIMER0_BASE (0x40001000)
volatile timer_t *TIMER0 = (timer_t*) TIMER0_BASE;
int main(void)
{
TIMER0->TAMR = 0x1234;
TIMER0->timerAMode = 2;
}
By using unnamend members you can access members of the union/struct directly without adding a field name for that union.
This allows accessing TAMR at once as well as the separate fields of it.

Reserved structure member in CMSIS device peripheral access file

Why in the CMSIS device file "TM4C123GH6PM.h" there are reserved structure members declared in some of the peripheral's structures for example in TIMER0_Type structure there are two reserved members.
does it have something to do with the microcontroller itself or is it concerned with word alignment and how the structure is going to be allocated in the memory?
typedef struct { /*!< TIMER0 Structure */
__IO uint32_t CFG; /*!< GPTM Configuration */
__IO uint32_t TAMR; /*!< GPTM Timer A Mode */
__IO uint32_t TBMR; /*!< GPTM Timer B Mode */
__IO uint32_t CTL; /*!< GPTM Control */
__IO uint32_t SYNC; /*!< GPTM Synchronize */
__I uint32_t RESERVED;
__IO uint32_t IMR; /*!< GPTM Interrupt Mask */
__IO uint32_t RIS; /*!< GPTM Raw Interrupt Status */
__IO uint32_t MIS; /*!< GPTM Masked Interrupt Status */
__O uint32_t ICR; /*!< GPTM Interrupt Clear */
__IO uint32_t TAILR; /*!< GPTM Timer A Interval Load */
__IO uint32_t TBILR; /*!< GPTM Timer B Interval Load */
__IO uint32_t TAMATCHR; /*!< GPTM Timer A Match */
__IO uint32_t TBMATCHR; /*!< GPTM Timer B Match */
__IO uint32_t TAPR; /*!< GPTM Timer A Prescale */
__IO uint32_t TBPR; /*!< GPTM Timer B Prescale */
__IO uint32_t TAPMR; /*!< GPTM TimerA Prescale Match */
__IO uint32_t TBPMR; /*!< GPTM TimerB Prescale Match */
__IO uint32_t TAR; /*!< GPTM Timer A */
__IO uint32_t TBR; /*!< GPTM Timer B */
__IO uint32_t TAV; /*!< GPTM Timer A Value */
__IO uint32_t TBV; /*!< GPTM Timer B Value */
__IO uint32_t RTCPD; /*!< GPTM RTC Predivide */
__IO uint32_t TAPS; /*!< GPTM Timer A Prescale Snapshot */
__IO uint32_t TBPS; /*!< GPTM Timer B Prescale Snapshot */
__IO uint32_t TAPV; /*!< GPTM Timer A Prescale Value */
__IO uint32_t TBPV; /*!< GPTM Timer B Prescale Value */
__I uint32_t RESERVED1[981];
__IO uint32_t PP; /*!< GPTM Peripheral Properties */
} TIMER0_Type;
On that particular part there is a 981 word gap between TIMER0_TBPV and TIMER0_PP, and a 1 word (32bit) gap between TIMER0_SYNC and TIMER0_IMR. From the datasheet:
The "reserved" fields simply force alignment with the hardware register map for which the type is used as an overlay. You certainly should not instantiate an object of this type in memory!
These structs are defined for easier access to memory mapped peripheral registers.
Each register has a fixed absolute address. The struct layout needs to be carefully designed such that the base address of the struct plus the offset of the member within the struct results in the register address.
As the register addresses are only partially contiguous, gaps without registers must be filled with dummy struct members, named RESERVEDxx.
They are a 1:1 map with the hardware. Say that you have only two registers:
A # 0x1000
B # 0x1004
You could define this struct:
struct {
u32* Ar;
u32* Br;
}regs;
And then assign manually the addresses:
struct regs myRegs;
myRegs.Ar = (u32*)0x1000;
myRegs.Br = (u32*)0x1004;
But doing this is error prone and also very long to do. What you can do, and what CMSIS does, is to define a struct with datatypes instead of pointers, knowing that the compiler will treat such structure as contiguous elements in the memory and will do pointer access for you.
struct {
u32 Ar;
u32 Br;
}regs;
struct regs* myRegsPtr = (struct regs*) 0x1000;
Now myRegsPtr holds the base address of the hardware register structure. Since now the C structure mimics the HW layout, accessing a member of the structure does exactly the pointer arithmetic you need for accessing the register you requested.
myRegs->Br; //This does 0x1000 + sizeof(all members before Br), reaching the correct offset.
Now back to your question. When we look at the datasheet we see this particular HW structure:
Can you spot the jump of 981*4 bytes? That is where you RESERVED area in your struct come from. In order to access the last register, the compiler must know that there are this amount of bytes to "jump".

How do I fix reference to register is pointing to the wrong one?

I'm trying to use the ADC in STM32 and I want to modify the ISR register so I'm doing ADC->ISR |= <bit>. However when I control-click on ISR it's bringing me to in stm32f0xx/cmsis_boot/core_cm0.h
/** \brief Union type to access the Interrupt Program Status Register (IPSR).
*/
typedef union
{
struct
{
uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */
uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */
} b; /*!< Structure used for bit access */
uint32_t w; /*!< Type used for word access */
} IPSR_Type;
I want to be brought to in stm32f0xx/cmsis_boot/stm32f0xx.h:
typedef struct
{
__IO uint32_t ISR; /*!< ADC Interrupt and Status register, Address offset:0x00 */
// other registers here
} ADC_TypeDef;
In my file, I'm not including either of those files so I'm not sure how the linking works. If I try to reference another register in ADC_TypeDef it works but I think because there are 2 ISR it can't find the right one. How do I fix this so that it's referencing the right one? Thanks!

CMSIS - Peripheral Definitions - Structs With Unions Syntax?

I've moving over from 8 bit bare-metal registers, and having to learn some new C Kungfu to wrap my head around the CMSIS Core approach.
I have a snippet of code here from a Peripheral Access Layer from a ARM Cortex M vendor. They create this SN_WDT_TYPE structure, which you can use to set watch-dog timer registers using their notation.
Why do they use the unions? I haven't seen this kind of syntax before.
If you use unions to create structures like that, do you they go several layers deep with pointers? Memory management with the unions? Is there some C syntax thing I'm missing here?
This might be CMSIS specific, does anyone know what the ": 1" is doing in those struct declarations...? I know the __IO ties back to some CMSIS definition of read/write.
HELPFUL STUFF I FOUND AFTER COMMENTS & ANSWERS:
ARM'S CMSCIS PERIPHERAL NAMING CONVENTION -- This example code doesn't seem to confirm too gracefully...
ARM'S BITFIELD COMPILER NOTES ON STRUCTS & UNIONS
/**
* #brief Watchdog Timer (SN_WDT)
*/
typedef struct { /*!< SN_WDT Structure */
union {
__IO uint32_t CFG; /*!< Offset:0x00 WDT Configuration Register */
struct {
__IO uint32_t WDTEN : 1; /*!< WDT enable */
__IO uint32_t WDTIE : 1; /*!< WDT interrupt enable */
__IO uint32_t WDTINT : 1; /*!< WDT interrupt flag */
uint32_t : 13;
__O uint32_t WDKEY : 16; /*!< Watchdog register key */
} CFG_b; /*!< BitSize */
};
union {
__IO uint32_t CLKSOURCE; /*!< Offset:0x04 WDT Clock Source Register */
struct {
__IO uint32_t CLKSOURCE : 2; /*!< WDT clock source */
uint32_t : 14;
__O uint32_t WDKEY : 16; /*!< Watchdog register key */
} CLKSOURCE_b; /*!< BitSize */
};
union {
__IO uint32_t TC; /*!< Offset:0x08 WDT Timer Constant Register */
struct {
__IO uint32_t TC : 8; /*!< Watchdog timer constant reload value */
uint32_t : 8;
__O uint32_t WDKEY : 16; /*!< Watchdog register key */
} TC_b; /*!< BitSize */
};
union {
__O uint32_t FEED; /*!< Offset:0x0C WDT Feed Register */
struct {
__O uint32_t FV : 16; /*!< Watchdog feed value */
__O uint32_t WDKEY : 16; /*!< Watchdog register key */
} FEED_b; /*!< BitSize */
};
} SN_WDT_Type;
The union allows you to access the hardware register as either a 32 bit word or as the bit fields contained in the register. Both representations have their uses. Perhaps you are missing the bit field syntax as it is not used in most application level coding. Bit field layout is compiler specific, but CMSIS headers are built to work with the intended compilers.

CMSIS register values

I have just started to explore the CMSIS for ARM controllers. It seems rather convenient to use it, however I was wondering where are the actual register values defined. Let's just take for example the GPIOs.
There is a structure GPIOA_AHB_Type defined with various members. Then, for GPIOB, there is a memory (or register?) address defined, let's say GPIOB_AHB_BASE. Afterwards, a pointer is set to GPIOB_AHB_BASE, like this:
#define GPIOB_AHB ((GPIOA_AHB_Type*) GPIOB_AHB_BASE)
GPIOB_AHB's member variables as GPIOB_AHB->DIR for example, to set it input or output. My question is, where precisely are these member variables initialized? I guess the actual address of the registers is device specific, so I tried to find them in the device specific header, but all I found was the GPIOB_AHB_BASE define and the declaration of the member variables. How does the compiler know that when I type GPIOB_AHB->DIR, I want to write into the register that sets that port's I/O direction?
If you look in your CMSIS header, you'll see all the structure definitions. Here's an example from my current project:
typedef struct
{
__IO uint32_t DATA; /*!< Port A Data Register */
__IO uint32_t CR; /*!< Port A Output Control Register */
__IO uint32_t FR1; /*!< Port A Function Register 1 */
__IO uint32_t FR2; /*!< Port A Function Register 2 */
uint32_t RESERVED0[6];
__IO uint32_t OD; /*!< Port A Open Drain Control Register */
__IO uint32_t PUP; /*!< Port A Pull-up Control Register */
uint32_t RESERVED1[2];
__IO uint32_t IE; /*!< Port A Input Control Register */
} TSB_PA_TypeDef;
Later on, a pointer to a structure of that type is defined:
#define PERI_BASE (0x40000000UL)
#define TSB_PA_BASE (PERI_BASE + 0x00C0000UL)
#define TSB_PA (( TSB_PA_TypeDef *) TSB_PA_BASE)
So that you can use it like:
TSB_PA->CR |= (1U << 2); // make Port A, bit 2 an output
value = TSB_PA->DATA & (1U << 5); // read Port A, bit 5.

Resources