Let's Make Robots!

LPC1114 -- Setup for Bare Metal ARM

Serially programs LPC1114 ARM Cortex M0

UPDATE: I tweaked the source and rebuilt lpc21isp to allow for automatic mode switching, bootloader and program, from an FTDI breakout.

A few months ago Bdk6 sent me an LPC1114 ARM processor.  Not going to lie, I had little idea how to use the chip.

Bdk6 and his kids had created the Valdez family with the chip:

The Valdez Family

I tried several IDEs to get the chip going.  I wasn't happy with any of them.

LPCXpresso was confusing and intimidating.  Since I was trying to learn the chip and a new IDE.  Add to this, NXP didn't have libraries for the chip, so I was trying to integrate the LPC1114 CodeBase libraries. They appeared to be incomplete and unkept.  It didn't matter, I couldn't seem to integrate the libraries into LPCExpresso.  

I then started using Mbed.  A lot more luck there.  But it was uncomfortable.  I'm betting most reading are familiar with Mbed, therefore, I won't go into the usual rants about it being webbased and closed-source.  

There are other problems with Mbed.

First, it is not a complete development solution.  You need a flashing tool to upload code to the LPC1114 chip.  The easiest tool to use is FlashMagic, which gives you a nice GUI to interact with the LPC1114.  There is a slight problem, Mbed produces a .bin file and the LPC1114 needs a .hex file, subsequently, FlashMagic only allows uploading of .hex files.  So, you have to use a third tool to convert the file from .bin to .hex before uploading.  Sigh.  It's a lot of trouble. 

 

Anyway, I eventually got it to blink a light

 

I craved more freedom, so I started looking for tools that'd allow me to code for the LPC1114 freely.  A bare-metal solution.  Just me, a compiler, and the LPC1114 User Manual (datasheet). Luckily, most of the work had been done for me.  Frank Duignan, Ted Burke, and Bdk6 had pretty much all the answers pre-compiled for my little brain.  Here's the steps I used to get a command-line programming environment setup.

 

1. Download and install GNU Tools for ARM Embedded Processors (Win32 Release -- 2013, quarter 3).  During the installation, make sure to check the box "Add path to environment variable.


 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Check "Add environment variable."

 

 

 

 

 

 

 

 

If you missed this part, you can add a path to the environment variables by:

Right clicking on This PC / My Computer --> Properties --> Advanced system settings --> Environment Variables --> Select "Path" under "System Variables --> Edit.  Go to the end of the list of paths, add a semicolon, then place the path of the GNU tools bin.

For me, this was "C:\Program Files (x86)\GNU Tools ARM Embedded\4.7 2013q3\bin"

We are going to add several paths to the path systems variables.  So, refer back to these steps as needed.

 

 

 

 

 

2. Download Frank Duignan's Windows linker script, LPC1114 header file, and build batch file.

Duignan's LPC1114 tools

Ted Burke was nice enough to put these up for us.  However, there's two pieces missing for us to use these amazing tools.

 

 

3. Create a workspace folder. e.g., "C:\Users\Ladvien\Documents\LPC1114_Bare_Metal".


4. Install binutils for file conversion.  Binutils has to be compiled for Windows, though, I was able to find them pre-compiled.

Download Binutils compiled for Windows

Really, we are only using Binutils for objcopy, which is at the end of the batch file.  This translates the .elf produced by the ARM compiler into a .hex file.  To unzip Binutils file I'd recommend using 7zip.  After installing them add the bin folder to your environment variable (see step 1).  For me, I added "C:\Users\Ladvien\Documents\LPC1114_Bare_Metal\Ming32\bin". 

 

5. Create a build script in a batch file.

Create a build batch file recommend by Duignan and Burke.  Open your workspace folder, create a new text file, enter the following:

arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -v -g -c init.c -o init.o
arm-none-eabi-gcc -mcpu=cortex-m0 -mthumb -v -g -c main.c -o main.o
arm-none-eabi-ld init.o main.o -v -L "C:\Program Files (x86)\GNU Tools ARM Embedded\4.7 2013q3\lib\gcc\arm-none-eabi\4.7.4\armv6-m" -lgcc -T linker_script.ld --cref -Map main.map -nostartfiles -o main.elf 
objcopy -O ihex main.elf main.hex 

 

