A project log for Open-source microcontroller development

Random notes on how to set up and build for various microcontrollers using only open-source code.

Stuart LonglandStuart Longland 12/09/2018 at 08:430 Comments

TI's MSP430 is a 16-bit RISC microcontroller with a very low power consumption.  These things, when you yank the power on them, will sometimes often just run off the decoupling capacitors (particularly if it's a beefy electrolytic).

Unlike PIC and AVR, but like ARM, these are a Von-Neumann architecture, so there's only one data bus (no pgmspace.h, you don't need it).  Code which gets declared const, will typically be placed by the linker into the .rodata section of the binary, which will translate to Flash or FRAM.

The newer devices use FRAM for their program storage.  The claim by TI is that this offers near infinite write endurance and can be written to almost as quickly as SRAM.

This sounded interesting, it's been about 10 years since I last did anything with MSP430.  The turn off years ago was the need for the proprietary gdbproxy to do debugging of the target microcontroller.  Today, we have mspdebug, so I figured these chips were worth another look.  I needed to fill an order to one parts suppler for shipping purposes, so I threw in a MSP-EXP430FR2433 development board to have a play.

These can be had for under AU$15, and include a small "ezFET" programming interface which can be used with other Spy-by-wire compatible MSP430 microcontrollers.  Ironically, the chip that implements this is a MSP430F5528, which is a bigger and more capable chip than the MSP430FR2433.  Also on the ezFET side of the board is a MSP430G2452 which looks after the power rails.

Toolchain set-up

Years ago, the de-facto open-source toolchain for these chips was MSPGCC, which was on Sourceforge.  This was a third-party toolchain done by the community.  Today it appears TI officially support a port of GCC of their own.

Download links

You'll need three files from TI's website to get going:

To build, you'll also want this patch.

Installing mspdebug

On Gentoo, run emerge mspdebug.  On Debian, apt-get install mspdebug will get you going.

Compiling and installing

Daniel Beer provides these instructions which are clear enough I think. This is needed for the tilib driver in mspdebug.

Installing the compiler and support files

#  cd /opt
# mkdir msp430
# cd msp430
# 7z x /path/to/msp430-gcc-
# mkdir support
# unzip /path/to/

That should give you a compiler in /opt/msp430/msp430-gcc-, and support files (linker scripts and includes) in /opt/msp430/support.

A quick hello-world

For this I did the lazy thing and grabbed TI's sources for the standard firmware, which you can get here.  You have to sign up and promise not to sell them on to Iran or other places before they'll let you download them.

This will give you a ZIP file with sources for Code Composer Studio and IAR.  We just need a Makefile to use the CCS sources with gcc.

In the archive, go to the Firmware/Source/BlinkLED_MSP430FR2433 directory. Create a file called Makefile and insert the following:

CPPFLAGS=-Idriverlib/MSP430FR2xx_4xx -I/home/stuartl/projects/msp430/msp430-gcc-support-files/include
CFLAGS=-mmcu=msp430fr2433 -Os -g
LDFLAGS=-mmcu=msp430fr2433 -L/home/stuartl/projects/msp430/msp430-gcc-support-files/include

