Placing Variables in Specific Memory Location - MSP430

From Texas Instruments Wiki
Jump to: navigation, search

Background

In many application, it is sometime necessary to place a variable in a specific memory location. This wiki shows a small guide to implement the specific variable placement for C programming language using most common compilers/IDEs for MSP430.


General Example

For the general example, the goal is to place a variable in InfoD segment of MSP430F5438A as follows:

Msp430 placing variable f54xxa mem map.PNG

As can be seen above, the InfoD segment of the MSP430F5438A is located at address 0x1800 - 0x187F. The information memory is often used to store calibrated application parameters which can be updated without affecting the code stored in the main flash memory. For evaluating the code, the IDE shall generate a TI-TXT binary file which shows that the variable is really stored at the desired location.


IAR EWB

Using location PRAGMA Or The At Sign

The IAR MSP430 EWB offers since a long time a very convenient and easy way to place a certain by using the location pragma or the at sign (@), which enables the specific placement of a variable by giving only the specified address as parameter.

  • Using the location pragma:
Code Generated TI-TXT file
#include <msp430.h>
 
#pragma location=0x1800
const unsigned char port_bit = BIT0;
 
void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;  // disable watchdog
  P1DIR = port_bit;          // set P1.x as output
 
  while(1)
  {
    P1OUT ^= port_bit;         // toggle P1.0
	  __delay_cycles(100000);
  }
}
@1800
01
@5C00
31 40 00 5C B0 13 0C 5C B0 13 48 5C B2 40 80 5A
5C 01 D2 42 00 18 04 02 D2 E2 00 18 02 02 00 3C
3F 40 33 82 3F 53 FE 2F F7 3F 03 43 0A 12 21 83
0A 4C 81 4A 00 00 0D 41 0D 53 5C 43 B0 13 4C 5C
F8 3F 03 43 80 00 2C 5C 80 00 44 5C 10 01
@FFFE
00 5C
q


  • Using the at sign (@):
Code Generated TI-TXT file
#include <msp430.h>
 
const unsigned char port_bit @ 0x1800 = BIT0;
 
void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;  // disable watchdog
  P1DIR = port_bit;          // set P1.x as output
 
  while(1)
  {
    P1OUT ^= port_bit;         // toggle P1.0
	  __delay_cycles(100000);
  }
}
@1800
01
@5C00
31 40 00 5C B0 13 0C 5C B0 13 48 5C B2 40 80 5A
5C 01 D2 42 00 18 04 02 D2 E2 00 18 02 02 00 3C
3F 40 33 82 3F 53 FE 2F F7 3F 03 43 0A 12 21 83
0A 4C 81 4A 00 00 0D 41 0D 53 5C 43 B0 13 4C 5C
F8 3F 03 43 80 00 2C 5C 80 00 44 5C 10 01
@FFFE
00 5C
q


Using constseg PRAGMA With Defined Section From The Linker Configuration File

It is also possible to use a section name which is already defined in the linker configuration file. For the example above, the default linker configuration file of MSP430F5438A which is called lnk430F5438A.xcl contains the definition of INFOD segment:

// -----------------------------------------------
// Read-only memory
//

// -------------------------------------
// Information memory
//

-Z(CONST)INFO=1800-19FF
-Z(CONST)INFOA=1980-19FF
-Z(CONST)INFOB=1900-197F
-Z(CONST)INFOC=1880-18FF
-Z(CONST)INFOD=1800-187F

This section can be used together with the constseg pragma as follows:

Code Generated TI-TXT file
#include <msp430.h>
 
#pragma constseg=INFOD
const unsigned char port_bit = BIT0;
#pragma constseg=default
 
void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;  // disable watchdog
  P1DIR = port_bit;          // set P1.x as output
 
  while(1)
  {
    P1OUT ^= port_bit;         // toggle P1.0
	  __delay_cycles(100000);
  }
}
@1800
01
@5C00
31 40 00 5C B0 13 0C 5C B0 13 48 5C B2 40 80 5A
5C 01 D2 42 00 18 04 02 D2 E2 00 18 02 02 00 3C
3F 40 33 82 3F 53 FE 2F F7 3F 03 43 0A 12 21 83
0A 4C 81 4A 00 00 0D 41 0D 53 5C 43 B0 13 4C 5C
F8 3F 03 43 80 00 2C 5C 80 00 44 5C 10 01
@FFFE
00 5C
q




CCS (Code Composer Studio)

Using location PRAGMA

The CCS v5.x comes with the Code Generation Tools (CGT) version v4.x which also supports the location pragma such the one in IAR EWB. The CGT v4.x however does not support the at sign (@) usage for placing the data in specified address.

The supported syntaxs of location pragma supported by the CGT v4.x are follows:

#pragma LOCATION( x , address );
int x;
#pragma location=address
int x;


Using DATA_SECTION PRAGMA With Defined Memory Section in Linker Command File

Older CCS v4.x version of CCS comes with older CGT version v3.x which does not support the location pragma, and instead for this purpose the DATA_SECTION pragma can be used. The DATA_SECTION pragma of older CGT v3.x version works the almost the same as constseg pragma in IAR EWB.

For the example above, the default linker command file lnk_msp430f5438a.cmd contains the following definition of INFOD segment:

MEMORY
{
    ........

    INFOA                   : origin = 0x1980, length = 0x0080
    INFOB                   : origin = 0x1900, length = 0x0080
    INFOC                   : origin = 0x1880, length = 0x0080
    INFOD                   : origin = 0x1800, length = 0x0080

    ........
}

SECTIONS
{
    ........

    .infoA     : {} > INFOA              /* MSP430 INFO FLASH MEMORY SEGMENTS */
    .infoB     : {} > INFOB
    .infoC     : {} > INFOC
    .infoD     : {} > INFOD

    ........
}

