Hi I am at a loss, i have some training with C++ but when it comes to jargon words, I am very confused as I cannot find references for them. It's very different from programming for program for PC, not program for chip.
I know when it comes to words for the constants and variables. I know where to look for declarations. But when it comes to words for hardware parts like - GPIOB->ODR, - TIM1->SR, - and in any other projects
How on earth can I find their references or information?
Clement
I have found the reference for those jargon words however, I find that they are not same. ie TIM1->SR, instead of TIM1_SR. Whhy is this so?
Those are names of STM32 hardware registers.
The place to look for chip-specific hardware details is the manufacturer's Datasheet and associated documentation.
For the STM32, you can find all the manufacturer's supporting documentation here: www.st.com/.../familiesdocs-110.html
You need the both the Datasheet and the RM0008 Reference Manual
If you are using the ST Firmware Library, you will also need the documentation for that.
The Hitex "Insider's Guide to the STM32 ARM® based Microcontroller" is also available for download from www.st.com/.../familiesdocs-110.html
Keil has a booklist here: http://www.keil.com/books
You should recognise TIM1->SR a a standard C/C++ pointer reference to a structure member?
TIM1_SR is a C/C++ symbol: if you right-click it in uVision, choose 'Go To Definition', that will take you to its definition - probably a header file somewhere.
> I have found the reference for those jargon words > however, I find that they are not same. ie TIM1->SR, > instead of TIM1_SR. Whhy is this so?
Hi,
this is easy.
There are different methods of programming registers of microcontrollers. All register blocks have the same access structure: BASE_ADDRESS + REGISTER_OFFSET
The values are defined in the headerfiles.
Now there are two methods of setting up the symbolic names for the register accesses, because it is hard to remember the addresses. I do leave out the *((volatile *)(...)) cast here...
1.
#define UART1_SR UART1_BASE + UART_SR_OFFSET #define UART1_CR UART1_BASE + UART_CR_OFFSET #define UART1_DR UART1_BASE + UART_DR_OFFSET ... #define UART2_SR UART2_BASE + UART_SR_OFFSET #define UART2_CR UART2_BASE + UART_CR_OFFSET #define UART2_DR UART2_BASE + UART_DR_OFFSET ... #define UART3_SR UART3_BASE + UART_SR_OFFSET #define UART3_CR UART3_BASE + UART_CR_OFFSET #define UART3_DR UART3_BASE + UART_DR_OFFSET ...
When using this method every register must be defined, and you'll get massive code overhead for i.e. UART1, UART2, UART3 and UART4, which all have the same offsets but different base addresses.
2.
typedef struct { uint32_t SR; uint32_t CR; uint32_t DR; ... } UART_t; #define UART1 ((UART_t *) UART1_BASE; #define UART2 ((UART_t *) UART3_BASE; #define UART3 ((UART_t *) UART4_BASE;
This is easier and less code. The complete register (with it's "RESERVEDS" is defined in a structure, and that structure is mapped to UART1, UART2, ...
Have a look at stm32f10x_map.h and / or CMSIS core_cm3.h
--- The '.' and the '->' are access methods for static and dynamic structures.
typedef struct { int foo; int bar; } fooBar_t;
When using a static structure, it's members are accessed with the '.'::
fooBar_t fooBar; fooBar.foo = 7; fooBar.bar = 'a';
When using a dynamic structure, it's content is accessed with '->':
fooBar_t *fooBar; fooBar = (fooBar_t *) malloc (sizeof(fooBar_t)); fooBar->foo = 7; fooBar->bar = 'a';
This is used when memory is allocated when it's needed.
--- Because of the mapping to addresses the pointer must be used for the register structures.
BR, /th.
Hi Andy and Thorsten Both of you are really helpful! Now I begin to understand a bit. It will take me some time to digest. Over the time I might might understand better. Thanks alot
Do you by "massive" think about the number of source lines in the header file, or did you think about the amount of generated object code when accessing the devices?
"When using this method every register must be defined, and you'll get massive code overhead for i.e. UART1, UART2, UART3 and UART4, which all have the same offsets but different base addresses."
Note that this is only an "overhead" in the source code - it puts absolutely no overhead whatsoever in the generated machine code!
"This is easier and less code."
Whether it's "easier" or not is a matter of opinion - which is why you'll find one method used in some places, and the other in other places.
Again, "less code" is only less source text.
"The '.' and the '->' are access methods for static and dynamic structures."
No, that's not correct; it's not to do with "static" vs "dynamic" - it's whether you access the structure directly or indirectly (ie, via a pointer). But this is just standard C/C++ - nothing specifically to do with registers or embedded.
Of course, dynamically-allocated things can never be directly accessed, so pointers always have to be used for dynamic things - but static things can be accessed either directly or indirectly.
Register addresses are, of course, "static"!
Bravo Andy, you are really good in explaining fundamental stuff!