Bare-metal mbed Development
(Last modified 31 Dec 2011)

I've started tinkering with the NXP mbed device.  This $60 board has a strong community following, centered at mbed.org.  The toolset and inexpensive hardware let you start development on the Cortex-m3 device with very little up-front cost.

However, the compiler provided by NXP for writing your programs lives on the web ("in the cloud").  I much prefer using my own tools, residing on my desktop, for development.  So I set out to create a toolset I like that works in a Windows XP desktop.

Note that I am not the first person to try bare-metal development for ARM processors, by any means.  You can find plenty of sites devoted to ARM development, mbed development, bare-metal GCC tool chains, makefiles, and other essentials with some diligent searches.  I have borrowed heavily from others in my work here, including Martin Thomas' site and other sites reachable via the mbed.org link above.  My thanks to all who have shared their work to help others.


CodeSourcery
CodeSourcery G++ Lite is a gcc tool suite suitable for developing mbed projects.  You can download the full tool suite from Mentor Graphics.  Here is a link to the download page for the ARM EABI suite, which works with the mbed board: https://sourcery.mentor.com/sgpp/lite/arm/portal/release1802.  Since I'm using Windows XP, I chose the IA32 Windows Installer from the list of recommended packages.  Save this installer to a folder on your desktop, then double-click the installer to launch it.

Note that when you install, CodeSourcery will provide a default install folder; DO NOT use the default!  Provide a new install path that does NOT contain spaces in the path!  I used c:\CodeSourcery.  Immediately after the install finishes, use the Windows file explorer to open the install folder and rename the folder \Sourcery G++ Lite to \SourceryG++Lite, again, to eliminate spaces in the path to the various CS tools.  If you don't do these steps, you will have all kinds of issues later when you try to build one of your projects.


Microsoft's Visual Studio 2005
CodeSourcery provides the compler, linker, assembler, make utility (cs-make) and other common gcc tools, but does not provide an integrated development environment (IDE).  I first tried using AVR Studio4 as an IDE for developing my mbed projects.  I made it work, but didn't like the results.  The IDE didn't provide a smooth connection between the many source and header files I was using, which made it difficult to keep the flow of code in my head as I searched through the many folders involved.  After a while, I gave up on AVR Studio4 and tried my hand at integrating CS G++ Lite with Visual Studio 2005 (VS2005).

I'm certainly not a fan of MS, but I'll give them credit when due.  VS2005 and its later iterations are superb IDEs.  I have used them for years and always cringe when I have to use something else.  If you've never used VS2005, you are in for a treat when you switch over mbed development to this IDE.  The ability to right-click on a function name, for example, and immediately open up the associated file, with the text line defining that function right in front of you, is huge.  No trudging through all the files in your project (or in distantly associated folders, such as the CS include folders), trying to find some obscure macro definition.  Just right-click on the name, select Go to Definition, and you're there!

However, VS2005 was built to use Microsoft's compiler tools, not GCC's.  Below, I provide instructions on integrating most of the GCC tool suite into VS2005, but there are a few rough edges yet.  Note, however, that even with these rough edges and missing features, I consider the resulting IDE way beyond, for example, AVR Studio 4.


makefiles
Before I get to the instructions for setting up VS2005, I need to comment on the use of makefiles.  You will be creating your own makefiles as part of the development process.  Yes, makefiles are not the simplest tool in the box to use, but they are not all that hard to grasp and there are LOTS of tutorials on the web for using them.  Plus, I will provide you with some boilerplate makefiles suitable for mbed compiling.  But expect to learn some of the makefile basics if you want to do much bare-metal mbed development.


Integrating VS2005 with GCC
The following instructions work for VS2005.  I suspect they will work as well with later versions of VS, but I don't have those and can't confirm.

VS2005 wants to organize your work in a hierarchy.  At the bottom of the pyramid are the source and header files, along with other related files.  The next layer up contains projects, which are collections of files for a common purpose.  At the top of the pyramid are solutions, which are collections of projects that define a final executable you are trying to create.

This layout for your work is quite powerful.  It helps you divide up your code into manageable projects that are all available to you in VS2005's Solution Explorer.  The Solutions Explorer lets you select single projects for rebuild, so you can focus on that project, or select all projects (the entire solution) for rebuild as needed.

