libmaple Unix Toolchain Quickstart

You'll need a Maple board, a mini-b USB cable, a functional computer, and possibly root access to that computer. This guide assumes you've had success with the IDE on your machine and that you are fairly comfortable with the unix command line. For generic installation/setup issues the install and troubleshooting pages may be helpful. If all else fails try google, our forum, or contact us directly!

These instructions are oriented towards Linux users using a contemporary debian-based distribution. It should be possible to get these development tools up and running on windows (using the cygwin Unix environment) or Mac OSX (using Xcode developer tools and/or macports), but we've already got our hands full supporting just the IDE on those platforms. If you're on another unix platform we're guessing that you can translate/port these directions on your own. As a jumping off point, you can find a stripped down distributions of the CodeSourcery GCC compiler tools for win32 and OSX 10.6 in the same download directory as the linux ones mentioned below. If you do have success on other platforms please post in the forums and we can fold your tips into this document!

1. Collect and Install Tools

First i'll give the commands to run, then explain:
sudo aptitude install build-essential git-core wget screen dfu-util \
openocd python python-serial 
You'll want to install a bunch of developer "basics" like make, tar, etc. A good catch-all for these tools is the "build-essential" meta-package on most debian platforms: installing this fake package will pull in dozens of useful tools without bogging your system down too much. git-core is the name of the git package; git is a distributed code versioning system we use to track changes in our source code. wget is a simple tool to download files over http from the command line and is optional (you could pull in the required downloads using a browser). screen is a really cool virtual terminal program; in the context of Maple we use it to connect to serial port devices.

dfu-util is a tool from the OpenMoko project that we use to upload programs to the Maple over USB.

openocd is a JTAG control program used in conjunction with an ARM JTAG device to do in circuit debugging (pause/resume program execution, upload and download code, read out register status, etc). (optional)

Lastly, our reset script (which sends control signals over the USB-serial connection to restart and enter the bootloader) is written in python and requires the PySerial library (the python-serial package; this could also be installed with easy_install).

2. Fetch libmaple and Compiler Toolchain

cd ~ 
git clone git://github.com/leaflabs/libmaple.git libmaple 
cd libmaple 
wget http://static.leaflabs.com/pub/codesourcery/\
arm-2009q3-68-arm-none-eabi-toolchain-linux32.tar.gz tar xvf arm-*.tar.gz
export PATH=$PATH:~/libmaple/arm/bin # or wherever these tools ended up 

Fairly straight forward... do a git clone of the libmaple repository to some directory, then download and extract the ARM compiler toolchain.

The arm/bin/ directory will needs to be added to PATH; you can check that this worked by entering arm-none- and hitting tab to auto-complete (bash should show a bunch of results). If you want to move that toolchain somewhere else and add it in a .bashrc script or whatever make sure to preserve the directory layout as the binaries will make relative path calls and references.

3. Install udev Rules

groups # make sure it includes plugdev; if not add yourself to it 
sudo cp support/scripts/45-maple.rules /etc/udev/rules.d/45-maple.rules 
sudo /etc/init.d/udev restart 

As a security precaution on linux, unknown USB devices can only be accessed by the superuser. This udev script identifies the Maple based on it's vendor and product IDs, mounts it to /dev/maple, and grants read/write permissions to the plugdev group. After restarting udev you'll need to fully unplug or power cycle any Maples connected to the computer.

4. Test compilation

cp main.cpp.example main.cpp
make clean 
make
Ok, here's where things start to get interesting, because our repository setup is a little unconventional. Usually libraries get compiled down to a binary archive which other programs link (or pull from) using hints from source code header files. With that structure the "library" code and build process is separated from the individual "program". At this point we frequently end up customizing the "library" part of the code to suit the "program", so we left it all mixed together.

The main.cpp file in the top directory is often the only "program" part of the code (of course it could reference arbitrary other source and header files if it helped break up a larger project). At a minimum it must declare an int main(void) function; our main.cpp.example files takes on a structure identical to Arduino "sketches" with setup() and loop() functions.

A second layer of confusion is the separation between the libmaple/ directory and the wirish/ directory. The libmaple/ directory contains our low-level, C-only library for accessing STM32 hardware peripherals. The wirish/ directory contains C++ code implementing the "Arduino programming language" (called Wiring); our implementation is not 100% compatible, it's just "Wiring-ish". When we casually refer to "libmaple" we usually mean both parts together. As you may imagine, mixing C and C++ code together so close to the metal can get pretty sticky; if you look through our code there are lots of #ifdefs and other nonsense to ensure the compiler doesn't throw up on it.

A last, important chunk of libmaple which isn't immediately obvious are the linker scripts in support/ld/ which are essential for actually building binary files. Hopefully you won't have to modify those unless you're porting the entire library, through it can be educational to read through the interrupt jump table.

The Makefile can build and upload to RAM or FLASH; the RAM target is useful for rapid development because it uploads a little faster and doesn't burn up FLASH write cycles, but programs in RAM won't persist after a power cycle and there is significantly less memory available for more elaborate programs. The target is determined by an environment variable, MAPLE_TARGET) which defaults to FLASH. It can be modified by editing the Makefile, specifying in the comman (eg, make MAPLE_TARGET=ram), or with the ram and flash targets, which modify the environment variable locally. The make sketch (or just make) target just builds .bin files; make install will build and upload the program. If you forget you can just make help, which dumps a table of targets. You might also find the make cscope or make ctags targets helpful as well if you use those tools.

