Christian's Blog

Linux, programming, hacking, electronics, Python… These are the things I love.

Getting Started with the TI Stellaris LaunchPad on Linux

STM32 microcontrollers are very nice and the STM32F0/ STM32VL/ STM32F3/ STM32F4/ STM32L- Discovery boards with the integrated debugger are well supported under Linux, in contrast to the LPCXpresso boards from NXP, so in principle there is no need to look further for other microcontrollers but I like trying new stuff and bought two cheep EK-LM4F120XL Stellaris LM4F120 LaunchPad Evaluation Boards for the promotional price of $4.99 each with free shipping from TI.

I’m planing to use them with some cheap nRF24L01 wireless modules from eBay, but this is the subject of another blog post.

First get a GCC cross compiler for ARM

Download the latest arm-none-eabi-gcc compiler from Launchpad:

Extract the tarball somewhere and add the compiler to the $PATH, e.g. edit your ~/.bashrc file and add a line like this:

export PATH=$PATH:$HOME/tools/gcc-arm-none-eabi-4_7-2013q1/bin

Install the lm4flash tool

[chris@thinkpad TI]$ git clone https://github.com/utzig/lm4tools.git
[chris@thinkpad TI]$ cd lm4tools/lm4flash/
[chris@thinkpad lm4flash]$ make
gcc -Wall -g -O2 -I/usr/include/libusb-1.0   lm4flash.c -L/lib64 -lusb-1.0   -o lm4flash
[chris@thinkpad lm4flash]$ sudo cp lm4flash /usr/bin/
[chris@thinkpad lm4flash]$

Build OpenOCD with ICDI support

Now we will build OpenOCD (the Open On-Chip Debugger) with ICDI (in-circuit debug interface) support to flash and debug the LaunchPad.

Since ICDI support has been merged into OpenOCD master branch we only need to enable it (--enable-ti-icdi) when configuring OpenOCD.

[chris@thinkpad ARM]$ git clone git://git.code.sf.net/p/openocd/code openocd.git
[chris@thinkpad ARM]$ cd openocd.git
[chris@thinkpad openocd.git]$ ./bootstrap
[chris@thinkpad openocd.git]$ ./configure --prefix=/usr --enable-maintainer-mode --enable-stlink --enable-ti-icdi
[chris@thinkpad openocd.git]$ make
[chris@thinkpad openocd.git]$ sudo make install

Compile and flash the demo project

Download StellarisWare for the Stellaris LM4F120 LaunchPad Evaluation Board (SW-EK-LM4F120XL) from TI:

After the login you should be able to download a file named SW-EK-LM4F120XL-9453.exe.

Now extract the files (including the demo project):

[chris@thinkpad ~]$ mkdir stuff/ARM/TI/StellarisWare
[chris@thinkpad ~]$ cd stuff/ARM/TI/StellarisWare
[chris@thinkpad StellarisWare]$ unzip ~/Downloads/SW-EK-LM4F120XL-9453.exe
Archive:  /home/chris/Downloads/SW-EK-LM4F120XL-9453.exe
  inflating: EULA.txt
  inflating: license.html
  inflating: makedefs
  inflating: Makefile
  inflating: manifest.html
...
[chris@thinkpad StellarisWare]$

Compile everything:

[chris@thinkpad StellarisWare]$ make
make[1]: Entering directory `/home/chris/stuff/ARM/TI/StellarisWare/driverlib'
make[2]: Entering directory `/home/chris/stuff/ARM/TI/StellarisWare/driverlib'
  CC    adc.c
  CC    can.c
...
  CC    ../../../utils/uartstdio.c
