Step 1 is just to make sure your LaunchPad works. With the original firmware on it, make sure it enumerates properly as both a mass-storage device, and a HID. Make sure pressing both buttons works as described on the TI page linked above. It's better to find out if your board works correctly now.
Once you have verified your LaunchPad functions, install mspgcc (and other required periphery):
# yum install msp430-gcc msp430-libc msp430mcu mspdebug dos2unix srecord
Now create a working directory to setup our Hello World project. Inside this directory, create a 'main.c' file and copy the Project0 source (shown below, with proper line break characters) into it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #include <msp430.h> unsigned int i = 0; // Initialize variables. This will keep count of how many cycles between LED toggles void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer. This line of code is needed at the beginning of most MSP430 projects. // This line of code turns off the watchdog timer, which can reset the device after a certain period of time. P1DIR |= 0x01; // P1DIR is a register that configures the direction (DIR) of a port pin as an output or an input. // To set a specific pin as output or input, we write a '1' or '0' on the appropriate bit of the register. // P1DIR = <pin7><pin6><pin5><pin4><pin3><pin2><pin1><pin0> // Since we want to blink the on-board red LED, we want to set the direction of Port 1, Pin 0 (P1.0) as an output // We do that by writing a 1 on the PIN0 bit of the P1DIR register // P1DIR = <pin7><pin6><pin5><pin4><pin3><pin2><pin1><pin0> // P1DIR = 0000 0001 // P1DIR = 0x01 <--this is the hexadecimal conversion of 0000 0001 for(;;) // This empty for-loop will cause the lines of code within to loop infinitely { P1OUT ^= 0x01; // Toggle P1.0 using exclusive-OR operation (^=) // P1OUT is another register which holds the status of the LED. // '1' specifies that it's ON or HIGH, while '0' specifies that it's OFF or LOW // Since our LED is tied to P1.0, we will toggle the 0 bit of the P1OUT register for(i=0; i < 20000; i++); //Delay between LED toggles. This for-loop will run until the condition is met. //In this case, it will loop until the variable i increments to 20000. } } |
Now, since we aren't animals, let's setup a basic Makefile (modified slightly from the one provided on the wiki):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | # # Makefile for msp430 # # 'make' builds everything # 'make clean' deletes everything except source files and Makefile # You need to set TARGET, MCU and SOURCES for your project. # TARGET is the name of the executable file to be produced # $(TARGET).elf $(TARGET).hex and $(TARGET).txt nad $(TARGET).map are all generated. # The TXT file is used for BSL loading, the ELF can be used for JTAG use # TARGET = project0 MCU = msp430f5529 # List all the source files here # eg if you have a source file foo.c then list it here SOURCES = main.c # Include are located in the Include directory INCLUDES = -IInclude # Add or subtract whatever MSPGCC flags you want. There are plenty more ####################################################################################### CFLAGS = -mmcu=$(MCU) -g -Os -Wall -Wunused $(INCLUDES) ASFLAGS = -mmcu=$(MCU) -x assembler-with-cpp -Wa,-gstabs LDFLAGS = -mmcu=$(MCU) -Wl,-Map=$(TARGET).map ######################################################################################## CC = msp430-gcc LD = msp430-ld AR = msp430-ar AS = msp430-gcc NM = msp430-nm OBJCOPY = msp430-objcopy RANLIB = msp430-ranlib STRIP = msp430-strip SIZE = msp430-size READELF = msp430-readelf MAKETXT = srec_cat CP = cp -p RM = rm -f MV = mv ######################################################################################## # the file which will include dependencies DEPEND = $(SOURCES:.c=.d) # all the object files OBJECTS = $(SOURCES:.c=.o) all: $(TARGET).elf $(TARGET).hex $(TARGET).txt $(TARGET).elf: $(OBJECTS) echo "Linking $@" $(CC) $(OBJECTS) $(LDFLAGS) $(LIBS) -o $@ echo echo ">>>> Size of Firmware <<<<" $(SIZE) $(TARGET).elf echo %.hex: %.elf $(OBJCOPY) -O ihex $< $@ %.txt: %.hex $(MAKETXT) -O $@ -TITXT $< -I unix2dos $(TARGET).txt # The above line is required for the DOS based TI BSL tool to be able to read the txt file generated from linux/unix systems. %.o: %.c echo "Compiling $<" $(CC) -c $(CFLAGS) -o $@ $< # rule for making assembler source listing, to see the code %.lst: %.c $(CC) -c $(ASFLAGS) -Wa,-anlhd $< > $@ # include the dependencies unless we're going to clean, then forget about them. ifneq ($(MAKECMDGOALS), clean) -include $(DEPEND) endif # dependencies file # includes also considered, since some of these are our own # (otherwise use -MM instead of -M) %.d: %.c echo "Generating dependencies $@ from $<" $(CC) -M ${CFLAGS} $< >$@ .SILENT: .PHONY: clean clean: -$(RM) $(OBJECTS) -$(RM) $(TARGET).* -$(RM) $(SOURCES:.c=.lst) -$(RM) $(DEPEND) |
Perform a make:
$ make Generating dependencies main.d from main.c Compiling main.c main.c:5:6: warning: return type of 'main' is not 'int' [-Wmain] Linking project0.elf >>>> Size of Firmware <<<< text data bss dec hex filename 218 0 4 222 de project0.elf unix2dos: converting file project0.txt to DOS format ...
Finally, let's write our newly created binary to the LaunchPad with mspdebug. This is by far the most convoluted part of the process.
The first issue is that mspdebug does not ship with the necessary shared library for the MSP-FET430UIF. I suspect due to licensing, but who knows, I just want to be able to program my LaunchPad. Luckily for us, TI provides what we need to be able to build the library. Make sure the following are installed before continuing:
# yum install gcc-c++ boost-devel hidapi-devel libusb-devel
Download the source provided by TI here. Extract the source somewhere and navigate to the directory. We need to create a couple of symlinks due to how TI chose to handle the hid library (if you aren't using a 64 bit Fedora install, adjust accordingly):
$ ln -s /usr/include/hidapi/hidapi.h ThirdParty/include $ ln -s /usr/lib64/libhidapi-libusb.so ThirdParty/lib/hid-libusb.o
Additionally, we need to modify 'EnergyTraceProcessorId7.h' to include 'cstdio'. Simply add '<cstdio>' to the include section of 'DLL430_v3/src/TI/DLL430/EnergyTrace_TSPA/EnergyTraceProcessorId7.h'.
Perform a make, if everything completed successfully, the result should be a 'libmsp430.so' shared library file that we need to get into the linker path. Since I don't recommend blindly copying files into the system library path, I recommend creating a 'lib' directory in your home directory, copying 'libmsp430.so' to it, and adding the following lines to your '.bash_profile':
LD_LIBRARY_PATH=$HOME/lib:$LD_LIBRARY_PATH export LD_LIBRARY_PATHAt this point, mspdebug should work as root, but I don't condone running it as root. The last step to getting mspdebug to work as a user is to set a udev rule. This is necessary due to how the JTAG is no longer accessed over a USB TTY like previous debuggers, but instead appears as a raw USB node. As root, create the file '/etc/udev/rules.d/69-ti-launchpad.rules' and add the following to it:
ATTRS{idVendor}=="0451", ATTRS{idProduct}=="f432", MODE="0660", GROUP="dialout"
Also add your user to the 'dialout' group:
# usermod -a -G dialout YOURUSERNAME
Reboot.
Open a new terminal and navigate to your working directory. Attempt to attach mspdebug:
$ mspdebug tilib
If you are lucky, you'll be given a debug prompt. If you aren't, you'll probably be prompted to a firmware update:
$ mspdebug tilib 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 FET firmware update is required. Re-run with --allow-fw-update to perform a firmware update. tilib: device initialization failedJust do what it says. Again, if you're lucky, you'll see:
$ mspdebug tilib --allow-fw-update 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 FET firmware update is required. Starting firmware update (this may take some time)... Initializing bootloader... Programming new firmware... 25 percent done 50 percent done 75 percent done 100 percent done 100 percent done Update complete Done, finishing... MSP430_VCC: 3000 mV MSP430_OpenDevice MSP430_GetFoundDevice
Device: MSP430F5529 (id = 0x0030) 8 breakpoints available MSP430_EEM_Init Chip ID data: 55 29 17
Available commands: = erase isearch power save_raw simio alias exit load prog set step break fill load_raw read setbreak sym cgraph gdb md regs setwatch verify delbreak help mw reset setwatch_r verify_raw dis hexout opt run setwatch_w Available options: color gdb_loop enable_bsl_access gdbc_xfer_size enable_locked_flash_access iradix fet_block_size quiet gdb_default_port
Type "help <topic>" for more information. Use the "opt" command ("help opt") to set options. Press Ctrl+D to quit. (mspdebug)
If you aren't, you won't. The most common error will be:
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 tilib: MSP430_Initialize: Interface Communication error (error = 35) tilib: device initialization failed
This is a bug. There is currently no fix that I can find. The solution is to simply unplug and replug the LaunchPad and try again (and again, and again...) until the update works.
Once you are finally connected to the JTAG, we can write our LED blinking Project0 to our board (you do remember that, right?):
(mspdebug) prog project0.hex Erasing... Programming... Writing 90 bytes at 4400... Writing 128 bytes at ff80... Done, 218 bytes total
Then run the program:
(mspdebug) run Running. Press Ctrl+C to interrupt...
"But wait!" I hear you exclaim. "Isn't the LED supposed to blink?" Oh, yeah. Let's examine our Makefile for a second (or, if you're hardcore, open the compiled binary in a hex editor). The "CFLAGS = -mmcu=$(MCU) -g -Os -Wall -Wunused $(INCLUDES)", contains "-Os" which tells GCC to optimize for size. This is usually a reasonable default for compiling for a micro, but in the case of cheesy demo applications like this one, it tends to break things. Specifically, the loop we are using for a delay ("for(i=0; i < 20000; i++);") gets optimized right out, so the LED gets turned on and off so fast we don't see it.
While we could turn off optimization for size, you are probably going to blindly copy this Makefile someday and wonder why your binaries are so huge. Instead, let's move our delay to a function, and tell GCC to not optimize it:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | #include <msp430.h> void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer. This line of code is needed at the beginning of most MSP430 projects. // This line of code turns off the watchdog timer, which can reset the device after a certain period of time. P1DIR |= 0x01; // P1DIR is a register that configures the direction (DIR) of a port pin as an output or an input. // To set a specific pin as output or input, we write a '1' or '0' on the appropriate bit of the register. // P1DIR = <pin7><pin6><pin5><pin4><pin3><pin2><pin1><pin0> // Since we want to blink the on-board red LED, we want to set the direction of Port 1, Pin 0 (P1.0) as an output // We do that by writing a 1 on the PIN0 bit of the P1DIR register // P1DIR = <pin7><pin6><pin5><pin4><pin3><pin2><pin1><pin0> // P1DIR = 0000 0001 // P1DIR = 0x01 <--this is the hexadecimal conversion of 0000 0001 for(;;) // This empty for-loop will cause the lines of code within to loop infinitely { P1OUT ^= 0x01; // Toggle P1.0 using exclusive-OR operation (^=) // P1OUT is another register which holds the status of the LED. // '1' specifies that it's ON or HIGH, while '0' specifies that it's OFF or LOW // Since our LED is tied to P1.0, we will toggle the 0 bit of the P1OUT register delay(); } } //Tell GCC to not optimize out the delay loop #pragma GCC push_options #pragma GCC optimize ("0") void delay(void) { unsigned int i = 0; //Delay between LED toggles. This for-loop will run until the condition is met. //In this case, it will loop until the variable i increments to 20000. for(i=0; i < 20000; i++); } #pragma GCC pop_options |
What we've done here is tell GCC to save whatever compile options are defined, do not optimize for the upcoming function, and when finished compiling the function, restore any compile options. Redo the make, reprogram, and watch the light blink!
This completes our Fedora 20 version of the 'Project0' tutorial. My next MSP430 article will discuss mspdebug in a bit more depth.
No comments:
Post a Comment