Save the text file in your workspace as "build.bat"  Be sure to include the quotation marks, since this will convert the file from a text file to a batch file.  This is the same build commands put together by Duignan, but I've added the "-v" option.  This is the verbose mode and will spit out an errors during compiling.

 

 

6. Setup a C++ friendly text editor, like Programmer's Notepad. 

7.  Create a file called main.c in your workspace directory.  Enter the following text:

/* Simple PWM demonstrator program
 * The program simply ramps the duty of pin 10
 * from 0% to 100%  and then resets back to 0%
 * 
 */

#include "lpc111x.h"

void ConfigPins()
{
	SYSAHBCLKCTRL |= BIT6 + BIT16; // Turn on clock for GPIO and IOCON 
	
	// Begin Port 0 setup.
	// Make Port 0 bit 5 behave as a generic output port (open drain)
	IOCON_PIO0_5 |= BIT8;
	// Make Port 0 bit 10 behave as a generic I/O port
	IOCON_SWCLK_PIO0_10  = 1; 
	// Make Port 0 bit 11 behave as a generic I/O port
	IOCON_R_PIO0_11  = 1; 
	// End Port 0 setup.
	
	
	// Make pin 10 behave as a PWM output CT32B1_MAT0
	IOCON_R_PIO1_1 |= BIT1 + BIT0; 
}
void initPWM()
{
	// will use counter/timer CT32B1
	// Turn on CT32B1
	SYSAHBCLKCTRL |= BIT10;
	// Use match register 3 as period register because its output
	// is not pinned out.  A value of 48000000 produces a frequency of 1Hz
	// so, to generate a 30kHz pwm signal, set MR3 = 48000000/30000 = 1600	
	TMR32B1MR3 = 1600; 
	TMR32B1MR0 = 1600; // Zero output to begin with
	TMR32B1MCR = BIT10; // Reset TC on match with MR3
	TMR32B1TC = 0 ; // Zero the counter to begin with
	TMR32B1PWMC = BIT0; // Enable PWM on channel 0
	TMR32B1TCR = 1; // Enable the timer	
	
}
void setDuty(int Duty)
{
	// sets the duty to the percent specified.
	// Need to 'invert' the requested duty as the PWM mechanism
	// resets the output at the start of each PWM cycle and then
	// sets it on match.
	TMR32B1MR0 = (100-Duty) << 4;
}
void delay(int dly)
{
	while(dly--);
}
int main()
{	
	int Duty=50;
	ConfigPins();
	initPWM();
	while(1) 
	{
		setDuty(Duty++);
		if (Duty > 100){
			for (Duty > 1; Duty--;){
				setDuty(Duty);
				delay(100000);
			}
		}	
		delay(100000);
	}    
}

Save the main.c file.

I've modified the above code from Duignan's to make it comparable to the Fade sketch in the Arduino examples.

8. Open the command prompt in your workspace directory.  Run your build.bat file.


After running the build.bat, it should build five files: main.o, int.o, main.map, main.elf, main.hex.  If it doesn't build correctly, double check the path variables for both the compiler and binutils.  

 We still have the problem of getting the main.hex uploaded to the LPC1114.  You can use FlashMagic, like above, but I'm trying to stick to the command line, that's where lpc21isp comes in.

I've pre-built lpc21isp for Windows.  

Download LPC21ISP (now with automatic mode switching! :)

But if this doesn't work for you, then you'll have to build it yourself.

 

10. Create a another batch file called, "LPC1114_upload.bat"

Only one line this time:

lpc21isp -wipe -localecho -hex main.hex COM3 57600 12000

You'll have to adjust the COM port to the port you are using.  Here is a little bit of a guide using lpc21isp.  Also, you'll either need to put the lpc21isp file in one of the folders added in the path variable.  Or, make sure the LPC1114_upload.bat and lpc21isp files are in the same directory as your main.hex.

 

11. Wire up your LPC1114.


One last bit I should point out, when "DP24" is connected to ground and then voltage is supplied to the LPC1114, it'll enter the hardware bootloader.  But, if DP24 is open or (preferably) pulled-up with a resistor when voltage is supplied to the LPC1114 then it'll run whatever code has been uploaded to the flash memory.  

