Saturday, July 12, 2014

MSP430F5529 LaunchPad 'Project0.2' - GDB on Fedora 20

When I initially promised "more depth" on mspdebug, I honestly believed it would be more user friendly. But frankly, the more I played with it, the less I wanted to use it as a debugger. Fortunately, it can function as a bridge to GDB which is a much more pleasant debugger to work with. Getting mspdebug to play well with GDB was not straightforward, but I'm pleased to say I have a solution that works.




Issue number one was actually installing a version of GDB that supports the msp430 target. The GDB version already packaged for Fedora doesn't (why would it?), and the msp430 binutils package doesn't include a version either (someone please prove me wrong in the comments below). Fortunately, a package was made, but for Fedora 14. Taking the source RPM from that project, updating the patches to the latest provided by the mspgcc project, resulted in my own project for compiling GDB 7.2a (the latest supported by mspgcc) on Fedora 20.

Luckily for you all, I've setup a copr repository so you don't have to worry about any of that. First, as root, setup a repo file for the repository:

# cd /etc/yum.repos.d 
# wget https://copr.fedoraproject.org/coprs/nielsenb/gdb-msp430-fedora/repo/fedora-20-i386/nielsenb-gdb-msp430-fedora-fedora-20-i386.repo

If you don't have wget (how do you live?), install it 'yum install wget' (or use curl).

I'm aware the repo has i386 in the file name, but I assure you x86 and x86_64 packages are provided.

Install msp430-gdb by typing 'yum install msp430-gdb'. At this point, we're done running things as root.

From here on out, any guide on using GDB with mspdebug is adequate. This one in particular is well done. Let's go through some basics anyway. Navigate to the directory where you did 'Project0.1' and start up mspdebug in gdb bridge mode:

$ mspdebug tilib gdb
MSPDebug version 0.22 - debugging tool for MSP430 MCUs
Copyright (C) 2009-2013 Daniel Beer <dlbeer@gmail.com>
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

MSP430_GetNumberOfUsbIfs
MSP430_GetNameOfUsbIf
Found FET: ttyACM0
MSP430_Initialize: ttyACM0
Firmware version is 30301004
MSP430_VCC: 3000 mV
MSP430_OpenDevice
MSP430_GetFoundDevice
Device: MSP430F5529 (id = 0x0030)
8 breakpoints available
MSP430_EEM_Init
Chip ID data: 55 29 17
Bound to port 2000. Now waiting for connection... 

In a separate terminal (navigate to the project directory so you can tab complete file names), connect to the bridge using our install of msp430-gdb:

$ msp430-gdb
GNU gdb (GDB) 7.2
Copyright (C) 2010 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=x86_64-unknown-linux-gnu --target=msp430".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
(gdb) target remote localhost:2000
Remote debugging using localhost:2000
0x00004400 in ?? ()

Note that, after GDB starts, we're given a GDB prompt '(gdb)', which we use to connect to our mspdebug bridge. Once that is successful, we'll be returned to the (gdb) prompt, which we can then use for our debugging. Let's use GDB to load our example program:

(gdb) file project0.elf 
A program is being debugged already.
Are you sure you want to change the file? (y or n) y
Reading symbols from /home/nielsenb/msp430/project0.1/project0.elf...done.
(gdb) load project0.elf 
Loading section .text, size 0x8a lma 0x4400
Loading section .vectors, size 0x80 lma 0xff80
Start address 0x4400, load size 266
Transfer rate: 395 bytes/sec, 133 bytes/write.
(gdb) continue
Continuing.

The 'file' command tells GDB the binary we're working with, if another file is already running on the LaunchPad, you'll be notified. Answer 'y' to continue. We then write the binary to our LaunchPad using 'load', and run the program with 'continue'.

At this point, GDB probably just seems like a more inconvenient mspdebug, let's use it to do some rudimentary debugging. First, stop executation with <ctrl>-<c>, you should be given your (gdb) prompt back. Now:

^C
Program received signal SIGTRAP, Trace/breakpoint trap.
0x00004476 in delay (delayCounts=20000) at delay.c:11
11        for(i=0; i < delayCounts; i++);
(gdb) break delay.c:7
Breakpoint 1 at 0x446c: file delay.c, line 7.
(gdb) continue
Continuing.
 
Breakpoint 1, delay (delayCounts=20000) at delay.c:7
7        uint16_t i = 0;

What we did was set a breakpoint at the specified line, continued, and then execution halted at the breakpoint we set, returning us our (gdb) prompt. From here, we can continue, or look around at program state:

(gdb) info variables
All defined variables:

Non-debugging symbols:
0x00002400  __wdt_clear_value
(gdb) info args
delayCounts = 20000
(gdb) info locals
i = 20000

First, we printed all defined global variables, you'll notice there really aren't any in this case. Next, we printed args, and you'll see delay (the function we're inside of) was called with delayCounts set to 20000. Finally, we printed local variables. You'll see i is currently 20000, despite the fact we haven't entered the loop yet. This is because it isn't cleared between calls. Let's clear our breakpoint, and set a new one at loop initialization:

(gdb) clear delay.c:7
Deleted breakpoint 1 
(gdb) break delay.c:11
Breakpoint 2 at 0x4470: file delay.c, line 11.
(gdb) c
Continuing.

Breakpoint 2, delay (delayCounts=20000) at delay.c:11
11        for(i=0; i < delayCounts; i++);
(gdb) info locals
i = 0

We're getting a little advanced here, using 'c' instead of 'continue' (you can also use 'i' instead of 'info', 'b' instead of 'break', if you feel so inclined most of the common abbreviations are on this reference card [caution, PDF link]). Notice i is now set to 0, as we would expect.

Alternatively, you can list and clear breakpoints with 'info' and 'del':

(gdb) i break
Num     Type           Disp Enb Address    What
2       breakpoint     keep y   0x00004470 in delay at delay.c:11
    breakpoint already hit 2 times
(gdb) del 2

Simply use 'del' and the number of the breakpoint you wish to delete (note, I had hit my breakpoint twice since I had continued once not shown here).

One other thing you may occasionally find useful is dumping register values:

(gdb) i registers
pc/r0: 4470  sp/r1: 43f8  sr/r2: 0001     r3: 0000  
fp/r4: 43fe     r5: 5a0c     r6: 7ebe     r7: 7ebe  
   r8: ffff     r9: ffff    r10: ffff    r11: ffff  
  r12: 0000    r13: 0002    r14: 0182    r15: 4e20

That is pretty much the limit of what we can do with our toy program. You can quit GDB (or play around more if you wish):

(gdb) quit
A debugging session is active.

    Inferior 1 [Remote target] will be killed.

Quit anyway? (y or n) y

This will return you to your command prompt, you'll notice in your other terminal that mspdebug took it upon itself to restart the program (with breakpoints cleared) on the LaunchPad and quit.

If you want to learn more, the GDB manual applies just as much to msp430 targets as anything else. If you've followed these tutorials, you should have mspgcc, mspdebug, and msp430-gdb all working, and should be able to point Eclipse (or any other IDE of your choosing) at them without much heartache. Good luck!

No comments:

Post a Comment