LPCXpresso “Hello, World” and Breadboard LED Blinking

Written by Jay Carlson

20131003-2347

NXP has a collection of low-cost development boards — their LPCXpresso line — that are great for getting into ARM development. As I mentioned in my previous post, the LPCXpresso is a development board that consists of various NXP target processors (depending on the actual board you get), as well as an LPC-Link debugger. What’s unique about the LPCXpresso board is that you can actually cut the board apart, separating the LPC-Link from the target, and allowing you to debug projects on custom boards — or as we’ll see in a minute, solderless breadboards.

Development hardware is worthless without good quality software, and NXP’s Code Red Suite has you covered. The free version (which only works with NXP MCUs) is code-size-limited, but it’s a very generous 256 KB download limit. Most beginners would be hard-pressed to reach that limit (and there are only a handful of MCUs out there that even have that much capacity).

Part I: Hello, World

To get started, you’ll need an LPCXpresso board. There are several to choose from, and for our purposes, any of them will work. For what it’s worth, I’ll be using an old LPC1343 board (which I don’t think they even make anymore).

Let’s start by downloading LPCXpresso. As you can see, LPCXpresso supports Windows, OS X, and Linux. Although I usually do development on my Windows desktop, I’ll be doing this project on my MacBook Air running OS X, just for fun. However, there is absolutely zero difference between the versions — they use exactly the same interface and compiler toolchain.

As soon as you install it, you’ll want to activate a free license — this requires a free NXP account. This option is under the Help menu. Once you register, NXP’s web page will toss an activation key at you, which you’ll enter (again, under the Help menu). Restart the program, and you’ll be looking at this screen shot:

Screen Shot 2013-10-03 at 3.39.32 PM

Now, let’s create a new project. First, we’ll import the CMSIS library into the workspace. This is obviously an Eclipse-based IDE, which supports multiple projects in the same workspace. NXP’s recommended way of separating an application from library code is to keep the library code in a separate, reusable project. Not a bad idea. CMSIS, by the way, provides a standard interface to the ARM Cortex CPU (and, optionally, to the MCU’s peripherals). We need the CMSIS core library to provide the system’s initialization code (trust me, you don’t want to write that stuff by hand). Start by clicking Import project(s) on the Quick Tasks list in the bottom-left pane. Specify the CMSIS_CORE_latest.zip file in the Examples folder (this ZIP archive actually contains several projects, as you’ll see):

CMSIS_core

Now, you’ll need to choose the project that matches the MCU on your LPCXpresso board. For me, that’s an LPC1343 (so I’ll select LPC13xx), but yours will probably be different.

LPCXpresso_CMSIS_chooseproject

Continue through the wizard, accepting defaults (when they seem reasonable). All finished!

LPCXpresso_CMSIS_imported

Now, let’s create a new Hello, World! project that references this library. You may think it’s a little strange to do “Hello, World” on a MCU — usually blinking an LED is the first step (as it’s typically more trivial to do). However, ARM Cortex MCUs have built-in debug printing using the debugger connection. Basically, when the MCU wants to send a character, it will trigger the debugger which will read the character and send it to the computer. This output pops up in the Eclipse console. All you have to do is call printf, just like you would in a C project running on your computer. To do this, we’ll need to make use of the Semihosting library — that will be important to specify in the next step.1

Click New project…, and select your CPU family, then choose C Project (Semihosted).

LPCXpresso_newproject_semihosted

Next, name the project something, select your CPU, and finish the wizard. Make sure you select the CMSIS Core library you imported. Don’t choose a CMSIS DSP library. I disabled CRP (code read protect), but left all other options to their defaults.

If you open up main.c in your new project, you should see this:

LPCXpresso_helloworld_c

First, build the project by clicking the hammer button (6 from the top-left). Watch the console’s output as the project is built, making sure there are no errors. Then click the debug button (the green bug that’s 13 icons from the top-left). NB: This is a different debug button than the normal Eclipse Debug Configurations button that’s on the right side of the screen. Don’t hit that button unless you want to set-up custom debug configurations. You should see a window pop-up asking you to select your LPC-Link:

LPCXpresso_LPCLink

Once selected, your code should promptly load on the target, and Eclipse will switch to a debug perspective, and break at the first instruction in main():

LPCXpresso_helloworld_debug

Notice that the Console below the screen is empty. Hit the “Run” button (keyboard shortcut: F5), or step over the function, and you’ll see “Hello, World” printed in the console:

LPCXpresso Hello World print

Not bad, eh?

 Part II: Breadboarded “Hello, World”

At this point, as an electrical engineer, I’m bored. I want to tear stuff apart, solder things, breadboard circuits, and make something blink. I’m not satisfied with printing “hello, world” from some circuit board someone else designed.