Note that you don't have to set up your work using the solution/project model.  You can certainly go with just a single project, putting all header and source files in a single folder, and I've done several projects just that way.  But at least go through the use of solutions so you know it is available later if you find the single-project model has limitations.

For my sample, I'm going to create a solution called blinky, since everyone blinks an LED as a first coding exercise.  blinky will consist of two separate projects.  The first project contains the start-up code that runs immediately after reset of the mbed device.  The second project contains the code for blinking an LED on the mbed board.

I'll begin by creating a project for the blinky source code.  Start by opening up VS2005.  You should see a blank page similar to this:

VS2005 startup

The Solution Explorer in the leftmost column is empty.  In the Recent Projects window, you can see some of my earlier work.

To create a new solution, select File/New/Project From Existing Code.  You will see a window like this:

New project from existing code

Leave the project type as Visual C++.  Click Next >.  You should see a window that allows you to select a project location and files to include.  I've filled out the window for the blinky solutions here:

blinky_spinloops project

I've called the project blinky_spinloops because I'm going to use spin-loops to control the blinkrate of the LED.  The source code for this project will live in the folder called out in the Project file location field you see here.  Note that I've unchecked the box marked Show all files in Solution Explorer.  If you don't uncheck this box, the Solution Explorer window can get pretty crowded.  I find it better to start with an empty view in the Solution Explorer, then add the files I want to access.

When you're all set up, click Next.  You should see a window that allows you to select the project's build settings.  Here, I've selected an external build system:

Settings for external build system

When you click Next > at this point, you should see a screen that allows you to set up the debug configuration.  VS2005 uses two main configurations for your projects and solutions.  The debug configuration is assumed to be one you will be debugging with and will likely have extra debug code and hooks built into it.  The other configuration, release, is intended for shipping code that has no debug hooks built in.  Here, I've set up my debug configuration by providing the name of the CodeSourcery tool used to execute a makefile.

Note that building the code later requires that the path to the cs-make.exe utility in CodeSourcery's /bin folder must be in your PATH environment variable!  If necessary, use the approriate tool in your control panel to add this path.

The debug configuration

After clicking Next >, you should see a window for setting up the release configuration.  This window by default uses the same setup information as the debug configuration.  Simply click Finish.

The release cofiguration

At this point, I have a solution named blinky_spinloops and an empty project named blinky_spinloops.  Time to add some source code.

Start by clicking File/New/File... and selecting the Text template.  This will get you an empty text file in the editor window.  Now use File/Save <textfile> As... to rename the file and save it into your blinky_spinloops folder as blinky_spinloops.c.  Here's what my editor page looks like now:

Empty C file

I've added the source code for the blinky_spinloops.c file to the editor window.  You can download the files for the blinky_spinloops project from the link at the bottom of this page.

Source for blinky_spinloops.c

At this point, I have the source for the LED blinker program, but I'm missing two important pieces.  First, I need the startup code, which takes control immediately after reset.  Second, I need a makefile to build all of this source into a final executable.

I already have a universal startup file, named startup_LPC17xx.s, that I use on all of my mbed projects.  This is an assembly language file, as denoted by its .s extension, that does only the most basic initialization of the MCU before handing off control to the main() function.  The startup file sets the stack pointer, zeroes out all declared variables, initializes all variables that require it, then jumps to main().  Additional initialization, such as setting up the PLL that controls the MCU's timing, is left to the main() function.  You can find the files for my startup_LPC17xx project in the link at the bottom of this page.

I could copy the startup source file into the same folder as my blinky_spinloops.c file.  Instead, I put the startup file and a few other common source files into a single folder called \object.  If I am working on a solution that requires the startup file (and they all will), I simply include the startup project in my solution.

To add an existing project to a solution you are developing, go into the Solution Explorer and right-click on the solution (the text and icon on the first line in the Solution Explorer window), then select Add and Existing Project....  Navigate to the folder holding the project file for the new project and select that project file; in this case, that would be the file startup_LPC17xx.vcproj in the folder C:\projects\mbed\object.  At this point, my blinky_spinloops solution looks like this:

Added startup_LPC17xx project

That takes care of the startup code.  Now I need the makefile.  Actually, I need two makefiles, one for the blinky_spinloops project and one for the startup_LPC17xx project.  This is because each project is built separately and each project is defined with its own makefile; refer to the above steps where I set up the debug and release configurations as I was creating the blinky_spinloops project.

