LPC17xx ARM Cortex M3 Assembly Language Example
LPC17xx ARM Cortex M3 Assembly Language Example
LPC17xx ARM Cortex M3 Assembly Language Example
Example
Table of Contents
1 Abstract
2 The hardware
2.1 Add Headers
2.2 Serial port
3 The software tools
3.1 The assembler and linker
3.2 The preprocessor
4 The assembly language program
4.1 Source code listing
4.2 Notes about the source code
5 Assembling and linking
6 Burning the flash with a JTAG connector
7 Burning the flash through the serial bootloader
8 Other files
8.1 The link file
8.2 The OpenOCD configuration file
8.3 Bonus section
9 Download
10 Dead ends
10.1 Using Code Red to program the flash
10.2 Using an Olimex JTAG probe with OpenOCD
10.3 Verify error with lpc21isp version 1.79
11 Conclusion
1 Abstract
This note describes an LED blinking program written in assembly language for the LPC17xx family of
ARM Cortex M3 chips. As written, it runs on the LPCXpresso LPC1769 board (where the LED is on Port
0, bit 22). To run on other LPC17xx boards where an LED is on a different port pin, either adjust this code
to use a different port pin or else use a logic probe on Port 0, bit 22, as a temporary LED, and run the
program as-is.
It shows the commands for assembling and linking with the GNU assembler and linker and also the
commands for burning the program into the board's flash memory via a JTAG connector and the
OpenOCD software or with the lpc21isp serial bootloader (flash) utility.
The binary file is also included in case you would like to jump right to burning it into flash.
2 The hardware
I used the LPCXpresso LPC1769 board. I do not recommend the LPCXpresso boards and suggest you get
a different LPC17xx board instead.
On the LPCXpresso board, an LED is connected to bit 22 of Port 0. This is labeled "LED2". It is near J6-
36. When Port 0 bit 22 is high, the LED lights up.
Below, I describe some hardware modifications (basically soldering some headers for easy access and
adding a serial adapter) . You may not need to do even this much if
you use an LPCXpresso board but can burn the flash successfully from the Code Red IDE
you use an LPCXpresso board in some sort of a base board that supplies a serial adapter and/or a
JTAG connector
you use a different LPC17xx board with a JTAG adapter or a serial port adapter
I also soldered a single-row 27-pin header on each edge of the LPC1769 side of the board to give easy
access to the serial port pins and other pins. This header is labeled J6 on the board.
The software described here, needed to preprocess, assemble, link, and burn the demo program into the
ARM Cortex board, runs on Linux. If you do not have Linux available, it can be as simple as temporarily
booting an Ubuntu live CD (see details at http://pygmy.utoh.org/riscy/) and installing the "Bundle of
Tools".
This is a cross assembler. It runs on a PC (such as a typical desktop or laptop with an Intel CPU) but
produces code for an ARM CPU.
If you don't have GNU binutils for the ARM installed, you can download my "Bundle of Tools" at
http://pygmy.utoh.org/riscy/.
The preprocessor program is named preasm.tcl and is included in the tools bundle mentioned in the
previous section. If you prefer, you can manually convert the semicolons to at-signs.
;;; led-lpc17xx.asm
;;; written by Frank Sergeant
;;; [email protected]
;;; http://pygmy.utoh.org/riscy
;;; This program is in the public domain. See http://pygmy.utoh.org/riscy/cortex/
;;; for notes about the program and how to assemble, link, and burn to flash.
;;; Blink the LED on the LPCXpresso LPC1769 ARM Cortex M3 board
;;; (or any LPC17xx ARM board with perhaps minor modifications).
;;; The LED on the Xpresso board is labeled LED2 and is just to the
;;; left of (inside of) J6-36. It is connected to P0.22. The LED is
;;; on when P0.22 is high.
;;; Directives
.thumb ; (same as saying '.code 16')
.syntax unified
;;; Equates
.section .text
.org 0
;;; Vectors
vectors:
.word STACKINIT ; stack pointer value when stack is empty
.word _start + 1 ; reset vector (manually adjust to odd for thumb)
.word _nmi_handler + 1 ;
.word _hard_fault + 1 ;
.word _memory_fault + 1 ;
.word _bus_fault + 1 ;
.word _usage_fault + 1 ;
_start:
loop:
str r0, [r5] ; clear P0.22, turning off LED
ldr r1, = LEDDELAY
delay1:
subs r1, 1
bne delay1
The LPC1769 MCU uses the "Thumb-2" instruction set, not the "ARM" instruction set. Even though the
.thumb directive is equivalent to the .code 16 directive, the processor is still a 32-bit processor.
We define some symbolic constants, including the initial stack value (STACKINIT) and the LED delay
value (LEDDELAY). If, after getting the program to run, you would prefer to make the LED blink faster or
slower, then change the value of LEDDELAY.
The program starts at address zero (0x0000 0000) with the vector table. Each vector table slot is 4 bytes
long. The first entry is the initial value for the stack pointer. We use 0x1000 4000 for the initial stack value.
The second slot in the vector table holds the address where program execution will begin. In this case, it is
at the label _start. Actually, we adjust the address slightly in the vector table by adding 1 to it to make it
odd. This is required because, in Thumb mode, a value loaded into the program counter must have its least
significant bit set. I suppose there is a way to avoid doing this by putting the vectors is a special section and
giving the linker certain command options and/or using an assembler directive.
We fill in several more slots in the vector table for various exceptions. They all point to a loop at the end of
the program. We do not expect any of these exceptions to be triggered, but if they are, the program will just
hang in a loop, incrementing two registers (so we will have something to look at if we are tracing the
program in a debugger).
The rest of the logic should be straightforward. We alternately write a "1" bit to the FIOCLR and the
FIOSET registers to turn bit 22 of Port 0 on and off (to turn the LED off and on), killing time so the LED
flashes at exactly the speed we like best (adjust LEDDELAY to your personal taste).
The goal is to produce the file led-lpc17xx.bin to burn into the MCU's flash memory.
6 Burning the flash with a JTAG connector
(I used the serial bootloader instead. See the next section.)
You can use any method you prefer to burn led-lpc17xx.bin into the flash. Here is how I might do it
if I had a working JTAG connection to the LPCXpresso board, using OpenOCD and the Olimex ARM
USB Tiny JTAG adaptor (http://olimex.com/dev/arm-usb-tiny.html):
$ openocd -f openocdlpc17xx.cfg
Then in the telnet terminal, type the following commands (not all are necessary)
> help
run above to see all OpenOCD commands
> halt
> poll
> flash erase_sector 0 0 0
erase sector 0 (where we will load our new program)
> flash info 0
> flash erase_check 0
hopefully this shows we erased sector 0 successfully
> flash write_bank 0 led-lpc17xx.bin 0
> mdw 0 7
above displays the 7 vector slots as 32-bit words, note all slots except
the first have the least significant bit set
> mdb 0 28
above displays the 7 vector slots as 28 bytes (note, little endian)
> cortex_m3 disassemble 0x1c 0x20
above disassembles the program starting at the label "_start"
> reset init
> resume
I used a serial adapter to convert the LPC1769 chip's UART0 TTL-level signals to RS232-level signals (or
close enough). I made the adapter with a 4049 hex inverter chip, using one gate for Rx and one gate for Tx
with a resistor on the inputs to provide a little current-limiting protection. I picked up power and ground
from J4-2 and J4-16. I picked up Tx and Rx from J6-22 and J6-21.
I also set up two jumper wires:
The chip can be reset by briefly touching the other end of this jumper to J6-1 (ground), eliminating
the need to unplug and replug the USB connector in order to reset the board
If this pin is low when the chip comes out of reset, the chip goes into serial bootloader mode.
8 Other files
You need several other files, whose contents are listed below. See the next section for the download bundle.
SECTIONS
{
/* interrupt vectors start at zero */
. = 0x0; /* start of flash */
.text : { *(.text) }
.bss :
{
*(.bss)
*(.ram)
}
}
# tell gdb our flash memory map and enable flash programming
gdb_memory_map enable
gdb_flash_program enable
9 Download
The file http://pygmy.utoh.org/riscy/cortex/led-lpc17xx.zip contains
led-lpc17xx.html
this file
openocdlpc17xx.cfg
the JTAG/OpenOCD configuration file
lpc17xx.ld
the linker file
led-lpc17xx.asm
the LED blinking program source code
led-lpc17xx.s
the preprocessed LED blinking program source code
led-lpc17xx.lst
the listing file produced by the assembler
led-lpc17xx.bin
the binary ready to burn into the MCU's flash
Also, the GNU binutils compiled on 32-bit Ubuntu 10.04 to cross assemble for the ARM (and ARM
Cortex) along with the preprocessor are available at http://pygmy.utoh.org/riscy/ look for "The Bundle of
Tools".
10 Dead ends
10.1 Using Code Red to program the flash
Although I found the "Program Flash" tool bar button, and could make it apparently go through the steps to
burn led-lpc17xx.bin, it didn't seem to work. (Of course, if you try this after you cut the traces between the
LPC-Link side and the LPC1769 side, you need to jumper them again. For example, solder a 2x8 header
into J4 then use shorting blocks on all 8 pairs).
If you should get this working, and especially if you are then able to tell Code Red that led-lpc17xx.s is the
source code file, and are then able to step through it in the Code Red debugger, please email me with full
details as to how you did it.
I did succeed in dumping memory, but attempting to program the flash and/or to single step failed.
Here is how I wired my connector, showing where I picked up the JTAG signals.
JTAG
Top View
.--------------------------------.
| |
(LPC J4-2) 3.3v | 1 Vref Vtarget 2 | 3.3v
| |
n/c | 3 NTRST GND 4 |
| |
(LPC J4-10) | 5 TDI GND 6 |
| |
(LPC J4-4) | 7 TMS GND 8 |
| |
(LPC J4-6) | 9 TCK GND 10 |
| |
n/c |11 RTCK GND 12 |
| |
(LPC J4-8) |13 TDO GND 14 |
| |
(LPC J4-12) |15 RST GND 16 |
| |
n/c |17 DBGRQ GND 18 |
| |
n/c |19 DBGACK GND 20 | GND (LPC J4-16)
| |
`--------------------------------'
I didn't bother with any pull-ups or pull-downs, assuming the signals that needed that were already pulled
up or down on the LPCXpresso board itself. That I was able to communicate through this adapter (the mdw
command to dump memory) seems to support this assumption.
I understand the RTCK signal is not needed. I really wanted to connect the NTRST signal, which
apparently comes from the LPC1769 chip's pin 100, but I could not find where the LPCXpresso board
brought that signal out to any connector and I did not want to try soldering to the tiny pins of the LPC1769
chip.
If you find that NTRST/pin 100 is in fact accessible somewhere on the board, please tell me where.
If you are able to get "real" JTAG (as opposed to the proprietary Code Red version) working with this
board, please tell me how you did it.
and it reported a verification failure. What I would like to know is whether the my particular LPC1769 chip
does indeed have some bad flash (but not in places that would prevent the LED blinking program from
running) or if the lpc21isp program (version 1.79) is failing to verify flash that in fact is programmed
successfully.
An obvious experiment, which I have not tried yet, is to slow down the baudrate, using somethink like
So, if you use lpc21isp to program the flash in an LPCXpresso board, please email me to tell me how it
worked for you.
11 Conclusion
Please email me with any comments or corrections or questions (or answers).