So, let’s go do it!

Sure — we could write some code to blink the on-board LED. But that’s no fun. And as I mentioned before, one thing I love about the LPCXpresso boards is that the LPC-Link debugger snaps apart from the target, enabling you to debug code running on custom boards. Since the interface the LPCXpresso boards use is just a single row of 0.1″ headers, we can easily hook the LPC-Link up to a breadboard.

And with their LPC1114FN28, NXP happens to be the only manufacturer who makes an ARM chip in a DIP package. Let’s breadboard!

I started by cutting the LPCXpresso board apart using some tin snips, but it’s probably better to score it with a razor blade and snap it. Be careful not to harm yourself or your LPCXpresso!

20131003-2352

Once that’s done, solder a row of headers on the board, and breadboard it up with the target MCU. I consulted the LPCXpresso schematics for my board, but the target pinout should be the same on all boards. The pinout is:

Pin Signal Description
1 VIO_3V3 Provides 3.3V to the target. Hook this up to VDD
2 SWDIO/TMS In SWD mode: SWDIO; in JTAG mode: TMS
3 SWCLK/TCLK In SWD mode: SWCLK; in JTAG mode: TCLK
4 SWO/TDO In SWD mode: SWO; in JTAG:TDO
5 TDI In JTAG mode: TDI. Unused in SWD mode.
6 RESET Reset pin
7 EXT_POW Undocumented — and doesn't appear to be hooked up on the target
8 GND Ground connection

By the way, if you didn’t already know this, the square pin indicates pin 1, so start from that side and work your way down.2

Since we’ll be debugging the LPC1114 using SWD mode (which is generally the case with all Cortex ARM microcontrollers), we’ll only need to connect power, ground, SWDIO, SWCLK, and RESET. Connect these signals to the MCU according to its datasheet. Here’s the pinout, for your reference:

LPC1114FN28

NB: For debugging, you don’t need to pull-up the reset pin to VDD, you can just run it straight into the LPC-Link. However, your project will only run when you’re doing a debug session. It’s usually best practice to always pull-up RESET, unless it is internally pulled-up inside the MCU. This will allow your project to run, even if it’s not connected to the debugger.

You should have something that looks like this:3

LPC1114FN28 breadboard

I decoupled the supply rails with some 100n capacitors because I’m fancy like that — but your project will probably run fine without those caps (so don’t fret if you don’t have any!)

Now, create a new project following the same procedure, but this time, target the LPC1114. When you start debugging, you’ll notice the processor never gets to the main function, and “Hello, World” doesn’t get printed. What’s going on? Let’s find out. Hit the “Break” button to break into the spot where the processor is. You should see this:

LPC1114 hanging

As you can see, we’re waiting for a PLL to stabilize. This should usually take about 1/100000000000000th of a second4, so obviously something’s wrong. If you’ve worked with MCUs as much as I have, you’ll immediately know that you probably screwed up the oscillator source. So, how do we check (and change) the oscillator source? Just edit your system_LPC11xx.c file!

Screen Shot 2013-10-04 at 2.46.21 AM

Ewww, that’s really nasty. Fortunately, all CMSIS system files were designed to be parsable by a GUI editor (built-in to Keil UVision). Luckily, there’s a free CMSIS Configurator Java app that you can use to read and modify this atrocious-looking C file. Just load it into the program, and go to Clock Configuration > System Clock Setup and look at the PLL input clock. As you can see, it’s defaulting to an external crystal oscillator. But we’re lazy — we want to use the internal one (even though it’s crappy). So change PLL input clock to IRC Oscillator (that’s code for the internal 12 MHz 1% trimmed RC oscillator). Like this:

CMSIS Configurator

Now, save the file, go back to LPCXpresso, and recompile the project. Debug it, and you should see “Hello, World” in the console once you free-run the project. Bam.

Part III: Breadboarded LED blinking

Now, let’s hook up an LED to our little man and see if we can get it blinking. While this is trivial to do on Arduino (which automagically includes the peripheral libraries for you), it takes a bit of configuring to do the same in LPCXpresso. Like everything in programming, there’s the easy way, and then there’s the right way. We could go ahead and start writing straight register calls to the GPIO peripheral, and sit in a while() loop executing NOP instructions — that would certainly get the job done. But let’s do it the right way. There’s basically three things that we need to do:

  1. Import the NXP peripheral library into our project — this will give us high-level GPIO functions so we won’t have to concern ourselves with direct register writes.
  2. Create a delay function using the SysTick timer
  3. Tie everything together in a main function.

Peripheral Library

In LPCXpresso, import the “common” project stored in the NXP_LPCXpresso1114-301 package:

LPCXpresso peripherallibrarypackage

In the workspace, you’ll see a folder named “driver” inside this new project. Move (or copy) this folder into your Hello, World LPC1114 project.

