This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

How the compiler know where to map the register to a certain address

Other Parts Discussed in Thread: MSP430F5438A

Hello,

 

I’m beginner in msp 430 families.

I’m write code to msp430f5439A, my IDE is code composer 5.2 (compiler version 4.1), and I write in C.

Whilst I’m learning about that new processor and environment, questions were rises up.

  1. in the file “msp430f5438a.h”  I saw those lines:

------

#ifdef __ASM_HEADER__ /* Begin #defines for assembler */

#define WDT_VECTOR      ".int58"      /* 0xFFF4 Watchdog Timer */

#else

#define WDT_VECTOR     (58 * 1u)     /* 0xFFF4 Watchdog Timer */

-----

how the compiler can understand the value of “(58 * 1u)” as an address of 0xFFF4? At first I thought that maybe the compiler is not ANCI C. but, and I want to quote (slau132g.pdf) “The compiler supports the 1989 version of the C language and the 1998 version of the C++ language….based on the ISO C standard”, (and I did not find any exception that can clarify the question).

 

  1. In order to understand how the CSL (chip select library, given by CCs v5.2) map identifier to be register in a certain address I following the register name and found those lines:

************************************************************

* WATCHDOG TIMER A

************************************************************/

#define __MSP430_HAS_WDT_A__ /* Definition to show that Module is available */

#define __MSP430_BASEADDRESS_WDT_A__ 0x0150

 

SFR_16BIT(WDTCTL);       /* Watchdog Timer Control */

SFR_8BIT(WDTCTL_L);      /* Watchdog Timer Control */

SFR_8BIT(WDTCTL_H);      /* Watchdog Timer Control */

************************************************************/

And later:

#define SFR_16BIT(address)  extern volatile unsigned int address

 

So it clear that WDTCL is address register. But:

a.                How that register was map to any address by the define “__MSP430_BASEADDRESS_WDT_A__ “ ?

b.                  And why that address that according to the Literature (slas655b.pdf) : Watchdog Registers (Base Address: 015Ch)  is map to 0x0150?

I look at the Errate (SLAZ057P) but there was no relating information.

 

Is there anyone have hint how to solve that enigma…?

 

Thanks.

 

 

  • Hi asher,

    welcome to the msp430 families :-)

    "how the compiler can understand the value of “(58 * 1u)” as an address of 0xFFF4? At first I thought that maybe the compiler is not ANCI C. but, and I want to quote (slau132g.pdf) “The compiler supports the 1989 version of the C language and the 1998 version of the C++ language….based on the ISO C standard”, (and I did not find any exception that can clarify the question)."

    To help you, I must first clarify something. The linker, not the compiler, defines the memory map. See the document already quoted (slau132g) chapter 6 "Run-Time Environment.

    slau132g -> 6.1.3: NOTE:

    "The linker, not the compiler, defines the memory map and allocates code and data into target memory. The compiler assumes nothing about the types of memory available, about any locations not available for code or data (holes), or about any locations reserved for I/O or control purposes. The compiler produces relocatable code that allows the linker to allocate code and data into the appropriate memory spaces."

    The compiler produces relocatable blocks of code and data. These blocks, called sections, are allocated in memory in a variety of ways. See slau132g->4.3.7 for sections created by the compiler. When you link your program, you must specify where to allocate the sections in memory. For more information about allocating sections into memory, see the MSP430 Assembly Language Tools User's Guide.

    I recommend another document (slau157u - Code Composer Studio™ v5.2 User's Guide for MSP430™) chapter 2 "Development flow" for some more details using code composer studio.

    I assume you have created a new managed project (File -> New -> CCS Project). You entered the name for the project and set the device family to MSP430. When you select a specific device variant (your msp430f5438A), CCS adds a file "lnk_msp430f5438a.cmd" to the project. Thats the linker command file containing the system memory map and sections allocations.

    For further reading you can find here an overview of code composer studio v5.

    I hope it helps.

    Best regards,
    Christian

  • Hi asher,

    I didn't answered part 2 of your question. So I would like to make a few additions.

    Open your linker command skript file "lnk_msp430f5438a.cmd" and scroll down to the end of the file. That file includes another file called "msp430f5438a.cmd". It contains the device specific peripherals memory map. The watchdog registers are defined as follows:

    /************************************************************
    * WATCHDOG TIMER A
    ************************************************************/
    WDTCTL             = 0x015C;
    WDTCTL_L           = 0x015C;
    WDTCTL_H           = 0x015D;

    __MSP430_BASEADDRESS_WDT_A__ is not the same as WDTCTL. Open "msp430xgeneric.h" header file . There you can find

    #define OFS_WDTCTL             (0x000C)       /* Watchdog Timer Control */

    You can access the msp430 registers in many ways. Either you use the standard register definition WDTCTL and include the header file for your device variant "msp4305438a.h". 

    WDTCTL = WDTPW + WDTHOLD; /* Stops the watchdog */

    Alternative you can access that peripheral registers with self-made register matching structs and a base pointer to that struct or you use that base address defined by TI (pointing to 0x0150) and the offset to the specific register (0x000C):

    #define HWREG(x) (*((volatile unsigned int *)(x)))
    HWREG(__MSP430_BASEADDRESS_WDT_A__ + OFS_WDTCTL) = WDTPW + WDTHOLD; /* Stops the watchdog */

    The MSP430 peripheral driver library written by TI uses that last approach. You can look at the source code. It is provided by TI and included with CCS. Many further examples written by TI are written the first approach.

    Best regards,
    Christian

  • Christian Steffen said:
    The MSP430 peripheral driver library written by TI uses that last approach.

    It has a reason.
    If defining a rgister with the SFR_* macros, this generates an absolute reference. The compiler is told that there is a variable x that is located at a fixed memory position y. The compiler can then generate the most effective code by directly using the address as provided in teh SFR_* macro. The linker won't touch these instructions anymore.
    This results in smallest code and fastest execution.

    However, it also means that the code needs to be recompiled when the register position changes.

    Now libraries are usually pre-compiled and linked into various project without being recompiled for the specific target. The second approach leaves the address of the register unresolved. The compiled code contains relocaiton information with the symbol name, so the linker will calculate and insert the final address. This increases linking time, library size (due to the reloation information) and may not always produce the fasterst and smallest code, but ensures that the final address is only inserted into the code when it is linked. So the same binary file can b e linked into projects for different MSPs with different register addresses. Without need to recompile the library.

    So on the bottom line: in all code that is compiled with the project, use the first method, in all code that is used to build a precompiled library that is only linked to a project, use the second, less comfortable but relocatable method.

    And to add to the quesiton about vectors: the 'number' is actually an offset into the vector table. So '58' is just the location 58 bytes (29 vectors) above beginning of the vector table (whose position is defined in the target-specific linker files). In assembly, this locaiton is also marked with the .int58 symbol.
    On your specific MSp, the 30th vector from beginning of the vector table (zero-based!) is the WDT interrupt vector.

**Attention** This is a public forum