MSP430 use all 128kB (not just 47kB)

Hi,
I am using a custom PCB using MSP430F5529 with a custom firmware using most of the 128kB flash memory. I am currently trying to migrate this project to PIO. I am running out of Memory because the second memory section at 0x10000 cannot be written only the the first memory section at 0x4400 seems to be available. I used build_flags = -Wl,-Map=output.map to create a memory map file (below). I think I somehow need to set the attributes xr for the far_rom. Maybe with some linker flags?

Name             Origin             Length             Attributes
sfr              0x00000000         0x00000010
peripheral_8bit  0x00000010         0x000000f0
peripheral_16bit 0x00000100         0x00000100
bsl              0x00001000         0x00000800
infomem          0x00001800         0x00000200
infod            0x00001800         0x00000080
infoc            0x00001880         0x00000080
infob            0x00001900         0x00000080
infoa            0x00001980         0x00000080
usbram           0x00001c00         0x00000800         xw
ram              0x00002400         0x00002000         xw
rom              0x00004400         0x0000bb80         xr
vectors          0x0000ff80         0x00000080
far_rom          0x00010000         0x00014400
ram2             0x00000000         0x00000000         xw
ram_mirror       0x00000000         0x00000000         xw
signature        0x00000000         0x00000000
tinyram          0x00000000         0x00000000         xw
*default*        0x00000000         0xffffffff

I tried to set board.upload.maximum_size in platformio.ini (below) but couldn’t succeed it seems to be ignored.

[env:lpmsp430f5529]
platform = timsp430
board = lpmsp430f5529
board_build.f_cpu = 24000000L ; change MCU frequency to 24 MHz
board.upload.maximum_size= 131072 ; gets ignored!
debug_tool = mspdebug
build_type = release
build_flags =
  -Wl,-Map=output.map
Processing lpmsp430f5529 (platform: timsp430; board: lpmsp430f5529)
--------------------------------------------------------------------------------------------------------------------------------------------------------------------Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/timsp430/lpmsp430f5529.html
PLATFORM: TI MSP430 (2.3.0) > TI LaunchPad MSP-EXP430F5529LP
HARDWARE: MSP430F5529 24MHz, 8KB RAM, 47KB Flash
DEBUG: Current (mspdebug) On-board (mspdebug)
PACKAGES:
 - toolchain-timsp430 1.40603.210219 (4.6.3)
LDF: Library Dependency Finder -> http://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 0 compatible libraries
Scanning dependencies...
No dependencies
Building in release mode
Checking size .pio\build\lpmsp430f5529\firmware.elf
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
RAM:   [===       ]  30.1% (used 2466 bytes from 8192 bytes)
Flash: [==        ]  19.6% (used 9426 bytes from 48128 bytes)
=================================================================== [SUCCESS] Took 0.75 seconds ===================================================================

Any help on this is would be very welcome!

board_upload.maximum_size = 131072.

Thanks @maxgerhardt maxgerhardt for pointing out the stupid typo. I now have included more code and get another problem which is related. The linker can’t fit in region ‘rom’, I think it is still missing some flags or so to be able to use the ‘far_rom’ at 0x10000. Any ideas?

Linking .pio\build\lpmsp430f5529\firmware.elf
c:/users/wolfg/.platformio/packages/toolchain-timsp430/bin/…/lib/gcc/msp430/4.6.3/…/…/…/…/msp430/bin/ld.exe: .pio\build\lpmsp430f5529\firmware.elf section .rodata' will not fit in region rom’
c:/users/wolfg/.platformio/packages/toolchain-timsp430/bin/…/lib/gcc/msp430/4.6.3/…/…/…/…/msp430/bin/ld.exe: section .vectors loaded at [0000ff80,0000ffff] overlaps section .rodata loaded at [0000e9d2,000108bb]
c:/users/wolfg/.platformio/packages/toolchain-timsp430/bin/…/lib/gcc/msp430/4.6.3/…/…/…/…/msp430/bin/ld.exe: region rom' overflowed by 2382 bytes c:/users/wolfg/.platformio/packages/toolchain-timsp430/bin/../lib/gcc/msp430/4.6.3/mcpu-430x/mmpy-16\libcrt0.a(_copy_data.o): In function __do_copy_data’:
/root/mspgcc-20120406/BUILD/gcc/gcc/…/…/…/gcc-4.6.3/gcc/config/msp430/crt0.S:195: relocation truncated to fit: R_MSP430_16_BYTE against symbol __data_load_start' defined in *ABS* section in .pio\build\lpmsp430f5529\firmware.elf .pio\build\lpmsp430f5529\src\serial_parser.o: In function _questionmark()’:

