This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

New to Programming STM32 ARM, unfamiliar with jargon words

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!