LD    gcc/capsense.axf
make[3]: Leaving directory `/home/chris/stuff/ARM/TI/StellarisWare/boards/ek-lm4f120xl-boost-capsense/capsense'
make[2]: Leaving directory `/home/chris/stuff/ARM/TI/StellarisWare/boards/ek-lm4f120xl-boost-capsense'
make[1]: Leaving directory `/home/chris/stuff/ARM/TI/StellarisWare/boards'
[chris@thinkpad StellarisWare]$

Note

As Leo Tindle has pointed out in the comments, the StellarisWare is also available on GitHub: https://github.com/yuvadm/stellaris.

[chris@thinkpad TI]$ git clone https://github.com/yuvadm/stellaris.git
[chris@thinkpad TI]$ cd stellaris/driverlib/
[chris@thinkpad driverlib]$ make clean
[chris@thinkpad driverlib]$ make
[chris@thinkpad driverlib]$ cd ../boards/ek-lm4f120xl/project0/
[chris@thinkpad project0]$ make
  CC    project0.c
  CC    startup_gcc.c
  LD    gcc/project0.axf
[chris@thinkpad project0]$

Add a new udev rule to let normal users access the LaunchPad and program it with OpenOCD:

[chris@thinkpad StellarisWare]$ sudo vim /etc/udev/rules.d/10-local.rules
[chris@thinkpad StellarisWare]$ cat /etc/udev/rules.d/10-local.rules
ATTR{idVendor}=="15ba", ATTR{idProduct}=="0004", GROUP="plugdev", MODE="0660" # Olimex Ltd. OpenOCD JTAG TINY
ATTR{idVendor}=="067b", ATTR{idProduct}=="2303", GROUP="plugdev", MODE="0660" # Prolific Technology, Inc. PL2303 Serial Port
ATTR{idVendor}=="10c4", ATTR{idProduct}=="ea60", GROUP="plugdev", MODE="0660" # USB Serial
ATTR{idVendor}=="1cbe", ATTR{idProduct}=="00fd", GROUP="plugdev", MODE="0660" # TI Stellaris Launchpad

[chris@thinkpad StellarisWare]$ sudo udevadm control --reload-rules

If it still does not work you can try this:

[chris@thinkpad StellarisWare]$ sudo groupadd plugdev
[chris@thinkpad StellarisWare]$ sudo usermod -aG plugdev chris #replace chris with your username
[chris@thinkpad StellarisWare]$ sudo usermod -aG dialout chris
[chris@thinkpad StellarisWare]$ sudo reboot

Modify the Makefile in StellarisWare/boards/ek-lm4f120xl/project0/ and add the flash rule (use a tabulator for indention like in the other make targets):

#
# The default rule, which causes the Project Zero Example to be built.
#
all: ${COMPILER}
all: ${COMPILER}/project0.axf

#
# The rule to flash the program to the chip.
#
flash:
  lm4flash gcc/project0.bin

Now you should be able to flash the board when running make flash:

[chris@thinkpad StellarisWare]$ cd boards/ek-lm4f120xl/project0/
[chris@thinkpad project0]$ make clean
[chris@thinkpad project0]$ make
  CC    project0.c
  CC    startup_gcc.c
  LD    gcc/project0.axf
[chris@thinkpad project0]$ make flash
lm4flash gcc/project0.bin
Found ICDI device with serial: 0E102397
ICDI version: 9270
[chris@thinkpad project0]$

Debug the example with Nemiver, OpenOCD and GDB

Make sure Nemiver is installed:

[chris@thinkpad project0]$ sudo yum install nemiver

Add another rule to the Makefile:

#
# The rule to rebuild the project and debug it with Nemiver.
#
debug: clean
debug: CFLAGS+=-g -D DEBUG
debug: ${COMPILER}
debug: ${COMPILER}/project0.axf
debug:
  ./debug_nemiver.sh

debug_nemiver.sh:

#!/bin/bash

# location of OpenOCD Board .cfg files
OPENOCD_BOARD_DIR=/usr/share/openocd/scripts/board

# start xterm with openocd in the background
xterm -e openocd -f $OPENOCD_BOARD_DIR/ek-lm4f120xl.cfg &

# save the PID of the background process
XTERM_PID=$!

# wait a bit to be sure the hardware is ready
sleep 2

# execute some initialisation commands via gdb
arm-none-eabi-gdb --batch --command=init.gdb gcc/project0.axf

# start the gdb gui
nemiver --remote=localhost:3333 --gdb-binary="$(which arm-none-eabi-gdb)" gcc/project0.axf

# close xterm when the user has exited nemiver
kill $XTERM_PID

init.gdb:

# Specify remote target
target extended-remote :3333

# Reset to known state
monitor reset halt
load
monitor reset init

# Set a breakpoint at main().
break main

# Run to the breakpoint.
continue

After this everything you have to do to start a new debug session is to run make debug:

[chris@thinkpad project0]$ make debug
  CC    project0.c
  CC    startup_gcc.c
  LD    gcc/project0.axf
./debug_nemiver.sh
0x00000000 in g_pfnVectors ()
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x000002bc msp: 0x20000100
Loading section .text, size 0x5e4 lma 0x0
Start address 0x2bd, load size 1508
Transfer rate: 6 KB/sec, 1508 bytes/write.
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x000002bc msp: 0x20000100
Breakpoint 1 at 0x26e: file project0.c, line 68.
Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, main () at project0.c:68
68          SysCtlClockSet(SYSCTL_SYSDIV_4|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|

Now you have an easy and fast way to debug your programs.

Running $ make debug

Running $ make debug

You may need to rebuild all libraries in debug mode to have debugging information available for library functions:

[chris@thinkpad project0]$ cd ../../../
[chris@thinkpad StellarisWare]$ make clean
make[1]: Entering directory `/home/chris/stuff/ARM/TI/StellarisWare/driverlib'
...
[chris@thinkpad StellarisWare]$ make DEBUG=1
make[1]: Entering directory `/home/chris/stuff/ARM/TI/StellarisWare/driverlib'
make[2]: Entering directory `/home/chris/stuff/ARM/TI/StellarisWare/driverlib'
  CC    adc.c
  CC    can.c
  CC    comp.c
  CC    cpu.c