If all goes well you should see an object size table dump something like:

find build -iname *.o | xargs arm-none-eabi-size -t
   text    data     bss     dec     hex filename
    482       4      24     510     1fe build/wirish/comm/HardwareSerial.o
    260       0       0     260     104 build/wirish/comm/HardwareSPI.o
     60       0       0      60      3c build/wirish/wirish.o

[...]

   2196       0       1    2197     895 build/libmaple/usb/usb_lib/usb_core.o
   1904       0       0    1904     770 build/libmaple/usb/usb_lib/usb_regs.o
     56       0       0      56      38 build/libmaple/usb/usb_lib/usb_init.o
    344       0       0     344     158 build/libmaple/usb/usb_hardware.o
   6637       0      58    6695    1a27 build/main.o
  21499     201     391   22091    564b (TOTALS)

Final Size:
arm-none-eabi-size build/maple.out
   text    data     bss     dec     hex filename
  21824     200     552   22576    5830 build/maple.out
Flash build
The "dec" field at the end gives the total program size in bytes. This program (the interactive test program, not main.cpp.example) is huge, about 22kb, and doesn't fit in to RAM, so I used the FLASH target. Of course the program could be easily optimized... but not today! The long listing of object files above the Final Size helps to identify bloated code; here you can see that our USB hardware management code and the main program itself are culprits.

5. Upload a Program

cp examples/test-session.cpp main.cpp 
make clean 
make
make install
Ok, let's blow away the little example program and upload the interactive test session. Before executing make install you'll want to have the udev rules setup as described above and have the Maple plugged in.

A number of things can go wrong at this stage; simple debugging steps include using the perpetual bootloader mode, restarting Maple a couple times, make-ing clean, etc.

6. Communicate over USB-serial interface

screen /dev/maple # control-A, k, y to quit 
If the interactive test program built and uploaded correctly, you should be able to connect with screen. Type 'h' or hit the space bar to get a response; there are a number of commands which demonstrate Maple peripheral features.

As of June 2010 the HardwareSerial library is blocking, so using any commands which would write to the USART Serial ports will cause the program to hang.

7. Debug with openocd

TODO. For now see this great guide from fun-tech.se.

8. Do it all with Code::Blocks

Code::Blocks is a generic cross platform IDE. We don't personally use it for development so we haven't worked out all the kinks (eg, debugging isn't intergrated), but it might be helpful for people who are allergic to vim and/or emacs. The simple configuration described here just calls down to the Makefile, so follow the above directions to get the command line tools configured (you'll definately need the arm-none-eabi-* tools on your path by default), then install Code::Blocks:
sudo aptitude install codeblocks 
The first time it runs you'll maybe want to disable all the glitzy "Getting started" crap (when will they learn?). We've added a .cbp "projects" file to the libmaple repository: you can try using that one by copying it from support/codeblocks/libmaple.cbp to the top level directory, but no promises (it might be missing new source files etc). It's probably worth reading through these instructions as well to get a feel for how it all works.

To create your own "libmaple" project, start with an "Empty Project" with the "Folder to create project in" set to your libmaple directory. Make sure that the "Resulting filename" is in the top level directory as well.

Select the "GNU GCC Compiler" (it won't be used anyways) and disable the "Debug" configuration in the next window. Now you should have a project with no files; add files by right clicking on the project in the left panel file heirarchy and "Add files recursively". Import both the wirish and libmaple directories recursively, then add main.cpp seperately.

Next we have to configure the Makefile targets. Go to the "Properties..." menu under "Project" and check the "This is a custom Makefile" box. Then go to the "Build tagets" tab and create "ram" and "flash" targets, both of type "Console application" and without the Auto-generated filename prefixes or extensions. Set the Output filename to support/codeblocks/program_flash.sh and support/codeblocks/program_ram.sh respectively; these scripts just call the program_ram/program_flash make targets and are a hack to get the "run" button to upload code to the Maple. The IDE will warn that these files will be overwritten, but they won't be. For both the "flash" and "ram" targets, click the "Build options..." button button (below "Virtual targets..." etc) and go to the far right tab ("'Make' commands"). Edit the Clean project/target line so it's just "clean" (not "clean$target"), and set the "Build project/target" and "Compile single file" commands to $make -f $makefile MAPLE_TARGET=$target and $make -f $makefile MAPLE_TARGET=$target $file respectively.

Save all these changes, go back to the main IDE window, and try to build/run. "Build" will compile everything, "Run" will run the upload script in a terminal window (if there are problems they will flash by very quickly; you can start Code::Blocks in a terminal window and check the output in that base window if necessary), and "Rebuild" will clean before rebuilding.


Success!

9. Go forth exuberantly!

Let us know what you come up with! Tag internet content with #leaflabs, post in the forums, track us down in the real world, whatever. We love projects!

About this Document

A more recent version of this document may be available from the LeafLabs website. Our documentation is versioned on github; you can track changes to the master branch at this link.

Creative Commons License
This documentation is released under a Creative Commons Attribution-Share Alike 3.0 license.

Translations are welcomed; give us a ping to make sure we aren't in the process of revising or editing first.