Introduction
To paralellize the software and hardware development, software for the LPC2148 was developed on an evaluation board from Olimex. The developed software will work exactly the same on the node front-end, since it only relies on the type of ARM chip. Two software programs were developed and shown to work on the Olimex evaluation board:
- a simple program to turn on and off an LED
- an eCos port to the LPC2148
The eCos port was an optional requirement for our project, and puts software development ahead of schedule.
Tools used
Our industry sponsors required all software used in this project to run under Linux. Running under Windows was optional, but software that is open-source is a big win. If the software is open-source, we can modify it when we find bugs and give the source back to the community.
Serial Terminal
The LPC2148 chip can communicate over the serial port. It will respond to special In-System Programming (ISP) commands specified in the Philips datasheet. These commands include (but are not limited to) setting the baud rate, writing to RAM, copying from RAM to flash, reading from memory, and echoing the part ID or boot code version.
The LPC2148 serial communication can easily be tested using a terminal that sends data over the serial port. In Linux, minicom is the software of choice. Minicom comes preinstalled with Debian Linux and open-source under the GNU General Public License (GPL). I used version 2.1 (compiled Nov 4 2005).
ISP Software
To download programs into flash and RAM on the LPC2148, a programmer needs to have In-System Programming (ISP) software. This software uses the ISP command specification to send program binaries over the serial port or JTAG. Typically, this means writing a chunk of program to RAM and then burning it to flash. A programmer would have to type hundreds of commands over the serial port if they wanted to do this manually.
There are several options for ISP software. Philips gives away a flash utility for LPC2xxx chips. However, they only distribute the executable, which doesn't work under Linux. http://www.semiconductors.philips.com/products/microcontrollers/support/software_download/lpc2000/index.html
Macraigor systems also distributes a flash memory programmer. It works under Linux and Windows, but requires JTAG. A JTAG connector is fairly expensive, so we wanted another alternative. http://www.macraigor.com/flash_prog.htm
The ISP software selected for use is a flash programmer that uses the serial port. It runs under Linux and in Windows (using Cygwin) and is fully open source. http://guest.engelschall.com/~martin/lpc21xx/isp/ I used version 1.31. The program is one c file that you'll need to compile. You should add the directory containing the compiled program to your path.
Cross-Compiler
In order to compile programs for the ARM chip, you need a cross-compiler. A cross-compiler builds native code (ARM programs) on non-native systems (Intel x86). GNU provides a c and c++ compiler tool chain called gcc. To build a gcc cross-compiler, follow the instructions at http://psas.pdx.edu/DebianCrossCompilerHowto. Replace any mention of "powerpc" or "ppc" with "arm". I used gcc 4.0 to build the cross-compiler.
eCos
The real-time operating system (RTOS) chosen to run on the nodes is the embedded Configurable operating system (eCos).
Building eCos
- Go to http://ecos.sourceware.org/getstart.html and follow the instructions under the section 'eCos'. Do not follow the 'Toolchain' instructions; those are equivalent to making the cross-compiler. I don't suggest installing eCos in /opt/ecos because it requires root to run the eCos configuration tool and update your sources.
- Make sure to add the configtool path to your PATH environment variable. configtool is found in
$ECOS_INSTALL_DIR/ecos/ecos-2.0/tools/bin
. - Go to http://ecos.sourceware.org/anoncvs.html and follow the instructions for checking out the latest eCos repository.
- Make sure that your environment has
ECOS_REPOSITORY
set to the packages directory in the eCos CVS sources. - Run configtool. Choose
Build -> Repository...
and enter the path to the eCos CVS directory.
You can check that eCos has found the repository by seeing if the GPL-GPS template is available. Go to Build
->Templates...
. In the first drop down menu, scroll down through the available templates. If you see the "GPS 4020" template, eCos has access to the CVS repository.
Serial Port Test
Software needed:
- minicom
First, flip switch 1 on the Olimex board to up. Next, you need to set up minicom. Start minicom up with minicom -s
. This brings you to the setup menu. Go to "Serial port setup" to change some settings. Type 'A' to change the serial device. I used a USB to serial adaptor in Linux, so I set up my output port to be /dev/ttyUSB0. Make sure hardware and software flow control are both set to 'No'. Type 'E' to set the Bps, parity, and stop bit. You should configure it for 8 data bits, 1 stop bit, no parity, and 38400 Bps.
Once minicom is configured, save the setup and exit to minicom. Type CTRL+A+A to add a linefeed to the data (the LPC2148 expects a carriage return followed by a linefeed at the end of every command).
Once minicom is setup and running, follow these steps:
- Send "?" (the synchronization character).
- Wait for the board to send back "Synchronized".
- Send "Synchronized" back.
- Board will send back "OK".
- Now the board is waiting for the frequency in kHz for the crystal oscillator on the board. "12000" is correct for the Olimex board.
- Board will send back "OK" if synchronization occurs. Otherwise it goes back to waiting for a synchronization character ("?").
After these steps, you can send any of the commands listed in Chapter 21 of the LPC214X User Manual. A simple test that doesn't touch memory is to make the chip echo the microcontroller part number. The command to send is "J". The LPC2148 should send back "67305253".
"Hello Blinky World!" Example
Tools needed:
- lpc21isp
- cross-compiler tool chain
Software needed:
Introduction
The source code for this demo was written by Jim Lynch. The source code and tutorial can be found on this SparkFun thread: http://www.sparkfun.com/cgi-bin/phpbb/viewtopic.php?t=1331.
License Issue
The header file LPC214x.h defines names for memory-mapped addresses. The header file was released by the USA Philips Marketing Team on the LPC2000 yahoo group. http://groups.yahoo.com/group/lpc2000/message/9444
The header file was part of a USB toolkit that Philips sold to consumers. It has a rather nasty license referenced in it, which says that you cannot use the header file in open source code or redistribute it anyone who hasn't agreed to licensing terms. The Philips Marketing Team invalidated this license by posting the header file on public forum. The header file is built on public knowledge and could be replicated by anyone with the LPC214x User Manual, which further weakens the license's copyright claims.
The LPC2000 prohibits users from posting copyrighted works in their files sections saying, "Do not upload any copyright material to the group's Files area. It will be deleted and the offender banned from the group." The file remains and Philips Marketing Team has not been banned from the group, which leads me suspect no one assumed the license was valid.
Modifications From Original
If you're a Linux user, change this line in main.c
#include lpc2141x.h
to
#include LPC2141x.h
The header file is misnamed in the top line. This bug doesn't show up for Windows users because Windows is case-insensitive.
Also, he got some bit math wrong in demo2148_blink_flash.cmd
ram_isp_low(A) : ORIGIN = 0x40000120, LENGTH = 223
should change to
ram_isp_low(A) : ORIGIN = 0x40000120, LENGTH = 224
This bug won't affect the blinky LED demo since it doesn't take up a lot of room in RAM.
The Makefile is created for the arm-elf tool chain, so you'll have to change the lines that start with "CC". Change the gcc compiler to "arm-linux-gnu-gcc" and the rest from "arm-elf-*" to "arm-linux-*".
Source Code Review
File usage:
- lpc2148_led_demo.cmd - defines the memory map for the LPC2148.
- crt.s - start-up assembly code.
- LPC214x.h - GPIO addresses.
- main.c - initialization of the system, endless toggling of the LED.
Code Snippet (main.c)
...
int main (void) {
...
// Initialize the system
Initialize();
// set io pins for led P0.10
SCS = 0x03; // select the "fast" version of the I/O ports
FIO0DIR |= 0x00000400; // pin P0.10 is an output,
// everything else is input after reset
FIO0SET = 0x00000400; // led off
FIO0CLR = 0x00000400; // led on
// endless loop to toggle the red LED P0.10
while (1) {
for (j = 0; j < 5000000; j++ ); // wait 500 msec
FIO0SET = 0x00000400; // red led off
for (j = 0; j < 5000000; j++ ); // wait 500 msec
FIO0CLR = 0x00000400; // red led on
}
}
...
The snippet from main.c is fairly simple. It makes the GPIO pin P0.10 an output, and then turns the LED on and off by setting and clearing the GPIO output.
The remaining 100 lines of main.c contains interrupt routine stubs and a function to initialize the chip. The initialization function sets the main clock frequency to 60MHz (an unacceptable rate to use USB with), initializes the current controlled oscillator, sets the number of clock cycles to fetch memory out of flash, enables MAM, and sets the peripheral clock to the main clock frequency. This code, along with the start-up assembly code and memory map file, would not be necessary if the program was running under eCos.
Compiling and Downloading Instructions
Once the necessary changes are made to the makefile, you can simply type 'make' in the demo directory. This will compile the program into a main.out and a main.hex file. Now you'll need to use lpc21isp to download the main.hex file to the LPC2148.
Set switch 1 on the Olimex board to on and plug the serial cable from RS232_0 (on the Olimex board) to your computer. Power cycle the board.
Now you'll want to send the program to the Olimex flash memory. lpc21isp will write a flash block's worth of the program to RAM, then burn that to flash. To send the main.hex file to the Olimex board, run the following command:
lpc21isp -debug -hex -PHILIPSARM main.hex /dev/ttyUSB0 38400 12000
The -debug
flag tells the program to print out debug statements. The -hex
flag means the program should expect a hex file to send, and the -PHILIPSARM
flag means we're sending to a Philips chip. main.hex
is the file to send, and /dev/ttyUSB0
is the port to send it over. I was using a USB to serial adaptor, so I used the Linux specific path that pointed to that USB device. If you're using Windows or a serial port on your computer, you'll need to replace "/dev/ttyUSB0" with the OS specific path (usually "com1" for serial in Windows).
The program will write bits across the serial cable for a couple minutes. Once the program is done, you'll see "Download Finished..." followed by a message that it's launching the new code. Launching from the software doesn't work. You'll need turn switch 1 off and push the reset button. Then you should see LED1 blinking away.
Results
The program worked as intended, and the LED attached to P0.10 blinked constantly. The author intended it to blink once a second, and it blinks a little slower than that. There is no guarantee what the compiler will do with the delay loops, so a better solution would have been to use an internal timer on the chip. However, for a simple demo, this works fine.
eCos Port
Tools needed:
- lpc21isp
- cross-compiler tool chain
- eCos
Software needed
- lpc2148 ecos.tgz - contains:
- LPC214x.h
- blinky.c
- lpc2148_rom.ecc
- Makefile
- target.ld
Introduction
To get eCos running on a microcontroller, a programmer must first create an eCos port for the microcontroller. This includes a memory map, initialization code, a hardware abstraction layer (HAL), and more. Typically an existing port for a similar processor can be modified, but it still requires a lot of work.
LPC2148 Port
Fortunately, Pawel Wodnicki has created a port for the LPC2136/8 and LPC2146/8 microcontrollers. (http://sourceware.org/ml/ecos-patches/2005-11/msg00014.html) The patch has not been merged into the CVS truck, but it can still be used to patch the current eCos sources. Download the patch into the ecos directory (the original, not the CVS repository). Then type patch -p1 < ecos-iH1-proc_lpc_1.patch
. There will be some warnings, but they should be fine.
Once you have a patched eCos, you can load Pawel's template for the LPC2148. Open configtool and go to Build -> Templates...
. In the first drop down menu, choose the template called "Hobby-Robotics iH 1_proc_lpc_1 board". This was designed to work on Pawel's evaluation board, but it will work for any LPC2148 board.
LPC2148 Port Modifications
I needed to make a couple configuration changes to compile under the arm-linux toolchain. The first fix was to change CYGBLD_GLOBAL_COMMAND_PREFIX
to "arm-linux-gnu".
Most of the other changes involved adding or removing compilation flags to make eCos build. The difference in flags are probably due to using a newer gcc (the eCos folks are still using gcc 3.2, whereas I compiled with gcc 4.0).
I changed CYGBLD_GLOBAL_CFLAGS from
-mcpu=arm7tdmi -mno-short-load-words -Wall -Wpointer-arith -Wstrict-prototypes -Winline -Wundef -Woverloaded-virtual -g -O2 -ffunction-sections -fdata-sections -fno-rtti -fno-exceptions -fvtable-gc -finit-priority
to
-mcpu=arm7tdmi -mno-short-load-words -Wall -Wpointer-arith -Wstrict-prototypes -Winline -Wundef -g -O2 -ffunction-sections -fdata-sections -fno-exceptions -fvtable-gc -ffreestanding -fno-use-cxa-atexit
The flag "-ffreestanding" wasn't strictly necessary, but the flag "-fno-use-cxa-atexit" solved many of the compilation errors.
There were still linker errors, so the CYGBLD_GLOBAL_LDFLAGS needed to be changed from
-mcpu=arm7tdmi -mno-short-load-words -Wl,--gc-sections -Wl,-static -g -nostdlib
to
-mcpu=arm7tdmi -Wl,--gc-sections -Wl,-static -g -nostdlib
The change of flags made some linker errors go away, but the linker was still complaining that certian sections weren't in the target.ld
file. There was no references to the sections any any other code, so we suspected it was a bug in the linker. To make the linker happy, we added this changed these lines in target.ld
.rom_vectors 0x00000000 : { __rom_vectors_vma = ABSOLUTE(.); . = .; KEEP (*(.vectors)) } > rom __rom_vectors_lma = LOADADDR(.rom_vectors);
.text ALIGN (0x1) : { _stext = ABSOLUTE(.); PROVIDE (__stext = ABSOLUTE(.)); *(.text*) *(.gnu.warning) *(.gnu.linkonce.t.*) *(.init) *(.glue_7) *(.glue_7t) } > rom _etext = .; PROVIDE (__etext = .);
to
.rom_vectors 0x00000000 : { __rom_vectors_vma = ABSOLUTE(.); . = .; KEEP (*(.vectors)) } > rom __rom_vectors_lma = LOADADDR(.rom_vectors);
.got ALIGN (0x4) : { . = .; *(.got*) *(.rel*) } > rom
.text ALIGN (0x1) : { _stext = ABSOLUTE(.); PROVIDE (__stext = ABSOLUTE(.)); *(.text*) *(.gnu.warning) *(.gnu.linkonce.t.*) *(.init) *(.glue_7) *(.glue_7t) } > rom _etext = .; PROVIDE (__etext = .);
Looking at the linker output, the added sections only took up 4 bytes.
Source Code Review
To test the eCos port, I wrote a program to turn on two LEDs. Here is "blinky.c" in its entirety:
#include "LPC214x.h"
#include <cyg/kernel/kapi.h>
void Initialize(void);
void feed(void);
void cyg_user_start(void)
{
// Initialize the system
// set io pins for led P0.10
SCS = 0x03; // select the "fast" version of the I/O ports
FIO0DIR |= 0x00000C00; // pin P0.10 and P0.11 are outputs
// bit 11 and 10 set = 0 1100 0000 0000
// = 0xC00
FIO0SET = 0x00000400; // P0.10 led off
FIO0SET = 0x00000800; // P0.11 led off
FIO0CLR = 0x00000400; // P0.10 led on
FIO0CLR = 0x00000800; // P0.11 led on
}
Comments
This code is much cleaner and simplier than the non-eCos code. The blinky.c code was 21 lines long, whereas the non-eCos main.c code was 168 lines of code (much of that initialization code). The eCos compiled code size is bigger than the non-eCos code size because of the linked eCos code. Here is a comparison of the code size in bytes obtained using arm-linux-gnu-size:
code type |
text |
data |
bss |
dec |
non-eCos demo |
788 |
24 |
28 |
840 |
eCos demo |
24808 |
844 |
17044 |
42696 |
The eCos demo is 42KB. The program resides in flash memory on the LPC2148, but parts of it will be loaded into RAM at run-time. The LPC2148 has 32KB RAM and 512MB flash, so that still leaves enough room for future software development.
Compiling the eCos Demo
Once you have patched your eCos repository with Pawel's patch (see the RTOS section), you're ready to build the eCos program. First, download the tarball lpc2148 ecos.tgz. Extract it with "tar xvzf lpc2148_ecos.tgz" in whatever directory you want.
Change to the lpc2148_ecos directory and run configtool. Open lpc2148_rom.ecc by choosing File -> Open
. Then create the eCos source tree by choosing Build -> Generate Build Tree
. Once that has finished, choose Build -> Library
. The command won't finish, due to errors from the target.ld
file. Replace target.ld
in /lpc2148_ecos/lpc2148_rom_install/lib/ with the target.ld
file in the tarball (found in the same directory as blinky.c).
Then type
make INSTALL_DIR=$TAR_DIR/lpc2148_ecos/lpc2148_rom_install
where $TAR_DIR is the directory where you extracted the tarball.
Now you should have a blinky.hex file in the directory.
Downloading Instructions
Set switch 1 on the Olimex board to on and plug the serial cable from RS232_0 (on the Olimex board) to your computer. Power cycle the board.
Now you'll want to send the program to the Olimex flash memory. lpc21isp will write a flash block's worth of the program to RAM, then burn that to flash. To send the blinky.hex file to the Olimex board, run the following command:
lpc21isp -debug -hex -PHILIPSARM blinky.hex /dev/ttyUSB0 38400 12000
(See the "Hello Blinky World!" section for an explanation of the command.)
The program will write bits across the serial cable for a couple minutes. Once the program is done, you'll see "Download Finished..." followed by a message that it's launching the new code. Launching from the software doesn't work. You'll need turn switch 1 off and push the reset button. Then you should see both LED1 and LED2 glowing.
Future Work
The next step in software development is to write an eCos USB driver for the LPC2148. There are a few examples of other eCos USB drivers in the eCos repository, but they only use control and bulk transfers. Implementing eCos isochronous transfer support will require intensive development and extensive knowledge of eCos and USB.
Once the eCos USB driver has been implemented, a user-land Linux USB driver needs to be developed for the flight computer. This project will require both Linux and USB knowledge. Both projects are beyond the scope of this capstone project.