To avoid having a bunch of crap get compiled into your object code, NXP uses #ifdefs to only include peripheral library code that you actually need. It expects a file named driver_config.h to be inside the driver folder, which contains definitions for which peripherals you want to have access to. Go ahead and create this driver_config.h file inside your project’s “driver” folder. In it, put:

#include "LPC11xx.h" // This is important!
#define CONFIG_ENABLE_DRIVER_GPIO		1

This file gets included by every peripheral module automatically, so this allows the modules to get access to the proper register settings (which are stored in the LPC11xx.h file), as well as figure out if they should be activated or not (that’s what the #define is for).

Alright, now include this file (driver_config.h), as well as gpio.h in your main file. It’s important that you include driver_config.h first, since gpio.h needs the CONFIG_ENABLE_DRIVER_GPIO #define to be set.

Let’s go ahead and create the skeleton of our main file. Something like this:

int main(void)
{
    Init();
    printf("Hello World\n");
    while(1) {
        LED_On();
        Delay(1000);
        LED_Off();
        Delay(1000);
    }
    return 0 ;
}

Now, we need to implement Init(), LED_On(), LED_Off(), and Delay(). I’ll be using P0.1 (PORT0, pin 1) for the LED. Let’s go ahead and implement the LED functions first:

void Init(void)
{
    GPIOInit();
    GPIOSetDir(PORT0, 1, 1);
}

void LED_On(void)
{
    GPIOSetValue(PORT0,1,0);
}

void LED_Off(void)
{
    GPIOSetValue(PORT0,1,1);
}

Note that I’ve got the MCU wired to sink, not source, the LED current — so if I want the LED on, I set the pin to 0, and if I want the LED off, I set the pin to 1.

SysTick Delays

Now, we need to implement Delay. We’ll implement it using SysTick, which is a built-in timer/interrupt that’s part of CMSIS Core. All we have to do is tell it how often we want the tick event to happen, then we’ll define our handler for that interrupt. To do delays, we’ll keep track of a global “tick” counter.

So, start with a global msTicks variable:

volatile uint32_t msTicks;

And then define the SysTick_Handler() function:

void SysTick_Handler (void)
{
    msTicks++;
}

Unlike most 8-bit MCUs which require you to place weird #pragmas or other proprietary decorations around interrupts, CMSIS allows you to define the function without any fanfare. The interrupt vector table has a built-in definition for SysTick_Handler(), plus an empty definition declared  ”weak.” That way, your project will compile even if you don’t explicitly define every interrupt function — which there are a ton of!

Now, we need to implement the actual delay function. We’ll get the current time, then wait in a while loop until enough time has passed:

static void Delay (uint32_t dlyTicks)
{
    uint32_t curTicks;
    curTicks = msTicks;
    while((msTicks - curTicks) < dlyTicks); // wait here...
}

One more thing: we need to call SysTick_Config() to specify the period of the timer and to actually start it. You can call this function once in the Init() function if you’d like — the only thing you have to be careful of is timer overflows; if the millisecond tick variable overflows to zero during a delay, the delay will hang for a long time. We’re using 32-bit unsigned variables, so the msTicks variable will overflow every 4,294,967,295 milliseconds, which is 1194 hours (about 50 days). So, if you left this on for 50 days, it’d stop working. A simple hack to overcome this overflow condition is to simply re-initialize the SysTick clock every time we call Delay(). So, instead of putting this in the init function, add this into the top of the Delay function:

SysTick_Config(48000000/1000); // we're operating at 48 MHz

Finishing Up / Fun with Toolchains

If you’ve tried to compile the project thus far, you’ll notice that LPCXpresso is freaking out about all sorts of stuff. The problem is our peripheral driver library is in a folder that our compiler isn’t compiling or including. We need to change all three of those. Right-click on the project and go to Properties. We’ll be able to change everything we need to in this view. First, add the “driver” folder as a Source Location under C/C++ General > Paths and Symbols:

Screen Shot 2013-10-03 at 8.55.45 PMNow, add the driver folder to the compiler’s include path:

Screen Shot 2013-10-04 at 2.10.33 AMYou should be good to go now. Run the program, and observe the blinking LED magic!5

LPC1114 blinking LED

Troubleshooting

Hardware

If LPCXpresso can’t find the target, make sure it’s installed properly using Device Manager or whatever tool your OS has to view and inspect devices. Obviously, if your OS can’t see it or assign a driver to it, LPCXpresso certainly won’t be able to use it. If the software is complaining about being unable to detect a target device, that means your SWD connection to your MCU is bad, or your MCU doesn’t have power. I didn’t need to use a pull-up resistor on the reset pin (I think it’s internally pulled up), but that’s a usual culprit, too.

Software

It’s easy to screw this stuff up, so make sure you understand error messages that are printed in the console. Always start by seeing which part of the toolchain is complaining — is it a compiler error, or a linking error? If a compiler is complaining about a missing include file, the usual culprit is a misspelled header file or referencing a header file in a location not in the include paths. Unfortunately, LPCXpresso is not recursive — so although you can organize all of your code into neat little folders, you’ll have to manually add all of them to the include path.

Linker problems can be harder to diagnose. If it’s complaining about undefined symbols, that means that the header files are there, but there’s no object code to provide the function implementations. This could be because you’ve used header files for a library you didn’t include — such as using the CMSIS functions with the CMSIS headers, without either adding the CMSIS project’s binary output to the linker includes, or by adding the CMSIS C implements to the project directly. It could also be because source files aren’t being compiled — like if you added the “driver” folder to the include path, but not the source path; in that case, GCC is skipping over all the C files in the driver folder, so there’s never any object code getting generated.

Conclusions and Thoughts

As you can see, writing C code on ARM is not inherently more difficult than any other platform — things just become more complicated when you want to start doing… you know… microcontroller stuff. This requires importing the peripheral library into your project and understanding how to actually use that library.

You’ve probably noticed the ARM hardware, itself, is no more difficult to work with than traditional 8-bit MCUs. Breadboarding the LPC1114 required nothing more than some wires and a few decoupling capacitors6. Even the Arduino — one of the simplest platforms to work on — requires a reset pull-up resistor and external crystal network to get going.

Luckily, now that you’ve got this project working, you can use it as a starting point for future projects. You’ve got the entire peripheral library included right now, so you’re ready to go — the peripheral library includes all the code you need to use the ADC, CAN, GPIO, I2C, SPI, USART, PWM, and timers. Check the documentation for information on how to use these peripherals.

Here’s a link to the project download archive, which includes the final code:

LPC1114_Blink

Have fun! Go build something!

 


  1. Semihosting and printf support requires a relatively large amount of memory, and it’s relatively slow. It’s useful for getting started, but you’ll probably just use the debugger (with breakpoints) way more often than you will printf(). 

  2. This is one of those really important things that no one teaches you 

  3. I’ve obviously connected the power rails on the breadboard — you can’t see these connections because they’re out of frame 

  4. Total exaggeration 

  5. Trust me, it’s blinking in reality — I was too lazy to figure out how to record/edit/upload a video of it 

  6. which probably aren’t even necessary 

8 thoughts on “LPCXpresso “Hello, World” and Breadboard LED Blinking

  1. Well, if you download the sample project at the bottom of the post, you’ll get a project with built-in peripheral library support. Just make sure enable the UART module in driver_config.h (by #defining CONFIG_ENABLE_DRIVER_UART to 1). Once that’s done, you should be good to go. Just read through the uart.c file to see how the UART functionality is implemented. Call UARTInit() with the baud rate you want to run at, and you should be done. There’s an IRQ handler built-in to the UART library, so you won’t have to mess with any of that — just poll UARTCount to get the number of bytes available to read, and then read them from UARTBuffer — both of these variables are defined in uart.c.

    If you want to do something fancier with the UART (like interrupt-based receiving), you’ll need to override the UART_IRQHandler() function (either by modifying the vectors table to point to a custom function, or by just modifying the function in-place in the uart.c file).

    Happy programming!

  2. I got it working! Thanks for the Posts! I created a “me too” post. The self-hosting library and project setting is required to get printf to work in Eclipse. The uart shoud also work. I have a SPI based DAC board I may also use. Or I will make sure the old LPC 1768 still works.

  3. Thanks for this post, it’s a good overview on getting started from scratch. I can’t get semihosting to work right now with the NXP provided examples for LPC1769, so I think I’ll have to start from zero and work my way back up to blinky LED. No shortcuts!

  4. m hesitant to easily bin my phones is really because I.

    Opera Mobile has become the browser of choice for the majority of Win – Mo users in this time, to the point that the majority of mobile phone providers supply Opera pre-packaged.
    The T- Mobile Dash3G mobile phone comes integrated with a 2.

  5. Website design performs a vital purpose in every prosperous
    company that’s done on the web. Almost all those who find themselves jogging an online business overemphasize this time period with no acknowledging or evern being familiar with the actual
    origins powering web-based organization. World wide web uilding is just like devbeloping any
    creating. It involves many things, in excess of just a additional visual appeal.
    Sites of wich focus on the particular good looks, and never around the site’s functionality are
    much less probably be within search engine results.

  6. Pretty section of content. I just stumbled upon your blog and in accession capital to assert that I get in fact enjoyed account your blog posts.
    Any way I will be subscribing to your feeds and even I achievement you access consistently quickly.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>