I like to keep the makefile in a separate folder, named Others, within the project.  This folder holds any miscellaneous files for the project, such as the makefile, any listings, a map file if there is such, etc.  As you can see in the above image, the startup_LPC17xx project already has an Others folder where I've put its makefile.  To add an Others folder to the blinky_spinloops project, just right-click on the icon for the blinky_spinloops project (not solution!), then select Add and New Filter.  (I'm sure there is a good reason why this is called a filter and not a folder, but I don't know what that reason is.)  Enter a name for the filter of Others, then press Enter.

To place an existing file, such as the blinky_spinloops.mak file, into one of the folders within a project, right-click the appropriate folder, then select Add/Existing Item..., locate the file of interest, and select it.  Now you can open a folder and view the list of files from within the Solution Explorer.

Now I need to create the actual makefile.  I have a universal makefile for mbed development, so all I really need to do is create a new text file, copy the template into the text file, then rename the text file to blinky_spinloops.mak and add that file to the Others folder I just made.  I can then open the makefile, change a couple of lines so the makefile creates the blinky_spinloop binary file, and save the changes back.  Here is what the editor window looks like while viewing the updated makefile:

The blinky_spinloops makefile

Now all of the pieces are in place.  Assuming I have not yet built the startup project, building the entire blinky_spinloops project is a two-step process.  First, build startup_LPC17xx.o by right-clicking on the icon for the startup_LPC17xx project and selecting Project Only/Rebuild Only startup_LPC17xx.  Second, use the same actions to select and rebuild the blinky_spinloops project.

Here is the editor window following a successful rebuild of the blinky_spinloops project:

Successful build of blinky_spinloops



Limitations and issues
The above example barely scratches the surface of what you can do with VS2005 in support of mbed development.  For example, I haven't shown anything about how IntelliSense eases the editing and project management tasks for larger, multi-file projects.

But there are some limits in what you see here.  For example, if you get errors during a compile, you cannot just double-click on the error message and have VS2005 take you directly to the offending line.  That should be working, but I don't have it correct yet.

Another limitation in this setup is the dependency on makefiles.  I've tried to keep my makefiles as simple and generic as possible, but such makefiles won't work in all cases and you will have to be strong enough with makefiles to find and fix any issues.

Speaking of dependencies, VS2005 allows you to alter build order based on projects depending on other projects building first.  This can become an issue when working with multi-project solutions and is handled gracefully by VS2005 when working with the VS compilers.  However, the dependency feature doesn't work very well in the setup I show here, because the makefile for a dependent project is fired off inside the directory for the higher-level project.  This means the object file for the dependent project is written to the root folder for the higher-level project and is now outside of the link path when the final executable is linked.  I might be able to fix this with modified makefiles, or there might be a simple method inside VS2005 that I've overlooked.  For now, I am careful to rebuild each project when it is changed, then build the final project (blinky_spinloops, in this case) only after all underlying projects have been rebuilt.  This is more error-prone than I like, so I'll try and come up with a fix.


The executable
The point of the entire exercise above was to get a bare-metal LED blinker running.  The final executable, blinky_spinloops.bin, weighs in at 792 bytes and works like a charm.  I just copy it into the MBED USB drive, reset the mbed device, and watch the light blink.


The files
Here is a zip file of the source and make files for this project.

NOTE:  There was an error in the PLL setup code in the original version of these files (30 Dec 11).  If you grabbed that set, please reload!

You will need to go through the steps I've outlined above to create your own VS2005 solution for this project.  Be sure you have the path to cs-make.exe (in the CodeSourcery /bin folder) in your PATH environment variable!  I've tried to add comments to my makefiles to help you understand how things are set up and where you might need to make changes to match your own system.

Note that the files blinky_spinloops.c and start_LPC17xx.s provide a working example of setting up a bare-metal mbed project from the moment following reset through system setup to blinking an LED.  This makes a great example for how to design your own bare-metal apps.

One of the files in the collection is the linker script, used in the blinky_spinloops makefile to place the final executable code in the MCU's memory.  This linker script, LPC17xx.ld, lives in the folder c:\projects\mbed\linker in my system.  You can see how the path to this script is set up in the makefile by locating the variable LSCRIPT.

OK, that's a wrap.  This has been a large page and I appreciate you taking the time to wade through all of this.  If you have questions or (even better) ways to improve what I have here, please drop me an email.



Home