OBJECTS = main.o $(patsubst %.c,%.o,$(wildcard driverlib/MSP430FR2xx_4xx/*.c))

blinkled: $(OBJECTS)
	$(CC) $(LDFLAGS) -o $@ $^

	-rm -f blinkled $(OBJECTS)

Save this file, then run:

$ make CROSS_COMPILE=/opt/msp430/msp430-gcc-

All going well,  you should find it finishes with a file called blinkled, file will tell you it's an ELF binary for MSP430.  In a terminal, do the following:

$ mspdebug tilib --allow-fw-update
MSPDebug version 0.25 - debugging tool for MSP430 MCUs
Copyright (C) 2009-2017 Daniel Beer 
This is free software; see the source for copying conditions.  There is NO
Chip info database from MSP430.dll v3.13.0.601 Copyright (C) 2013 TI, Inc.

Using new (SLAC460L+) API
Found FET: ttyACM0
MSP430_Initialize: ttyACM0
FET firmware update is required.
Starting firmware update (this may take some time)...
Initializing bootloader...
Programming new firmware...
    16 percent done
   100 percent done
Initializing bootloader...
Programming new firmware...
    13 percent done
   100 percent done
Update complete
Done, finishing...
MSP430_VCC: 3000 mV
Device: MSP430FR2433 (id = 0x01c6)
3 breakpoints available
Chip ID data:
  ver_id:         8240
  ver_sub_id:     0000
  revision:       10
  fab:            55
  self:           5555
  config:         10
  fuses:          55
Device: MSP430FR2433 [FRAM]

Available commands:
    !               fill            power           setwatch_r      
    =               gdb             prog            setwatch_w      
    alias           help            read            simio           
    blow_jtag_fuse  hexout          regs            step            
    break           isearch         reset           sym             
    cgraph          load            run             verify          
    delbreak        load_raw        save_raw        verify_raw      
    dis             md              set             
    erase           mw              setbreak        
    exit            opt             setwatch        

Available options:
    color                       gdb_loop                    
    enable_bsl_access           gdbc_xfer_size              
    enable_fuse_blow            iradix                      
    enable_locked_flash_access  lowercase_dis               
    fet_block_size              quiet                       

Type "help " for more information.
Use the "opt" command ("help opt") to set options.
Press Ctrl+D to quit.

(mspdebug) load blinkled
(mspdebug) load /home/stuartl/projects/msp430/Firmware/Source/BlinkLED_MSP430FR2433/blinkled
Writing    2 bytes at fffe [section: __reset_vector]...
Writing  344 bytes at c400 [section: .rodata]...
Writing   80 bytes at c558 [section: .rodata2]...
Writing 4096 bytes at c5a8 [section: .text]...
Writing 4096 bytes at d5a8 [section: .text]...
Writing 3158 bytes at e5a8 [section: .text]...
Writing    2 bytes at f1fe [section: .data]...
Done, 11778 bytes total
(mspdebug) run
Running. Press Ctrl+C to interrupt...

Your code should now be running.  Note that after you've updated the firmware on the ezFET part of the board, doing so on subsequent runs should not be necessary.

Debugging on MSP430

The Spy-by-wire interface allows for single-stepping of the code on the microcontroller.  On AVR, the equivalent is DebugWire, and on ARM, JTAG and SWD implement this.

To start a debug server, hit Ctrl+C as instructed, then run gdb:

(mspdebug) gdb
Bound to port 2000. Now waiting for connection...

 Now, open up a new terminal… and run:

$ /opt/msp430/msp430-gcc- blinkled
GNU gdb (Mitto Systems Limited - msp430-gcc 8.1
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=msp430-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
Find the GDB manual and other documentation resources online at:
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from blinkled...(no debugging symbols found)...done.
(gdb) target extended-remote localhost:2000
Remote debugging using localhost:2000
0x0000c5a8 in __crt0_start ()

It has stopped right at the C library initialisation code.  Not useful, but you can type "continue" to begin execution, or numerous other commands, e.g.

0x0000c5a8 in __crt0_start ()
(gdb) break main
Breakpoint 1 at 0xc6bc: file main.c, line 59.
(gdb) c

Breakpoint 1, main () at main.c:59
59          WDT_A_hold(WDT_A_BASE);
(gdb) list
54      int main(void) {
56          volatile uint32_t i;
58          // Stop watchdog timer
59          WDT_A_hold(WDT_A_BASE);
61          // Set P1.0 to output direction
62          GPIO_setAsOutputPin(
63              GPIO_PORT_P1,
(gdb) s
WDT_A_hold (baseAddress=baseAddress@entry=460) at driverlib/MSP430FR2xx_4xx/wdt_a.c:56
56              ((HWREG16(baseAddress + OFS_WDTCTL) & 0x00FF) | WDTHOLD);
(gdb) s
55          uint8_t newWDTStatus =
(gdb) s
58          HWREG16(baseAddress + OFS_WDTCTL) = WDTPW + newWDTStatus;
(gdb) s
59      }
(gdb) bt
#0  WDT_A_hold (baseAddress=baseAddress@entry=460) at driverlib/MSP430FR2xx_4xx/wdt_a.c:59
#1  0x0000c6c4 in main () at main.c:59

You can now single-step your code and debug it.  Very handy, and often more flexible than printf-style debugging.  The microcontroller is just a puppet now with you pulling its strings via the gdb terminal.