"DP24" is actually pin 1 on port 0.


 

12. Connect your LPC1114's RX/TX to an serial connector, put it into the bootloader mode by connecting DP24 to ground, then apply power to the LPC1114.  Lastly, run the LPC1114_upload.bat file.  This should result in the LED connected to "SWDIO" pin to fade on and off.   

And that's what I've got.  I'm going to start working on coding now, so I'll trade to add to this write-up as I've more to share.  I plan to try these steps on my lab machine around June 1st to make sure they work.  But if anyone uses them before them, please let me know if there are corrections to be made.  As always, I value feedback and critique.

Update: FTDI Mode switching

The lpc21isp allows for automatic mode switching, that is, you can use an FTDI cable as below:

Then replace the line in your LPC1114_upload.bat file with

lpc21isp -wipe -localecho -control -hex main.hex COM3 57600 12000

This will automatically put the LPC1114 into program mode, upload your code, then reset to run your newly uploaded program. Just like Arduino! (Bdk6, you didn't see that statement, right? :)

Of course, lpc21isp is an agglomeration and had an error(?) that wouldn't reset the chip after downloading the new code.  I simply commented an if-statement and it is now "working."  I'm sure I've lost some robustness, but hell, it does what I want with no apparent side-effects.  If you would like to know more about how I "broke" lpc21isp check my Github readme on the issue.


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Here is another article covering bare metal programming Cortex chips:

http://www.embedded.com/design/mcus-processors-and-socs/4007119/Building-Bare-Metal-ARM-Systems-with-GNU-Part-1--Getting-Started

I have only skimmed it, but it seems to have some useful information.

Wow, nifty! That's an article I've been looking for but didn't know the words to find.

What a wonderful writeup!   Thank you for more Ladvien style clear and concise documentation.

I had been looking at a LPC1114 daughterboard for the Raspberry Pi but I appreciate your links, references, and breakdown.  Thanks again Sir.

 

 

It is such a fun chip!  I just hope to dig in and write some sensible tutorials to make it robot-builder friendly.  And you're too kind, Mr. UG.  You've still got me beat on write-ups, I've got two more blogs of yours to read before I'm caught up. :)

What do you think of it? Is there anything particularly useful or interesting to recommend this chip above the ones we're more familiar with for robotic or other applications?

Atmega328P on steroids, and cheaper too!

I planned on adding a comparison chart, etc, but Mothers' Day here.  I'll add it in a day or so.

Quick highlights:

  1. 48mhz with no passives (internal crystal trimmed to 1%; PLL).
  2. Serial bootloader hardware (no bootloader flashing needed).
  3. Atmega328P: $ 3.61 vs LPC1114FBD48/302: $3.08.
  4. Comes in a DIP22 version ($2.92) that's super breadboard friendly.

It'd be a great robot chip.  Only bit that might send robot folk away, it operates at 3.3v.

I'm very glad you have this working.  I am still working on my setup, trying to get it complete and ready to make available.  This is great stuff you are doing.

One note about LPC21ISP.  On Linux, mine will hang if the chip isn't ready to program (bootloader not activated).   The screen says "press [ESC] to exit" but it never works.  So be sure the chip is ready or you will may have to kill the process manually.

The LPC is a great chip.  The peripherals are VERY powerful.  It has a great deal of potential. For instance, I have used one timer running continuously to produce the trigger pulse and read the value of an HC-SR04 ultrasonic module.  A very short interrupt routine reads the value each time a reading is taken and stores it in a global variable, available any time for use.

Great work.  Have fun. And thanks.

Mr. Bdk6, I owe half my electron education to Google and the other half to you, sir.

I did notice that with LPC21ISP you can only flash it once per reset.  That is, if I put it into bootloader mode, upload code, then try to upload code a second time, it'll hang.  I have to reset the bootloader to upload again.  

I stated elsewhere, I wish I had all the brains to make the most of this chip.  I feel like I've only opened the door to an alien-ship with hardware well past my ability to understand; the power is evident, but the instructions are in another language.

Again, sir, thank you for sending the chip and answering all my silly questions.  I hope you are well.  And let me know when you start teaching at college, I'll make sure Silas attends :)