...
  LD    gcc/project0.axf
../../../driverlib/gcc-cm4f/libdriver-cm4f.a(gpio.o): In function `GPIODirModeSet':
/home/chris/stuff/ARM/TI/StellarisWare/driverlib/gpio.c:288: undefined reference to `__error__'
...
make[3]: *** [gcc/project0.axf] Error 1
make[3]: Leaving directory `/home/chris/stuff/ARM/TI/StellarisWare/boards/ek-lm4f120xl/project0'
make[2]: *** [all] Error 2
make[2]: Leaving directory `/home/chris/stuff/ARM/TI/StellarisWare/boards/ek-lm4f120xl'
make[1]: *** [all] Error 2
make[1]: Leaving directory `/home/chris/stuff/ARM/TI/StellarisWare/boards'
make: *** [all] Error 2
[chris@thinkpad StellarisWare]$

Theoretical this should work, it is explicitly stated in StellarisWare/makedefs:

#
# Tell the compiler to include debugging information if the DEBUG environment
# variable is set.
#
ifdef DEBUG
CFLAGS+=-g -D DEBUG
endif

http://e2e.ti.com/support/microcontrollers/stellaris_arm_cortex-m3_microcontroller/f/471/t/44656.aspx:

The “undefined reference to __error__” problem you are seeing most likely indicates that you have a mismatch between debug and release versions of the DriverLib library you are linking and your application code. Alternatively, you may be using the ASSERT() macro without having defined the __error__() function in your application.

In a debug build (when you define label DEBUG either in your IDE or using “-DDEBUG” passed to your compiler), error checking code is included in DriverLib via the macro ASSERT(). This macro generates a call to function __error__ if the assert fails and it is expected that the application code will include this function. Typically, all it does is enter a while(1) to stop execution and allow you to debug the problem but you can also add other code there to dump status or provide other useful information.

To get rid of the problem, you have a couple of choiced. First, you can rebuild DriverLib without DEBUG defined then link this version to your application code (assuming you don’t use ASSERT() anywhere in the app). The other option, if you want to use the debug features, is to add a function to your application along the lines of the following:

#ifdef DEBUG
void __error__(char *pcFilename, unsigned long ulLine)
{
  //
  // Something horrible happened! You need to look
  // at file "pcFilename" at line "ulLine" to see
  // what error is being reported.
  //
  while(1)
  {
  }
}
#endif

After adding that function to project0.c compiling in debug mode is successful and debugging information is available for the underlying library functions:

Debugging project0 with Nemiver

Debugging project0 with Nemiver

Running GDB manually

First terminal:

[chris@thinkpad project0]$ make clean
[chris@thinkpad project0]$ make DEBUG=1
  CC    project0.c
  CC    startup_gcc.c
  LD    gcc/project0.axf
[chris@thinkpad project0]$ openocd -f /usr/share/openocd/scripts/board/ek-lm4f120xl.cfg
Open On-Chip Debugger 0.8.0-dev-00011-g70a2ffa (2013-05-16-18:50)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.sourceforge.net/doc/doxygen/bugs.html
Info : This adapter doesn't support configurable speed
Info : ICDI Firmware version: 9270
Info : lm4f120h5qr.cpu: hardware has 6 breakpoints, 4 watchpoints

Second terminal:

[chris@thinkpad project0]$ arm-none-eabi-gdb gcc/project0.axf
GNU gdb (GNU Tools for ARM Embedded Processors) 7.4.1.20130312-cvs
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
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=i686-linux-gnu --target=arm-none-eabi".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/chris/Projects/ARM/TI/stellaris.git/boards/ek-lm4f120xl/project0/gcc/project0.axf...done.
(gdb) target extended-remote :3333
Remote debugging using :3333
0x00000000 in g_pfnVectors ()
(gdb) monitor reset halt
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x00000af4 msp: 0x20000910
(gdb) load
Loading section .text, size 0x9f8 lma 0x0
Start address 0x2bd, load size 2552
Transfer rate: 7 KB/sec, 2552 bytes/write.
(gdb) monitor reset init
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x000002bc msp: 0x20000100
(gdb) monitor reset init
target state: halted
target halted due to debug-request, current mode: Thread
xPSR: 0x01000000 pc: 0x000002bc msp: 0x20000100
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/chris/Projects/ARM/TI/stellaris.git/boards/ek-lm4f120xl/project0/gcc/project0.axf

c^C0x00000876 in SysCtlDelay (ulCount=1763554, ulCount@entry=2000000) at sysctl.c:1856
1856        __asm("    subs    r0, #1\n"
(gdb) c
Continuing.
^C
Program received signal SIGINT, Interrupt.
SysCtlDelay (ulCount=13615, ulCount@entry=2000000) at sysctl.c:1856
1856        __asm("    subs    r0, #1\n"
(gdb) break project0.c:85
Breakpoint 1 at 0x282: file project0.c, line 85.
(gdb) c
Continuing.
Note: automatically using hardware breakpoints for read-only addresses.

Breakpoint 1, main () at project0.c:85
85              GPIOPinWrite(GPIO_PORTF_BASE, RED_LED|BLUE_LED|GREEN_LED, RED_LED);
(gdb)

Launchpad’s serial connection

The USART of the target processor is available through ICDI as /dev/ttyACM0, /dev/ttyACM2 or /dev/ttyACM3 under Linux.

[chris@thinkpad project0]$ cd ../qs-rgb/
[chris@thinkpad qs-rgb]$ make
make: Nothing to be done for `all'.
[chris@thinkpad qs-rgb]$ lm4flash gcc/qs-rgb.bin
Found ICDI device with serial: 0E102397
[chris@thinkpad qs-rgb]$ sudo screen /dev/ttyACM3 115200
Welcome to the Stellaris LM4F120 LaunchPad!
Type 'help' for a list of commands
> External or other reset
>
>help
help               : Display list of commands
hib                : Place system into hibernate mode
rand               : Start automatic color sequencing
intensity          : Adjust brightness 0 to 100 percent
rgb                : Adjust color 000000-FFFFFF HTML notation
>rgb 000EEE
>
[screen is terminating]
[chris@thinkpad qs-rgb]$

The bad stuff

Some of the example files from the StellarisWare have a really ugly license:

// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.

You know I mean the “viral” open-source part.

And TI please fix your website, lots of 404 links, just use such a “viral” open-source script to check all links.