Mhm the thing is if PlatformIO already has a wrong flash size information for this microcontroller, there might a few more things wrong. Per docs it has 47kByte, and per datasheet an MSP430F5529 definitely has 128 kByte. (Yes there might be a bootloader but that can impossibly take up ~80kByte – i’m no TI MSP430 expert though).

Another thing would be regarding the toolchain version. MSP430 GCC version 4.6.3 might be very old – what’s the msp430-gcc --version that is used in the base project?

Thanks! The thing is there are two seperate flash memory segments in MSP430F5529 and only the first memory segment is addressed im PlatformIO. It is not really wrong to just use the 47kByte but it is also not complete.

MSP430-gcc Version 4.6.3 is currently the default at PIO but you are right it seems quite old. Can I update this?

Could linker scripts be a solution for my problem?

Mhm the thing is when I build with your platformio.ini, there is no linker script being used.

The final linker command is, for a simple project

msp430-gcc -o .pio\build\lpmsp430f5529\firmware.elf -Os -mmcu=msp430f5529 -Wl,-gc-sections,-u,main .pio\build\lpmsp430f5529\src\main.o -L.pio\build\lpmsp430f5529 -Wl,–start-group -lm -Wl,–end-group

If there was a linker script it would be there with a -Wl,T path/to/linkerscript.ld.

Per API search, the package’s latest version is 1.40603.210219 meaning GCC 4.6.3 – so sadly that’s alraedy at the latest PlatformIO has. With a platform_packages command another toolchain, e.g. one on the disk, can be chosen (if you put a package.json file in the toolchain folder, aking to c:/users/wolfg/.platformio/packages/toolchain-timsp430/package.json).

  • Does your original script use a linker script?
  • What’s msp430-gcc --version for the toolchain your original project works with?

Thanks @maxgerhardt for helping me!
In the meantime I was researching and adapting the platformio.ini

[env]
platform = timsp430
board = lpmsp430f5529
board_build.mcu = msp430f5529 ; change microcontroller
board_build.f_cpu = 24000000L ; change MCU frequency
board_upload.maximum_size = 131072 ; 128kByte = 131072 Byte / 48128 Bytes is default
debug_tool = mspdebug
[env:lpmsp430f5529]
;extra_scripts = extra_build_script.py
board_build.ldscript = msp430f5529.ld ; linker script
build_type = release ; debug or release
build_flags =
  ;-v ; Verbose
  -Wall ; warning message generation and syntax checking
  ;-O ;optimization O0,-O,-O1,-O2, and-O3
  ;-std=c99
  -Wl,-Map=output.map #linker create an output.map file

I found the following msp430f5529.ld which i I copied into my project.

it is not compiling and thrrows may errors like: undefined reference to `__ADC12MEM0’ which are register addresses of the microcontroller
maybe i am missing something important…

I just added
build_flags = -Wl,-T msp430f5529.ld
and put the linker script in the folder .platformio\platforms\timsp430\builder

but at build there are a lot of invalid characters af of a sudden …


ignoring invalid character `\000’ in expression
c:/users/wolfg/.platformio/packages/toolchain-timsp430/bin/…/lib/gcc/msp430/4.6.3/…/…/…/…/msp430/bin/ld.exe:.pio\build\lpmsp430f5529\src\main.o:1: syntax errorcollect2: ld returned 1 exit status
*** [.pio\build\lpmsp430f5529\firmware.elf] Error 1

Originally I was using IAR so I think it is a completely different toolchain and no GCC compiler.

we use a linker script to be able to write into the bootloader memory but it looks very different to the linker scripts we are talking about.

lnk430f5529.xcl


-Z(CODE)INTVEC=FF80-FFFF
-Z(CODE)RESET=FFFE-FFFF
-Z(CODE)BSL=1000-17FF

But is it the one you use in the project?