The memory section can be used in the code with DATA_SECTION pragma as follows:

Code Generated TI-TXT file
#include <msp430.h>
 
#pragma DATA_SECTION(port_bit, ".infoD")
const unsigned char port_bit = BIT0;
 
void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;  // disable watchdog
  P1DIR = port_bit;          // set P1.x as output
 
  while(1)
  {
    P1OUT ^= port_bit;         // toggle P1.0
	  __delay_cycles(100000);
  }
}
@1800
01
@5c00
31 40 00 5C B0 13 AA 5C 0C 93 02 24 B0 13 1A 5C
0C 43 B0 13 88 5C B0 13 AE 5C 1A 14 3F 40 00 00
3F 90 01 00 22 28 3F 40 00 00 3F 90 01 00 1D 28
3A 40 00 00 3A 80 00 00 3A 50 07 00 5A 09 39 40
00 00 3C 49 3D 49 CF 0D 0F 18 4F 5F 00 18 4F DC
6F 4F 4F 4F 5F 06 00 18 5B 4F 00 00 1C 53 0D 63
3E 49 3F 49 4B 13 1A 83 EC 23 3F 40 00 00 3F 90
00 00 08 24 3A 40 00 00 02 3C 6A 13 2A 52 3A 90
00 00 FB 23 19 16 10 01 B2 40 80 5A 5C 01 D2 42
00 18 04 02 D2 E2 00 18 02 02 0D 14 3D 40 32 82
1D 83 FE 23 0D 16 F6 3F 03 43 1C 43 10 01 03 43
FF 3F
@fffe
00 5C
q


Modifying The Linker Configuration File

As shown above, the defined memory segments of IAR's linker configuration file and memory section of CCS's linker command file can be used with constseg pragma and DATA_SECTION pragma respectively to put a variable inside a specific memory location. Therefore it is possible to modify the linker configuration/command file to define a new memory segment/section and put the necessary variable inside the defined memory segment/location.

For more information regarding modifying the linker configuration/command file, please refer to the CCS and IAR documentation.



Generating JTAG Lock

One most common example for placing variable inside specific memory location is defining the electronic JTAG fuse of MSP430x5xx/6xx devices (or even MSP430FR57xx) inside the program as variable, so that once the program is downloaded into the device the JTAG access will be disabled after the next power cycle.

On the MSP430x5xx/6xx devices, the electronic JTAG fuse is defined as the content of memory location 0x17FC-0x17FF. Any value besides 0x00s or 0xFFs will disable the JTAG access. The following example shows how to define the JTAG fuse as variable to be not removed by the linker since it is mostly considered as dead variable when not accessed by any part of the program:

  • IAR: using the required pragma
Code Generated TI-TXT file
#include <msp430.h>
 
const unsigned long int jtag_lock @ 0x17FC = 0xAAAAAAAA;
 
#pragma required=jtag_lock
void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;  // disable watchdog
  P1DIR = BIT0;              // set P1.0 as output
 
  while(1)
  {
    P1OUT ^= BIT0  ;         // toggle P1.0
	  __delay_cycles(100000);
  }
}
@17FC
AA AA AA AA
@5C00
31 40 00 5C B0 13 0C 5C B0 13 44 5C B2 40 80 5A
5C 01 D2 43 04 02 D2 E3 02 02 00 3C 3F 40 33 82
3F 53 FE 2F F8 3F 03 43 0A 12 21 83 0A 4C 81 4A
00 00 0D 41 0D 53 5C 43 B0 13 48 5C F8 3F 03 43
80 00 28 5C 80 00 40 5C 10 01
@FFFE
00 5C
q


  • CCS: using the RETAIN pragma
Code Generated TI-TXT file
#include <msp430.h>
 
#pragma RETAIN(jtag_lock)
#pragma location=0x17FC
const unsigned long int jtag_lock = 0xAAAAAAAA;
 
void main(void)
{
  WDTCTL = WDTPW + WDTHOLD;  // disable watchdog
  P1DIR = BIT0;              // set P1.0 as output
 
  while(1)
  {
    P1OUT ^= BIT0  ;         // toggle P1.0
	  __delay_cycles(100000);
  }
}
@17fc
AA AA AA AA
@5c00
31 40 00 5C B0 13 A6 5C 0C 93 02 24 B0 13 1A 5C
0C 43 B0 13 88 5C B0 13 AA 5C 1A 14 3F 40 00 00
3F 90 01 00 22 28 3F 40 00 00 3F 90 01 00 1D 28
3A 40 00 00 3A 80 00 00 3A 50 07 00 5A 09 39 40
00 00 3C 49 3D 49 CF 0D 0F 18 4F 5F 00 18 4F DC
6F 4F 4F 4F 5F 06 00 18 5B 4F 00 00 1C 53 0D 63
3E 49 3F 49 4B 13 1A 83 EC 23 3F 40 00 00 3F 90
00 00 08 24 3A 40 00 00 02 3C 6A 13 2A 52 3A 90
00 00 FB 23 19 16 10 01 B2 40 80 5A 5C 01 D2 43
04 02 D2 E3 02 02 0D 14 3D 40 32 82 1D 83 FE 23
0D 16 F7 3F 03 43 1C 43 10 01 03 43 FF 3F
@fffe
00 5C
q

When trying to program the code into the device, don't forget to enable the access to the BSL memory since it is per default disabled. Please refer to the following wiki page for getting information on how to enable the BSL memory access in various software programmers/debuggers: MSP430_FAQ#How_to_enable_the_access_to_BSL_Flash_memory_in_MSP430F5xx.2F6xx_devices_.3F