You can also take another approach at this: Given your original compiling project, log all compiler commands (if it’s Makefile based it’s maybe make V=1.

Compare that to what PlatformIO is doing. You can inspect the exact compiler and linker invocations with the project task “Advanced → Verbose Build” , or pio run -v.

If there are missing build flags, add them via build_flags. If there flags which shouldn’t be there, remove them using build_unflags. If all compiler invocations match but you still get an error, it must be the toolchain version that’s at fault, so you need to choose a different one with platform_packages per link above.

Oh okay then the approach above doesn’t make a lot of sense except for macros. But that shouldn’t be the cause of the linker errors…

Yeah it is really a different world…

what about this memory map I can generate? I can see the far_rom memeory section. This I want to be able to access. It just doesn’t have any attributes like xr as the rom has…
Do you have any ideas on that?

Ah, I’m beginning to get a grasp on the problem.

First of all, I can use the above linker script you’ve posted by copying it as msp430f5529.ld in the project and using

[env:lpmsp430f5529]
platform = timsp430
board = lpmsp430f5529
board_upload.maximum_size = 131072 
build_flags = -Wl,-T"$PROJECT_DIR/msp430f5529.ld" -O0
debug_tool = mspdebug
build_unflags = -Os

(just using $PROJECT_DIR to directly refer to my project root directory).

Then, with that linker script, I however have to make a concious effort to put things in HIROM, by using GCC’s __attribute__((section("<section name>"))) for functions or variables that I want to place in HIROM, while respecting the names of sections as defined in the linker script of course. (The linker script also supports putting an entire compilation unit, e.g. abc.o object file, in the section, so that one doesn’t have to hand-annotate it… Sadly GCC doesn’t seem to support “auto-splitting” on demand here)

Consider this test code as main.cpp (C or C++ doesn’t really matter here)

#include <string.h>
#include <stdio.h>

/* https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variable-Attributes.html */
#define HIROM_FUNC __attribute__ ((section (".upper.text")))
#define HIROM_CONST_DATA __attribute__ ((section (".upper.rodata")))

/* create test function in HIROM */
int HIROM_FUNC my_function_in_hirom(int a, int b) {
	printf("Entry params: %d, %b\n", a, b);
	return a + b;
}

/* place constant in HIROM */ 
const int constant_in_hirom HIROM_CONST_DATA = 123;

extern "C" int putchar(int c) { 
	/* supposed to print to UART as support for function for printf().. just ignore*/ 
	return c; 
}

int main() {
	my_function_in_hirom(1,2);
	printf("Constant test: %d\n", constant_in_hirom);
	
	return 0;
}

Compiling this will result in the error.

.pio\build\lpmsp430f5529\src\main.o: In function main': main.cpp:(.init9+0xa): relocation truncated to fit: R_MSP430_16 against symbol my_function_in_hirom(int, int)’ defined in .upper.text section in .pio\build\lpmsp430f5529\src\main.o
collect2: ld returned 1 exit status
*** [.pio\build\lpmsp430f5529\firmware.elf] Error 1

The cause of this is the following: From the memory map it is clear that the ROM and HIROM are seperated memory regions. The calls / jumps in the code can only reach a certain distance in bytes. The function my_function_in_hirom is in HIROM, somewere “up there” but it’s calling the e.g. printf function which is in the lower ROM “down there”, and it can’t reach. For for e.g. very old Intel processors you would have to use the far keywoard to indicate that you’re jumping / calling to a function that is very “far” away, e.g. more than +/-16Kbyte.

See e.g. Issue Using Large Memory Model with new GCC for MSP430(X) in CCSv6 - Code Composer Studio forum - Code Composer Studio™︎ - TI E2E support forums.

However, for that, the compiler supports a “large memory model”, as shown in MSP430 Options (Using the GNU Compiler Collection (GCC)) with the -mlarge, 20-bit addressing mode, as opposed to -msmall, 16-bit addressing mode. The caveat here is however that doing

build_flags = -Wl,-T"$PROJECT_DIR/msp430f5529.ld" -O0 -mlarge

results in

cc1plus.exe: error: unrecognized command line option ‘-mlarge’

Which probably means that the compiler is too old, since it should work per documentation.

I’ll try and grab the newest toolchain I can find and retry with that – if that’s the cause that should be a major step forward.

thank you for pointing that out, I am still relatively new at PIO.

I remember in IAR we also needed to make the change from the 16bit data model to 20bit some time ago in order to be able to reach 0x10000.

I would love to hear on that. I read your post on that but will need some time to figure out how to actually do it.

HA! Success.

Should have read the freaking manual better.

What I’ve done:

  • replace the ancient 4.6.3 toolchain from GCC toolchain for MSP430 download | SourceForge.net by the one that superseeds it, created by TI, at MSP430-GCC-OPENSOURCE IDE, configuration, compiler or debugger | TI.com, which is at version 9.3.1 – a gigantic leap forward
  • fixup compiler tool names… the old toolchain had msp430-gcc, but the new toolchain names it msp430-elf-gcc… code here needs to be changed.
  • read the freaking manual to see that the user does not have to manually use another linker script or write the code differently to put things in low or highrom…
  • add -mlarge to both the build_flags (during compilation of c files to object files) and to the final linker command. Otherwise the linker will choose the small datamodel and say main.o uses the large data model whereas [..]/msp430-elf/lib/crt0.o uses the small data mode. Changing the linker flags has to be done in the main.py builder script file though…

And when I again use the code

#include <string.h>
#include <stdio.h>

/* https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variable-Attributes.html */
#define HIROM_FUNC __attribute__ ((section (".upper.text")))
#define HIROM_CONST_DATA __attribute__ ((section (".upper.rodata")))

/* create test function in HIROM */
int HIROM_FUNC my_function_in_hirom(int a, int b) {
	printf("Entry params: %d, %b\n", a, b);
	return a + b;
}

/* place constant in HIROM */ 
/* volatile only to turn off compiler optimizations */
volatile const int constant_in_hirom HIROM_CONST_DATA = 123;

int main() {
	my_function_in_hirom(1,2);
	printf("Constant test: %d\n", constant_in_hirom);
	
	return 0;
}

and compile it, the compilation log is

msp430-elf-g++ -o .pio\build\lpmsp430f5529\src\main.o -c -fno-exceptions -fno-threadsafe-statics -ffunction-sections -fdata-sections -mmcu=msp430f5529 -mlarge -DF_CPU=25000000L -DPLATFORMIO=50200 -DENERGIA_ARCH_MSP430 -DENERGIA_MSP_EXP430F5529LP -Iinclude -Isrc src\main.cpp
msp430-elf-gcc -o .pio\build\lpmsp430f5529\firmware.elf -mmcu=msp430f5529 -Wl,-gc-sections,-u,main -mlarge .pio\build\lpmsp430f5529\src\main.o -L.pio\build\lpmsp430f5529 -Wl,--start-group -lm -Wl,--end-group
MethodWrapper(["checkprogsize"], [".pio\build\lpmsp430f5529\firmware.elf"])
msp430-elf-objcopy -O ihex -R .eeprom .pio\build\lpmsp430f5529\firmware.elf .pio\build\lpmsp430f5529\firmware.hex
=========================== [SUCCESS] Took 2.19 seconds ===========================

So it can successfully use the large data model. I can also check that the functions and constants have been indeed placed in HIROM starting at 0x10000, by using nm to see the address of the symbols.

> C:\Users\Max\.platformio\packages\toolchain-timsp430\bin\msp430-elf-nm .\.pio\build\lpmsp430f5529\firmware.elf    
00010000 D constant_in_hirom
00010002 T _Z20my_function_in_hiromii

So the function and the constant really lives in HIROM now.

Of course I can also just leave the explicit placement out and let the compiler put stuff automatically in the required regions. They’ll be placed in low rom of course then since there’s still lots of space left.

Long story short: I’ll quickly publish the changes to the platform code, and then should just need to use a different

platform = <link to fixed platform repo>

and platform_packages for the newer compiler in the platformio.ini, and it should work.

Could you please check whether you can successfully compile and upload https://github.com/maxgerhardt/pio-timsp430-new-toolchain-example? A base example should be prepared there, attempting to place some functions into HIROM and printing their addresses via UART.

The platform code was altered so that no custom platformio.ini modifications are necessary anyore – the board has by default the full 128kByte and the compiler is set up for the large memory-model, with -mlarge -mcode-region=either -mdata-region=either.

Since I do not have a board, I cannot test it however – compiling works for me.

Wow Fantastic to hear that you managed to solve that. I will totally look into the example, please give me a couple of days for that. But I will give you feed-back! Did I understand right, if all that works, i will have to do is to use another platform within the .ini file and that’s it?