Академический Документы
Профессиональный Документы
Культура Документы
This book is useful guide for everyone who uses the Philips LPC2148 Microcontrollers in a new design. It can be
used as both as a reference book and as a tutorial. Here it is treated that the reader has some basic knowledge in
programming of microcontrollers for embedded systems and are well verse with the C language. The important
technical information is covered in the first four chapters, and it should be read in order if you are completely new
to the ARM7 CPU and the LPC2148.
The chapter 1 gives an introduction to the major features of the ARM7 CPU. This Chapter will give you enough
understanding about the programming any ARM7 device. In this first chapter we discuss how the RISC (Reduced
Instruction Set Computer) design philosophy was adapted by ARM to create a flexible embedded processor. We
then introduce an example embedded device and discuss the typical hardware and software technologies that
surround an ARM processor. The final section introduces the architecture implementations by subdividing them
into specific ARM processor core families.
Chapter 2 covers embedded systems with focus on the actual processor itself. First, we will provide an overview
of the processor core and describe how data transfers between its different parts. We will describe the
programmer's model from a software developer's view of the ARM processor, which will show you the functions
of the Data flow model of ARM core. We will also take a look at the core extensions that form an ARM processor.
Core extensions speed up and organize main memory as well as extend the instruction set. We will then cover the
register file of ARM, know the function of LR, PC and SP registers, know the structure of CPSR register. The
function of conditional flag bits, interrupt mask bits and mode bit. A brief introduction into the different processor
modes. - Banked registers Explanation of 3-staged pipelining of ARM-7 with an example. A brief introduction
to exceptions, interrupts and the vector table Action on entering and leaving an exception.
Chapter 3 this is fundamental chapter gives information about ARM instruction set. Consequently, it is placed
here before we start going into any depth on optimization and efficient algorithms. This chapter introduces the
most common and useful ARM instructions and builds on the ARM processor fundamentals covered in the last
chapter. Since all our programming examples are written in C there is no need to be an expert ARM7 assembly
programmer. However an understanding of the underlying machine code is very important in developing efficient
programs.
Chapter 4 gives the overview of the THUMB instructions. Explains the register usage, interworking of
ARM-THUMB. We will also study about THUMB instructions.
Chapter 5 gives basic rules we need to follow while programming ARM7 in ‘C’. We discuss data types, symbols,
declaring variables, defining labels, Unary operators, Binary operators, Addition, subtraction, Shift operators,
Relational operators ,Boolean operates and logical operators which widely used while programming.
Chapter 6 this chapter gives General structure of an assembly language, Meaning of AREA, ENTRY directives.
Explains how Subroutines can be used with different methods of passing parameters with example programs,
ARM APCS specification, Exception handling, ARM processor exceptions and modes, Vector table, Exception
priorities, link register offsets. Interrupts, standard design practices in assigning interrupts, interrupt latency, IRQ
and FIQ exceptions, Enabling and disabling of FIQ and IRQ exceptions. Basic interrupt stack design and
implementation- examples for stack implementation in user, supervisor and IRQ modes. Listing of different
interrupt handling schemes, process of writing a non nested interrupt handler using inline assembler in C, inline
assembly syntax, restrictions on inline assembly operations. Embedded assembler, embedded assembly syntax,
Restrictions on embedded assembly operations, calling between C and assembly. Method of writing Interrupt
service routines in C with examples.
Chapter 7 this chapter gives the features of LPC2148 microcontroller. Explains the block diagram of LPC 2148
microcontroller and the function of pins of LPC 2148 microcontroller. We then study the features of on chip
program memory and on chip static RAM, the memory map, the functional features of Interrupt controller, pin
connect block, DAC,ADC ,USB controller,UART,I2C,SPI,SSP controllers, general purpose timers, Watch dog
timers, RTC& Pulse width modulator(PWM). Study the feature of system control units like PLL, Brown out
detector, reset and wake up timer, code security, External interrupt inputs, Memory mapping control, Power
control, and APB bus
Chapter 8 this chapter gives a fair idea about peripherals of LPC 2148 controller. Here we will study about
purpose of Pin Connect Block GPIO: Features, Application, Pin description, Register description, examples.PLL:
Introduction, Register description, about PLL frequency. Calculation, procedure for determining PLL settings,
SPI: block diagram of SPI solution. Timers: Architecture of timer module, Register description, and examples.
PWM: Introduction, register description, rules for single/double edge controlled PWM outputs.RTC:
Introduction, architecture, register description, RTC interrupts, usage, Prescaler-Examples of prescaler
usage.ADC: Pin description, register description, operation. DAC: Pin description, register description, operation
Chapter 9 this chapter explains the interfacing of some of the real time devices such as LCD, Seven segment
Display, Stepper Motor, Dc Motor, Relay and HEX keypad with LPC2148.We explain the basic working
principle and construction of these devices along with the interfacing program. All the program is in “C”
Chapter 1:
Introduction to ARM EMBEDDED
SYSTEM
1.1History of ARM processor design
After achieving some success with the BBC Micro computer, Acorn Computers Ltd considered how to
move on from the relatively simple MOS Technology 6502 processor to address business markets like the one
that would soon be dominated by the IBM PC, launched in 1981. The Acorn Business Computer (ABC) plan
required a number of second processors to be made to work with the BBC Micro platform, but processors such as
the Motorola 68000 and National Semiconductor 32016 were unsuitable, and the 6502 was not powerful enough
for a graphics based user interface.
Acorn would need a new architecture, having tested all of the available processors and found them
wanting. Acorn then seriously considered designing its own processor, and their engineers came across papers on
the Berkeley RISC project. They felt it showed that if a class of graduate students could create a competitive
32-bit processor, then Acorn would have no problem. A trip to the Western Design Center in Phoenix, where the
6502 was being updated by what was effectively a single-person company, showed Acorn engineers Steve Furber
and Sophie Wilson that they did not need massive resources and state-of-the-art R&D facilities.
The official “Advanced RISC Machine (ARM)” project started in October 1983. VLSI Technology, Inc
was chosen as silicon partner, since it already supplied Acorn with ROMs and some custom chips. The design was
led by Wilson and Furber, with a key design goal of achieving low-latency input/output (interrupt) handling like
the 6502. The 6502's memory access architecture had allowed developers to produce fast machines without the
use of costly direct memory access hardware. VLSI produced the first ARM silicon on 26 April 1985 – it worked
first time and came to be known as ARM1 by April 1985. The first "real" production systems named ARM2 were
available in the following year.
Its first practical application was as a second processor to the BBC Micro, where it was used to develop
the simulation software to finish work on the support chips (VIDC, IOC, MEMC) and to speed up the operation of
the CAD software used in developing ARM2. Wilson subsequently coded BBC Basic in ARM assembly
language, and the in-depth knowledge obtained from designing the instruction set allowed the code to be very
dense, making ARM BBC Basic an extremely good test for any ARM emulator. The original aim of a principally
ARM-based computer was achieved in 1987 with the release of the Acorn Archimedes.
Such was the secrecy surrounding the ARM CPU project that when Olivetti were negotiating to take a
controlling share of Acorn in 1985, they were not told about the development team until after the negotiations had
been finalized. In 1992 Acorn once more won the Queen's Award for Technology for the ARM.
The ARM2 featured a 32-bit data bus, a 26-bit address space and sixteen 32-bit registers. Program code
had to lie within the first 64 Mbyte of the memory, as the program counter was limited to 26 bits because the top
4 and bottom 2 bits of the 32-bit register served as status flags. The ARM2 was possibly the simplest useful 32-bit
microprocessor in the world, with only 30,000 transistors (compare the transistor count with Motorola's six-year
older 68000 model which was aptly named, since it contained 68,000 transistors). Much of this simplicity comes
from not having microcode (which represents about one-quarter to one-third of the 68000) and, like most CPUs of
the day, not including any cache. This simplicity led to its low power usage, while performing better than the Intel
80286. A successor, ARM3, was produced with a 4 KB cache, which further improved performance.
In the late 1980s Apple Computer and VLSI Technology started working with Acorn on newer versions
of the ARM core. The work was so important that Acorn spun off the design team in 1990 into a new company
called Advanced RISC Machines Ltd. Advanced RISC Machines became ARM Ltd when its parent company,
ARM Holdings plc, floated on the London Stock Exchange and NASDAQ in 1998.
The new Apple-ARM work would eventually turn into the ARM6, first released in early 1992. Apple
used the ARM6-based ARM 610 as the basis for their Apple Newton PDA. In 1994, Acorn used the ARM 610 as
the main CPU in their RISC PC computers. DEC licensed the ARM6 architecture and produced the Strong ARM.
At 233 MHz this CPU drew only 1 Watt of power (more recent versions draw far less). This work was later passed
to Intel as a part of a lawsuit settlement, and Intel took the opportunity to supplement their aging i960 line with the
Strong ARM. Intel later developed its own high performance implementation known as X-Scale which it has
since sold to Marvell.
The ARM architectures used in smart phones, personal digital assistants and other mobile devices range
from ARMv5, in obsolete/low-end devices, to the ARM M-series, in current high-end devices. X-Scale and
ARM926 processors are ARMv5TE, and are now more numerous in high-end devices than the Strong ARM,
ARM9TDMI and ARM7TDMI based ARMv4 processors, but lower-end devices may use older cores with lower
licensing costs. ARMv6 processors represented a step up in performance from standard ARMv5 cores, and are
used in some cases, but Cortex processors (ARMv7) now provide faster and more power-efficient options than all
those previous generations. Cortex-A targets applications processors, as needed by smart phones that previously
used ARM9 or ARM11. Cortex-R targets real-time applications, and Cortex-M targets microcontrollers.
In 2009, some manufacturers introduced notebooks based on ARM architecture CPUs, in direct
competition with notebooks based on Intel Atom.
ARM provides a summary of the numerous vendors who implement ARM cores in their design. KEIL
also provides a somewhat newer summary of vendors of ARM based processors. ARM further provides a chart
displaying an overview of the ARM processor lineup with performance and functionality versus capabilities for
the more recent ARM7, ARM9, ARM11, Cortex-M, Cortex-R and Cortex-A device families.
Typical MIPS
ARM Family ARM Architecture ARM Core Feature Cache (I/D), MMU
@ MHz
ARM1 ARMv1 ARM1 First implementation None
ARMv2 added the MUL 4 MIPS @ 8 MHz
ARMv2 ARM2 None
(multiply) instruction 0.33 DMIPS/MHz
ARM2 Integrated MEMC (MMU),
Graphics and IO processor. None,
ARMv2a ARM250 7 MIPS @ 12 MHz
ARMv2a added the SWP and MEMC1a
SWPB (swap) instructions.
12 MIPS @ 25 MHz
ARM3 ARMv2a ARM3 First integrated memory cache. 4 KB unified
0.50 DMIPS/MHz
ARMv3 first to support 32-bit
ARM6 ARMv3 ARM60 memory address space None 10 MIPS @ 12 MHz
(previously 26-bit)
As ARM60, cache and coprocessor 28 MIPS @
ARM600 4 KB unified
bus (for FPA10 floating-point unit). 33 MHz
As ARM60, cache, no coprocessor 17 MIPS @ 20 MHz
ARM610 4 KB unified
bus. 0.65 DMIPS/MHz
ARM700 8 KB unified 40 MHz
ARM710 As ARM700, no coprocessor bus. 8 KB unified 40 MHz
ARM7 ARMv3
40 MHz
ARM710a As ARM710 8 KB unified
0.68 DMIPS/MHz
15 MIPS @
ARM7TDMI 16.8 MHz
3-stage pipeline, Thumb None
(-S) 63 DMIPS @
70 MHz
ARM7 ARM710T As ARM7TDMI, cache 8 KB unified, MMU 36 MIPS @ 40 MHz
ARMv4T
TDMI
8 KB unified, MMU
60 MIPS @
ARM720T As ARM7TDMI, cache with Fast Context
59.8 MHz
Switch Extension
ARM740T As ARM7TDMI, cache MPU
5-stage pipeline, Thumb, Jazelle
ARM7EJ ARMv5TEJ ARM7EJ-S None
DBX, Enhanced DSP instructions
5-stage pipeline, static branch
84 MIPS @ 72 MHz
ARM8 ARMv4 ARM810[16] prediction, double-bandwidth 8 KB unified, MMU
1.16 DMIPS/MHz
memory
Strong 16 KB/8–16 KB, 203–206 MHz
ARMv4 SA-1 5-stage pipeline
ARM MMU 1.0 DMIPS/MHz
ARM9TDMI 5-stage pipeline, Thumb none
16 KB/16 KB, MMU
with FCSE (Fast 200 MIPS @
ARM9TD ARM920T As ARM9TDMI, cache
ARMv4T Context Switch 180 MHz
MI Extension)
ARM922T As ARM9TDMI, caches 8 KB/8 KB, MMU
ARM940T As ARM9TDMI, caches 4 KB/4 KB, MPU
variable, tightly
Thumb, Enhanced DSP
ARM946E-S coupled memories,
instructions, caches
MPU
ARMv5TE
Thumb, Enhanced DSP
ARM966E-S no cache, TCMs
instructions
ARM9E
ARM968E-S As ARM966E-S no cache, TCMs
Thumb, Jazelle DBX, Enhanced variable, TCMs, 220 MIPS @
ARMv5TEJ ARM926EJ-S
DSP instructions MMU 200 MHz
Clockless processor, as no caches, TCMs,
ARMv5TE ARM996HS
ARM966E-S MPU
6-stage pipeline, Thumb, Enhanced
ARM1020E 32 KB/32 KB, MMU
ARMv5TE DSP instructions, (VFP)
ARM10E ARM1022E As ARM1020E 16 KB/16 KB, MMU
Thumb, Jazelle DBX, Enhanced variable, MMU or
ARMv5TEJ ARM1026E J-S
DSP instructions, (VFP) MPU
7-stage pipeline, Thumb, Enhanced
XScale 32 KB/32 KB, MMU 133–400 MHz
DSP instructions
Wireless MMX, Wireless
Bulverde 32 KB/32 KB, MMU 312–624 MHz
XScale ARMv5TE SpeedStep added
32 KB/32 KB (L1),
Monahans Wireless MMX2 added optional L2 cache up up to 1.25 GHz
to 512 KB, MMU
740 @
8-stage pipeline, SIMD, Thumb,
532–665 MHz
ARMv6 ARM1136J (F)-S Jazelle DBX, (VFP), Enhanced variable, MMU
(i.MX31 SoC),
DSP instructions
400–528 MHz
ARM1156T2 8-stage pipeline, SIMD, Thumb-2,
ARMv6T2 variable, MPU
(F)-S (VFP), Enhanced DSP instructions
ARM11
965 DMIPS @
ARM1176JZ variable, MMU + 772 MHz, up to 2
ARMv6ZK As ARM1136EJ(F)-S
(F)-S Trust Zone 600 DMIPS with
four processors[20]
As ARM1136EJ(F)-S, 1–4 core
ARMv6K ARM11 MPCore variable, MMU
SMP
Flash/ROM
ARM Memory Controller
Cache Program
ARM7 TDMI CORE RAM
EEPROM
Data
Interrupts Core
Controller
Parallel I/O
IO
RTC Real-time Clock
Interrupt
Customer Customer IP
IO Watchdog Timer Watch Dog
Over Flow
High-Performance High-Bandwidth
ARM Processor On-chip RAM
UART Timer
B
R
AHB or ASB
High-Bandwidth I APB
External memory
D
Interface
G
E
DMA bus
Master Keypa PIO
d
Bridging between this higher level of bus and the current ASB/APB can be done efficiently to ensure that
any existing designs can be easily integrated. An AMBA AHB design may contain one or more bus masters,
typically a system would contain at least the processor and test interface. However, it would also be common for
a Direct Memory Access (DMA) or Digital Signal Processor (DSP) to be included as bus masters. The external
memory interface, APB bridge and any internal memory are the most common AHB slaves. Any other peripheral
in the system could also be included as an AHB slave. However, low-bandwidth peripherals typically reside on
the APB.
High-Performance High-Bandwidth
ARM Processor On-chip RAM
UART Timer
B
R
AHB
High-Bandwidth I APB
External memory
D
Interface
G
E
DMA bus
Master Keypa PIO
d
High-Performance High-Bandwidth
ARM Processor On-chip RAM
UART Timer
B
ASB R
High-Bandwidth APB
I
External memory
Interface D
G
E
DMA bus
Keypa PIO
Master
d
High-Performance High-Bandwidth
ARM Processor On-chip RAM
UART Timer
B
R
AHB or ASB
High-Bandwidth I APB
External memory D
Interface
G
E
DMA bus
Master Keypa PIO
d
1.10 Peripherals
Peripheral device are essential for embedded systems to interact with external world. A peripheral device
performs input and output functions for the processor by connecting to different devices or sensors that are
external to the chip. Each peripheral device usually performs a single function and may reside on-chip.
Peripherals range from a simple serial communication device to a more complex 802.11 wireless device.
All ARM peripherals are memory mapped—the programming interface is a set of memory-addressed
registers. The address of these registers is an offset from a specific peripheral base address.
Controllers are specialized peripherals that provide higher levels of functionality within an embedded
system. Two important types of controllers are memory controllers and interrupt controllers.
D [31:0]
A [31:0]
The seq signal is automatically asserted whenever a memory address is obtained from the incrementer. The above
fig1.9 shows how the sequential signals are generated in ARM.
1.10.2 Interrupt Controllers
Whenever a peripheral or device requires the function of processor, it generates an interrupt signal to the
processor. An interrupt controller provides a programmable interrupt service that allows software to determine
which peripheral or device can interrupt the processor at any specific time by setting the appropriate bits in the
interrupt controller registers.
ARM processor has two types of interrupt controller:
1. The standard interrupt controller and
2. The vector interrupt controller (VIC).
The standard interrupt controller generates an interrupt signal when an external device requests interrupt
servicing. By writing program SIC can be configured to ignore or mask an individual interrupt device or set of
interrupt devices. The interrupt handler determines which device requires servicing by reading a device bitmap
register in the interrupt controller.
The VIC is more powerful than the standard interrupt controller because it prioritizes interrupts and
simplifies the determination of which device caused the interrupt. After associating a priority and a handler
address with each interrupt, the VIC only asserts an interrupt signal to the core if the priority of a new interrupt is
higher than the currently executing interrupt handler. Depending on its type, the VIC will either call the standard
interrupt exception handler, which can load the address of the handler for the device from the VIC, or cause the
core to jump to the handler for the device directly.
The VIC provides a software interface to the interrupt system. In a system with an interrupt controller,
software must determine the source that is requesting service and where its service routine is loaded. A VIC does
both of these in hardware. It supplies the starting address, or vector address, of the service routine corresponding
to the highest priority requesting interrupt source.
In an ARM system, two levels of interrupt are available:
Fast Interrupt reQuest (FIQ)
For fast, low latency interrupt handling.
Interrupt ReQuest (IRQ)
For more general interrupts generally, you only use a single FIQ source at a time in a system to provide a
true low-latency interrupt. This has the following benefits:
• You can execute the interrupt service routine directly without determining the source of the interrupt.
• It reduces interrupt latency. You can use the banked registers available for FIQ
interrupts more efficiently, because you do not require a context save.
The interrupt inputs must be level sensitive, active HIGH, and held asserted until the
interrupt service routine clears the interrupt. Edge-triggered interrupts are not compatible.
The interrupt inputs do not have to be synchronous to HCLK.
Note
The VIC does not handle interrupt sources with transient behavior. For example, an interrupt is asserted and then
deserted before software can clear the interrupt source. In this case, the CPU acknowledges the interrupt and
obtains the vectored address for the interrupt from the VIC, assuming that no other interrupt has occurred to
overwrite the vectored address. However, when a transient interrupt occurs, the priority logic of the VIC is not
set, and lower priority interrupts can interrupt the transient interrupt service routine, assuming interrupt nesting
is permitted.
Hardware Device
Operating System
Application
Lastly, an application performs one of the tasks required for a device. For example, a mobile phone
performs SMS application, even though there may be many other applications running on the same device,
controlled by the operating system.
The software components can run from ROM or RAM. ROM code that is fixed on the device (for
example, the boot code) is called firmware.
1 .1 1 .3 A P P L I C A T I O N S
Applications are scheduled by OS. Which is the code dedicated for handling a pre-defined application.
An application carries a processing work; while the OS controls the environment. An embedded system can have
one active application or several applications running simultaneously.
ARM processors are found in various market segments, including networking, automation, mobile and
consumer devices, mass storage, and imaging processing. Within each segment ARM processors can be found in
multiple applications.
For example, the ARM processor is found in networking applications like home gateways, DSL modems
for high-speed Internet communication, and 802.11 wireless communications. The mobile device segment is the
largest application area for ARM processors because of mobile phones. ARM processors are also found in mass
storage devices such as hard drives and imaging products such as inkjet printers—applications that are cost
sensitive and high volume.
In contrast, ARM processors are not found in applications that require leading-edge high performance.
Some of them are
Industrial control
Medical systems
Access control
Point-of-sale
Communication gateway
Embedded soft modem
General purpose applications
Example.
Automotive Infotainment
Increasingly, the electronics functionality embedded in a vehicle is becoming a key decision criterion for
buyers. ARM and its Partners have been present in the area of infotainment for a long period of time, with a
number of high volume platforms (the Ford Sync being one example) being powered by ARM® technology. The
success of the ARM architecture in wireless applications has led to the availability of many ingredients necessary
to build a successful telematics or infotainment product. OEMs are looking for compelling, power-efficient
hardware platforms for high-end Navigation and Multimedia systems. From the software perspective, the
investment that ARM is making in ensuring the availability of optimized web browsers and Adobe Flash 10
support for the ARM architecture enables car suppliers to offer the same web experience inside a vehicle that
users are familiar with on a PC or a Smartphone.
Description: Ford and Microsoft have collaborated on the "Sync" in-car communications and entertainment
system which enables you to stay connected to your handheld devices, even when you’re on the road. Sync is a
voice-activated, hands-free, in-car communications and entertainment system which fully integrates your mobile
phone and digital media player.
One touch of the 'telephone button' on the steering wheel as shown in fig 1.11is all it takes to make a
call. Names and numbers in a mobile phone’s address book will be transferred wirelessly and automatically to
the vehicle. Users will be able to access their mobile phones or digital music players – including genre,
album, artist and song title, via voice commands. Sync will also host, nearly any digital media player, including
the Apple iPod®, Microsoft Zune, PlaysForSure players and most USB storage devices.
The first models which will offer the "Sync" system (As an option on 2008-models) will be; Ford,
Lincoln and Mercury models: Edge, Explorer, Five Hundred, Focus, Freestyle, Fusion, Milan, MKX, MKZ,
Montego, Mountaineer, and Sport-Trac.
Features:
Voice-activated, hands-free calling
Uninterrupted connections
Audible text messages
Advanced calling features
Voice-activated music
Instant voice recognition
Ring tone support
Automatic phonebook transfer
Multilingual intelligence
Chapter 2:
ARM PROCESSOR FUNDAMENTALS
2.1 INTRODUCTION
Now that we have an idea of the ARM7 system, now it is better understand about the programmer’s model
and operating modes. This chapter covers dataflow model for the program developer’s view. We will study about
data flow model, register file structure. The ARM7 is a load-and-store architecture, so in order to perform any data
processing instructions the data has first to be moved from the memory store into a central set of registers, the data
processing instruction has to be executed and then the data is stored back into memory. We will also look at the
Structure of Cpsr (current program status register). The CPSR contains a number of flags which report and control
the operation of the ARM7 CPU, Register banks in ARM7.We will also at the different operating modes of ARM7.
We will then cover about Exceptions in ARM7.
One of the most interesting features of the ARM7 is instruction execution, where instructions are executed
in 3 Staged pipeline. A three-stage pipeline is the simplest form of pipeline and does not suffer from the kind of
hazards such as read-before-write seen in pipelines with more stages. Finally we will discuss about Vector table.
Vector table gives the idea about execution of exception interrupt.
The ARM processor uses load-store architecture. That is it has two instruction types for transferring
data in and out of the processor: load instructions copy data from memory to registers and the store instructions
copy data from registers to memory. There is no data processing instruction, which directly works on data in
memory. Thus, data processing is performed only with the registers. Data items are placed in the register file—a
storage bank made up of 32-bit register- Since the ARM core is a 32-bit processor, most instructions treat the
registers as storing; signed or unsigned 32-bit values. The sign extend hardware converts signed 8-bit and 16- r
numbers to 32-bit values as they are read from memory and placed in a register.
ARM instructions have two source registers, Rn and Rm, and a single result storing- destination register,
Rd. Source operands are read from the register file using the internal buses A and B, respectively.
The ALU (arithmetic logic unit) or MAC (multiply-accumulate unit) takes the renter values Rn and Rm
from the A and B buses and computes a result. Data processor: instructions write the result in Rd directly to the
register file. Load and store instruction use the ALU to generate an address to be held in the address register and
broadcast on the Address bus.
One important feature of the ARM is that register Rm alternatively can be preprocessed in the barrel
shifter before it enters the ALU. Together the barrel shifter and ALU can calculate a wide range of expressions
and addresses. After passing through the functional units, the result in Rd is written back to the register file using
the ALU bus. For load and store instructions the incrementer updates the address register before the core reads or
writes the next register value from or to the next sequential memory location. The processor continues executing
instructions until an exception or interrupt changes the normal execution flow. Now that you have an overview of
the processor core we'll take a more detailed look at some of the key components of the processor: the registers,
the current program status register (cpsr), and the pipeline.
General-purpose registers hold either data or an address. They are identified with the letter R prefixed to
the register number. For example, register 4 is given the label R4. Figure 2.3 shows the active registers available
in user mode—a protected mode normally
There are up to 18 active registers: The central sets of registers are a bank of 16 user data registers R0 –
R15 and 2 processor status registers. Data registers are visible to the programmer as R0 to R15.Each of these
registers is 32 bits wide and R0 – R12 are user registers in that they do not have any specific other function. The
Registers R13 – R15 do have special functions in the CPU.
Stack Pointer (SP):
R13 is used as the stack pointer (SP) and stores the top of stack, though this has only been defined as a
programming convention. Unusually the ARM instruction set does not have PUSH and POP instructions so stack
handling is done via a set of instructions that allow loading and storing of multiple registers in a single operation.
Link register (LR):
R14 is called the link register (LR). When a call is made to a function the return address is automatically
stored in the link register and is immediately available on return from the function. This allows quick entry and
return into a ‘leaf’ function (a function that is not going to call further functions). If the function is part of a branch
(i.e. it is going to call other functions) then the link register must be preserved on the stack (R13).
Program counter (PC):
R15 is the program counter (PC) and contains the address of the next instruction to be fetched by the
processor. Interestingly, many instructions can be performed on R13- R15 as if they were standard user registers.
Current Program Status Register (CPSR):
In addition to the register bank there is an additional 32 bit wide register called the ‘current program status
register’ (CPSR). The CPSR contains a number of flags which report and control the operation of the ARM7 CPU.
In addition to the register bank there is an additional 32 bit wide register called the ‘current program status
register’ (CPSR). The CPSR as shown in fig 2.4contains a number of flags which report and control the operation
of the ARM7 CPU.
31 30 29 28 27 8 7 6 5 4 3 2 1 0
N Z C V I F T M M M M M
4 3 2 1 0
Conditional Code flags Interrupt Enable operating mode
Negative IRQ
Zero FIQ IRQ
Carry Thumb instruction set System
oVerflow User
Undefined instruction
Abort
The top four bits (28 to 31) of the CPSR contain the condition codes which are set by the CPU. The
condition codes report the result status of a data processing operation. From the condition codes you can tell if a
data processing instruction generated a negative (N), zero (Z), carry(C) or overflow (V) result. The lower eight
bits (0 to 7) in the CPSR contain flags which may be set or cleared by the application code. Bits 7 and 8 are the
I and F bits. These bits are used to enable and disable the two interrupt sources which are external to the ARM7
CPU. You should be careful when programming these two bits because in order to disable either interrupt source
the bit must be set to ‘1’ not ‘0’ as you might expect. Bit 5 is the THUMB bit.
2.3.1 Condition Code flags: There are four bits, Bit 28 to bit 31 are kept aside for representing the status of a
data processing operation. Functions of these flags are as follows.
Negative Flag Bit (31):
This flag bit indicates the result of arithmetic or logical operation is negative. It is set 1 if result of
arithmetic or logical operation is negative otherwise it is reset to 0.
Zero Flag (Bit 30):
Set and reset according to the flag setting operation is zero or not. It records zero condition. It is set 1 if
result of arithmetic or logical operation is zero otherwise it is reset to 0.
Carry Flag (Bit 29):
This can also be called as unsigned overflow Flag. Set and reset according to the flag setting operation
results in a carry or not. It is set 1 if result of 32 bit arithmetic operation generates carry; otherwise it is reset to 0.
oVerflow Flag (Bit 28):
This can also be called as Signed overflow Flag. Set and reset according to the flag setting operation in a
signed over flow or not. It is set 1 if result of 32 bit signed integer arithmetic operation generates carry; otherwise
it is reset to 0.
For example 0x7Effffff+0x010000001=0x80000000 sets overflow flag because sum of two positive 32 bit
integers is a negative 32 bit integer.
User:
This mode is used to run the application code. Once in user mode the CPSR cannot be written to and
modes can only be changed when an exception is generated.
FIQ: (Fast Interrupt reQuest):
This supports high speed interrupt handling. Generally it is used for a single critical interrupt source in a
system
IRQ: (Interrupt ReQuest):
This supports all other interrupt sources in a system
Supervisor:
A “protected” mode for running system level code to access hardware or run OS calls. The ARM 7
enters this mode after reset.
Abort:
If an instruction or data is fetched from an invalid memory region, an abort exception will be generated
Undefined Instruction:
If a FETCHED opcode is not an ARM instruction, an undefined instruction exception will be generated.
The ARM7 CPU has six operating modes which are used to process exceptions. The shaded registers are banked
memory that is “switched in” when the operating mode changes. The SPSR register is used to save a copy of the
CPSR when the switch occurs.
Figure 2.5 shows all 37 registers in the register file. Of those, 20 registers are hidden from a program at
different times. These registers are called banked registers and are identified by the shading in the diagram. They
are available only when the processor is in a particular mode; for example, abort mode has banked registers
rl3_abt, rl4_abt and spsr_abt. Banked registers of a particular mode are denoted by an underline character
post-fixed to the mode mnemonic or _mode.
Every processor mode except user mode can change mode by writing directly to the mode bits of the
cpsr. All processor modes except system mode have a set of associated banked registers that are a subset of the
main 16 registers. A banked register maps one-to- one onto a user mode register. If you change processor mode, a
banked register from the new mode will replace an existing register.
For example, when the processor is in the interrupt request mode, the instructions you execute still access
registers named rl3 and rl4. However, these registers are the banked registers rl3_irq and rl4_irq. The user mode
registers rl3_usr and rl4_usr are not affected by the instruction referencing these registers. A program still has
normal access to the other registers rO to rl2.
The User registers R0-R7 are common to all operating modes. However FIQ mode has its own R8 –R14
that replace the user registers when FIQ is entered. Similarly, each of the other modes have their own R13 and
R14 so that each operating mode has its own unique Stack pointer and Link register. The CPSR is also common to
all modes. However in each of the exception modes, an additional register - the saved program status register
(SPSR), is added. When the processor changes the current value of the CPSR stored in the SPSR, this can be
restored on exiting the exception mode.
2.6 3-Staged Pipelining of ARM-7
At the heart of the ARM7 CPU is the instruction pipeline. The pipeline is used to process instructions
taken from the program store. On the ARM 7 a three-stage pipeline is used.
T1 T2 T3 T4 T5
During time T1, the instruction1 Add r0, r1, r2 is fetched from memory. Now during time T2,
instruction1 is decoded and instruction2 Sub r0, r1, r2 is fetched from memory. During time T3, instruction1 is
executed i.e. content of register r1 and r2 are added and sum is moved on to register r0, at the same time
instruction2 is decoded and instruction3 Cmp r3, r4 is fetched from memory. Similarly During time T4 new
instruction4 is fetched, instruction2 is executed i.e. content of r2 is subtracted from r1 and the result is stored in r0
and instruction3 is decoded. This process continues and at any point of time ARM7 performs three functions,
Fetch, Decode and execute.
MOVS R15, R14; Move Link register into the PC and switch modes.
However, in the case of the FIQ and IRQ instructions, when an exception occurs the current instruction
being executed is discarded and the exception is entered. When the code returns from the exception the link register
contains the address of the discarded instruction plus four. In order to resume processing at the correct point we
need to roll back the value in the Link register by four. In this case we use the subtract instruction to deduct four
from the link register and store the results in the PC. As with the move instruction, there is a form of the subtract
instruction which will also restore the operating mode. For an IRQ, FIQ or Prog Abort, the return instruction is:
SUBS R15, R14, #4 In the case of a data abort instruction, the exception will occur one instruction after
execution of the instruction which caused the exception. In this case we will ideally enter the data abort ISR, sort
out the problem with the memory and return to reprocess the instruction that caused the exception. In this case we
have to roll back the PC by two instructions i.e. the discarded instruction and the instruction that caused the
exception. In other words subtract eight from the link register and store the result in the PC. For a data abort
exception the return instruction is SUBS R15, R14,#8.Once the return instruction has been executed, the modified
contents of the link register are moved into the PC, the user mode is restored and the SPSR is restored to the CPSR.
Also, in the case of the FIQ or IRQ exceptions, the relevant interrupt is enabled. This exits the privileged mode and
returns to the user code ready to continue processing.
At the end of the exception the CPU returns to user mode and the context is restored by moving the SPSR
to the CPSR
2.7.1 Entering an exception:
The ARM7TDMI processor handles an exception as follows:
1. Preserves the address of the next instruction in the appropriate LR. When the exception entry is from
ARM state, the ARM7TDMI processor copies the address of the next instruction into the LR, current PC+4 or
PC+8 depending on the exception.
When the exception entry is from Thumb state, the ARM7TDMI processor writes the value of the PC into
the LR, offset by a value, current PC+4 or PC+8 depending on the exception, that causes the program to resume
from the correct place on return.
The exception handler does not have to determine the state when entering an exception. For example, in
the case of a SWI, always returns to MOVS PC, r14_svc the next instruction regardless of whether the SWI was
executed in ARM or Thumb state.
2. Copies the CPSR into the appropriate SPSR.
3. Forces the CPSR mode bits to a value that depends on the exception.
4. Forces the PC to fetch the next instruction from the relevant exception vector.
The ARM7TDMI processor can also set the interrupt disable flags to prevent otherwise
Unmanageable nestings of exceptions.
Note
Exceptions are always entered in ARM state. When the processor is in Thumb state and an exception occurs, the
switch to ARM state takes place automatically when the exception vector address is loaded into the PC. An
exception handler might change to Thumb state but it must return to ARM state to allow the exception handler to
terminate correctly.
Note
The action of restoring the CPSR from the SPSR automatically resets the T bit to whatever value it held
immediately prior to the exception.
.
2.8 Vector table
When an exception or interrupt occurs, the processor suspends normal execution and starts loading
instructions from the exception vector table (see Table 2.6). Each vector table entry contains a form of branch
instruction pointing to the start of a specific routine:
Reset vector is the location of the first instruction executed by the processor when power is applied. This
instruction branches to the initialization code.
Undefined instruction vector is used when the processor cannot decode an instruction.
Software interrupt vector is called when you execute a SWI instruction. The SWI instruction is frequently used as
the mechanism to invoke an operating system routine.
Prefetch abort vector occurs when the processor attempts to fetch an instruction from an address without the
correct access permissions. The actual abort occurs in the decode stage.
Data abort vector is similar to a prefetch abort but is raised when an instruction attempts to access data memory
without the correct access permissions.
Interrupt request vector is used by external hardware to interrupt the normal execution flow of the processor. It
can only be raised if IRQs are not masked in the cpsr.
Chapter 3
ARM 7 Instruction Set
3.1 Introduction
Now that we have an idea of the ARM7 architecture, programmers model and operating modes we need to
take a look at its instruction set or rather sets. Since all our programming examples are written in C there is no need
to be an expert ARM7 assembly programmer. However an understanding of the underlying machine code is very
important in developing efficient programs. Before we start our overview of the ARM7 instructions it is important
to set out a few technicalities. The ARM7 CPU has two instruction sets: the ARM instruction set which has 32-bit
wide instructions and the THUMB instruction set which has 16-bit wide instructions. In the following section the
use of the word ARM means the 32-bit instruction set and ARM7 refers to the CPU.
One of the most interesting features of the ARM instruction set is that every instruction may be
conditionally executed. In a more traditional microcontroller the only conditional instructions are conditional
branches and maybe a few others like bit test and set. However in the ARM instruction set the top four bits of the
operand are compared to the condition codes in the CPSR. If they do not match then the instruction is not executed
and passes through the pipeline as a NOP (no operation).
Rn Rm
No Pre-Processing
Pre-Processing
Barrel Shifter
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
Carry
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
Table 3.3 Barrel Shift operation Syntax for data processing instructions
Shift operations Syntax
Immediate #immediate
Register Rm
Logical Shift Left by immediate Rm, LSL #shift_imm
Logical Shift Left by Register Rm, LSL Rs
Logical Shift Right by immediate Rm, LSR #shift_imm
Logical Shift Right by Register Rm, LSR Rs
Arithmetically Shift Right by immediate Rm, ASR #shift_imm
Arithmetically Shift Right by Register Rm, ASR Rs
Rotate Right by immediate Rm, ROR #shift_imm
Rotate Right by Register Rm, ROR Rs
Rotate Right with extend Rm, RRX
Let R0=0x00000000
R2=0x00000011
R3=0x00000800
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0
= 0x00000011+0x00001000
= 0x00001011
Let R0=0x00000000
R2=0x00000011
R3=0x00000800
R4=0x00000001
First R3 value is logically shifted left (LSL) by on bit, the content of R4(0x01)
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0
= 0x00000011+0x00001000
= 0x00001011
Let R0=0x00000000
R2=0x00000011
R3=0x00000800
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 4 0 0
= 0x00000011+0x00000400
= 0x00000411
3.5.6 Logical Shift Right by Register Operand.
The register value is shifted right by a value contained in a register. The C flag will be updated with the
last value shifted out of Rm unless the value in Rs is 0.
Let R0=0x00000000
R2=0x00000011
R3=0x00000800
R4=0x00000001
First R3 value is logically shifted Right (LSR) by on bit
Cy
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 4 0 0
= 0x00000011+0x00000400
= 0x00000411
3.5.7 Arithmetic Shift Right by Immediate Operand.
The register value is arithmetically shifted right by an immediate value in the range 1-32. The
arithmetic shift fills from the left with the sign bit, preserving the sign of the number. The C flag will be updated
with the last value shifted out of Rm.
Syntax: <Rm>, ASR #<immediate>
Example 3.7: ADD R0, R2, R3, ASR #1 ; R0 = R2 + (R3 >> 1)
Let R0=0x00000000
R2=0x00000011
R3=0x80000800
R4=0x00000001
First R3 value is arithmetically shifted Right (ASR) by on bit
Cy
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
Cy
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
C 0 0 0 0 4 0 0
= 0x00000011+0xC0000400
= 0xC0000411
Let R0=0x00000000
R2=0x00000011
R3=0x80000800
1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0
Carry
1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
C 0 0 0 0 4 0 0
= 0x00000011+0xC0000400
= 0xC0000411
Let R0=0x00000000
R2=0x00000011
R3=0x00000800
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
Carry
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 4 0 0
Let R0=0x00000000
R2=0x00000011
R3=0x00000800
R4=0x00000001
First R3 value is logically Rotated Right (ROR) by on bit
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
Carry
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 4 0 0
= 0x00000011+0x00000400
= 0x00000411
3.5.11 Rotate Right with Extend Operand.
The register value is rotated right by one bit through the C flag, i.e. C Rm[0], Rm[31] C,
Rm[30] Rm[29], etc.
Let R0=0x00000000
R2=0x00000011
R3=0x00000800
R4=0x00000001
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
Carry
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 4 0 0
dest = op_1
if(cond)
Rd shifter_operand
if(S==1 and Rd==R15)
Flags updated if S used and Rd is not R15 (PC): N, Z, C
You can specify the same register for the effect of a NOP instruction, or you can shift the same register if you
choose:
MOV R0, R0 ; R0 = R0... NOP instruction
If R15 is the destination, the program counter or flags can be modified. This is used to return to calling code, by
moving the contents of the link register into R15:
MOV PC, R14 ; Exit to caller
MOVS PC, R14 ; Exit to caller preserving flags (not 32-bit compliant)
MOV performs a move to a register from another register or an immediate value.
MOV R1, R0 ; R1 R0
MOV R1, R0, LSL #2 ; R1 R0 * 4
MOV R1, #1 ; R1 0x0000001
If the S bit is set and the destination is R15 (the PC), the SPSR is also copied to CPSR. This form of the instruction
used to return from an exception mode
Examples 3.12:
MOV R1, R0 ; R1 R0
This instruction will Move (Copy) the content of operand two R0 into operand one R1, without changing the
content of operand two.
Let
R1 = 0x00000000
R0 = 0x00000011
After the Execution of this instruction
R1 = 0x00000011
R0 = 0x00000011
Examples 3.13:
MOV R1, R0, LSL #2 ; R1 R0 << 2
This instruction will Move (Copy) the content of logically shifted by two bit value of operand two R0 into
operand one R1, without changing the content of operand two.
Let
R1 = 0x00000000
R0 = 0x00000018
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0
Examples 3.14:
MOV R1, #1 ; R1 0x0000001
This instruction will Move the immediate value 00000001 into operand one R1.
Let
R1 = 0x00000000
After the Execution of this instruction
R1 = 0x00000001
if(cond)
Rd NOT shifter_operand
if(S==1 and Rd==R15)
Flags updated if S used and Rd is not R15 (PC): N, Z, C
This instruction loads a value into the destination register, from another register, a shifted register, or an
immediate value. The difference is the bits are inverted prior to moving, thus you can move a negative value into
a register. Due to the way this works (two's complement), you want to move one less than the required number:
MVN R1, R0 ; R1 NOT R0
MVN R1, R0, LSL #2 ; R1 <- NOT (R0 * 4)
MVN R0, #4 ; R0 = -5
Examples 1.5:
MVN R1, R0 ; R1 NOT R0
This instruction will Move the complimented value of the content of operand two(R0) into operand one (R1),
without changing the content of operand two.
Let
R1 = 0x00000000
R0 = 0x00000008
After the Execution of this instruction
R1 = 0xFFFFFFF7(Two’s Complement of 9) = -9
R0 = 0x00000008
Examples 3.16:
` MVN R1, R0, LSL #2 ; R1 NOT R0 << 2
This instruction will Move(Copy) the complimented value of logically shifted by two bit of operand two R0 into
operand one R1, without changing the content of operand two.
Let
R1 = 0x00000000
R0 = 0x00000018
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0
0 0 0 0 0 0 0 C
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1
F F F F F F F 3
MRS
R0
CPSR/SPSR
R1
5
MSR
R0
CPSR/SPSR
R1
5
The CPSR and SPSR are not memory-mapped or part of the central register file.The only instructions which
operate on them are the MSR and MRS instructions.These instructions are disabled when the CPU is in USER
mode.
The MSR and MRS instructions will work in all processor modes except the USER mode.So it is only possible to
change the operating mode of the process, or to enable or disable interrupts, from a privileged mode. Once you
have entered the USER mode you cannot leave it, except through an exception, reset, FIQ, IRQ or SWI instruction
if(cond)
Rd CPSR/SPSR
Flags updated: None
Usage and Examples:
Moves the value of CPSR or the current SPSR into a general-purpose register.
if(cond)
CPSR/SPSR immediate/register value
Flags updated: N/A
if (cond)
Rd. Rn + shifter_operand
Flags updated if S used: N, Z, V, C
This instruction will add the two operands, placing the result in the destination register. Operand 1 is a register,
operand 2 can be a register, shifted register, or an immediate value:
Let R0=0X0000
R1=0x0011
Immediate Data=256
Now R0 = R1 + Immediate Data
= 0x0011 + 256
= 0x0267
Examples 3.20:
ADD R0, R2, R3, LSL#1 ; R0 = R2 + (R3 << 1)
Let R0=0x00000000
R2=0x00000011
R3=0x00000800
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0
= 0x00000011+0x00001000
= 0x00001011
Syntax:
ADC{<cond>}{S} <Rd>, <Rn>, <shifter operand>
if(cond)
Rd Rn + shifter operand + C
Flags updated if S used: N, Z, V, C
This instruction will add the two operands, placing the result in the destination register. It uses a carry bit, so can
add numbers larger than 32 bits. Operand 1 is a register, operand 2 can be a register, shifted register, or an
immediate value:
Example 3.21.
If 64-bit numbers are stored in R1:0 and R3:2, their sum can be stored in R5:4 as shown below.
Let R5 = 0x00000000
R4 = 0x00000000 Destination registers
R3 = 0x00000800 MSB Word
R2 = 0x00000310 LSB Word 64 bit data1
R1 = 0x00000300 MSB Word
R0 = 0x00000250 LSB Word 64 bit data2
dadadata2
Now After ADDS R4, R2, R0
R4 = R2 + R0 = 00000310 + 00000250 =00000560 with Carry = 0
Now after ADC R5, R3, R1
R5 = R3 + R1+ Carry =00000800 +00000300 + 0 =00000B00
Syntax:
SUB{<cond>}{S} <Rd>, <Rn>, <shifter_operand>
:
if(cond)
Rd . Rn - shifter_operand
Flags updated if S used: N, Z, V, C
This instruction will subtract operand two from operand one, placing the result in the destination register.
Operand 1 is a register, operand 2 can be a register, shifted register, or an immediate value:
Examples 3.22:
Let R0 = 0X00000000
R2 = 0x000015F1
R3 = 0x000008E0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0
Syntax:
SBC{<cond>}{S} <Rd>, <Rn>, <shifter_operand>
if(cond)
Rd Rn - shifter_operand – NOT C
Flags updated if S used: N, Z, V, C
This instruction will subtract the two operands, placing the result in the destination register. It uses the carry bit to
represent 'borrow', so can subtract numbers larger than 32bits. SUB and SBC generate the Carry flag the wrong
way around, if a borrow is required then the carry flag is UNSET. Thus, this instruction requires a NOT Carry flag
- it inverts the flag automatically during the instruction. The subtraction may be performed on signed or unsigned
numbers.
SBC R0, R1, R2 ; R0 = R1 - R2- NOT C
SBC R0, R1, #0x00008000 ; R0 = R1 - 0x00008000 - NOT C
SBC R0, R2, R3, LSL#1 ; R0 = R2 - (R3 << 1) – NOT C
Examples 3.25:
Let R0 = 0X00000000
R2 = 0x000015F1
R3 = 0x000008E0
C = 0
First R3 value is logically shifted left(LSL) by on bit
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0
After LSL R3 = 0x000011C0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0
0 0 0 0 1 1 C 0
Syntax:
RSB{<cond>}{S} <Rd>, <Rn>, <shifter_operand>
if(cond)
Rd shifter_operand - Rn
Flags updated if S used: N, Z, V, C
This instruction will subtract operand one from operand two, placing the result in the destination
register.Please note that normal subtraction operand2 is subtracted from operand1 Operand 1 is a register,
operand 2 can be a register, shifted register, or an immediate value: Normally this instruction is used for
“negating or 2’s Complementing” of numbers.
Syntax:
RSC{<cond>}{S} <Rd>, <Rn>, <shifter_operand>
:
if(cond)
Rd shifter_operand - Rn - NOT Carry
Flags updated if S used: N, Z, V, C
This instruction will subtract “Operand one and complemented value of Carry from Operand two” placing the
result in the destination register. Please note that normal subtraction operand2 is subtracted from operand1.
Operand 1 is a register, operand 2 can be a register, shifted register, or an immediate value:
Syntax:
AND{<cond>}{S} <Rd>, <Rn>, <shifter_operand>
if(cond)
Rd Rn AND shifter_operand
Flags updated if S used: N, Z, C
This instruction will perform a logical AND operation between the two operands, placing the result in the
destination register; this is useful for masking the bits you wish to work on. Operand 1 is a register; operand 2 can
be a register, shifted register, or an immediate value:
AND R0, R1, R2 ; R0 = R1 AND R2
AND R0, R1, #0x00008000 ; R0 = R1 AND 0x8000
AND R0, R2, R3, LSL#1 ; R0 = R2 AND (R3 << 1)
Example: 3.30
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0
0 0 0 0 1 1 C 0
Now R0 = R2 AND (R3 << 1) R2 = 0000 0000 0000 0000 0000 0000 1111 0001
= 0x000000F1 AND 0x000011C0 R3 = 0000 0000 0000 0000 0001 0001 1100 0000
= 0x000000C0 R0 = 0000 0000 0000 0000 0000 0000 1100 0000
Syntax:
ORR{<cond>}{S} <Rd>, <Rn>, <shifter_operand>
:
if(cond)
Rd . Rn OR shifter_operand
Flags updated if S used: N, Z, C
This instruction will perform a logical OR between the two operands, placing the result in the destination register;
this is useful for setting certain bits to be set. Operand 1 is a register, operand 2 can be a register, shifted register,
or an immediate value:
ORR R0, R1, R2 ; R0 = R1 OR R2
ORR R0, R1, #0x8000 ; R0 = R1 OR 0x8000
ORR R0, R2, R3, LSL#1 ; R0 = R2 OR (R3 << 1)
Example 3.33:
ORR R0, R1, R2 ; R0 = R1 OR R2
Here operand 2 is a register R2
Let R0 = 0X0000
R1 = 0x0011
R2 = 0x0033
Now R0 = R1 OR R2 R1 = 0000 0000 0001 0001
= 0x0011 OR 0x0033 R2 = 0000 0000 0011 0011
= 0x0033 R3 = 0000 0000 0011 0011
Examples 3.34:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0
0 0 0 0 1 1 C 0
Now R0 = R2 OR (R3 << 1) R2 = 0000 0000 1111 0001
= 0x00F1 OR 0x11C0 R3 = 0001 0001 1100 0000
= 0x11F1 R0 = 0001 0001 1111 0001
Example 3.36:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 1 0 0 0 0 0 0
0 0 0 0 1 1 C 0
Now R0 = R2 X-OR (R3 << 1) R2 = 0000 0000 1111 0001
= 0x00F1 OR 0x11C0 R3 = 0001 0001 1100 0000
= 0x1121 R0 = 0001 0001 0011 0001
Example 3.39:
BIC R0, R1, R2 ; R0 = R1 & ~ R2
Here operand 2 is a register R2
Let R0 = 0X00000000
R1 = 0x0000000F
R2 = 0x00000005
Now R0 = R1 & ~ R2 R1= 0000 0000 0000 0000 0000 0000 0000 1111
= 0x0000000F & ~ 0x00000005 ~R2 = 1111 1111 1111 1111 1111 1111 1111 1010
= 0x0000000A R0 = 0000 0000 0000 0000 0000 0000 0000 1010
Examples 3.40:
BIC R0, R1, #0x00000005 ; R0 = R1 & ~ #00000005
Let R0=0X00000000
R1=0x00000005
Immediate Data=00000011
Now R0 = R1 &~ Immediate Data R1 = 0000 0000 0000 0000 0000 0000 0001 0001
= 0x00000011 &~ 00000005 ~R2 = 1111 1111 1111 1111 1111 1111 1111 1010
= 0x0000010 R0 = 0000 0000 0000 0000 0000 0000 0001 0000
Examples 3.41:
BIC R0, R1, R2, LSL#1 ; R0 = R1 & ~ (R2 << 1)
Let R0=0x00000000
R1=0x00000011
R2=0x00000800
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
= 0x00000011&~0xFFFFEFFF
= 0x00000011
Obviously you do not need to explicitly specify the S suffix as the point of the command is to update the status
flags... If you do specify it, it will be ignored.Operand 1 is a register, operand 2 can be a register, shifted register,
or an immediate value:
Let R0 = 0x00000033
Then R0 value is X-OR with immediate data 0x00008000
This instruction performs a 32x32 multiply operation, then stores the sum of Rn and the 32-bit multiplication
result to Rd. Since only the least significant 32-bits of the multiplication are used, the result is the same for signed
and unsigned numbers.
Examples 3.44:
MLA R3,R2,R1,R0
The instruction below adds the product of R1 and R2 to R0 and stores the result in R3
Let R0 = 0x00000002
R1 = 0x00000004
R2 = 0x00000006
R3 = 0x00000000
Branching Instructions:
The basic branch instruction (as its name implies) allows a jump forwards or backwards of up to 32 MB.
A modified version of the branch instruction, the branch link, allows the same jump but stores the current PC
address plus four bytes in the link register.
B 0x8000 0x0400
PC=0x8000
LDR R2,#10
0x8000
B 0x8000 0x0400
PC=0x8000
R14= 0x0400 + 4
LDR R2,#10 0x8000
The branch instruction has several forms. The branch instruction will jump you to a destination address.
The branch link instruction jumps to the destination and stores a return address in R14.So the branch link
instruction is used as a call to a function storing the return address in the link register and the branch instruction can
be used to branch on the contents of the link register to make the return at the end of the function. By using the
condition codes we can perform conditional branching and conditional calling of functions. The branch
instructions have two other variants called “branch exchange” and “branch link exchange”. These two instructions
perform the same branch operation but also swap instruction operation from ARM to THUMB and vice versa.
B : Branch
B<suffix> <address>
B is the simplest branch. Upon encountering a B instruction, the ARM processor will jump immediately
to the address given, and resume execution from there.
Note that the actual value stored in the branch instruction is an offset from the current value of R15; rather than an
absolute address.
Example 4.45:
This example shows a forward and backward branch. Because these loops are address, we do not include
the pre- and post-conditions. The forward branch skips three instructions. The backward branch creates an infinite
loop.
B Forward
ADD R2,R3, #4
ADD RO, R6, #2
ADD R3, R7, #4
Forward:
SUB Rl, R2, #4
Backward:
ADD Rl, R2, #4
SUB Rl, R2, #4
ADD R4, R6, R7
B Backward
Branches are used to change execution flow. Most assemblers hide the details of a branch instruction
encoding by using labels. In this example, forward and backward are the labels. The branch labels are placed at
the beginning of the line and are used to mark an address that can be used later by the assembler to calculate the
branch offset.
BL<suffix> <address>
BL is another branch instruction. This time, Link register R14 is loaded with the contents of R15 just
before the branch. You can reload R14 into R15 to return to the instruction after the branch - a primitive but
powerful implementation of a subroutine.
The branch with link, or BL, instruction is similar to the B instruction but overwrites the link register LR with a
return address. It performs a subroutine call. This example shows a simple fragment of code that branches to a
subroutine using the BL instruction. To return from a subroutine, you copy the link register to the pc.
ADDTION:
ADD Rl, R2, #4
SUB Rl, R2, #4
ADD R4, R6, R7
MOV PC,LR ; Return from subroutine by moving PC =LR
Syntax
BX{cond} Rm
where:
cond is an optional condition code (see Conditional execution).
Rm is an ARM register containing the address to branch to. Bit 0 of Rm is not used as part of the address.If bit
0 of Rm is set, the instruction sets the T flag in the CPSR, and the code at the destination is interpreted as Thumb
code.If bit 0 of Rm is clear, bit 1 must not be set.
The BX instruction is used to branch to a target address stored in a register, based on an optional condition. If bit
0 of the register is set to 1, then the processor will switch to Thumb execution. (Bit 0 is forced to 0 in before the
branch address is stored in the PC.) The sample code below shows a call to a Thumb subroutine
Examples 3.46:
ADR R0, sub ;get subroutine address
ORR R0, #1 ;Bit 0 of R0 is set to 1
MOV LR, PC ;load link register with PC (this address + 8)
BX R0 ;branch to Thumb subroutine
Syntax
BLX{cond} Rm
BLX label
where:
cond is an optional condition code (see Conditional execution).
Rm is an ARM register containing the address to branch to. Bit 0 of Rm is not used as part of the address.
If bit 0 of Rm is set, the instruction sets the T flag in the CPSR, and the code at the destination is
interpreted as Thumb code. If bit 0 of Rm is clear, bit 1 must not be set.
label
Note
BLX label cannot be conditional. BLX label always causes a change to Thumb state.
Usage
copies the address of the next instruction into R14 (LR, the link register)
o bit 0 of Rm is set
The machine-level BLX label instruction cannot branch to an address outside ±32Mb of the current instruction.
When necessary, the ARM linker adds code to allow longer branches (see The ARM linker chapter in ADS Linker
and Utilities Guide). The added code is called a veneer.
Examples 3.47:
BLX r2
BLXNE r0
BLX thumbsub
Incorrect example
Memory Locations
Let R0 = 0x00000002 0A 00
R1 = 0x00000004
0B 01
06 02
09 03
80 04
00 05
88 06
56 07
This instruction reads a half word from memory, and zero-extends it to 32-bits in the register. See the
section Miscellaneous Load/Store Addressing Modes for a description of the available addressing modes.
Examples 3.49:
LDRH R0, [R1] ; R0 = zero-extended memory [R1]
Memory Locations
0A 00
0B 01
Let R0 = 0x00000002
06 02
R1 = 0x00000004
09 03
80 04
22 05
Half Word 88 06
R0 = 0 x 0000 2280
R1 = 0 x 0000 0004
Zero Extended bits[31:16]
Example 3.50:
LDRB R0, [R1] ; R0 = memory [R1] (zero-extended)
Memory Locations
Let R0 = 0x00000002 0A 00
R1 = 0x00000004
0B 01
06 02
09 03
Byte 80 04
22 05
After LDRB R0,[R1]
88 06
R0 = 0x 000000 80 56 07
R1 = 0x 000000 04
Zero Extended bits [31:8]
Example 3.51:
The LDRSB instruction reads a byte from memory, and sign-extends it to 32-bits in the register. See the section
Miscellaneous Load/Store Addressing Modes for a description of the available addressing modes.
Let R0 = 0x00000002 0A 00
R1 = 0x00000004
0B 01
06 02
09 03
80 04
Byte
22 05
After LDRB R0,[R1]
88 06
R0 = 0x FFFFFF 80 56 07
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0
F F F F F F 8 0
Let R0 = 0x00000002 0A 00
R1 = 0x00000004
0B 01
06 02
09 03
80 04
22 05
After LDRB R0,[R1]
88 06
R0 = 0x 0000 2280 56 07
Memory Locations
Let R0 = 0x11223344 0A 00
R1 = 0x00000000
0B 01
06 02
09 03
80 04
00 05
88 06
56 07
R0 = 0x11223344 0A 00
R1 = 0x00000000
0B 01
Memory = [R1+4] 06 02
= 0x00000000 + 4 09 03
= 0x00000004
44 04
Word 33 05
R0 = 0x11223344
22 06
R1 = 0x00000000 11 07
Memory Locations
0A 00
Let R0 = 0x11223344
0B 01
R1 = 0x00000000 06 02
09 03
80 04
00 05
88 06
56 07
R0 = 0x11223344 0A 00
R1 = 0x00000000
0B 01
Memory = [R1+4] 06 02
= 0x00000000 + 4 09 03
= 0x00000004
44 04
Byte
00 05
R0 = 0x1122 33 44 LSB Byte
88 06
R1 = 0x0000 0000 56 07
Let R0 = 0x11223344 0A 00
R1 = 0x00000000
0B 01
06 02
09 03
80 04
00 05
88 06
56 07
After STRB R0,[R1,#4] Memory Locations
R0 = 0x11223344 0A 00
R1 = 0x00000000
0B 01
Memory = [R1+4] 06 02
= 0x00000000 + 2
09 03
= 0x00000002
80 04
00 05
56 07
R1 = 0x0000 0000
NOTE: The “!” following Rn controls the value of the write back bit (bit W), and signifies that Rn should be
updated with the ending address at the end of the instruction. If the “!” is not present (W=0), the value of Rn
will be unchanged at the end of the instruction.
Example 3.56.
1. LDMIA R7, {R0, R2-R4} ; R0 memory [R7]
; R2 memory [R7+4]
; R3 memory [R7+8]
; R4 memory [R7+12]
; R7 is unchanged
Memory Locations
Let R7 = 0x00000004 0A 00
R0 = 0x00000000 0B 01
06 02
R0 = 0x00000000 09 03
R0 = 0x00000000 80 04
R0 = 0x00000000 00 05
88 06
56 07
11 08
22 09
33 0A
44 0B
55 0C
66 0D
77 0E
00 0F
15 10
32 11
18 12
1B 13
R7 = 0x00000004 80 04[R7]
00 05
R0 = 0x56880080 88 06
56 07
11 08[R7+4]
22 09
R2 = 0x44332211 33 0A
44 0B
55 0C[R7+8]
66 0D
77 0E
R3 = 0x00776655
00 0F
15 10[R7+12]
32 11
R4 = 0x1B183215 18 12
1B 131133
Examples 3.57:
LDMDB R7!, {R0, R2-R4} ; R0 memory [R7-16]
; R2 memory [R7-12]
; R3 memory [R7-8]
; R4 memory [R7-4]
; R7 R7 - 16
Memory Locations
Let R7 = 0x00000013 80 04
R0 = 0x00000000
00 05
R2 = 0x00000000
R3 = 0x00000000 88 06
R4 = 0x00000000 56 07
11 08
22 09
33 0A
44 0B
55 0C
66 0D
77 0E
00 0F
15 10
32 11
18 12
1B 13
Let 23 00
09 01
R0 = 0x 45000923 00 02
45 03[R7-16] R7 = 0x00000003
80 04
00 05
R2 = 0x 56880080 88 06
56 07[R7-12]
11 08
22 09
R3 = 0x 44332211 33 0A
44 0B
55 0C[R7-8]
66 0D
R4 = 0x 00776655
77 0E
00 0F
15 10[R7-4]
32 11
18 12
1B 13
STM – Store Multiple
There are two distinct variants of the STM instruction. One of them is for use in conjunction with exception
processing, and is not described here. Further information can be obtained in the ARM Architecture Reference
Manual.
Syntax:
STM{<cond>}<addressing_mode>, <Rn>{!}, <registers>
:
if(cond)
start_address . Rn
for i = 0 to 15
if(register_list[i] == 1)
memory[next_address] . Ri
if(writeback)
Rn . end_address
Flags updated: None
The STM instruction permits block moves of registers to memory and enables efficient
stack operations. The registers may be listed in any order, but the registers are always
stored in order with the lowest numbered register going to the lowest memory address.
If Rn is also listed in the register list and register writeback (W bit) is set, the final value
stored for Rn can be unpredictable.
The addressing_mode field determines how next_address is calculated (bits P & W),
which control how the address is updated in conjunction with each register store. The
four addressing_mode values are;
IA - increment address by 4 after each load (post-increment)
IB - increment address by 4 before each load (pre-increment)
DA - decrement address by 4 after each load (post-decrement)
DB - decrement address by 4 before each load (pre-decrement)
NOTE: The “!” following Rn controls the value of the write back bit (bit W), and signifies
that Rn should be updated with the ending address at the end of the instruction. If the “!”
is not present (W=0), the value of Rn will be unchanged at the end of the instruction.
Example 3.58.
STMIA R7, {R0, R2-R4} ; memory [R7] R0
; memory [R7+4] R2
; memory [R7+8] R3
; memory [R7+12] R4
; R7 is unchanged
Memory Locations
Let R7 = 0x00000004 80 04
R0 = 0x000509A6 00 05
R2 = 0x0580C900 88 06
R3 = 0x02030405 56 07
R4 = 0x12131415 11 08
22 09
33 0A
44 0B
55 0C
66 0D
77 0E
00 0F
15 10
32 11
18 12
1B 13
After STMIA R7, {R0, R2-R4}
Memory Locations
Examples 3.59:
1. STMDB R7!, {R0, R2-R4} ; Memory [R7-4] R0
; Memory [R7-8] R2
; Memory [R7-12] R3
; Memory [R7-16] R4
; R7 [R7 – 16]
Let R7 = 0x00000013 00 03
R0 = 0x000509A6 A6 04
R2 = 0x0580C900 09 05
R3 = 0x02030405 05 06
R4 = 0x12131415 00 07
00 08
C9 09
80 0A
05 0B
05 0C
04 0D
03 0E
02 0F
15 10
14 11
13 12
12 13
After STMDB R7, {R0, R2-R4}
Memory Locations
44 00
80 02
R4 = 0x 15141312 09 02
11 03[R7-16] R7 = 0x00000003
12 04
13 05
R3 = 0x 05040302 14 06
15 07[R7-12]
02 08
03 09
R2 = 0x 00C98005 04 0A
05 0B[R7-8]
05 0C
80 0D
R0 = 0x A6090500
C9 0E
00 0F[R7-4]
00 10
05 11
09 12
A6 13[R7]
NOTE: When using a stack you have to decide whether the stack will grow up or down in memory. A stack is either
ascending(A) or descending(D). Ascending stacks grow towards higher memory addresses; in contrast, descending stacks
grow towards lower memory addresses.
When you use a full stack(F), the stack pointer SP points to an address that is the last used or full location (i.e., SP points to
the last item on the stack). In contrast, if you use an empty stack(E) the SP points to an address that is the first unused or
empty location (i.e., it points after the last item on the stack).
Push operation
Examples 3.60:
STMEA R13!, {R0, R2-R3, LR} ; memory [R13] R0
; memory [R13 +4] R2
; memory [R13+8] R3
; memory [R13 +12] R14
; R13(Sp) R13 + 16
Memory Locations
Let 00 03
R13(Sp) = 0x00000004 A6 04
R4 = 0x000509A6 09 05
R3 = 0x0580C900 05 06
R2 = 0x02030405 00 07
R0 = 0x12131415 00 08
C9 09
80 0A
05 0B
05 0C
04 0D
03 0E
02 0F
15 10
14 11
13 12
12 13
12 04
13 05
R0 = 0x 15131412 14 06
15 07
02 08[R7+4]
03 09
R2 = 0x 05040302 04 0A
05 0B
05 0C[R7+8]
80 0D
R3 = 0x 00C98005 C9 0E
00 0F
00 10[R7+12]
05 11
LR=R14 = 0x A6090500
09 12
A6 13
Empty 14 Sp = 0x00000014
POP operation
Examples 3.61:
LDMEA R13!, {R0, R2-R3, PC} ; R0 memory [R13 -4]
; R2 memory [R13 -8]
; R3 memory [R13 -12]
; PC memory [R13 -16]
; R13 (Sp) [R13 – 16]
Let R13 = 0x00000014 80 04
R0 = 0x00000000 00 05
88 06
R2 = 0x00000000 56 07
R3 = 0x00000000 11 08
PC = 0x00000000 22 09
33 0A
44 0B
55 0C
66 0D
77 0E
00 0F
15 10
32 11
18 12
1B 13
empty 14
23 00
PC = 0x 45000923 09 01
00 02
45 03[R13-16] R13(Sp) =0 x00000003
80 04
00 05
R3 = 0x 56880080 88 06
56 07[R13-12]
11 08
22 09
R2 = 0x 44332211 33 0A
44 0B [R13-8]
55 0C
66 0D
R0 = 0x 00776655 77 0E
00 0F[R13-4]
15 10
32 11
18 12
1B 13
Empty 14
NOTE: This instruction is not reachable from the C language and is supported by intrinsic
Syntax: functions
withinSWP{<cond>}
the compiler<Rd>,
library.
<Rm>, [<Rn>]
:
if(cond)
temp [Rn]
[Rn] Rm
Rd temp
Flags updated: None
Examples 3.62:
SWP R0, R1, [R2] ; R0 = [R2]
; [R2] = R1
; R1 = unchanged
Syntax:
SWI {<cond>} <immediate_24>
:
If (cond)
R14_svc address of next instruction after SWI instruction
SPSR_svc CPSR ; save current CPSR
CPSR[4:0] 10011b ; supervisor mode
CPSR[5] 0 ; ARM execution
CPSR[7] 1 ; disable interrupts
PC 0x00000008 ; jump to exception vector
Flags updated: N/A
Examples 3.63:
The SWI instruction causes a SWI exception. The processor disables interrupts, switches to ARM
execution if previously in Thumb, and enters supervisory mode. Execution starts at the SWI exception address.
The 24-bit immediate value is ignored by the instruction, but the value in the instruction can be
determined by the exception handler if desired. Parameters can also be passed to the SWI handler in
general-purpose registers or memory locations.
Here we have a simple example of an SWI call with SWI number 0x123456, used by ARM toolkits as a
debugging SWI. Typically the SWI instruction is executed in user mode.
PRE
CPSR = n z c V q i f t_USER
PC = 0x00008000
LR = 0x003FFFFF; LR = Rl4
R0 = 0x12
POST
CPSR = n z c Vq l f t_SVC
SPSR = n z c Vq I f t _USER
PC = 0x00000008 LR = 0x00008604
R0 = 0x12
Since SWI instructions are used to call operating system routines, you need some form of parameter
passing. This is achieved using registers. In this example, register rO is used to pass the parameter 0x12. The
return values are also passed back via registers.
Description:
The ADR pseudo-instruction assembles to a single ADD or SUB instruction, normally with the PC as an
operand. This produces position-independent code. The assembler will report an error if it cannot create a valid
instruction to load the address. If the label is program-relative, it must be in the same assembler area as the ADR
instruction. (The ADRL pseudo-instruction can reach a wider address range.)
Description:
The ADRL pseudo-instruction will always generate a two-instruction sequence to load the address of the
given label into the destination register, giving it a wider target range than the ADR instruction. The code is
position-independent. The assembler will report an error if it cannot create a valid instruction sequence. (The
LDR pseudo-instruction with a label argument can reach any address.)
Description:
ASR is a synonym for the MOV instruction with an ASR-shifted register operand. If an immediate shift
count is used, it is limited to the range 1-32. If Rm is not included, the assembler will assume it is the same as Rd.
Description:
The LDR pseudo-instruction will generate an instruction to load the destination register with the desired
value.
The <expression> field must evaluate to a numeric constant. If the constant is an allowable immediate
expression (or the complement of one), a MOV or MVN instruction will be generated. If it is not, the assembler
will place the value in a memory location, and generate a PC-relative load instruction to load it from that memory
location. If a label is specified, the assembler will generate a local memory location to store the label address, and
include the appropriate linker directives so that the correct address will be in that location after linking.
Description:
LSR is a synonym for the MOV instruction with an LSR shifter operand. If an immediate shift count is
used, it is limited to the range 1-32. If Rm is not included, the assembler will assume it is the same as Rd.
NOP – No Operation
Syntax:
NOP
Description:
There are numerous ways to encode a NOP (no operation) instruction for the ARM7TDMI processor,
such as adding 0 to a register, ORing a register with 0, branching to the next instruction, etc. The actual encoding
of the NOP is assembler-dependent.
POP - Pop
Syntax:
POP {cond} reg_list
Description:
POP is a pseudonym for the LDMIA instruction, with R13! specified for the base register (Rn). The
PUSH/POP instructions assume a full-descending (FD) stack organization.
PUSH - Push
Syntax:
PUSH {cond} reg_list
Description:
PUSH is a pseudonym for the STMDB instruction, with R13! Specified for the base register (Rn). The
PUSH/POP instructions assume a full-descending (FD) stack organization.
Programming Examples:
Program 3.2: — Divide a 32 bit binary no by a 16 bit binary no store the quotient and remainder there is no ’DIV’
instruction in ARM!
Program 3.3: — Add two packed BCD numbers to give a packed BCD result
Program 3.6:— Scan a series of 32 bit numbers to find how many are negative
Program 3.7: — Scan a series of 16 bit numbers to find how many are negative
21 Digit
22 DCD &0C ; the hex digit
23
24 AREA Data2, DATA
25 Result DCD 0 ; storage for result
26
27 END
Program 3.12: — Convert a 32 bit hexadecimal number to an ASCII string and output to the terminal
Program 6.8: factorial.s—Lookup the factorial from a table by using the address of the memory location
1 * Lookup the factorial from a table by
2 * using the address of the memory location
3
4 TTL factorial
5 AREA Program, CODE, READONLY
6 ENTRY
7
8 Main
9 LDR R0, =DataTable ; load the address of the lookup table
10 LDR R1, Value ; offset of value to be looked up
11 MOV R1, R1, LSL#0x2 ; data is declared as 32bit - need
12 ; to quadruple the offset to point at the
13 ; correct memory location
14 ADD R0, R0, R1 ; R0contains memory address to store
15 LDR R2, [R0]
16 ADR R3, Result ; the address to store the answer
17 STR R2, [R3] ; store the answer
18
19 SWI &11
20
21 AREA DataTable, DATA
22
23 DCD 1 ; 0! = 1; the data table containing the
factorials
24 DCD 1 ; 1! = 1
25 DCD 2 ; 2! = 2
26 DCD 6 ; 3! = 6
27 DCD 24 ; 4! = 24
28 DCD 120 ; 5! = 120
29 DCD 720 ; 6! = 720
30 DCD 5040 ; 7! = 5040
31 Value DCB 5
32 ALIGN
33 Result DCW 0
34
35
Divide the least significant byte of the 8-bit variable Value into two 4-bit nibbles and store one nibble in each byte
of the 16-bit variable Result. The low-order four bits of the byte will be stored in the low-order four bits of the
least significant byte of Result. The high-order four bits of the byte will be stored in the low-order four bits of the
most significant byte of Result.
Sample Problems
Input: Value = 5F
Output: Result = 050F
Program 6.5: splitbyte.s — Disassemble a byte into its high and low order nibbles
1 * Disassemble a byte into its high and low order nibbles
2
3 TTL split byte
4 AREA Program, CODE, READONLY
5 ENTRY
6
7 Main
8 LDR R1, Value ; Load the value to be disassembled
9 LDR R2, Mask ; Load the bitmask
10 MOV R3, R1, LSR#0x4 ; Copy just the high order nibble into R3
11 MOV R3, R3, LSL#0x8 ; now left shift it one byte
12 AND R1, R1, R2 ; AND the number with the bitmask
13 ADD R1, R1, R3 ; Add the result of that to
14 ; what we moved into R3
15 STR R1, Result ; Store the result
16 SWI &11
17
18 Value DCB &FB ; Value to be shifted
19 ALIGN ; keep the memory boundaries
20 Mask DCW &000F ; bitmask = %0000000000001111
21 ALIGN
22 Result DCD 0 ; Space to store result
23 END
64-Bit Adition
Add the contents of two 64-bit variables Value1 and Value2. Store the result in Result.
Sample Problems
Input: Value1 = 12A2E640, F2100123
Value2 = 001019BF, 40023F51
Output: Result = 12B30000, 32124074
Program 6.7: 64bitadd.s — 64 bit addition
1 * 64 bit addition
2
3 TTL 64bitadd
4 AREA Program, CODE, READONLY
5 ENTRY
6
7 Main
8 ADR R0, Value1 ; Pointer to first value
9 LDMIA R0, {R1, R2} ; Load the value to be added
10 ADR R0, Value2 ; Pointer to second value
11 LDMIA R0, {R3, R4} ; Load the value to be added
12 ADDS R6, R2, R4 ; Add lower 4 bytes and set carry flag
13 ADC R5, R1, R3 ; Add upper 4 bytes including carry
14 ADR R0, Result ; Pointer to Result
15 STMIA R0, {R5, R6} ; Store the result
16 SWI &5
17 SWI &11
18
19 Value1 DCD &12A2E640, &F2100123 ; Value to be added
20 Value2 DCD &001019BF, &40023F51 ; Value to be added
21 Result DCD 0 ; Space to store result
22 END
Chapter 4:
Introduction to THUMB Instruction Set
Introduction:
Thumb is:a compressed, 16-bit representation of a subset of the ARM instruction set
– Primarily to increase code density
– also increases performance in some cases
It is not a complete architecture
All ‘Thumb-aware’ cores also support the ARM instruction set
– Therefore the Thumb architecture need only support common functions
The Thumb bit
The ‘T’ bit in the CPSR controls the interpretation of the instruction stream
switch from ARM to Thumb (and back) by executing BX instruction
exceptions also cause switch to ARM code
return symmetrically to ARM or Thumb code
Note: do not change the T bit with MSR
The THUMB instruction set does not contain MSR and MRS instructions, so you can only indirectly
affect the CPSR and SPSR. If you need to modify any user bits in the CPSR you must change to ARM mode. You
can change modes by using the BX and BLX instructions. Also, when you come out of RESET, or enter an
exception mode, you will automatically change to ARM mode.
After Reset the ARM7 will execute ARM (32-bit) instructions. The instruction set can be exchanged at
any time using BX or BLX. If an exception occurs the execution is automatically forced to ARM (32- bit)
The THUMB instruction set has the more traditional PUSH and POP instructions for stack manipulation.
They implement a fully descending stack, hardwired to R13. The THUMB instruction set has dedicated PUSH and
POP instructions which implement a descending stack using R13 as a stack pointer
One of the most important features of the ARM9 CPU is its ability to run 16 bit THUMB code and 32 bit
ARM code. In order to get a reasonably complex application to fit into the on-chip FLASH memory, it is very
important to interwork these two instruction sets so that most of the application code is encoded in the THUMB
instruction set and is effectively compressed to take minimal space in the on-chip FLASH memory. Any time
critical routines where the full processing power of the ARM9 is required need to be encoded in the ARM 32 bit
instruction set.When generating the code, the compiler must be enabled to allow interworking. This is achieved
with the following switch:
m-THUMB-interwork
The GCC compiler is designed to compile a given C module in either the THUMB or ARM instruction
set. Therefore you must lay out your source code so that each module only contains functions that will be encoded
as ARM or THUMB functions. By default the compiler will encode all source code in the ARM instruction set. To
force a module to be encoded in the THUMB instruction set, use the following directive when you compile the
code:
-mTHUMB
The linker can then take both ARM and THUMB object files and produce a final executable that
interworks both instruction sets.
• T (Thumb)-extension shrinks the ARM instruction set to 16-bit word length -> 35-40% saving in
amount of memory compared to 32-bit instruction set
• Extension enables simpler and significantly cheaper realization of processor system. Instructions take
only half of memory than with 32-bit instruction set without significant decrease in performance or
increase in code size.
• Extension is made to instruction decoder at the processor pipeline
• Registers are preserved as 32-bit but only half of them are
Thumb extension
• Thumb-instruction decoder is placed in pipeline
• Change to Thumb-mode happens by turning the state of multiplexers feeding the instruction decoders
and data bus
• A1 selects the 16-bit half word from the 32-bit bus
Arithmetic instructions:
Addition instructions.
This group consists of the following instructions.
1. ADC Rd, Rs ; Rd= Rd + Rs + Carry bit
This instruction adds the content of Source register Rd and destination register Rs along with
carry bit and stores the result in destination register Rd.
2. ADD Rd, Rs, Rn ; Rd= Rn + Rs
This instruction adds the content of Source register Rd and destination register Rs and stores
the result in destination register Rd.
3. ADD Rd, Rn, #immediate ; Rd= Rn +#immediate value
This instruction adds the content of Source register Rd and destination register Rs and stores
the result in destination register Rd. immediate range is between 0-7.
Subtraction instructions.
This group consists of the following instructions.
1. SUB Rd, Rn, Rm ; Rd := Rn – Rm
This instruction subtracts the content of Rm from register Rn and stores the result in destination
register Rd. Flags affected are N Z C V. Immediate range 0-7.
2. SUB Rd, Rn, #<immed> ; Rd: = Rn – immed
This instruction subtracts the immediate value from register Rn and stores the result in
destination register Rd. Flags affected are N Z C V. Immediate range 0-7.
3. SUB Rd, #<immed> ; Rd: = Rd – immed
This instruction subtracts the immediate value from register Rd and stores the result in
destination register Rd. Flags affected are N Z C V. Immediate range 0-255.
4. SBC Rd, Rm N Z C V ; Rd: = Rd – Rm – NOT C-bit
This instruction subtracts the content of register Rm and complemented value of carry Bit
(Borrow) from register Rd and stores the result in destination register Rd. Flags affected are N Z C V.
5. SUB SP, #<immed> ; R13:= R13 – immed
This instruction subtracts the immediate value from the content of Stack pointer (SP) register
R13 and stores the result in SP (R13). Immediate range 0-508 (word-aligned). Flags not affected.
6. NEG Rd, Rm N Z C V ; Rd: = – Rm
This instruction performs the two’s complement of the content of Source register Rm. and stores
the result in Rd. Flags affected are N Z C V.
Multiplication instruction.
This group consists of the following instructions.
Compare instructions.
This group consists of the following instructions.
Logical instructions:
These include AND, OR, NOT, Exclusive -OR and Bit Clear instruction.
These include Logical shift left, logical shift right, arithmetic shift right and rotate instruction.
1. LSL Rd, Rm, #<shift> ; Rd := Rm << #shift
This instruction performs logical shift left operation by immediate shift value on the content of
Rm and stores the result in destination register Rd. Flags affected are N Z and C. Immediate shift value is
between 0-31. C flag unaffected if shift is 0.
2. LSL Rd, Rs ; Rd := Rd << Rs[7:0]
This instruction performs logical shift left operation by the shift value stored in the register Rm
and stores the result in destination register Rd. Flags affected are N Z and C.
C flag unaffected if shift is 0.
3. LSR Rd, Rm, #<shift> N Z C ; Rd := Rm >> shift
This instruction performs logical shift right operation by the immediate shift value
and stores the result in destination register Rd. Flags affected are N Z and C. Immediate shift value is
between 1-32.
4. LSR Rd, Rs ; Rd := Rd >> Rs[7:0]
This instruction performs logical shift right operation by the shift value stored in the register Rs
and stores the result in destination register Rd. Flags affected are N Z and C. C flag unaffected if shift is
0.
5. ASR Rd, Rm, #<shift> ; Rd := Rm ASR #immediate value
This instruction performs Arithmetic shift right operation by the immediate shift value on the
content of register Rm and stores the result in destination register Rd. Flags affected are N Z and C.
Immediate shift value is between 1-32.
6. ASR Rd, Rs ; Rd := Rd ASR shift Rs[7:0]
This instruction performs Arithmetic shift right operation by the shift value stored in the register
Rs on the content of register Rd and stores the result in destination register Rd. Flags affected are N Z and
C. C flag unaffected if shift is 0
7. ROR Rd, Rs ; Rd := Rd ROR Rs[7:0]
This instruction performs Rotate the content of register Rd towards right by the value stored in
Rs and stores the result in destination register Rd. Flags affected are N Z and C. C flag unaffected if rotate
is 0.
Move instructions:
Load instructions:
Store instructions:
Push/Pop Instructions
Branching instructions.
5.1 Fields:
Assembly language instructions (or “statements”) are divided into a number of “fields”. The operation
code field is the only field which can never he empty; it always contains either an instruction mnemonic or a
directive to the assembler, sometimes called a “pseudo-instruction,” “pseudo-operation,” or “pseudo-op.”The
operand or address field may contain an address or data, or it may be blank. The comment and label fields are
optional. A programmer will assign a label to a statement or add a comment as a personal convenience: namely, to
make the program easier to read and use. Of course, the assembler must have some way of telling where one field
ends and another begins. Assemblers often require that each field start in a specific column. This is a “fixed
format.” However, fixed formats are inconvenient when the input medium is paper tape; fixed formats are also a
nuisance to programmers. The alternative is a “free format” where the fields may appear anywhere on the line.
5.1.1 Delimiters:
If the assembler cannot use the position on the line to tell the fields apart, it must use something else.
Most assemblers use a special symbol or “delimiter” at the beginning or end of each field.
Whitespace Between label and operation code, between operation code and address,and before an
entry in the comment field
Comma Between operands in the address field
Asterisk Before an entire line of comment
Semicolon Marks the start of a comment on a line that contains preceding code
The most common delimiter is the space character. Commas, periods, semicolons, colons, slashes,
question marks, and other characters that would not otherwise be used in assembly language programs also may
serve as delimiters. The general form of layout for the ARM assembler is: You will have to exercise a little care
with delimiters. Some assemblers are fussy about extra spaces or the appearance of delimiters in comments or
labels. A well-written assembler will handle these minor problems, but many assemblers are not well-written. Our
recommendation is simple: avoid potential problems if you can. The following rules will help:
• Do not use extra spaces, in particular, do not put spaces after commas that separate
operands, even though the ARM assembler allows you to do this.
• Do not use delimiter characters in names or labels.
• Include standard delimiters even if your assembler does not require them. Then it will be
more likely that your programs are in correct form for another assembler.
5.1.2 Labels:
The label field is the first field in an assembly language instruction; it may be blank. If a label is present,
the assembler defines the label as equivalent to the address into which the first byte of the object code generated
for that instruction will be loaded. You may subsequently use the label as an address or as data in another
instruction’s address field. The assembler will replace the label with the assigned value when creating an object
program.
The ARM assembler requires labels to start at the first character of a line. However, some other
assemblers also allow you to have the label start anywhere along a line, in which case you must use a colon (:) as
the delimiter to terminate the label field. Colon delimiters are not used by the ARM assembler. Labels are most
frequently used in Branch or SWI instructions. These instructions place a new value in the program counter and so
alter the normal sequential execution of instructions. B 15016 means “place the value 15016 in the program
counter.” The next instruction to be executed will be the one in memory location 15016. The instruction B
START means “place the value assigned to the label START in the program counter.” The next instruction to be
executed will be the on at the address corresponding to the label START. Figure 2.1 contains an example.
Why use a label? Here are some reasons:
When the machine language version of this program is executed, the instruction BAL START causes the
address of the instruction labeled START to be placed in the program counter That instruction will then be
executed.
• The assembler can relocate the whole program by adding a constant (a “relocation constant”) to
each address in which a label was used. Thus we can move the program to allow for the insertion of
other programs or simply to rearrange memory.
• The program is easier to use as a library program; that is, it is easier for someone else to take your
program and add it to some totally different program.
• You do not have to figure out memory addresses. Figuring out memory addresses is particularly
difficult with microprocessors which have instructions that vary in length.
You should assign a label to any instruction that you might want to refer to later.
The next question is how to choose a label. The assembler often places some restrictions on the number
of characters (usually 5 or 6), the leading character (often must be a letter), and the trailing characters (often must
be letters, numbers, or one of a few special characters). Beyond these restrictions, the choice is up to you.
Our own preference is to use labels that suggest their purpose, i.e., mnemonic labels. Typical examples
are ADDW in a routine that adds one word into a sum, SRCHETX in a routine that searches for the ASCII
character ETX, or NKEYS for a location in data memory that contains the number of key entries. Meaningful
labels are easier to remember and contribute to program documentation. Some programmers use a standard
format for labels, such as starting with L0000. These labels are self-sequencing (you can skip a few numbers to
permit insertions), but they do not help document the program.
Some label selection rules will keep you out of trouble. We recommend the following:
• Do not use labels that are the same as operation codes or other mnemonics. Most assemblers will not
allow this usage; others will, but it is confusing.
• Do not use labels that are longer than the assembler recognises. Assemblers have various rules, and
often ignore some of the characters at the end of a long label.
• Avoid special characters (non-alphabetic and non-numeric) and lower-case letters. Some assemblers
will not permit them; others allow only certain ones. The simplest practice is to stick to capital letters
and numbers.
• Start each label with a letter. Such labels are always acceptable.
• Do not use labels that could be confused with each other. Avoid the letters I, O, and Z and the numbers
0, 1, and 2. Also avoid things like XXXX and XXXXX. Assembly programming is difficult enough
without tempting fate or Murphy’s Law.
• When you are not sure if a label is legal, do not use it. You will not get any real benefit
from discovering exactly what the assembler will accept.
Note: These are recommendations, not rules. You do not have to follow them but don’t blame us if you
waste time on unnecessary problems.
5.3 Directives:
Some assembly language instructions are not directly translated into machine language instructions.
These instructions are directives to the assembler; they assign the program to certain areas in memory, define
symbols, designate areas of memory for data storage, place tables or other fixed data in memory, allow references
to other programs, and perform minor housekeeping functions.
To use these assembler directives or pseudo-operations a programmer places the directive’s mnemonic
in the operation code field, and, if the specified directive requires it, an address or data in the address field.
The most common directives are:
DEFINE CONSTANT (Data)
EQUATE (Define)
AREA
DEFINE STORAGE (Reserve)
ENTRY
Different assemblers use different names for those operations but their functions are the same.
Housekeeping directives include:
We will discuss these pseudo-operations briefly, although their functions are usually obvious.
VTECH DCW 12
will place the number 12 in the next available memory location and assign that location the name BNG. Every DC
directive usually has a label, unless it is one of a series. The data and label may take any form that the assembler
permits.
More elaborate define constant directives that handle a large amount of data at one time are provided, for
example:
VTECH DCB ’ERROR’
SQRS DCW 1,4,9,16,25
A single directive may fill many bytes of program memory, limited perhaps by the length of a line or by
the restrictions of a particular assembler. Of course, you can always overcome any restrictions by following one
define constant directive with another:
MSG DCB " NOW IS THE”
DCB “TIME FOR ALL”
DCB “TO GO WITH VT”
DCB " TO GAIN THE”
DCB “KNOWLEDGE”
DCB “STATE ", 0 ; note the ’0’ terminating the string
Microprocessor assemblers typically have some variations of standard define constant directives. Define
Byte or DCB handles 8-bit numbers; Define Word or DCW handles 32-bit numbers or addresses. Other special
directives may handle character-coded data. The ARM assembler also defines DCD to (Define Constant Data)
which may be used in place of DCW.
When do you use a name? The answer is: whenever you have a parameter that you might want to change
or that has some meaning besides its ordinary numeric value. We typically assign names to time constants, device
addresses, masking patterns, conversion factors, and the like. A name like DELAY, HERE, KBD, KROW, or
OPEN not only makes the parameter easier to change, but it also adds to program documentation. We also assign
names to memory locations that have special purposes; they may hold data, mark the start of the program, or be
available for intermediate storage.
What name do you use? The best rules are much the same as in the case of labels, except that here
meaningful names really count. Why not call the teletypewriter TTY instead of X15, a bit time delay BTIME or
BTDLY rather than WW, the number of the “GO” key on a keyboard GOKEY rather than HORSE? This advice
seems straightforward, but a surprising number of programmers do not follow it.
Where do you place the EQUATE directives? The best place is at the start of the program, under
appropriate comment headings such as i/o addresses, temporary storage, time constants, or program locations.
This makes the definitions easy to find if you want to change them. Furthermore, another user will be able to look
up all the definitions in one centralized place. Clearly this practice improves documentation and makes the
program easier to use.
Definitions used only in a specific subroutine should appear at the start of the subroutine.
These are recommendations, not rules. You do not have to follow them but don’t blame us if you waste
time on unnecessary problems.
The AREA directive allows the programmer to specify the memory locations where programs,
subroutines, or data will reside. Programs and data may be located in different areas of memory depending on the
memory configuration. Startup routines interrupt service routines, and other required programs may be scattered
around memory at fixed or convenient addresses.
The assembler maintains a location counter (comparable to the computer’s program counter) which
contains the location in memory of the instruction or data item being processed. An area directive causes the
assembler to place a new value in the location counter, much as a Jump instruction causes the CPU to place a new
value in the program counter. The output from the assembler must not only contain instructions and data, but must
also indicate to the loader program where in memory it should place the instructions and data.
Microprocessor programs often contain several AREA statements for the following purposes:
• Reset (startup) address • Stack
• Interrupt service addresses • Main program
• Trap (software interrupt) addresses • Subroutines
• RAM storage • Input/output
Still other origin statements may allow room for later insertions, place tables or data in memory, or
assign vacant memory space for data buffers. Program and data memory in microcomputers may occupy widely
separate addresses to simplify the hardware. Typical origin statements are:
AREA RESET
AREA $1000
AREA INT3
The assembler will assume a fake address if the programmer does not put in an AREA statement. The AREA
statement at the start of an ARM program is required, and its absence will cause the assembly to fail.
The ENTRY directive indicates the point in the code where program execution should begin. There
should be only ONE entry point per complete program. Note that in developing the software for an embedded
system, execution will begin at the reset vector, so the code entry point will be determined by what code is linked
at that address and the ENTRY directive is not used.
It is good practice to enter numbers in the base in which their meaning is the clearest: that is, decimal
constants in decimal; addresses and BCD numbers in hexadecimal; masking patterns or bit outputs in
hexadecimal.
5.4.3 Names:
Names can appear in the operand field; they will be treated as the data that they represent. Remember,
however, that there is a difference between operands and addresses. In an ARM assembly language program the
sequence:
FIVE EQU 5
ADD R2, #FIVE
will add the contents of memory location FIVE (not necessarily the number 5) to the contents of data register R2.
We have made some recommendations during this section but will repeat them and add others here. In
general, the user should strive for clarity and simplicity. There is no payoff for being an expert in the intricacies of
an assembler or in having the most complex expression on the block.
We suggest the following approach:
• Use the clearest number system or character code for data.
• Masks and BCD numbers in decimal, ASCII characters in octal, or ordinary numerical
constants in hexadecimal serve no purpose and therefore should not be used.
• Remember to distinguish data from addresses.
• Don’t use offsets from the location counter.
• Keep expressions simple and obvious. Don’t rely on obscure features of the assembler.
5.5 Comments:
All assemblers allow you to place comments in a source program. Comments have no effect on the
object code, but they help you to read, understand, and document the program. Good commenting is an essential
part of writing computer programs, programs without comments are very difficult to understand. We will discuss
commenting along with documentation in a later chapter, but here are some guidelines:
• Use comments to tell what application task the program is performing, not how the
microcomputer executes the instructions.
• Comments should say things like “is temperature above limit?”, “linefeed to TTY,” or “examine load
switch.”
• Comments should not say things like “add 1 to Accumulator,” “jump to Start,” or “look at carry.” You
should describe how the program is affecting the system; internal effects on the CPU should be
obvious from the code.
• Keep comments brief and to the point. Details should be available elsewhere in the documentation.
• Comment all key points.
• Do not comment standard instructions or sequences that change counters or pointers; pay special
attention to instructions that may not have an obvious meaning.
• Do not use obscure abbreviations.
• Make the comments neat and readable.
• Comment all definitions, describing their purposes. Also mark all tables and data storage areas.
• Comment sections of the program as well as individual instructions.
• Be consistent in your terminology. You can (should) be repetitive, you need not consult a thesaurus.
• Leave yourself notes at points that you find confusing: for example, “remember carry was set by last
instruction.” If such points get cleared up later in program development, you may drop these
comments in the final documentation. A well-commented program is easy to use. You will recover the
time spent in commenting many times over. We will try to show good commenting style in the
programming examples, although we often over-comment for instructional purposes.
5.7 Errors:
Assemblers normally provide error messages, often consisting of an error code number. Some typical
errors are:
Undefined name often a misspelling or an omitted definition
Illegal character such as a 2 in a binary number
Illegal format wrong delimiter or incorrect operands
Invalid expression for example, two operators in a row
Illegal value usually too large
Missing operand
Double definition two different values assigned to one name
Illegal label such as a label on a pseudo-operation that cannot have one
Missing label
Undefined operation code
In interpreting assembler errors, you must remember that the assembler may get on the wrong track if it
finds a stray letter, an extra space, or incorrect punctuation. The assembler will then proceed to misinterpret
the succeeding instructions and produce meaningless error messages. Always look at the first error very
carefully; subsequent ones may depend on it. Caution and consistent adherence to standard formats will
eliminate many annoying mistakes.
5.8 Loaders:
The loader is the program which actually takes the output (object code) from the assembler and places it
in memory. Loaders range from the very simple to the very complex. We will describe a few different types.
A bootstrap loader is a program that uses its own first few instructions to load the rest of itself or another
loader program into memory. The bootstrap loader may be in ROM, or you may have to enter it into the
computer memory using front panel switches. The assembler may place bootstrap loader at the start of the
object program that it produces.
A relocating loader can load programs anywhere in memory. It typically loads each program into the
memory space immediately following that used by the previous program. The programs, however, must
themselves be capable of being moved around in this way; that is, they must be relocatable. An absolute
loader, in contrast, will always place the programs in the same area of memory.
A linking loader loads programs and subroutines that have been assembled separately; it resolves
cross-references — that is, instructions in one program that refer to a label in another program. Object programs
loaded by a linking loader must be created by an assembler that allows external references. An alternative
approach is to separate the linking and loading functions and have the linking performed by a program called a
link editor and the loading done by a loader.
5.6 Subroutines
None of the examples that we have shown thus far is a typical program that would stand by itself. Most
real programs perform a series of tasks, many of which may be used a number of times or be common to other
programs. The standard method of producing programs which can be used in this manner is to write subroutines
that perform particular tasks. The resulting sequences of instructions can be written once, tested once, and then
used repeatedly.
There are special instructions for transferring control to subroutines and restoring control to the main program.
We often refer to the special instruction that transfers control to a subroutine as Call, Jump, or Brach to a
Subroutine. The special instruction that restores control to the main program is usually called Return.
In the ARM the Branch-and-Link instruction (BL) is used to Branch to a Subroutine. This saves the
current value of the program counter (PC or R15) in the Link Register (LR or R14) before placing the starting
address of the subroutine in the program counter. The ARM does not have a standard Return from Subroutine
instruction like other processors, rather the programmer should copy the value in the Link Register into the
Program Counter in order to return to the instruction after the Branch-and-Link instruction. Thus, to return from a
subroutine you should the instruction:
MOV PC, LR
Should the subroutine wish to call another subroutine it will have to save the value of the Link Register before
calling the nested subroutine.
In this approach, all parameters are passed and results are returned on the stack.
The stack grows downward (toward lower addresses). This occurs because elements are pushed onto the stack
using the pre-decrement address mode. The use of the pre-decrement mode causes the stack pointer to always
contain the address of the last occupied location, rather than the next empty one as on some other
microprocessors. This implies that you must initialise the stack pointer to a value higher than the largest address in
the stack area.
When passing parameters on the stack, the programmer must implement this approach as follows:
1. Decrement the system stack pointer to make room for parameters on the system stack, and store
them using offsets from the stack pointer, or simply push the parameters on the stack.
2. Access the parameters by means of offsets from the system stack pointer.
3. Store the results on the stack by means of offsets from the systems stack pointer.
4. Clean up the stack before or after returning from the subroutine, so that the parameters are removed
and the results are handled appropriately.
Regardless of which language a routine is written in, routines that make cross-calls to other modules
must observe standard conventions for passing arguments and results. For ARM processors, this convention is
called the “ARM Procedure Call Standard, or APCS”. In this chapter, we briefly introduce APCS and discuss its
role for passing and returning values in ARM assembly language and C routines.
The ARM Procedure Call Standard, or APCS, is a set of rules which governs calls between functions in
separately compiled or assembled code fragments. The APCS defines:
Constraints on the use of registers
Stack conventions
The format of a stack back-trace data structure
Argument passing and result returns
Support for the ARM shared library mechanism
The APCS standard consists of a family of variants. Each variant is exclusive, so that code which
conforms to one variant cannot be used with a code defined for another variant. Your choice of variant depends on
the following criteria:
Whether stack limit checking is explicit (performed by code) or implicit (performed by memory
management hardware).
Whether floating-point values are passed to floating-point registers.
Whether code is reentrant or non-reentrant.
To summarize:
a1-a4 are used to pass arguments to functions. a1 is also used to return integer results. These registers can be
corrupted by a called function.
v1-v5 are used as register variables. They must be preserved by called functions.
Sb, Sl, FP, IP, SP, LR, PC sometimes have a dedicated role in an APCS variant. In other words, some of these
registers can be used for other purposes while also strictly conforming to APCS standard. In some APCS variants,
a1
a2 Assembler function
C-Function a3
a4
Stack Area
EXAMPLE CODE
The following two program samples include C and assembly code versions:
EXAMPLE A
Assembly code: Add four integer arguments and return the result value.
EXPORT Add_ASM ; Declare Add_ASM as extern function
Add_ASM
ADD a1, a1, a2 ; a1 = 0, a2 = 5, a3 = 10, a4 = 15
ADD a1, a1, a3
ADD a1, a1, a4 ; a1 = return value (= 30)
MOV pc, lr
EXAMPLE B
Assembly code: Add six integer arguments and return the result value.
EXCEPTION HANDLING
An exception occurs when the normal flow of execution through a user program is diverted to allow the
processor to handle events generated by internal or external sources. Two examples of such events are:
— Externally-generated interrupts
— An attempt by the processor to execute an undefined instruction
When handling exceptions, the previous processor status must be preserved so that the execution of the
original user program can resume immediately after the appropriate execution routine is completed. The ARM
processor recognizes seven types of exceptions:
Reset Occurs when the CPU reset pin is asserted. This exception normally occurs
to signal a power-up, or to initiate a reset following CPU power-up. It is
therefore useful for initiating a “soft” reset.
Undefined Instruction Occurs if neither the CPU nor any attached coprocessor recognizes the
instruction currently being executed.
Software Interrupt A user-defined synchronous interrupt instruction which allows a program
running in User mode to request privileged operations that run in
Supervisor mode.
Pre-fetch Abort Occurs when the CPU attempts to execute an instruction which has been
pre-fetched from an illegal address. In this case, an illegal address is an
address that the memory management subsystem has determined is
inaccessible to the CPU in its current mode.
Data Abort Occurs when a data transfer instruction attempts to load or store data at an
illegal address.
IRQ Occurs when the CPU’s external interrupt request pin is asserted (Low)
and the I bit in the CPSR is clear.
FIQ Occurs when the CPU’s external fast interrupt request pin is asserted
(Low) and the F bit in the CPSR is clear.
Address Exception Mode on entry I state on entry F state on entry
0x00000000 Reset Supervisor Set Set
0x00000004 Undefined instruction Undefined Set Unchanged
0x00000008 Software interrupt Supervisor Set Unchanged
0x0000000C Prefetch Abort Abort Set Unchanged
0x00000010 Data Abort Abort Set Unchanged
0x00000014 Reserved Reserved - -
0x00000018 IRQ IRQ Set Unchanged
0x0000001C FIQ FIQ Set Set
The following table provides an overview of ARM exceptions and how they are processed.
Prefered return
Exception Priority Status Mode FIQ IRQ Vector
instruction
Reset 1 Not available Supervisor Disabled Disabled Base+0 Not available
Data Access 2 SPSR_abt=CPSR Abort Unchanged Disabled Base+16 SUBS PC,R14_abt,#8
Memory Abort
(Data Abort)
Fast Interrupt 3 SPSR_fiq=CPSR FIQ Disabled Disabled Base+28 SUBS PC,R14_fiq,#4
(FIQ)
Normal Interrupt 4 SPSR_irq=CPSR IRQ Unchanged Disabled Base+24 SUBS PC,R14_irq,#4
(IRQ)
Instruction Fetch 5 SPSR_abt=CPSR Abort Unchanged Disabled Base+12 SUBS PC,R14_abt,#4
Memory Abort
(Prefetch Abort)
Software 6 SPSR_svc=CPSR Supervisor Unchanged Disabled Base+8 MOVS PC,R14_svc
Interrupt (SWI)
Undefined 6 SPSR_und=CPSR Undefined Unchanged Disabled Base+4 MOVS PC,R14_und
Instruction
Note
2: The normal vector base address is 0x00000000. Some implementations allow the vector base address to be
moved to 0xFFFF0000.
3: When the instruction at the breakpoint causes a prefetch abort, then the abort request is handled first. When the
abort handler fixes the abort condition and returns to the aborted instruction, then the debug request is handled.
5: PC is the address of the instruction that did not get executed after the interrupt occured.
6: PC is the address of the SWI, BKPT or undefined instruction or the instruction that had the prefetch abort.
7: Intentionally the FIQ vector is placed at the end of the vector table. No additional branch is required. The
handler can directly start at this location.
8: This re-executes the aborted instruction. If this is not intended, use SUBS PC,R14_abt,#4 instead.
Interrupts
There are two types of interrupts available on ARM processor. The first type is the interrupt caused by
external events from hardware peripherals and the second type is the SWI
instruction.
The ARM core has only one FIQ pin, that is why an external interrupt controller is always used so that
the system can have more than one interrupt source which are prioritized with this interrupt controller and then the
FIQ interrupt is raised and the handler identifies which of the external interrupts was raised and handle it.
3.1 How are interrupts assigned?
It is up to the system designer who can decide which hardware peripheral can produce which interrupt
request. By using an interrupt controller we can connect multiple external interrupts to one of the ARM interrupt
requests and distinguish between them
.There is a standard design for assigning interrupts adopted by system designers:
• SWIs are normally used to call privileged operating system routines.
• IRQs are normally assigned to general purpose interrupts like periodic timers.
• FIQ is reserved for one single interrupt source that requires fast response time, like DMA or any time
critical task that requires fast response.
User Stack
Heap
Code Heap
Vector Table
Vector Table
The first is the traditional stack layout. The second layout has the advantage that when overflow occurs, the vector
table remains untouched so the system has the chance to correct itself.
Disable
Interrupt
Save
Context
Interrupt
Handler
ISR
Restore Context
Resume to
Task Enable Interrupts
In this handling scheme handling more than one interrupt at a time is possible. This is achieved by
re-enabling interrupts before the handler has fully served the current interrupt. This feature increases the
complexity of the system but improves the latency. The scheme should be designed carefully to protect the
context saving and restoration from being interrupted. The designer should balance between efficiency and safety
by using defensive coding style that assumes problems will occur. The goal of nested handling is to respond to
interrupts quickly and to execute periodic tasks without any delays. Re-enabling interrupts requires switching out
of the IRQ mode to user mode to protect link register from being corrupted. Also performing context switch
requires emptying the IRQ stack because the handler will not perform switching if there is data on the IRQ stack,
so all registers saved on the IRQ stack have to be transferred to task stack. The part of the task stack used in this
process is called stack frame.
The main disadvantage of this interrupt handling scheme is that it doesn’t differ between interrupts by
priorities, so lower priority interrupt can block higher priority interrupts.
Disable
Save
Context
Interrupt
Handler
Interrupt
Prepare stack.
Switch mode.
Restore Context Construct a frame.
Enable interrupts.
Resume to
Task
Complete serving Interrupt
interrupt
Interrupt
In this scheme the handler will associate a priority level with a particular interrupt source. A higher
priority interrupt will take precedence over a lower priority interrupt. Handling prioritization can be done by
means of software or hardware. In case of hardware prioritization the handler is simpler to design because the
interrupt controller will give the interrupt signal of the highest priority interrupt requiring service. But on the other
side the system needs more initialization code at start-up since priority level tables have to be constructed before
the system being switched on.
Figure 6 Priority Interrupt Handler
When an interrupt signal is raised, a fixed amount of comparisons with the available set of priority levels
is done, so the interrupt latency is deterministic but at the same point this could be considered a disadvantage
because both high and low priority interrupts take the same amount of time.
Inline assembly.
We can instruct the compiler to insert the code of a function into the code of its callers, to the point where
actually the call is to be made. Such functions are inline functions. Similar to a Macro.
Benefit of inline:
This method of in lining reduces the function-call overhead. And if any of the actual argument values are
constant, their known values may permit simplifications at compile time so that not all of the inline function’s
code needs to be included. The effect on code size is less predictable, it depends on the particular case. To declare
an inline function, we’ve to use the keyword inline in its declaration.
Now we are in a position to guess what inline assembly is. It’s just some assembly routines written as
inline functions. They are handy, speedy and very much useful in system programming. Our main focus is to
study the basic format and usage of (GCC) inline assembly functions. To declare inline assembly functions, we
use the keyword asm.
Inline assembly is important primarily because of its ability to operate and make its output visible on C
variables. Because of this capability, "asm" works as an interface between the assembly instructions and the "C"
program that contains it.
__asm{instruction[;instruction]}
Note: You cannot include comments.
__asm
{
...
instruction
...
}
You can use C or C++ comments anywhere in an inline assembly language block.
If you include multiple instructions on the same line, you must separate them with a semicolon (;). If you
use double quotes, you must enclose all the instructions within a single set of double quotes (").
If an instruction requires more than one line, you must specify the line continuation with the backslash
character (\).
For the multiple line format, you can use C or C++ comments anywhere in the inline assembly language
block. However, you cannot embed comments in a line that contains multiple instructions.
The comma (,) is used as a separator in assembly language, so C expressions with the comma operator
must be enclosed in parentheses to distinguish them:
__asm
{
ADD x, y, (f(), z)
}
An asm statement must be inside a C++ function. An asm statement can be used anywhere a C++
statement is expected.
Register names in the inline assembler are treated as C or C++ variables. They do not necessarily relate
to the physical register of the same name. If you do not declare the register as a C or C++ variable, the
compiler generates a warning.
Do not save and restore registers in inline assembler. The compiler does this for you. Also, the inline
assembler does not provide direct access to the physical registersIf registers other than CPSR and SPSR
are read without being written to, an error message is issued.
For example:
int f(int x)
{
__asm
{
STMFD sp!, {r0} // save r0 - illegal: read before write
ADD r0, x, 1
EOR x, r0, x
LDMFD sp!, {r0} // restore r0 - not needed.
}
return x;
}
The function must be written as:
int f(int x)
{
int r0;
__asm
{
ADD r0, x, 1
EOR x, r0, x
}
return x;
}
Restrictions on inline assembly operations:
There are a number of restrictions on the operations that can be performed in inline assembly code.
These restrictions provide a measure of safety, and ensure that the assumptions in compiled C and C++ code are
not violated in the assembled assembly code.
The inline assembler has the following restrictions:
• The inline assembler is a high-level assembler, and the code it generates might not always be exactly what you
write. Do not use it to generate more efficient code than the compiler generates. Use embedded assembler or
the ARM assembler armasm for this purpose.
• Some low-level features that are available in the ARM assembler armasm, such as branching and writing to
PC, are not supported.
• Label expressions are not supported.
• You cannot get the address of the current instruction using dot notation (.) or {PC}.
• The & operator cannot be used to denote hexadecimal constants. Use the 0x prefix instead. For example:
__asm { AND x, y, 0xF00 }
• The notation to specify the actual rotation of an 8-bit constant is not available in inline assembly language.
This means that where an 8-bit shifted constant is used,the C flag must be regarded as corrupted if the NZCV
flags are updated.
• You must not modify the stack. This is not necessary because the compiler automatically stacks and restores
any working registers as required. The compiler does not permit you to explicitly stack and restore work
registers.
Embedded assembler:
The ARM compiler enables you to include assembly code out-of-line, in one or more C or C++ function
definitions. Embedded assembler provides unrestricted, low-level access to the target processor, enables you to
use the C and C++ preprocessor directives, and gives easy access to structure member offsets.
#include <stdio.h>
__asm void my_strcpy(const char *src, char *dst)
{
loop
LDRB r2, [r0], #1
STRB r2, [r1], #1
CMP r2, #0
BNE loop
BX lr
}
int main(void)
{
const char *a = "Hello world!";
char b[20];
my_strcpy (a, b);
printf("Original string: '%s'\n", a);
printf("Copied string: '%s'\n", b);
return 0;
}
Example 7-1 String copy with embedded assembler
Note: This makes it possible to fall through to the next function, because the embedded assembler guarantees to
emit the __asm functions in the order you have defined them. However, inlined and template functions behave
differently
• __asm functions do not change the AAPCS rules that apply. This means that all calls between an __asm function
and a normal C or C++ function must adhere to the AAPCS, even though there are no restrictions on the assembly
code that an __asm function can use (for example, change state).
The following rules apply to calling C++ functions from C and assembly language:
• To call a global (non-member) C++ function, declare it extern "C" to give it C linkage.
• Member functions (both static and non-static) always have mangled names. You can determine the
mangled symbol by using decaof -sm on the object file that defines the function
• C++ inline functions cannot be called from C unless you ensure that the C++ compiler generates an
out-of-line copy of the function. For example, taking the address of the function results in an
out-of-line copy.
• Non-static member functions receive the implicit this parameter as a first argument in r0, or as a
second argument in r1 if the function returns a non int-like structure. Static member functions do not
receive an implicit this parameter.
Examples
Example:
Calling assembly language from C
#include <stdio.h>
extern void strcopy (char *d, char *s);
int main ()
{ char *srcstr = "First string - source ";
char *dststr = "Second string - destination ";
printf ("Before copying:\n");
printf (" %s\n %s\n", srcstr, dststr);
strcopy (dststr, srcstr);
printf ("After copying:\n");
printf (" %s\n %s\n", srcstr, dststr);
return (0);
}
The ARM assembly language module that implements the string copy subroutine:
Example 8-10
In assembly language:
This chapter provides basic rules we need to follow while programming ARM7 in ‘C’. We discuss data types,
symbols, declaring variables, defining labels, Unary operators, Binary operators, Addition, subtraction, Shift
operators, Relational operators ,Boolean operates and logical operators which widely used while programming.
The need to follow the below general rules for naming the symbol :
• Symbol names must be unique within their scope.
• Uppercase letters, lowercase letters, numeric characters, or the underscore character are legal symbol
names. Symbol names are case-sensitive, and all characters in the symbol name are significant.
• Numeric characters should not be used for the first character of symbol names, except in local labels.
• Symbols must not use the same name as built-in variable names or predefined symbol names.
• If you use the same name as an instruction mnemonic or directive, use double bars to delimit the
symbol name. For example: ||ASSERT|| The bars are not part of the symbol.
• You must not use the symbols |$a|, |$t|, |$t.x|, or |$d| as program labels. These are mapping symbols used
to mark the beginning of ARM, Thumb, ThumbEE, and data within the object file.
• Symbols beginning with the characters $v are mapping symbols that are related to VFP and might be
output when building for a target with VFP. You are recommended to avoid using symbols beginning
with $v in your source code.
If you have to use a wider range of characters in symbols, for example, when working with compilers,
use single bars to delimit the symbol name. For example:|.text| The bars are not part of the symbol. You
cannot use bars, semicolons, or newlines within the bars.
Variables
The value of a variable can be changed as assembly proceeds. Variables are local to the assembler. This means that
in the generated code or data, every instance of the variable has a fixed value.
Variables are of three types:
• Numerical
• Logical
• String.
The type of a variable cannot be changed.
The range of possible values of a numeric variable is the same as the range of possible values of a numeric
constant or numeric expression.
The possible values of a logical variable are {TRUE} or {FALSE}.
The range of possible values of a string variable is the same as the range of values of a string expression.
Use the GBLA, GBLL, GBLS, LCLA, LCLL, and LCLS directives to declare symbols representing variables, and
assign values to them using the SETA, SETL, and SETS directives.
8.2.1 Example
x SETA 100 ; Value of ‘x’ is 100
L1 MOV R1, #(x*2) ; in the object file, this is MOV R1, #200
x SETA 500 ; Value of ‘x’ is 500 only after this point.
; The previous instruction will always be MOV R1, #200
…
BNE L1 ; When the processor branches to L1, it executes
; MOV R1, #500
Numeric constants
These constants are 32-bit integers. Hay can be used as unsigned numbers in the range 0 to 232–1, or signed
numbers in the range –231 to 23 –1. But, the assembler will not differentiatebetween –n and 232–n. Relational
operators such as >= use the unsigned interpretation. This means that 0 > –1 is {FALSE}.EQU directive can be
used to define constants. Once the value of numeric constant is defined it cannot be changed. Expressions can be
defined by combining numeric constants and binary operators.
Assembly time substitution of variables
String variable can be used for a whole line of assembly language, or any part of a line. Use the variable with a $
prefix in the places where the value is to be substituted for the variable. The dollar character instructs the
assembler to substitute the string into the source code line before checking the syntax of the line. The assembler
faults if the substituted line is larger than the source line limit.
Numeric and logical variables can also be substituted. The current value of the variable is converted to a
hexadecimal string (or T or F for logical variables) before substitution.
Use a dot to mark the end of the variable name if the following character would be permissible in a symbol name.
You must set the contents of the variable before you can use it.
If you require a $ that you do not want to be substituted, use $$. This is converted to a single $.
You can include a variable with a $ prefix in a string. Substitution occurs in the same way as anywhere else.
Substitution does not occur within vertical bars, except that vertical bars within double quotes do not affect
substitution.
8.4.1 Example
;Substitution
GBLS v1
GBLS v2
GBLS here
GBLA count
;
count SETA 10
v1 SETS "a$$b$count" ; v1 now has value a$b0000000A
v2 SETS "abc"
here SETS "|xy$v2.z|" ; here now has value |xyabcz|
|C$$code| MOV r4,#16 ; but the label here is C$$code
A PC-relative expression is written in source code as the PC or a label combined with a numeric expression. It can
also be expressed in the form [PC, #number]. It is represented in the instruction as the PC value plus or minus a
numeric offset. The assembler calculates the required offset from the label and the address of the current
instruction. If the offset is too big, the assembler produces an error.
It is recommended to write PC-relative expressions using labels rather than PC because the value of PC depends
on the instruction set.
Note
• In ARM state, the value of the PC is the address of the current instruction plus 8 bytes.
• In Thumb state:
— For B, BL, CBNZ, and CBZ instructions, the value of the PC is the address of the current instruction plus 4
bytes.
— For all other instructions that use labels, the value of the PC is the address of the current instruction plus 4
bytes, with bit[1] of the result cleared to 0 to make it word-aligned.
8.5.1 Example
LDR r4, =data+4*n ; n is an assembly-time variable
; code
MOV pc, lr
Data DCD value_0
; N-1 DCD directives
DCD value_n ; data+4*n points here
; More DCD directives
Labels
Labels are symbols representing the memory addresses of instructions or data. The address can be PC-relative,
register-relative, or absolute. Labels are local to the source file unless you make them global using the EXPORT
directive.
The address given by a label is calculated during assembly. The assembler calculates the address of a label relative
to the origin of the section where the label is defined. A reference to a label within the same section can use the PC
plus or minus an offset. This is called PC-relative addressing.
Addresses of labels in other sections are calculated at link time, when the linker has allocated specific locations in
memory for each section.
Labels for PC-relative addresses
These represent the PC, plus or minus a numeric value. Use them as targets for branch instructions, or to access
small items of data embedded in code sections. You can define PC-relative labels using a label on an instruction or
on one of the data definition directives.
You can also use the section name of an AREA directive as a label for PC-relative addresses. In this case the label
points to the first byte of the specified AREA. Using AREA names as branch targets is not recommended because
when branching from ARM to Thumb state or Thumb to ARM state in this way, the processor does not change the
state properly.
Labels for register-relative addresses
These represent a named register plus a numeric value. T hey are most often used to access data in data sections.
You can define them with a storage map. You can use the EQU directive to define additional register-relative
labels, based on labels defined in storage maps.
Example 8-1 Storage map definitions
MAP 0, r9
MAP 0xff, r9
Local labels
Local labels are a subclass of label. A local label is a number in the range 0-99, optionally followed by a name.
Unlike other labels, a local label can be defined many times and the same number can be used for more than one
local label in an area.
Local labels do not appear in the object file. This means that, for example, a debugger cannot set a breakpoint
directly on a local label, like it can for labels kept using the KEEP directive.
A local label can be used in place of symbol in source lines in an assembly language module:
• On its own, that is, where there is no instruction or directive
• On a line that contains an instruction
• On a line that contains a code- or data-generating directive.
A local label is generally used where you might use a PC-relative label.
Local labels are typically used for loops and conditional code within a routine, or for small subroutines that are
only used locally. They are particularly useful when you are generating labels in macros.
The scope of local labels is limited by the AREA directive. Use the ROUT directive to limit the scope of local
labels more tightly. A reference to a local label refers to a matching label within the same scope. If there is no
matching label within the scope in either direction, the assembler generates an error message and the assembly
fails.
You can use the same number for more than one local label even within the same scope. By default, the assembler
links a local label reference to:
• The most recent local label of the same number, if there is one within the scope
• The next following local label of the same number, if there is not a preceding one within the
scope. Use the optional parameters to modify this search pattern if required.
If neither F nor B is specified, the assembler searches backwards first, then forwards.
If neither A nor T is specified, the assembler searches all macros from the current level to the top level, but does
not search lower level macros.
If routname is specified in either a label or a reference to a label, the assembler checks it against the name of the
nearest preceding ROUT directive. If it does not match, the assembler generates an error message and the
assembly fails.
String expressions
String expressions consist of combinations of string literals, string variables, string manipulation operators, and
parentheses.
Characters that cannot be placed in string literals can be placed in string expressions using the : CHR: unary
operator. Any ASCII character from 0 to 255 is permitted.
The value of a string expression cannot exceed 5120 characters in length. It can be of zero length.
8.12.1 Example
improb SETS "vasundhara": CC :( strvar2: LEFT: 4)
; sets the variable improb to the value "vasundhara" with the left-most four characters
of
; The contents of string variable strvar2 appended
String literals
String literals consist of a series of characters or spaces contained between double quote characters. The length of
a string literal is restricted by the length of the input line.
To include a double quote character or a dollar character within the string literal, include the character twice as a
pair. For example, you must use $$ if you require a single $ in the string.
C string escape sequences are also enabled and can be used within the string, unless --no_esc is specified.
8.13.1 Examples
abc SETS "this string contains only one "" double quote"
def SETS "this string contains only one $$ dollar symbol"
Numeric expressions
Numeric expressions consist of combinations of numeric constants, numeric variables, ordinary numeric literals,
binary operators, and parentheses.
Numeric expressions can contain register-relative or program-relative expressions if the overall expression
evaluates to a value that does not include a register or the PC.
Numeric expressions evaluate to 32-bit integers. You can interpret them as unsigned numbers in the range 0 to
232–1, or signed numbers in the range –231 to 231–1. However, the assembler
makes no distinction between –n and 232–n. Relational operators such as >= use the unsigned interpretation. This
means that 0 > –1 is {FALSE}.
8.14.1 Example
x SETA 256*256 ; 256*256 is a numeric expression
MOV r1, #(x*22) ; (x*22) is a numeric expression
Numeric literals
Numeric literals can take any of the following forms:
decimal-digits
0xhexadecimal-digits
&hexadecimal-digits
n_base-n-digits
'character'
where:
decimal-digits Is a sequence of characters using only the digits 0 to 9.
hexadecimal-digits Is a sequence of characters using only the digits 0 to 9 and the letters A to F or a to f.
character Is any single character except a single quote. Use the standard C escape character (\') if you require a
single quote. The character must be enclosed within opening and closing single quotes. In this case the value of the
numeric literal is the numeric code of the character.
You must not use any other characters. The sequence of characters must evaluate to an integer in the range 0 to
232–1 (except in DCQ and DCQU directives, where the range is 0 to 264–1).
8.15.1 Examples
Logical expressions
Logical expressions consist of combinations of logical literals ({TRUE} or {FALSE}), logical variables, Boolean
operators, relations, and parentheses.
Relations consist of combinations of variables, literals, constants, or expressions with appropriate relational
operators.
Logical literals
The logical or boolean literals can have one of two values:
• {TRUE}
• {FALSE}.
Unary operators
Unary operators have the highest precedence and are evaluated first. A unary operator precedes its operand.
Adjacent operators are evaluated from right to left.
Table 8-2 lists the unary operators that return numeric values.
Binary operators
Binary operators are written between the pair of sub-expressions they operate on.
Binary operators have lower precedence than unary operators. Binary operators appear in this section in order of
precedence.
Note
The order of precedence is not the same as in C.
Multiplicative operators
Multiplicative operators have the highest precedence of all binary operators. They act only on numeric
expressions.
Table 8-3 shows the multiplicative operators.
* A*B Multiply
/ A/B Divide
:MOD: % A:MOD:B A modulo B
String manipulation operators
Table 8-4 shows the string manipulation operators. In CC, both A and B must be strings. In the
slicing operators LEFT and RIGHT:
• A must be a string
• B must be a numeric expression.
Shift operators
Shift operators act on numeric expressions, shifting or rotating the first operand by the amount specified by the
second.
Table 8-5 shows the shift operators.
Note
SHR is a logical shift and does not propagate the sign bit.
Relational operators
Table 8-7 shows the relational operators. These act on two operands of the same type to produce a logical value.
The operands can be one of:
• numeric
• PC-relative
• register-relative
• strings.
Strings are sorted using ASCII ordering. String A is less than string B if it is a leading substring of string B, or if
the left-most character in which the two strings differ is less in string A than in string B.
Arithmetic values are unsigned, so the value of 0>-1 is {FALSE}.
Boolean operators
These are the operators with the lowest precedence. They perform the standard logical operations on their
operands.
In all three cases both A and B must be expressions that evaluate to either {TRUE} or {FALSE}.
Table 8-8 shows the Boolean operators.
Operator precedence
The assembler includes an extensive set of operators for use in expressions. Many of the operators resemble their
counterparts in high-level languages such as C.
There is a strict order of precedence in their evaluation:
1. Expressions in parentheses are evaluated first.
2. Operators are applied in precedence order.
3. Adjacent unary operators are evaluated from right to left.
4. Binary operators of equal precedence are evaluated from left to right.
For example, (1 + 2: SHR: 3) evaluates as (1 + (2: SHR: 3)) = 1 in armasm. The equivalent expression in C
evaluates as ((1 + 2) >> 3) = 0.
You are recommended to use brackets to make the precedence explicit.
If your code contains an expression that would parse differently in C, and you are not using the --unsafe option,
armasm normally gives a warning:
A1466W: Operator precedence means that expression would evaluate differently in C
Table 8-9 shows the order of precedence of operators in armasm, and a comparison with the order in C
(see Table 8-10).
From these tables:
• The highest precedence operators are at the top of the list.
• The highest precedence operators are evaluated first.
• Operators of equal precedence are evaluated from left to right.
Table 8-9 Operator precedence in armasm
armasm precedence equivalent C operators
unary operators unary operators
* / :MOD: */%
string manipulation n/a
:SHL: :SHR: :ROR: :ROL: << >>
+ - :AND: :OR: :EOR: +-&|^
= > >= < <= /= <> == > >= < <= !=
:LAND: :LOR: :LEOR: && ||
16-bit/32-bit ARM7 microcontroller in a tiny LQFP64 package.8 kB to 40 kB of on-chip static RAM and 32 kB to
512 kB of on-chip flash memory.128-bit wide interface/accelerator enables high-speed 60 MHz operation.
In-System Programming/In-Application Programming (ISP/IAP) via on-chip boot loader Software. Single flash
sector or full chip erase in 400 ms and programming of 256 bytes in 1 ms.Embedded ICE RT and Embedded
Trace interfaces offer real-time debugging with the On-chip Real Monitor software and high-speed tracing of
instruction execution.USB 2.0 Full-speed compliant device controller with 2 kB of endpoint RAM. In addition,
the LPC2146/48 provides 8 kB of on-chip RAM accessible to USB by DMA. One or two 10-bit ADCs provide a
total of 6/14 Analog inputs, with conversion times as low as 2.44 µs per channel. Single 10-bit DAC provides
variable analog output .Two 32-bit timers/external event counters (with four capture and four compare Channels
each), PWM unit (six outputs) and watchdog. Low power Real-Time Clock (RTC) with independent power and
32 kHz clock input. Multiple serial interfaces including two UARTs (16C550), two Fast I 2C-bus (400 kbit/s),SPI
and SSP with buffering and variable data length capabilities. Vectored Interrupt Controller (VIC) with
configurable priorities and vector addresses. Up to 45 of 5 V tolerant fast general purpose I/O pins in a tiny
LQFP64 package. Up to 21 external interrupt pins available. 60 MHz maximum CPU clock available from
programmable on-chip PLL with settling time of 100 µs.On-chip integrated oscillator operates with an external
crystal from 1 MHz to 25 MHz.Power saving modes include idle and Power-down. Individual enable/disable of
peripheral functions as well as peripheral clock scaling for additional power optimization. Processor wake-up
from Power-down mode via external interrupt or BOD. Single power supply chip with POR and BOD circuits:
CPU operating voltage range of 3.0 V to 3.6 V (3.3 V ± 10 %) with 5 V tolerant I/O pads.
This chapter explains about the LPC2148 peripherals in details. Here we discuss in details about Pin connect
block, different GPIO registers, working of ADC, DAC with example program. We also look into the details of
RTC, PWM, SPI and General purpose timers/external event counters
Allows individual pin configuration. The purpose of the Pin connect block is to configure the microcontroller pins
to the desired functions.
Description
The pin connect block allows selected pins of the microcontroller to have more than one function. Configuration
registers control the multiplexers to allow connection between the pin and the on chip peripherals.
Peripherals should be connected to the appropriate pins prior to being activated, and prior to any related
interrupt(s) being enabled. Activity of any enabled peripheral function that is not mapped to a related pin should
be considered undefined.
Selection of a single function on a port pin completely excludes all other functions otherwise available on the
same pin.
The only partial exception from the above rule of exclusion is the case of inputs to the A/D converter. Regardless
of the function that is selected for the port pin that also hosts the A/D input, this A/D input can be read at any time
and variations of the voltage level on this pin will be reflected in the A/D readings. However, valid analog
reading(s) can be obtained if and only if the function of an analog input is selected. Only in this case proper
interface circuit is active in between the physical pin and the A/D module. In all other cases, a part of digital logic
necessary for the digital function to be performed will be active, and will disrupt proper behavior of the A/D.
Register description
Reset value reflects the data stored in used bits only. It does not include reserved bits content.
PINSEL0 Pin function select register 0. Read/Write 0x0000 0000 0xE002 C000
PINSEL1 Pin function select register 1. Read/Write 0x0000 0000 0xE002 C004
The PINSEL0 register controls the functions of the pins as per the settings listed in Table 40. The direction control
bit in the IO0DIR register is effective only when the GPIO function is selected for a pin. For other functions,
direction is controlled automatically.
31:30 29:28 27:26 25:24 23:22 21:20 19:18 17:16 15:14 13:12 11:10 9:8 7:6 5:4 3:2 1:0
P0.15 P0.14 P0.13 P0.12 P0.11 P0.10 P0.9 P0.8 P0.7 P0.6 P0.5 P0.4 P0.3 P0.2 P0.1 P0.0
Table 37. Pin function Select register 0 (PINSEL0 - address 0xE002 C000) bit description
The PINSEL1 register controls the functions of the pins as per the settings listed in following tables. The direction
control bit in the IO0DIR register is effective only when the GPIO function is selected for a pin. For other
functions direction is controlled automatically.
Bit Symbol Value Function Reset Value
00 GPIO P0.16
1.0 P0.16 01 EINT0 0
10 Capture 0.2 (Timer 0)
11 Match 0.2 (Timer 0)
00 GPIO Port 0.17
3.2 P0.17 01 Capture 1.2 (Timer 1) 0
10 SCK1 (SSP)
11 Match 1.2 (Timer 1)
5.4 P0.18 00 GPIO Port 0.18 0
01 Capture 1.3 (Timer 1)
10 MISO1 (SSP)
11 Match 1.3 (Timer 1)
00 GPIO Port 0.19
7.6 P0.19 01 Match 1.2 (Timer 1) 0
10 MOSI1 (SSP)
11 Capture 1.2 (Timer 1)
00 GPIO Port 0.20
9.8 P0.20 01 Match 1.3 (Timer 1) 0
10 SSEL1 (SSP)
11 EINT3
00 GPIO Port 0.21
11:10 P0.21 01 PWM5 0
10 AD1.6
11 Capture 1.3 (Timer 1)
00 GPIO Port 0.22
13:12 P0.22 01 AD1.7 0
10 Capture 0.0 (Timer 0)
11 Match 0.0 (Timer 0)
00 GPIO Port 0.23
15:14 P0.23 01 VBUS 0
10 Reserved
11 Reserved
00 GPIO Port 0.24
17:16 P0.24 01 Reserved 0
10 Reserved
11 Reserved
00 GPIO Port 0.25
19:18 P0.25 01 AD0.4 0
10 Aout(DAC)
11 Reserved
00 GPIO Port 0.26
21:20 P0.26 01 Reserved 0
10 Reserved
11 Reserved
00 GPIO Port 0.27
23:22 P0.27 01 Reserved 0
10 Reserved
11 Reserved
00 GPIO Port 0.28
25:24 P0.28 01 AD0.1 0
10 Capture 0.2 (Timer 0)
11 Match 0.2 (Timer 0)
00 GPIO Port 0.29
27:26 P0.29 01 AD0.2 0
10 Capture 0.3 (Timer 0)
11 Match 0.3 (Timer 0)
00 GPIO Port 0.30
29:28 P0.30 01 AD0.3 0
10 EINT3
11 Capture 0.0 (Timer 0)
00 GPIO Port 0.31
31:30 P0.31 01 UP_LED 0
10 CONNECT
11 Reserved
Table 38. Pin function Select register 1 (PINSEL1 - address 0xE002 C004) bit description
The PINSEL2 register controls the functions of the pins as per the settings listed in Table 39. The direction control
bit in the IO1DIR register is effective only when the GPIO function is selected for a pin. For other functions
direction is controlled automatically.
Note: use read-modify-write operation when accessing PINSEL2 register. Accidental write of 0 to bit 2
and/or bit 3 results in loss of debug and/or trace functionality! Changing of either bit 2 or bit 3 from 1 to 0 may
cause an incorrect code execution!
Reset value for bit 2 of PINSEL2 register will be inverse of the external state of the P1.26/RTCK. Reset value for
bit 2 will be set to 1 if P1.26/RTCK is externally pulled low and reset value for bit 2 will be set to 0 if there is no
pull-down.
Reset value for bit 3 of PINSEL2 register will be inverse of the external state of the P1.20/TRACESYNC. Reset
value for bit 3 will be set to 1 if P1.20/TRACESYNC IS externally pulled low and reset value for bit 3 will be set
to 0 if there is no pull-down.
Pins P1.31 thru 16 can be determined via hardware pins prior to de-asserting of reset.
Table 39. Pin function Select register 2 (PINSEL2 - 0xE002 C014) bit description
The PINSEL registers control the functions of device pins as shown below. Pairs of bits in these registers
correspond to specific device pins.
The direction control bit in the IO0DIR/IO1DIR register is effective only when the GPIO function is selected for
a pin. For other functions, direction is controlled automatically. Each derivative typically has a different pinout
and therefore a different set of functions possible for each pin. Details for a specific derivative may be found in the
appropriate data sheet.
Device pins that are not connected to a specific peripheral function are controlled by the GPIO registers. Pins may
be dynamically configured as inputs or outputs. Separate registers allow setting or clearing any number of outputs
simultaneously. The value of the output register may be read back, as well as the current state of the port pins.
• GPIO registers are relocated to the ARM local bus for the fastest possible I/O timing.
• Mask registers allow treating sets of port bits as a group, leaving other bits unchanged.
• All GPIO registers are byte addressable.
Features
Every physical GPIO port is accessible via either the group of registers providing an enhanced features and
accelerated port access or the legacy group of registers
Backward compatibility with other earlier devices is maintained with legacy registers
appearing at the original addresses on the APB bus
Applications
• General purpose I/O
• Driving LEDs, or other indicators
• Controlling off-chip devices
• Sensing digital inputs
Pin description
Register description
LPC2148 has two 32-bit General Purpose I/O ports. Total of 30 input/output and a single output only pin out of 32
pins are available on PORT0. PORT1 has up to 16 pins available for GPIO functions. PORT0 and PORT1 are
controlled via two groups of 4 registers namely
Function, Accessibility, reset value and port addresses of these registers are shown in Table 65 and Table 66.
The Legacy registers shown in Table 65 allow compatibility to work with earlier family devices, using existing
code. The functions and relative timing of older GPIO implementations is preserved.
The user must select whether a GPIO will be accessed via registers that provide enhanced features or a legacy set
of registers.While both of a port’s fast and legacy GPIO registers are controlling the same physical pins, these two
port control branches are mutually exclusive and operate independently. For example, changing a pin’s output via
a fast register will not be observable via the corresponding legacy register.
Generic Description Access Reset PORT0 PORT1
Name Value Address & Address &
Name Name
IOPIN GPIO Port Pin value register. The current state R/W NA 0xE002 8000 0xE002 8010
of the GPIO configured port pins can always be IO0PIN IO1PIN
read from this register, regardless of pin
direction.
IOSET GPIO Port Output Set register. This register R/W 0 0xE002 8004 0xE002 8014
controls the state of output pins in conjunction IO0SET IO1SET
with the IOCLR register. Writing ones produces
highs at the corresponding port pins. Writing
zeroes has no effect
IODIR GPIO Port Direction control register. This R/W 0 0xE002 8008 0xE002 8018
register individually controls the direction of IO0DIR IO1DIR
each port pin.
IOCLR GPIO Port Output Clear register. This register WO 0 0xE002 800C 0xE002 801C
controls the state of output pins. Writing ones IO0CLR IO1CLR
produces lows at the corresponding port pins
and clears the corresponding bits in the IOSET
register. Writing zeroes has no effect.
LPC2148 consists of five registers with enhanced GPIO features. They are
All of these registers are located directly on the local bus of the CPU for the fastest possible read and write timing.
An additional feature has been added that provides byte addressability of all GPIO registers. A mask register
allows treating groups of bits in a single GPIO port separately from other bits on the same port.
Table 66. GPIO register map (local bus accessible registers - enhanced GPIO features)
This word accessible register is used to control the direction of the pins when they are configured as GPIO port
pins. Direction bit for any pin must be set according to the pin functionality. LPC 2148 consists of two Legacy
registers namely IO0DIR and IO1DIR, and two enhanced GPIO function registers namely FIO0DIR and
FIO1DIR registers
Port0 consists of 32 bits named as 31:0.Thease bits are used Slow GPIO direction control.P0.0 is controlled by
bit0, P0.1 is controlled by bit1, and P0.2 is controlled by bit 2 and so on.
This port is symbolized as P0xDIR.Address of this port is 0xE002 8008. Upon reset this port will have a value
0x0000 0000
Port1 consists of 32 bits named as 31:0.Thease bits are used Slow GPIO direction control.P1.0 is controlled by
bit0, P1.1 is controlled by bit1, and P1.2 is controlled by bit 2 and so on.
This port is symbolized as P1xDIR.Address of this port is 0xE002 8018. Upon reset this port will have a value
0x0000 0000
Port0 consists of 32 bits named as 31:0.Thease bits are used for Fast GPIO direction control. P0.0 is controlled by
bit0, P0.1 is controlled by bit1, and P0.2 is controlled by bit 2 and so on.
Port1 consists of 32 bits named as 31:0.Thease bits are used for Fast GPIO direction control. P1.0 is controlled by
bit0, P1.1 is controlled by bit1, and P1.2 is controlled by bit 2 and so on.
If 0 is written to these bits they are configured as input ports.
This port is symbolized as FP1xDIR.Address of this port is 0x3FFF C020. Upon reset this port will have a value
0x0000 0000
Every fast GPIO port can also be controlled via several byte and half-word accessible registers rather than the
32-bit long and word only accessible FIODIR register, and these are listed in Table 71 and Table 72. These
additional registers allow easier and faster access to the physical port pins along with providing the same
functions as the FIODIR register.
Register
Register Reset
Length(bits) Address Description
Name value
& Access
FIO0DIR0 8(Byte) 0x3FFF C000 Fast GPIO Port 0 Direction control register 0. Bit 0x00
0 in FIO0DIR0, register corresponds to P0.0 ... bit
7 to P0.7.
FIO0DIR1 8(Byte) 0x3FFF C001 Fast GPIO Port 0 Direction control register 1. Bit 0x00
0 in FIO0DIR1, register corresponds to P0.8 ... bit
7 to P0.15.
FIO0DIR2 8(Byte) 0x3FFF C002 Fast GPIO Port 0 Direction control register 2. Bit 0x00
0 in FIO0DIR2, register corresponds to P0.16 ...
bit 7 to P0.23.
FIO0DIR3 8(Byte) 0x3FFF C003 Fast GPIO Port 0 Direction control register 3. Bit 0x00
0 in FIO0DIR3, register corresponds to P0.24 ...
bit 7 to P0.31.
FIO0DIRL 16(Half-Word) 0x3FFF C000 Fast GPIO Port 0 Direction control Lower half 0x00
word register. Bit 0 in FIO0DIRL, register
corresponds to P0.0 ... bit15 to P0.15.
FIO0DIRU 16(Half-Word) 0x3FFF C002 Fast GPIO Port 0 Direction control upper half 0x00
word register. Bit 0 in FIO0DIRU, register
corresponds to P0.16 ... bit 7 to P0.31.
Table 71. Fast GPIO port 0 Direction control byte and half-word accessible register description
Register
Register Reset
Length(bits) Address Description
Name value
& Access
FIO1DIR0 8(Byte) 0x3FFF C020 Fast GPIO Port 1 Direction control register 0. Bit 0x00
0 in FIO1DIR0, register corresponds to P0.0 ... bit
7 to P0.7.
FIO1DIR1 8(Byte) 0x3FFF C021 Fast GPIO Port 1 Direction control register 1. Bit 0x00
0 in FIO1DIR1, register corresponds to P0.8 ... bit
7 to P0.15.
FIO1DIR2 8(Byte) 0x3FFF C022 Fast GPIO Port 1 Direction control register 2. Bit 0x00
0 in FIO1DIR2, register corresponds to P0.16 ...
bit 7 to P0.23.
FIO1DIR3 8(Byte) 0x3FFF C023 Fast GPIO Port 1 Direction control register 3. Bit 0x00
0 in FIO1DIR3, register corresponds to P0.24 ...
bit 7 to P0.31.
FIO1DIRL 16(Half-Word) 0x3FFF C020 Fast GPIO Port 1 Direction control Lower half 0x00
word register. Bit 0 in FIO1DIRL, register
corresponds to P0.0 ... bit15 to P0.15.
FIO1DIRU 16(Half-Word) 0x3FFF C022 Fast GPIO Port 1 Direction control Upper half 0x00
word register. Bit 0 in FIO1DIRU, register
corresponds to P0.16 ... bit 7 to P0.31.
Table 72. Fast GPIO port 1 Direction control byte and half-word accessible register description
This register is available in the enhanced group of registers only. It is used to select ports pins that will and will not
be affected by a write accesses to the FIOPIN, FIOSET or FIOSLR register. Mask register also filters out port’s
content when the FIOPIN register is read.
A zero in this register’s bit enables an access to the corresponding physical pin via a read or write access. If a bit
in this register is one, corresponding pin will not be changed with write access and if read, will not be reflected in
the updated FIOPIN register.
LPC 2148 consists of two Mask registers namely FIO0MASK and FIO1MASK.
Port0 consists of 32 bits named as 31:0.Thease bits are used Fast GPIO physical pin access control.
If 0 is written to these bits Pin is affected by writes to the FIOSET, FIOCLR, and FIOPIN registers. Current state
of the pin will be observable in the FIOPIN register.
If 1 is written to these bits Physical pin is unaffected by writes into the FIOSET, FIOCLR and FIOPIN registers.
When the FIOPIN register is read, this bit will not be updated with the state of the physical pin.
This port is symbolized as FP0xMASK.Address of this port is 0x03FF C010. Upon reset this port will have a
value 0x0000 0000
Port0 consists of 32 bits named as 31:0.Thease bits are used Fast GPIO physical pin access control.
If 0 is written to these bits Pin is affected by writes to the FIOSET, FIOCLR, and FIOPIN registers. Current state
of the pin will be observable in the FIOPIN register.
If 1 is written to these bits Physical pin is unaffected by writes into the FIOSET, FIOCLR and FIOPIN registers.
When the FIOPIN register is read, this bit will not be updated with the state of the physical pin.
This port is symbolized as FP1xMASK.Address of this port is 0x03FF C030. Upon reset this port will have a
value 0x0000 0000
Every fast GPIO port can also be controlled via several byte and half-word accessible registers rather than the
32-bit long and word only accessible FIOMASK register, and these are listed in Table 75 and Table 76. These
additional registers allow easier and faster access to the physical port pins along with providing the same
functions as the FIOMASK register.
Register
Register Reset
Length(bits) Address Description
Name value
& Access
FIO0MASK0 8(Byte) 0x3FFF C010 Fast GPIO Port 0 Mask register 0. Bit 0 in 0x00
FIO0MASK0, register corresponds to P0.0 ... bit 7
to P0.7.
FIO0MASK1 8(Byte) 0x3FFF C011 Fast GPIO Port 0 Mask register 1. Bit 0 in 0x00
FIO0MASK 1, register corresponds to P0.8 ... bit
7 to P0.15.
FIO0MASK2 8(Byte) 0x3FFF C012 Fast GPIO Port 0 Mask register 2. Bit 0 in 0x00
FIO0MASK 2, register corresponds to P0.16 ... bit
7 to P0.23.
FIO0MASK3 8(Byte) 0x3FFF C013 Fast GPIO Port 0 Mask register 3. Bit 0 in 0x00
FIO0MASK 3, register corresponds to P0.24 ... bit
7 to P0.31.
FIO0MASKL 16(Half-Word) 0x3FFF C010 Fast GPIO Port 0 Mask Lower half- word register. 0x0000
Bit 0 in FIO0MASKL, register corresponds to
P0.0 ... bit15 to P0.15.
FIO0MASKU 16(Half-Word) 0x3FFF C012 Fast GPIO Port 0 Mask upper half word register. 0x0000
Bit 0 in FIO0MASKU, register corresponds to
P0.16 ... bit 7 to P0.31.
Table 75. Fast GPIO port 0 Mask byte and half-word accessible register description
Register
Register Reset
Length(bits) Address Description
Name value
& Access
FIO1MASK0 8(Byte) 0x3FFF C030 Fast GPIO Port 1 Mask register 0. Bit 0 in 0x00
FIO1MASK0, register corresponds to P0.0 ... bit 7
to P0.7.
FIO1MASK1 8(Byte) 0x3FFF C031 Fast GPIO Port 1 Mask register 1. Bit 0 in 0x00
FIO1MASK 1, register corresponds to P0.8 ... bit
7 to P0.15.
FIO1MASK2 8(Byte) 0x3FFF C032 Fast GPIO Port 1 Mask register 2. Bit 0 in 0x00
FIO1MASK 2, register corresponds to P0.16 ... bit
7 to P0.23.
FIO1MASK3 8(Byte) 0x3FFF C033 Fast GPIO Port 1 Mask register 3. Bit 0 in 0x00
FIO1MASK 3, register corresponds to P0.24 ... bit
7 to P0.31.
FIO1MASKL 16(Half-Word) 0x3FFF C030 Fast GPIO Port 1 Mask Lower half- word register. 0x0000
Bit 0 in FIO1MASKL, register corresponds to
P0.0 ... bit15 to P0.15.
FIO1MASKU 16(Half-Word) 0x3FFF C032 Fast GPIO Port 1 Mask upper half word register. 0x0000
Bit 0 in FIO1MASKU, register corresponds to
P0.16 ... bit 7 to P0.31.
Table 76. Fast GPIO port 0 Mask byte and half-word accessible register description
This register provides the value of port pins that are configured to perform only digital functions. The register will
give the logic value of the pin regardless of whether the pin is configured for input or output, or as GPIO or an
alternate digital function. As an example, a particular port pin may have GPIO input, GPIO output, UART
receive, and PWM output as selectable functions. Any configuration of that pin will allow its current logic state to
be read from the IOPIN register.
If a pin has an analog function as one of its options, the pin state cannot be read if the analog configuration is
selected. Selecting the pin as an A/D input disconnects the digital features of the pin. In that case, the pin value
read in the IOPIN register is not valid. Writing to the IOPIN register stores the value in the port output register,
bypassing the need to use both the IOSET and IOCLR registers to obtain the entire written value. This feature
should be used carefully in an application since it affects the entire port.
LPC 2148 consists of two Legacy registers namely IO0PIN and IO1PIN, and two enhanced GPIO function
registers namely FIO0PIN and FIO1PIN registers
Access to a port pins via the FIOPIN register is conditioned by the corresponding FIOMASK register Only pins
masked with zeros in the Mask register will be correlated to the current content of the Fast GPIO port pin value
register.
Port0 consists of 32 bits named as 31:0.Thease bits configured to perform only digital functions.
Port0 consists of 32 bits named as 31:0.Thease bits configured to perform only digital functions.
Port0 consists of 32 bits named as 31:0.Thease bits configured to perform only digital functions.
Port0 consists of 32 bits named as 31:0.Thease bits configured to perform only digital functions.
Every fast GPIO port can also be controlled via several byte and half-word accessible registers rather than the
32-bit long and word only accessible FIOPIN register, and these are listed in Table 81 and Table 82. These
additional registers allow easier and faster access to the physical port pins along with providing the same
functions as the FIOPIN register.
Register
Register Reset
Length(bits) Address Description
Name value
& Access
FIO0PIN0 8(Byte) 0x3FFF C014 Fast GPIO Port 0 PIN register 0. Bit 0 in 0x00
FIO0PIN0, register corresponds to P0.0 ... bit 7 to
P0.7.
FIO0PIN1 8(Byte) 0x3FFF C015 Fast GPIO Port 0 PIN register 1. Bit 0 in FIO0 0x00
PIN1, register corresponds to P0.8 ... bit 7 to
P0.15.
FIO0PIN2 8(Byte) 0x3FFF C016 Fast GPIO Port 0 PIN register 2. Bit 0 in FIO0 0x00
PIN2, register corresponds to P0.16 ... bit 7 to
P0.23.
FIO0PIN3 8(Byte) 0x3FFF C017 Fast GPIO Port 0 PIN register 3. Bit 0 in FIO0 0x00
PIN3, register corresponds to P0.24 ... bit 7 to
P0.31.
FIO0PINL 16(Half-Word) 0x3FFF C014 Fast GPIO Port 0 PIN Lower half- word register. 0x0000
Bit 0 in FIO0PINL, register corresponds to P0.0 ...
bit15 to P0.15.
FIO0PINU 16(Half-Word) 0x3FFF C016 Fast GPIO Port 0 PIN upper half word register. 0x0000
Bit 0 in FIO0PINU, register corresponds to P0.16
... bit 7 to P0.31.
Table 81. Fast GPIO port 0 Pin value byte and half-word accessible register description
Register
Register Reset
Length(bits) Address Description
Name value
& Access
FIO1PIN0 8(Byte) 0x3FFF C034 Fast GPIO Port 1 PIN register 0. Bit 0 in 0x00
FIO1PIN0, register corresponds to P0.0 ... bit 7 to
P0.7.
FIO1PIN1 8(Byte) 0x3FFF C035 Fast GPIO Port 1 PIN register 1. Bit 0 in FIO1 0x00
PIN1, register corresponds to P0.8 ... bit 7 to
P0.15.
FIO1PIN2 8(Byte) 0x3FFF C036 Fast GPIO Port 1 PIN register 2. Bit 0 in FIO0 0x00
PIN2, register corresponds to P0.16 ... bit 7 to
P0.23.
FIO1PIN3 8(Byte) 0x3FFF C037 Fast GPIO Port 1 PIN register 3. Bit 0 in FIO0 0x00
PIN3, register corresponds to P0.24 ... bit 7 to
P0.31.
FIO1PINL 16(Half-Word) 0x3FFF C034 Fast GPIO Port 0 PIN Lower half- word register. 0x0000
Bit 0 in FIO0PINL, register corresponds to P0.0 ...
bit15 to P0.15.
FIO0PINU 16(Half-Word) 0x3FFF C036 Fast GPIO Port 0 PIN upper half word register. 0x0000
Bit 0 in FIO0PINU, register corresponds to P0.16
... bit 7 to P0.31.
Table 82. Fast GPIO port 1 Pin value byte and half-word accessible register description
In order to produces a HIGH level at the corresponding port pins we need to write 1 to the corresponding pins.
If any pin is configured as an input or a secondary function, writing 1 to the corresponding bit in the IOSET has no
effect.
Reading the IOSET register returns the value of this register, as determined by previous writes to IOSET and
IOCLR (or IOPIN as noted above). This value does not reflect the effect of any outside world influence on the I/O
pins.
LPC 2148 consists of two Legacy registers namely IO0SET and IO1SET, and two enhanced GPIO function
registers namely FIO0SET and FIO1SET registers. Access to a port pins via the FIOSET register is conditioned
by the corresponding FIOMASK register.
Port0 consists of 32 bits named as 31:0.Thease bits are used Slow GPIO direction control.P0.0 is controlled by
bit0, P0.1 is controlled by bit1, and P0.2 is controlled by bit 2 and so on.
In order to produces a HIGH level at the corresponding port pins we need to write 1 to the corresponding pins.
Port1 consists of 32 bits named as 31:0.Thease bits are used Slow GPIO direction control.P1.0 is controlled by
bit0, P1.1 is controlled by bit1, and P1.2 is controlled by bit 2 and so on.
In order to produces a HIGH level at the corresponding port pins we need to write 1 to the corresponding pins.
This port is symbolized as P1xSET.Address of this port is 0xE002 8014. Upon reset this port will have a value
0x0000 0000
Port0 consists of 32 bits named as 31:0.Thease bits are used for Fast GPIO direction control. P0.0 is controlled by
bit0, P0.1 is controlled by bit1, and P0.2 is controlled by bit 2 and so on.
In order to produces a HIGH level at the corresponding port pins we need to write 1 to the corresponding pins.
This port is symbolized as FP0xSET.Address of this port is 0x3FFF C018. Upon reset this port will have a value
0x0000 0000
Port1 consists of 32 bits named as 31:0.Thease bits are used for Fast GPIO direction control. P1.0 is controlled by
bit0, P1.1 is controlled by bit1, and P1.2 is controlled by bit 2 and so on.
In order to produces a HIGH level at the corresponding port pins we need to write 1 to the corresponding pins.
This port is symbolized as FP1xSET.Address of this port is 0x3FFF C038. Upon reset this port will have a value
0x0000 0000
Every fast GPIO port can also be controlled via several byte and half-word accessible registers rather than the
32-bit long and word only accessible FIOSET register, and these are listed in Table 87 and Table 88. These
additional registers allow easier and faster access to the physical port pins along with providing the same
functions as the FIOSET register.
Register
Register Reset
Length(bits) Address Description
Name value
& Access
FIO0SETN0 8(Byte) 0x3FFF C018 Fast GPIO Port 0 SET register 0. Bit 0 in 0x00
FIO0SET0, register corresponds to P0.0 ... bit 7 to
P0.7.
FIO0SET1 8(Byte) 0x3FFF C019 Fast GPIO Port 0 SET register 1. Bit 0 in FIO0 0x00
SET1, register corresponds to P0.8 ... bit 7 to
P0.15.
FIO0SET2 8(Byte) 0x3FFF C01A Fast GPIO Port 0 SET register 2. Bit 0 in FIO0 0x00
SET2, register corresponds to P0.16 ... bit 7 to
P0.23.
FIO0SET3 8(Byte) 0x3FFF C01B Fast GPIO Port 0 SET register 3. Bit 0 in FIO0 0x00
SET3, register corresponds to P0.24 ... bit 7 to
P0.31.
FIO0SETL 16(Half-Word) 0x3FFF C018 Fast GPIO Port 0 SETLower half- word register. 0x0000
Bit 0 in FIO0SETL, register corresponds to P0.0
... bit15 to P0.15.
FIO0SETU 16(Half-Word) 0x3FFF C01A Fast GPIO Port 0 SET upper half word register. 0x0000
Bit 0 in FIO0SETU, register corresponds to P0.16
... bit 7 to P0.31.
Table 87. Fast GPIO port 0 output Set byte and half-word accessible register description
Register
Register Reset
Length(bits) Address Description
Name value
& Access
FIO1SETN0 8(Byte) 0x3FFF C038 Fast GPIO Port 1 SET register 0. Bit 0 in 0x00
FIO3SET0, register corresponds to P0.0 ... bit 7 to
P0.7.
FIO1SET1 8(Byte) 0x3FFF C039 Fast GPIO Port 1 SET register 1. Bit 0 in FIO1 0x00
SET1, register corresponds to P0.8 ... bit 7 to
P0.15.
FIO1SET2 8(Byte) 0x3FFF C03A Fast GPIO Port 1 SET register 2. Bit 0 in FIO1 0x00
SET2, register corresponds to P0.16 ... bit 7 to
P0.23.
FIO1SET3 8(Byte) 0x3FFF C03B Fast GPIO Port 1 SET register 3. Bit 0 in FIO1 0x00
SET3, register corresponds to P0.24 ... bit 7 to
P0.31.
FIO1SETL 16(Half-Word) 0x3FFF C038 Fast GPIO Port 1 SETLower half- word register. 0x0000
Bit 0 in FIO1SETL, register corresponds to P0.0
... bit15 to P0.15.
FIO1SETU 16(Half-Word) 0x3FFF C03A Fast GPIO Port 1 SET upper half word register. 0x0000
Bit 0 in FIO1SETU, register corresponds to P0.16
... bit 7 to P0.31.
Table 88. Fast GPIO port 1 output Set byte and half-word accessible register description
This register is used to produce a LOW level output at port pins configured as GPIO in an
OUTPUT mode.
In order to produces a LOW level at the corresponding port pins we need to write 1 to the corresponding pins.
If any pin is configured as an input or a secondary function, writing to IOCLR has no effect
Reading the IOSET register returns the value of this register, as determined by previous writes to IOSET and
IOCLR (or IOPIN as noted above). This value does not reflect the effect of any outside world influence on the I/O
pins.
LPC 2148 consists of two Legacy registers namely IO0SET and IO1SET, and two enhanced GPIO function
registers namely FIO0SET and FIO1SET registers. Access to a port pins via the FIOSET register is conditioned
by the corresponding FIOMASK register.
Port0 consists of 32 bits named as 31:0.Thease bits are used Slow GPIO direction control.P0.0 is controlled by
bit0, P0.1 is controlled by bit1, and P0.2 is controlled by bit 2 and so on.
In order to produces a LOW level at the corresponding port pins we need to write 1 to the corresponding pins.
Writing 0 has no effect.
This port is symbolized as P0xCLR.Address of this port is 0xE002 800C. Upon reset this port will have a value
0x0000 0000
In order to produces a Low level at the corresponding port pins we need to write 1 to the corresponding pins.
Writing 0 has no effect.
This port is symbolized as P1xCLR.Address of this port is 0xE002 801C. Upon reset this port will have a value
0x0000 0000
Port0 consists of 32 bits named as 31:0.Thease bits are used for Fast GPIO direction control. P0.0 is controlled by
bit0, P0.1 is controlled by bit1, and P0.2 is controlled by bit 2 and so on.
In order to produces a LOW level at the corresponding port pins we need to write 1 to the corresponding pins.
This port is symbolized as FP0xSET.Address of this port is 0x3FFF C01C. Upon reset this port will have a value
0x0000 0000
Port1 consists of 32 bits named as 31:0.Thease bits are used for Fast GPIO direction control. P1.0 is controlled by
bit0, P1.1 is controlled by bit1, and P1.2 is controlled by bit 2 and so on.
In order to produces a LOW level at the corresponding port pins we need to write 1 to the corresponding pins.
This port is symbolized as FP1xCLR.Address of this port is 0x3FFF C03C. Upon reset this port will have a value
0x0000 0000
Every fast GPIO port can also be controlled via several byte and half-word accessible registers rather than the
32-bit long and word only accessible FIOCLR register, and these are listed in Table 93 and Table 94. These
additional registers allow easier and faster access to the physical port pins along with providing the same
functions as the FIOSET register.
Register
Register Reset
Length(bits) Address Description
Name value
& Access
FIO0CLR0 8(Byte) 0x3FFF C01C Fast GPIO Port 0 CLR register 0. Bit 0 in FIO0 0x00
CLR 0, register corresponds to P0.0 ... bit 7 to
P0.7.
FIO0 CLR1 8(Byte) 0x3FFF C01D Fast GPIO Port 0 CLR register 1. Bit 0 in FIO0 0x00
CLR 1, register corresponds to P0.8 ... bit 7 to
P0.15.
FIO0CLR 2 8(Byte) 0x3FFF C01E Fast GPIO Port 0 CLR register 2. Bit 0 in FIO0 0x00
CLR 2, register corresponds to P0.16 ... bit 7 to
P0.23.
FIO0CLR3 8(Byte) 0x3FFF C01F Fast GPIO Port 0 CLR register 3. Bit 0 in FIO0 0x00
CLR 3, register corresponds to P0.24 ... bit 7 to
P0.31.
FIO0CLRL 16(Half-Word) 0x3FFF C01C Fast GPIO Port 0 CLR Lower half- word register. 0x0000
Bit 0 in FIO0 CLR L, register corresponds to P0.0
... bit15 to P0.15.
FIO0CLRU 16(Half-Word) 0x3FFF C01E Fast GPIO Port 0 CLR upper half word register. 0x0000
Bit 0 in FIO0 CLR U, register corresponds to
P0.16 ... bit 7 to P0.31.
Table 93. Fast GPIO port 0 output Set byte and half-word accessible register description
Register
Register Reset
Length(bits) Address Description
Name value
& Access
FIO1CLRN0 8(Byte) 0x3FFF C03C Fast GPIO Port 1 CLR register 0. Bit 0 in FIO3 0x00
CLR 0, register corresponds to P0.0 ... bit 7 to
P0.7.
FIO1CLR1 8(Byte) 0x3FFF C03E Fast GPIO Port 1 CLR register 1. Bit 0 in FIO1 0x00
CLR1, register corresponds to P0.8 ... bit 7 to
P0.15.
FIO1CLR2 8(Byte) 0x3FFF C03D Fast GPIO Port 1 CLR register 2. Bit 0 in 0x00
FIO1CLR2, register corresponds to P0.16 ... bit 7
to P0.23.
FIO1CLR3 8(Byte) 0x3FFF C03F Fast GPIO Port 1 CLR register 3. Bit 0 in 0x00
FIO1CLR3, register corresponds to P0.24 ... bit 7
to P0.31.
FIO1CLRL 16(Half-Word) 0x3FFF C03C Fast GPIO Port 1 CLR Lower half- word register. 0x0000
Bit 0 in FIO1CLRL, register corresponds to P0.0
... bit15 to P0.15.
FIO1CLRU 16(Half-Word) 0x3FFF C03E Fast GPIO Port 1 CLR upper half word register. 0x0000
Bit 0 in FIO1CLRU, register corresponds to P0.16
... bit 7 to P0.31.
Table 94. Fast GPIO port 0 output Set byte and half-word accessible register description
Example 1: sequential accesses to IOSET and IOCLR affecting the same GPIO pin/bit
State of the output configured GPIO pin is determined by writes into the pin’s port IOSET and IOCLR registers.
Last of these accesses to the IOSET/IOCLR register will determine the final output of a pin.
In case of a code:
P0.7 is configured as an output (write to IO0DIR register). After this, P0.7 output is set to low (first write to
IO0CLR register). Short high pulse follows on P0.7 (write access to IO0SET), and the final write to IO0CLR
register sets pin P0.7 back to low level.
Write access to port’s IOSET followed by write to the IOCLR register results with pins outputting 0s being
slightly later then pins outputting 1s. There are systems that can tolerate this delay of a valid output, but for some
applications simultaneous output of a binary content (mixed 0s and 1s) within a group of pins on a single GPIO
port is required. This can be accomplished by writing to the port’s IOPIN register.
Following code will preserve existing output on PORT0 pins P0. [31:16] and P0. [7:0] and at the same time set
P0.[15:8] to 0xA5, regardless of the previous value of pins P0.[15:8]:
IO0PIN = (IO0PIN && 0xFFFF00FF) || 0x0000A500
The same outcome can be obtained using the fast port access.
FIO0MASK = 0xFFFF00FF;
FIO0PIN = 0x0000A500;
FIO0MASKL = 0x00FF;
FIO0PINL = 0xA500;
FIO0PIN1 = 0xA5;
Write to the IOPIN register enables instantaneous output of a desired content on the parallel GPIO. Binary data
written into the IOPIN register will affect all output configured pins of that parallel port: 0s in the IOPIN will
produce low level pin outputs and 1s in IOPIN will produce high level pin outputs. In order to change output of
only a group of port’s pins, application must logically AND readout from the IOPIN with mask containing 0s in
bits corresponding to pins that will be changed and 1s for all others. Finally, this result has to be logically ORed
with the desired content and stored back into the IOPIN register. Example 2 from above illustrates output of 0xA5
on PORT0 pins 15 to 8 while preserving all other PORT0 output pins as they were before.
The enhanced features of the fast GPIO ports available on this microcontroller make GPIO pins more responsive
to the code that has task of controlling them. In particular, software access to a GPIO pin is 3.5 times faster via the
fast GPIO registers than it is when the legacy set of registers is used. As a result of the access speed increase, the
maximum output frequency of the digital pin is increased 3.5 times, too. This tremendous increase of the output
frequency is not always that visible when a plain C code is used, and a portion of an application handling the fast
port output might have to be written in an assembly code and executed in the ARM mode.
Here is a code where the pin control section is written in assembly language for ARM. It illustrates the difference
between the fast and slow GPIO port output capabilities.
Execution from the on-chip SRAM is independent from the MAM setup.
The LPC2148 each contain one SPI controller. The SPI is a full duplex serial interface, designed to handle
multiple masters and slaves connected to a given bus. Only a single master and a single slave can communicate on
the interface during a given data transfer. During a data transfer the master always sends a byte of data to the
slave, and the slave always sends a byte of data to the master.
Features
Figure 30 is a timing diagram that illustrates the four different data transfer formats that are available with the SPI.
This timing diagram illustrates a single 8 bit data transfer. The first thing you should notice in this timing diagram
is that it is divided into three horizontal parts. The first part describes the SCK and SSEL signals. The second part
describes the MOSI and MISO signals when the CPHA variable is 0. The third part describes the MOSI and
MISO signals when the CPHA variable is 1.
In the first part of the timing diagram, note two points. First, the SPI is illustrated with CPOL set to both 0 and 1.
The second point to note is the activation and de-activation of the SSEL signal. When CPHA = 0, the SSEL signal
will always go inactive between data transfers. This is not guaranteed when CPHA = 1 (the signal can remain
active).
CPOL CPHA Firsta data driven Other data driven Data sampled
0 0 Prior to first SCK rising edge SCK falling edge SCK rising edge
0 1 First SCK rising edge SCK rising edge SCK falling edge
1 0 Prior to first SCK falling edge SCK rising edge SCK falling edge
1 1 First SCK falling edge SCK falling edge SCK rising edge
The data and clock phase relationships are summarized in Table 197. This table
summarizes the following for each setting of CPOL and CPHA.
When a device is a master, the start of a transfer is indicated by the master having a byte of data that is ready to be
transmitted. At this point, the master can activate the clock, and begin the transfer. The transfer ends when the last
clock cycle of the transfer is complete.
SPI Registers:
SPI control register: The SPI control register contains a number of programmable bits used to control the
function of the SPI block. The settings for this register must be set up prior to a given data transfer taking place.
SPI status register: The SPI status register contains read only bits that are used to monitor the status of the SPI
interface, including normal functions, and exception conditions. The primary purpose of this register is to detect
completion of a data transfer. This is indicated by the SPIF bit. The remaining bits in the register are exception
condition indicators. These exceptions will be described later in this section.
SPI data register: The SPI data register is used to provide the transmit and receive data bytes. An internal shift
register in the SPI block logic is used for the actual transmission and reception of the serial data. Data is written to
the SPI data register for the transmit case. There is no buffer between the data register and the internal shift
register. A write to the data register goes directly into the internal shift register. Therefore, data should only be
written to this register when a transmit is not currently in progress. Read data is buffered. When a transfer is
complete, the receive data is transferred to a single byte data buffer, where it is later read. A read of the SPI data
register returns the value of the read data buffer.
SPI clock counter register: The SPI clock counter register controls the clock rate when the SPI block is in master
mode. This needs to be set prior to a transfer taking place, when the SPI block is a master. This register has no
function when the SPI block is a slave.
The I/Os for this implementation of SPI are standard CMOS I/Os. The open drain SPI option is not implemented
in this design. When a device is set up to be a slave, its I/Os are only active when it is selected by the SSEL signal
being active.
Master operation
The following sequence describes how one should process a data transfer with the SPI block when it is set up to be
the master. This process assumes that any prior data transfer has already completed.
1. Set the SPI clock counter register to the desired clock rate.
2. Set the SPI control register to the desired settings.
3. Write the data to transmitted to the SPI data register. This write starts the SPI data transfer.
4. Wait for the SPIF bit in the SPI status register to be set to 1. The SPIF bit will be set after the last cycle of the
SPI data transfer.
5. Read the SPI status register.
6. Read the received data from the SPI data register (optional).
7. Go to step 3 if more data is required to transmit.
Note that a read or write of the SPI data register is required in order to clear the SPIF status bit. Therefore, if the
optional read of the SPI data register does not take place, a write to this register is required in order to clear the
SPIF status bit.
Slave operation
The following sequence describes how one should process a data transfer with the SPI block when it is set up to be
a slave. This process assumes that any prior data transfer has already completed. It is required that the system
clock driving the SPI logic be at least 8X faster than the SPI.
Note that a read or write of the SPI data register is required in order to clear the SPIF status bit. Therefore, at least
one of the optional reads or writes of the SPI data register must take place, in order to clear the SPIF status bit.
Pin description
SPI contains four pins. Function of these pins are as follows
SCK0 (Serial Clock): This is an Input/output pin, used to synchronize the transfer of data across the SPI
interface. The SPI is always driven by the master and received by the slave. The clock is programmable to be
active high or active low. The SPI is only active during a data transfer. Any other time, it is either in its inactive
state, or tri-stated.
SSEL0 (Slave Select): This is an Input pin and is an active low signal that indicates which slave is currently
selected to participate in a data transfer. Each slave has its own unique slave select signal input. The SSEL must be
low before data transactions begin and normally stays low for the duration of the transaction. If the SSEL signal
goes high any time during a data transfer, the transfer is considered to be aborted. In this event, the slave returns to
idle, and any data that was received is thrown away. There are no other indications of this exception. This signal is
not directly driven by the master. It could be driven by a simple general purpose I/O under software control.
On the LPC2148 the SSEL0 pin can be used for a different function when the SPI0 interface is only used in
Master mode. For example, pin hosting the SSEL0 function can be configured as an output digital GPIO pin and
used to select one of the SPI0 slaves.
MISO0 (Master In Slave Out): This is an Input/output pin. The MISO signal is a unidirectional signal used to
transfer serial data from the slave to the master. When a device is a slave, serial data is output on this signal. When
a device is a master, serial data is input on this signal. When a slave device is not selected, the slave drives the
signal high impedance.
MOSI0(Master Out Slave In): This is an Input/output pin. The MOSI signal is a unidirectional signal used to
transfer serial data from the master to the slave. When a device is a master, serial data is output on this signal.
When a device is a slave, serial data is input on this signal.
Register of SPI
The SPI contains 5 registers. All registers are byte, half word and word accessible. They are
This register controls the operation of the SPI. This is a R/W register having address of 0xE002 0000. The
S0SPCR register controls the operation of the SPI0 as per the configuration bits setting. Function of each bit is
summarized in the following table.
- - - - CB CB CB CB SPIE LSBF MSTR CPOL CPHA BE - -
Bit 0 to 1( Reserved): User software should not write ones to reserved bits. The value read from a reserved bit is
not defined.
Bit 2 (Bit Enable):
0 - The SPI controller sends and receives 8 bits of data per transfer
1 - The SPI controller sends and receives the number of bits selected
by bits 11:8
Bit 3 (CPHA): Clock phase control determines the relationship between the data and the clock on SPI transfers,
and controls when a slave transfer is defined as starting and ending.
0 - Data is sampled on the first clock edge of SCK. A transfer starts and ends with
activation and deactivation of the SSEL signal.
1 - Data is sampled on the second clock edge of the SCK. A transfer starts with
the first clock edge, and ends with the last sampling edge when the SSEL
signal is active.
Bit 4 (CPOL): Clock polarity control.
0 - SCK is active high.
1 - SCK is active low.
Bit 5 (MSTR): Master mode select.
0 - The SPI operates in Slave mode
1 - The SPI operates in Master mod
Bit 6 (LSBF): LSB First controls which direction each byte is shifted
when transferred.
0 - SPI data is transferred MSB (bit 7) first.
1 - SPI data is transferred LSB (bit 0) first
Bit 7 (SPIE): Serial peripheral interrupt enable.
0 - SPI interrupts are inhibited.
1 - A hardware interrupt is generated each time the SPIF or
WCOL bits are activated.
Bits 11 to 8 (BITS): When bit 2 of SPI Control register is 1, this field controls the
number of bits per transfer:
1000 - 8 bits per transfer
1001 - 9 bits per transfer
1010 - 10 bits per transfer
1011 - 11 bits per transfer
1100 - 12 bits per transfer
1101 - 13 bits per transfer
1110 - 14 bits per transfer
1111 - 15 bits per transfer
0000 - 16 bits per transfer
Bits 15 to 12 ( Reserved BITS): User software should not write ones to reserved bits. The value read from a
reserved bit is not defined.
This register shows the status of the SPI. The S0SPSR register controls the operation of the SPI0 as per the
configuration bits setting. This read only register having address0xE002 0004 .It consists of 8 bit and function of
them is summarized in the following table.
The Timer/Counter is designed to count cycles of the peripheral clock (PCLK) or an externally supplied clock and
optionally generate interrupts or perform other actions at specified timer values, based on four match registers. It
also includes four capture inputs to trap the timer value when an input signal transitions, optionally generating an
interrupt. Multiple pins can be selected to perform a single capture or match function, providing an application
with ‘or’ and ‘and’, as well as ‘broadcast’ functions among them. The LPC2148 can count external events on one
of the capture inputs if the minimum external pulse is equal or longer than a period of the PCLK. In this
configuration, unused capture lines can be selected as regular timer capture inputs, or used as external interrupts.
Features
A 32-bit timer/counter with a programmable 32-bit prescaler.
External event counter or timer operation.
Four 32-bit capture channels per timer/counter that can take a snapshot of the timer
value when an input signal transitions. A capture event may also optionally generate an interrupt.
Four 32-bit match registers that allow:
– Continuous operation with optional interrupt generation on match.
– Stop timer on match with optional interrupt generation.
– Reset timer on match with optional interrupt generation.
Four external outputs per timer/counter corresponding to match registers, with the following
capabilities:
– Set LOW on match.
– Set HIGH on match.
– Toggle on match.
– Do nothing on match.
Applications
• Interval Timer for counting internal events.
• Pulse Width Demodulator via Capture inputs.
• Free running timer.
Pin description
Timer/Counter pins are categorized in two groups as Capture Signals and External Match Output. Functions of
these pins are as follows.
CAP0.3 to 0.0 and CAP1.3 to 1.0: Input Capture Signals- A transition on a capture pin can be configured to
load one of the Capture Registers with the value in the Timer Counter and optionally generate an interrupt.
Capture functionality can be selected from a number of pins. When more than one pin is selected for a Capture
input on a single TIMER0/1 channel, the pin with the lowest Port number is used. If for example pins 30 (P0.6)
and 46 (P0.16) are selected for CAP0.2, only pin 30 will be used by TIMER0 to perform CAP0.2 function.
Here is the list of all CAPTURE signals, together with pins on where they can be selected:
• CAP0.0 (3 pins): Thease pins are connected to P0.2, P0.22 and P0.30
• CAP0.1 (1 pin): This pin is connected to P0.4
• CAP0.2 (3 pin): Thease pins are connected to P0.6, P0.16 and P0.28
• CAP0.3 (1 pin): This pin is connected to P0.29
• CAP1.0 (1 pin): This pin is connected to P0.10
• CAP1.1 (1 pin): This pin is connected to P0.11
• CAP1.2 (2 pins): Thease pins are connected to P0.17 and P0.19
• CAP1.3 (2 pins): Thease pins are connected to P0.18 and P0.21
Timer/Counter block can select a capture signal as a clock source instead of the PCLK derived clock.
MAT0.3 to 0.0 to MAT1.3 to1.0 Output External Match Output 0/1- When a match register 0/1 (MR3:0)
equals the timer counter (TC) this output can either toggle, go low, go high, or do nothing. The External Match
Register (EMR) controls the functionality of this output. Match Output functionality can be selected on a number
of pins in parallel. It is also possible for example, to have 2 pins selected at the same time so that they provide
MAT1.3 function in parallel.
Here is the list of all MATCH signals, together with pins on where they can be selected:
• MAT0.0 (2 pins): Thease pins are connected to P0.3 and P0.22
• MAT0.1 (1 pin): This pin is connected to P0.5
• MAT0.2 (2 pin): Thease pins are connected to P0.16 and P0.28
• MAT0.3 (1 pin): This pin is connected to P0.29
• MAT1.0 (1 pin): This pin is connected to P0.12
• MAT1.1 (1 pin): This pin is connected to P0.13
• MAT1.2 (2 pins): Thease pins are connected to P0.17 and P0.19
• MAT1.3 (2 pins): Thease pins are connected to P0.18 and P0.20
Timer / Counter Register: Each Timer/Counter contains the registers as shown below.
Interrupt Register (IR): This is a read write register. The IR can be written to clear interrupts. The IR can be read
to identify which of eight possible interrupt sources are pending. The Interrupt Register consists of four bits for
the match interrupts and four bits for the capture interrupts. If an interrupt is generated then the corresponding bit
in the IR will be high. Otherwise, the bit will be low. Writing a logic one to the corresponding IR bit will reset the
interrupt. Writing a zero has no effect.
Timer Control Register (TCR): This is a read write register The TCR is used to control the Timer Counter
functions. The Timer Counter can be disabled or reset through the TCR.
Timer Counter (TC): This is a read write register The 32-bit TC is incremented every PR+1 cycles of PCLK.
The TC is controlled through the TCR. The 32-bit Timer Counter is incremented when the Prescale Counter
reaches its terminal count. Unless it is reset before reaching its upper limit, the TC will count up through the value
0xFFFF FFFF and then wrap back to the value 0x0000 0000. This event does not cause an interrupt, but a Match
register can be used to detect an overflow if needed.
Prescale Register (PR): This is a read write register The Prescale Counter (below) is equal to this value, the next
clock increments the TC and clears the PC. The 32-bit Prescale Register specifies the maximum value for the
Prescale Counter.
Prescale Counter (PC): This is a read write register The 32-bit PC is a counter which is incremented to the value
stored in PR. When the value in PR is reached, the TC is incremented and the PC is cleared. The PC is observable
and controllable through the bus interface. The 32-bit Prescale Counter controls division of PCLK by some
constant value before it is applied to the Timer Counter. This allows control of the relationship of the resolution of
the timer versus the maximum time before the timer overflows. The Prescale Counter is incremented on every
PCLK. When it reaches the value stored in the Prescale Register, the Timer Counter is incremented and the
Prescale Counter is reset on the next PCLK. This causes the TC to increment on every PCLK when PR = 0, every
2 PCLKs when PR = 1, etc
Match Control Register (MCR): This is a read write register The MCR is used to control if an interrupt is
generated and if the TC is reset when a Match occurs. The Match Control Register is used to control what
operations are performed when one of the Match Registers matches the Timer Counter
Match Registers (MR0 to MR3): These are read write register MR0 to MR3 can be enabled through the MCR to
reset the TC, stop both the TC and PC, and/or generate an interrupt every time MR0 matches the TC. The Match
register values are continuously compared to the Timer Counter value. When the two values are equal, actions can
be triggered automatically. The action possibilities are to generate an interrupt, reset the Timer Counter, or stop
the timer. Actions are controlled by the settings in the MCR register.
Capture Control Register (CCR): This is a read write register The CCR controls which edges of the capture
inputs are used to load the Capture Registers and whether or not an interrupt is generated when a capture takes
place. The Capture Control Register is used to control whether one of the four Capture Registers is loaded with
the value in the Timer Counter when the capture event occurs, and whether an interrupt is generated by the capture
event. Setting both the rising and falling bits at the same time is a valid configuration, resulting in a capture event
for both edges. In the description below, "n" represents the Timer number, 0 or 1.
Capture Registers (CR0 to CR3): These are read only register. CR0 to CR3 are loaded with the value of TC
when there is an event on the CAPn.0(CAP0.0 or CAP1.0 respectively) input.
Each Capture register is associated with a device pin and may be loaded with the Timer Counter (TC) value when
a specified event occurs on that pin. The settings in the Capture Control Registers determine whether the capture
function is enabled, and whether a capture event happens on the rising edge of the associated pin, the falling edge,
or on both edges.
External Match Register (EMR): This is a read write register The EMR controls the external match pins
MATn.0-3 (MAT0.0-3 and MAT1.0-3 respectively). The External Match Register provides both control and
status of the external match pins MAT(0-3).
Count Control Register (CTCR): This is a read write register The CTCR selects between Timer and Counter
mode, and in Counter mode selects the signal and edge(s) for Counting. When Counter Mode is chosen as a mode
of operation, the CAP input (selected by the CTCR bits 3:2) is sampled on every rising edge of the PCLK clock.
After comparing two consecutive samples of this CAP input, one of the following four events is recognized: rising
edge, falling edge, either of edges or no changes in the level of the selected CAP input. Only if the identified event
corresponds to the one selected by bits 1:0 in the CTCR register, the Timer Counter register will be incremented.
Effective processing of the externally supplied clock to the counter has some limitations.
Since two successive rising edges of the PCLK clock are used to identify only one edge on the CAP selected
input, the frequency of the CAP input cannot exceed one fourth of the PCLK clock. Consequently, duration of the
high/
Pin description:
LPC2148 has 6 pins namely PWM1 to PWM6 for pulse width modulation operation. Functions of these pins are
as follows
PWM1: This is an Output pin from PWM channel 1.
PWM2: This is an Output pin from PWM channel 2.
PWM3: This is an Output pin from PWM channel 3.
PWM4: This is an Output pin from PWM channel 4.
PWM5: This is an Output pin from PWM channel 5.
PWM6: This is an Output pin from PWM channel 6.
PWM Registers:
PWM Interrupt Register (PWMIR): This is a read write pin. The PWMIR can be written to clear interrupts.
The PWMIR can be read to identify which of the possible interrupt sources are pending. The PWM Interrupt
Register consists of eleven bits (See Appendix Table 249), seven for the match interrupts and four reserved for the
future use. If an interrupt is generated then the corresponding bit in the PWMIR will be high. Otherwise, the bit
will be low. Writing a logic one to the corresponding IR bit will reset the interrupt. Writing a zero has no effect
PWM Timer Control Register (PWMTCR): This is a read write pin The PWMTCR is used to control the
Timer Counter functions. The Timer Counter can be disabled or reset through the PWMTCR. The PWM Timer
Control Register (PWMTCR) is used to control the operation of the PWM Timer Counter. For detailed function of
each of the bits(see Appendix Table 250.)
PWM Timer Counter (PWMTC): This is a read write pin .The 32-bit TC is incremented every PWMPR+1
cycles of PCLK. The PWMTC is controlled through the PWMTCR.R/W. The 32-bit PWM Timer Counter is
incremented when the Prescale Counter reaches its terminal count. Unless it is reset before reaching its upper
limit, the PWMTC will count up through the value 0xFFFF FFFF and then wrap back to the value 0x0000 0000.
This event does not cause an interrupt, but a Match register can be used to detect an overflow if needed.
PWM Prescale Register (PWMPR): This is a read write pin. The PWMTC is incremented every
PWMPR+1cycles of PCLK. The 32-bit PWM Prescale Register specifies the maximum value for the PWM
Prescale Counter.
PWM Prescale Counter (PWMPC): This is a read write pin .The 32-bit PC is a counter which is incremented to
the value stored in PR. When the value in PWMPR is reached, the PWMTC is incremented. The PWMPC is
observable and controllable through the bus interface. The 32-bit PWM Prescale Counter controls division of
PCLK by some constant value before it is applied to the PWM Timer Counter. This allows control of the
relationship of the resolution of the timer versus the maximum time before the timer overflows. The PWM
Prescale Counter is incremented on every PCLK. When it reaches the value stored in the PWM Prescale Register,
the PWM Timer Counter is incremented and the PWM Prescale Counter is reset on the next PCLK. This causes
the PWM TC to increment on every PCLK when PWMPR = 0, every 2 PCLKs when PWMPR = 1, etc.
PWM Match Control Register (PWMMCR): This is a read write pin. The PWMMCR is used to control if an
interrupt is generated and if the PWMTC is reset when a Match occurs. The PWM Match Control Register is used
to control what operations are performed when one of the PWM Match Registers matches the PWM Timer
Counter. For detailed function of each of the bits (see Appendix Table 251.)
PWM Match Registers (PWMMR0 to PWMMR6): These are read write pins. PWMMR0 to PWMMR6 can
be enabled through PWMMCR to reset the PWMTC, stop both the PWMTC and PWMPC, and/or generate an
interrupt when it matches the PWMTC. In addition, a match between PWMMR0 and the PWMTC sets all PWM
outputs that are in single-edge mode, and sets PWM1 The 32-bit PWM Match register values are continuously
compared to the PWM Timer Counter value. When the two values are equal, actions can be triggered
automatically.
The action possibilities are to generate an interrupt, reset the PWM Timer Counter, or stop the timer. Actions are
controlled by the settings in the PWMMCR register.
PWM Control Register (PWMPCR): This is a read write pin .Enables PWM outputs and selects PWM channel
types as either single edge or double edge controlled. The PWM Control Register is used to enable and select the
type of each PWM channel. For detailed function of each of the bits (see Appendix Table 252.)
PWM Latch Enable Register (PWMLER): This is a read write pin .Enables use of new PWM match values.
The PWM Latch Enable Register is used to control the update of the PWM Match registers when they are used for
PWM generation. When software writes to the location of a PWM Match register while the Timer is in PWM
mode, the value is held in a shadow register. When a PWM Match 0 event occurs (normally also resetting the
timer in PWM mode), the contents of shadow registers will be transferred to the actual Match registers if the
corresponding bit in the Latch Enable Register has been set. At that point, the new values will take effect and
determine the course of the next PWM cycle. Once the transfer of new values has taken place, all bits of the LER
are automatically cleared. Until the corresponding bit in the PWMLER is set and a PWM Match 0 event occurs,
any value written to the PWM Match registers has no effect on PWM operation.
For example, if PWM2 is configured for double edge operation and is currently running, a
typical sequence of events for changing the timing would be:
• Write a new value to the PWM Match1 register.
• Write a new value to the PWM Match2 register.
• Write to the PWMLER, setting bits 1 and 2 at the same time.
• The altered values will become effective at the next reset of the timer (when a PWM
Match 0 event occurs).
The order of writing the two PWM Match registers is not important, since neither value will be used until after the
write to PWMLER. This insures that both values go into effect at the same time, if that is required. A single value
may be altered in the same way if needed. For detailed function of each of the bits (see Appendix Table 253.)
RTC Oscillator
MUX
Clock Generator
Reference Clock
Divider(PreScaler)
Alarm
Timer Comparators Register
Counters s
Interrupt Generator
RTC interrupts:
Interrupt generation is controlled through the Interrupt Location Register (ILR), Counter Increment
Interrupt Register (CIIR), the alarm registers, and the Alarm Mask Register (AMR). Interrupts are generated only
by the transition into the interrupt state. The ILR separately enables CIIR and AMR interrupts. Each bit in CIIR
corresponds to one of the time counters. If CIIR is enabled for a particular counter, then every time the counter is
incremented when an interrupt is generated. The alarm registers allow the user to specify a date and time for an
interrupt to be generated. The AMR provides a mechanism to mask alarm compares. If all non-masked alarm
registers match the value in their corresponding time counter, then an interrupt is generated. The RTC interrupt
can bring the microcontroller out of power-down mode if the RTC is operating from its own oscillator on the
RTCX1-2 pins. When the RTC interrupt is enabled for wakeup and its selected event occurs, XTAL1/2 pins
associated oscillator wakeup cycle is started. For details on the RTC based wakeup process
Registers of RTC:
The RTC includes a number of registers. The address space is split into four sections by functionality.
The first eight addresses are the Miscellaneous Register Group. The second set of eight locations are the Time
Counter Group. The third set of eight locations contain the Alarm Register Group. The remaining registers control
the Reference Clock Divider. The Real Time Clock includes the register (see Appendix Table 260).Detailed
descriptions of the registers follow.
The Interrupt Location Register is a 2-bit register that specifies which blocks are generating an interrupt (see
Appendix Table 262). Writing a one to the appropriate bit clears the corresponding interrupt. Writing a zero has
no effect. This allows the programmer to read this register and write back the same value to clear only the
interrupt that is detected by the read.
Analog to digital converters are the most widely used devices for data acquisition. It is very much essential to
convert the physical quantities like pressure, humidity, temperature and velocity in to digital data for processing
with digital computers. First these physical quantities are converted into analog signals (either voltage or current)
with the help of transducers or sensors. Then these analog signals are converted into digital data using Analog to
digital converters (ADC), so that microcontrollers or processors can read digital data and process them. An ADC
has n-bit resolution where n can be 8,10,12,16 or 24 bits. The higher resolution ADC can provide a smaller step
size, where step size is the smallest change in analog data that an ADC can convert in to digital data.
The LPC2148 contain two analog to digital converters. These converters are single 10-bit successive
approximation analog to digital converters. While ADC0 has six channels, ADC1 has eight channels. Therefore,
total number of available ADC inputs for LPC2148 is 14.
Features
• 10 bit successive approximation analog to digital converter.
• Measurement range of 0 V to VREF (2.0 V ≤ VREF ≤ VDDA).
• Each converter capable of performing more than 400,000 10-bit samples per second.
• Every analog input has a dedicated result register to reduce interrupt overhead.
• Burst conversion mode for single or multiple inputs.
• Optional conversion on transition on input pin or timer match signal.
• Global Start command for both converters
Pin description
Analog Inputs
ADC0: AD0.7, AD0.6, AD0.4, AD0.3.AD0.2, AD0.1
ADC1: AD1.7, AD1.6, AD1.5, AD1.4, AD1.3, AD1.2, AD1.1, AD1.0.
The ADC cell can measure the voltage on any of these input signals. Note that these analog inputs are always
connected to their pins, even if the Pin function Select register assigns them to port pins. A simple self-test of the
ADC can be done by driving these pins as port outputs.
Note: if the ADC is used, signal levels on analog input pins must not be above the level of V3A at any time.
Otherwise, A/D converter readings will be invalid. If the A/D converter is not used in an application then the
pins associated with A/D inputs can be used as 5 V tolerant digital IO pins.
Warning: while the ADC pins are specified as 5 V tolerant, the analog multiplexing in the ADC block is not.
More than 3.3 V (VDDA) should not be applied to any pin that is selected as an ADC input, or the ADC reading
will be incorrect. If for example AD0.0 and AD0.1 are used as the ADC0 inputs and voltage on AD0.0 = 4.5 V
while AD0.1 = 2.5 V, an excessive voltage on the AD0.0 can cause an incorrect reading of the AD0.1, although
the AD0.1 input voltage is within the right range.
Voltage Reference (VREF): Pin no: 63
This pin is provides a voltage reference level for the A/D converter(s).LPC 2148 uses 3.3 volts as Vref.
Analog Power and Ground (VDDA, VSSA): Pin nos: 07 &59
These should be nominally the same voltages as VDD and VSS, but should be isolated to minimize noise and
error
ADC Registers:
The A/D Converter registers are shown in Table 279.
The LPC2148 contain Six registers which controls the function of ADC. These registers are
A/D Control Register (ADCR): This is a read /Write register, control data must be written into this register to
select the operating mode before A/D conversion can occur.
A/D Global Data Register (ADGDR): This is a read /Write register; it contains the ADC’s DONE bit and the
result of the most recent A/D conversion.
A/D Status Register (ADSTAT): This is a read only register, it contains DONE and OVERRUN flags for all of
the A/D channels, as well as the A/D interrupt flag.
A/D Global Start Register (ADGSR): This is a Write only register, address can be written (in the AD0 address
range) to start conversions in both A/D converters simultaneously.
A/D Interrupt Enable Register (ADINTEN): This is a read /Write register, it contains enable bits that allow the
DONE flag of each A/D channel to be included or excluded from contributing to the generation of an A/D
interrupt.
A/D Data Registers (ADDR): This is a read only register. Each channel contains separate ADDR as shown
below.
A/D Channel 1 Data Register (ADDR1). This register contains the result of the most recent conversion completed
on channel 1.
A/D Channel 2 Data Register (ADDR2). This register contains the result of the most recent conversion completed
on channel 2.
A/D Channel 3 Data Register (ADDR3). This register contains the result of the most recent conversion completed
on channel 3.
A/D Channel 4 Data Register (ADDR4). This register contains the result of the most recent conversion completed
on channel 4.
A/D Channel 5 Data Register (ADDR5). This register contains the result of the most recent conversion completed
on channel 5.
A/D Channel 6 Data Register (ADDR6). This register contains the result of the most recent conversion completed
on channel 6.
A/D Channel 7 Data Register. This register contains the result of the most recent conversion completed on
channel 7.
A/D Control Register (AD0CR and AD1CR): This is a 32 bit register; user must write control word on to this
register to select the mode of operation before the conversion starts. Function of each bits of this register is as
follows
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 8 7 0
- - - - EDGE START - - PDN - CLKS BRUST CLKDIV SEL
Bits 15:0
Reserved, user software should not write ones to reserved bits. The value read from a Reserved bit is not defined.
BURST (Bits 16):
1 The AD converters do repeated conversions at the rate selected by their
CLKS fields, scanning (if necessary) through the pins selected by 1s in their
SEL field. The first conversion after the start corresponds to the
least-significant 1 in the SEL field, then higher numbered 1-bits (pins) if
applicable. Repeated conversions can be terminated by clearing this bit, but
the conversion that’s in progress when this bit is cleared will be completed.
Remark: START bits must be 000 when BURST = 1 or conversions will not start.
0 Conversions are software controlled and require 11 clocks.
Bits 23:17:
Reserved, user software should not write ones to reserved bits. The value read from a reserved bit is not defined.
START (26:24):
When the BURST bit is 0, these bits control whether and when an A/D conversion is started:
000 No start (this value should be used when clearing PDN to 0).
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
0
OVER OVER OVER OVER OVER OVER OVER OVER DONE DONE DONE DONE DONE DONE DONE DONE
RUN7 RUN6 RUN5 RUN4 RUN3 RUN2 RUN1 RUN0 7 6 5 4 3 2 1 0
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17
16
AD
- - - - - - - - - - - - - - -
INT
DONE0 (Bit0): This bit mirrors the DONE status flag from the result register for A/D channel 0.
DONE1 (Bit1): This bit mirrors the DONE status flag from the result register for A/D channel 1.
DONE2 (Bit2): This bit mirrors the DONE status flag from the result register for A/D channel 2.
DONE3 (Bit3): This bit mirrors the DONE status flag from the result register for A/D channel 3.
DONE4 (Bit4): This bit mirrors the DONE status flag from the result register for A/D channel 4.
DONE5 (Bit5): This bit mirrors the DONE status flag from the result register for A/D channel 5.
DONE6 (Bit6): This bit mirrors the DONE status flag from the result register for A/D channel 6.
DONE7 (Bit7): This bit mirrors the DONE status flag from the result register for A/D channel 7.
OVERRUN0 (Bit8): This bit mirrors the OVERRRUN status flag from the result register for A/D channel 0.
OVERRUN1 (Bit9): This bit mirrors the OVERRRUN status flag from the result register for A/D channel 1.
OVERRUN2 (Bit10): This bit mirrors the OVERRRUN status flag from the result register for A/D channel 2.
OVERRUN3 (Bit11): This bit mirrors the OVERRRUN status flag from the result register for A/D channel 3.
OVERRUN4 (Bit12): This bit mirrors the OVERRRUN status flag from the result register for A/D channel 4.
OVERRUN5 (Bit13): This bit mirrors the OVERRRUN status flag from the result register for A/D channel 5.
OVERRUN6 (Bit14): This bit mirrors the OVERRRUN status flag from the result register for A/D channel 6.
OVERRUN7 (Bit15): This bit mirrors the OVERRRUN status flag from the result register for A/D channel 7.
ADINT (Bit16): This bit is the A/D interrupt flag. It is one when any of the individual A/D channel Done flags is
asserted and enabled to contribute to the A/D interrupt via the ADINTEN register.
Bits 31:17: Reserved, user software should not write ones to reserved bits. The value read from a reserved bit is
not defined.
A/D Interrupt Enable Register (ADINTEN, ADC0: AD0INTEN and ADC1: AD1INTEN):
This register allows control over which A/D channels generate an interrupt when a conversion is complete. For
example, it may be desirable to use some A/D channels to monitor sensors by continuously performing
conversions on them. The most recent results are read by the application program whenever they are needed. In
this case, an interrupt is not desirable at the end of each conversion for some A/D channels.
31 9 8 7 6 5 4 3 2 1 0
- ------- AD AD AD AD AD AD AD AD AD
GINTEN INTEN INTEN INTEN INTEN INTEN INTEN INTEN INTEN
8 7 6 5 4 3 2 1 0
ADINTEN0 (Bit0):
0 Completion of a conversion on ADC channel 0 will not generate an interrupt.
1 Completion of a conversion on ADC channel 0 will generate an interrupt.
ADINTEN1 (Bit1):
0 Completion of a conversion on ADC channel 1 will not generate an interrupt.
1 Completion of a conversion on ADC channel 1 will generate an interrupt.
ADINTEN2 (Bit2):
0 Completion of a conversion on ADC channel 2 will not generate an interrupt.
1 Completion of a conversion on ADC channel 2 will generate an interrupt.
ADINTEN3 (Bit3):
0 Completion of a conversion on ADC channel 3 will not generate an interrupt.
1 Completion of a conversion on ADC channel 3 will generate an interrupt.
ADINTEN4 (Bit4):
0 Completion of a conversion on ADC channel 4 will not generate an interrupt.
1 Completion of a conversion on ADC channel 4 will generate an interrupt.
ADINTEN5 (Bit5):
0 Completion of a conversion on ADC channel 5 will not generate an interrupt.
1 Completion of a conversion on ADC channel 5 will generate an interrupt.
ADINTEN6 (Bit6):
0 Completion of a conversion on ADC channel 6 will not generate an interrupt.
1 Completion of a conversion on ADC channel 6 will generate an interrupt.
ADINTEN7 (Bit7):
0 Completion of a conversion on ADC channel 7 will not generate an interrupt.
1 Completion of a conversion on ADC channel 7 will generate an interrupt.
ADGINTEN (Bit8):
0 Only the individual ADC channels enabled by ADINTEN7:0 will generate
interrupts.
1 Only the global DONE flag in ADDR is enabled to generate an interrupt.
Bits 31:17:
Reserved, user software should not write ones to reserved bits. The value read from a reserved bit is not defined
A/D Data Registers :( ADDR0 to ADDR7, ADC0: AD0DR0 to AD0DR7 and ADC1: AD1DR0 to
AD1DR7).
The A/D Data Register hold the result when an A/D conversion is complete, and also include the flags that
indicate when a conversion has been completed and when a conversion overrun has occurred.
31 30 29 16 15 14 13 12 11 10 9 8 7 6 5 0
Over
Done - ---------- - R R R R R R R R R R - --- -
Run
Result bits
Bits 5:0:
Reserved, user software should not write ones to reserved bits. The value read from a reserved bit is not defined.
RESULT (Bits15:6):
When DONE is 1, this field contains a binary fraction representing the voltage on the AIN pin, divided by the
voltage on the VREF pin (V/VREF). Zero in the field indicates that the voltage on the AIN pin was less than,
equal to, or close to that on VSSA, while 0x3FF indicates that the voltage on AIN was close to, equal to, or greater
than that on VREF.
Bits 29:16:
Reserved, user software should not write ones to reserved bits. The value read from a reserved bit is not defined.
OVERRUN (Bit 30):
This bit is 1 in burst mode if the results of one or more conversions was (were) lost and overwritten before the
conversion that produced the result in the RESULT bits. This bit is cleared by reading this register.
DONE (Bit 31):
This bit is set to 1 when an A/D conversion completes. It is cleared when this register is read.
Programming ADC:
This program generates a digital data equivalent to the voltage at P0.29 and loads the digital data on to AD0CR
register. This digital data is displayed as voltage on to the LCD
LPC 2148
3.3V
Sensor interfacing:
Sensors or transducers convert physical quantities such as temperature, light intensity, velocity, pressure and
speed etc to electrical signals depending on the transducer, the output generated is in the form of voltage,
current, resistance or capacitance. For example a thermistor converts temperature into resistance which in turn
converted onto voltage. There are simple and widely used liner sensors like LM 35 are available by National
Semiconductor Corp.
The LM35 series sensors are precision integrated circuit temperature sensors whose output voltage is
linearly proportional to the Celsius temperature. The LM35 requires no external calibration since it is
internally calibarated.It outputs 10mV for each degree of centigrade temarature.
Vref =3.3V
LM35
1 2 3
5V
LPC2148
ADC1
75E
1µf
As the LM 35 produces 10mV for every degree change in temperature and LPC 2148 uses 3.3V as V ref , we can
read up to 330° temperature and ADC1 input of LPC2148 correspond directly to the temperature as monitored
by LM35. This voltage at P0.28(ADC1) is then converted into equalint digital data and loads the digital data on
to AD0CR register. This digital data is displayed as voltage on to the LCD. Refer the table –
Temp (°C) ADC1(mV) AD0CR Value
LM 35 output
0 0 0000000000
1 10 0000000001
2 20 0000000010
3 30 0000000011
5 50 0000000101
10 100 0000001010
20 200 0000010100
30 300 0000011110
40 400 0000101000
Example program:
AD0CR = 0x00200D02;
AD0CR |= 0x01000000; // Start A/D Conversion
do
{
i = AD0GDR; // Read A/D Data Register
} while ((i & 0x80000000) == 0); // Wait for end of A/D Conversion
return (i >> 6) & 0x03FF; // bit 6:15 is 10 bit AD value
}
////////// DISPLAY ADC VALUE /////////////////
Display_ADC()
{
unsigned int adc_value = 0;
char buf[4] = {5};
float voltage = 0.0;
adc_value = Read_ADC();
sprintf((char *)buf, "%3d", adc_value);
lcd_putstring16(0,"ADC VAL = 000 ");
lcd_putstring16(1,"TEMP = 000.0 dgC");
lcd_gotoxy(0,10);
lcd_putstring(buf);
}
////////// MAIN /////////////////
int main (void)
{
init_lcd();
Init_ADC();
lcd_putstring16(0,"** ADC - TEMP **");
lcd_putstring16(1,"** DEMO **");
delay(60000);
delay(60000);
while(1)
{
Display_ADC();
delay(50000);
}
}
In LPC2148 the digital inputs are converted to analog output voltage at pin DACOUT(P0.25).The total voltage
provided by the DACOUT pin is function of binary number written on to bits 6 (D0) to bit 15(D9) of DAC
Register(DACR) and the reference voltage Vref(3.3V),it is as follows
𝐷9 𝐷8 𝐷7 𝐷6 𝐷5 𝐷4 𝐷3 𝐷2 𝐷1 𝐷0
Vout =Vref [
2
+
4
+
8
+
16
+
32
+
64
+
128
+
256
+
512
+
1024
]
Where D0 is the LSB and D9 is MSB
Example:
Find the analog voltage for the digital data 1056 loaded on to DACR
Solution:
First the digital value is converted to binary, is equal to 10000100000 and Vref=3.3V
Now the analog output voltage is calculated as
𝐷9 𝐷8 𝐷7 𝐷6 𝐷5 𝐷4 𝐷3 𝐷2 𝐷1 𝐷0
Vout =Vref [
2
+
4
+
8
+
16
+
32
+
64
+
128
+
256
+
512
+
1024
]
1 0 0 0 0 0 1 0 0 0
Vout =3.3 [ 2
+ + +
4 8 16
+
32
+
64
+
128
+
256
+
512
+
1024
]
Vout =3.3 [ 0.5 + 0.078 ]
Vout =1.678Volts
Pin description
Table 286 gives a brief summary of each of DAC related pins.
Analog Output (AOUT):
This is Analog output pin. Analog voltage equal to (10 bit digital VALUE)/1024 x V REF is generated on this pin
after the selected settling time after the bit 6 to 15 of DACR is written with a new value.
Voltage Reference (VREF):
This pin provides a voltage reference level for the D/A converter.
Analog Power and Ground (VDDA, VSSA):
These should be nominally the same voltages as V3 and VSSD, but should be isolated to minimize noise and error.
31 17 16 15 14 13 12 11 10 9 8 7 6 5 0
0
- ---------- - BIAS V9 V8 V7 V6 V5 V4 V3 V2 V1 V0 - ---- -
Note: Before loading digital value on to DACR we need to shift the digital value left by six (6)
bits so that the digital value will be loaded to D6 to D15 of DACR.
LPC2148
DAC out
Analog out to CRO
Square wave can be generated by loading “00” and ‘1023” values to DACR of LPC 2148 with the required
amount of delay between the two values.
Example Prog:
LPC2148
DAC out
Analog out to CRO
Saw Tooth wave can be generated by incrementing the DACR value from “00” and ‘1023” and then
loading “00” continuously. In this case the maximum value of digital number is “1023’. Hence maximum
output voltage available at DACout pin is
𝐷9 𝐷8 𝐷7 𝐷6 𝐷5 𝐷4 𝐷3 𝐷2 𝐷1 𝐷0
Vout =Vref [ + + + + + + + + + ]
2 4 8 16 32 64 128 256 512 1024
1 1 1 1 1 1 1 1 1 1
Vout =3.3 [ + + + + + + + + + ]
2 4 8 16 32 64 128 256 512 1024
1023
Vout =3.3 [
1024
]
Vout =3.29Volts
Example Prog:
LPC2148
DAC out
Analog out to CRO
To generate Sine wave we first need a table whose value represents the magnitude of sine wave of angle between
0 to 360°. The values of sine function vary from -1.0 to +1.0 for 0 to 360° angle. Therefore the table values are
integer numbers representing the voltage magnitude for sine of ‘ϴ’. Table123 shows the angles of sine values,
the voltage magnitudes and the integer values representing the voltage magnitude of each angle ( with 30 degree
increment).To generate table123 we considered 3.3V as the full scale voltage for DAC output. Full scale output
of DAC is obtained when all the data inputs of DACR are high. Therefore to obtain the full scale of 3.3V output
we use the following equation,
Aout values of DAC for various angles is calculated and shown in table123
Angle ϴ (degree) Sinϴ Aout (voltage Magnitude) DACR Value
1.65+ (1.65 x Sinϴ) Aoutx 310.3
0 0 1.65 512
15 0.26 2.08 645
30 0.50 2.48 770
45 0.71 2.82 875
60 0.87 3.09 959
75 0.97 3.25 1008
90 1.00 3.30 1024
105 0.97 3.25 1008
120 0.87 3.09 959
135 0.71 2.82 875
150 0.50 2.48 770
165 0.26 2.08 645
180 0.00 1.65 512
195 -0.26 1.22 379
210 -0.50 0.83 258
225 -0.71 0.48 149
240 -0.86 0.23 71
255 -0.97 0.05 16
270 -1.00 0.00 0
285 -0.97 0.05 16
300 -0.87 0.21 65
315 -0.71 0.48 149
330 -0.50 0.83 258
345 -0.26 1.22 379
360 0.00 1.65 512
To find the values to write into the DACR, simply multiply the Aout value by 310.0, because there are 1024(2 10)
steps and full scale is 3.3V.therefore 1024 steps/full scale= 1024/3.3=310.3 steps per volts and voltage per steps
is 1V/steps per volt =1/310.3 =0.003V.look at the following example, which continuously sends digital values to
DACR to produce a pure sine wave. Here we are sending digital values in 256 steps so that smooth curve will be
obtained. We can also use the formula arry[i] = Int((Sin((2 * i * Pi) / 256) * 512) + 512) where i can take the
values of 0 to 255.
Example Program:
const unsigned int tab[256] = {512, 525, 537, 550, 562, 575, 587, 599, 612, 624, 636, 648, 661, 673, 684,
696, 708, 719, 731, 742, 753, 764, 775, 786, 796, 807, 817, 827, 837, 846, 856, 865,
874, 883, 891, 900, 908, 915, 923, 930, 938, 944, 951, 957, 963, 969, 975, 980, 985,
990, 994, 998, 1002, 1005, 1009, 1011, 1014, 1016, 1018, 1020, 1021, 1023, 1023,
1024,1024,1024,1023,1023,1022, 1020, 1019, 1017, 1014, 1012, 1009, 1006, 1002,
998, 994, 990, 985, 980, 975, 970, 964, 958, 951, 945, 938, 931, 924, 916, 908, 900,
892, 883, 874, 865, 856, 847, 837, 828, 818, 807, 797, 786, 765, 754, 743, 732, 720,
709, 697, 685, 673, 661, 649, 637, 625, 613, 600, 588, 575, 563, 550, 538, 525, 513,
500, 488, 475, 463, 450, 438, 425, 413, 401, 388, 376, 364, 352, 340, 329, 317, 305,
294, 283, 271, 260, 250, 239, 228, 218, 208, 198, 188, 178, 169, 160, 151, 142, 133,
125, 117, 109, 101, 94, 87, 80, 73, 67, 61, 55, 50, 44, 39, 35, 30, 26, 22, 19, 16, 13, 10,
8, 6, 4, 3, 1, 1, 0, 0,1 , 1, 2, 4, 5, 7, 10, 12, 15, 18, 22, 25, 29, 34, 38, 43, 49, 54, 60,
66, 72, 79, 86, 93, 100, 108, 115, 123, 132, 140, 149, 158, 167, 176, 186, 196, 206,
216, 226, 237, 248, 258, 269, 280, 292, 303, 315, 326, 338, 350, 362, 374, 386, 398,
411, 423, 435, 448, 460, 473, 485, 498 };
The model described here is for its low price and great capabilities most frequently used in practice. It is based
on the HD44780 microcontroller (Hitachi) and can display messages in two lines with 16 characters each. It
displays all the letters of alphabet, Greek letters, punctuation marks, mathematical symbols etc. In addition, it is
possible to display symbols made up by the user. Other useful features include automatic message shift (left and
right), cursor appearance, LED backlight etc.
LCD Pins
There are pins along one side of a small printed board. These are used for connecting to the microcontroller.
There are in total of 14 pins marked with numbers (16 if it has backlight). Their function is described in the table
below:
Pin
Function Name Logic State Description
Number
Ground 1 Vss - 0V
Power supply 2 Vdd - +5V
Contrast 3 Vee - 0 - Vdd
5 R/W 0
Control of 1 Write data (from controller to LCD)
operating Read data (from LCD to controller)
0
6 E
Access to LCD disabled Normal operating
1 Data/commands are transferred to LCD
7 D0 0/1 Bit 0 LSB
8 D1 0/1 Bit 1
9 D2 0/1 Bit 2
Data / 10 D3 0/1 Bit 3
commands 11 D4 0/1 Bit 4
12 D5 0/1 Bit 5
13 D6 0/1 Bit 6
14 D7 0/1 Bit 7 MSB
LCD screen:
An LCD screen consists of two lines each containing 16 characters. Each character consists of 5x7, 5x8 or 5x11
dot matrix. This book covers the most commonly used display, i.e. the 5x7 character display.
Display contrast depends on the power supply voltage and whether messages are displayed in one or two lines.
For this reason, varying voltage 0-Vdd is applied on the pin marked as Vee. Trimmer potentiometer is usually
used for that purpose. Some LCD displays have built-in backlight (blue or green LEDs). When used during
operation, a current limiting resistor should be serially connected to one of the pins for backlight power supply
(similar to LEDs).
If there are no characters displayed or if all of them are dimmed when the display is on, the first thing that should
be done is to check the potentiometer for contrast regulation. Is it properly adjusted? The same applies if the
mode of operation has been changed (writing in one or two lines).
LCD Memory:
It works quite simply: it is sufficient to configure the display so as to increment addresses automatically (shift
right) and set the starting address for the message that should be displayed (for example 00 hex).
After that, all characters sent through lines D0-D7 will be displayed in the message format we are used to- from
left to right. In this case, displaying starts from the first field of the first line since the address is 00 hex. If more
than 16 characters are sent, then all of them will be memorized, but only the first sixteen characters will be
visible. In order to display the rest of them, a shift command should be used. Virtually, everything looks as if the
LCD display is a “window” which moves left-right over memory locations containing different characters. This
is how the effect of message “moving” on the screen is made.
If the cursor is on, it appears at the location which is currently addressed. In other words, when a character
appears at the cursor position, it will automatically move to the next addressed location.
Since this is a sort of RAM memory, data can be written to and read from it, but its contents is irretrievably lost
when the power goes off.
CGROM Memory:
CGROM memory contains the default character map with all characters that can be displayed on the screen.
Each character is assigned to one memory location.
The addresses of CGROM memory locations match the characters of ASCII. If the program being currently
executed encounters a command “send character P to port”, then the binary value 0101 0000 appears on the port.
This value is the ASCII equivalent to the character P. It is then written to LCD, which results in displaying the
symbol from 0101 0000 location of CGROM. In other words, the character “P” is displayed. This applies to all
letters of alphabet (capitals and small), but not to numbers.
As seen on the previous “map”, addresses of all digits are pushed forward by 48 relative to their values (digit 0
address is 48, digit 1 address is 49, digit 2 address is 50 etc.). Accordingly, in order to display digits correctly,
each of them needs to be added a decimal number 48 prior to be sent to LCD.
CGRAM memory:
Apart from standard characters, the LCD display can also display symbols defined by the user itself. It can be
any symbol in the size of 5x8 pixels. RAM memory called CGRAM in the size of 64 bytes enables it.
Memory registers are 8 bits wide, but only 5 lower bits are used. Logic one (1) in every register represents a
dimmed dot, while 8 locations grouped together represent one character. It is best illustrated in figure below:
Symbols are usually defined at the beginnig of the program by simply writing zeros and ones to registers of
CGRAM memory so that they form desired shapes. In order to display them it is sufficient to specify their
address. Pay attention to the first coloumn in the CGROM map of characters. It doesn't contain RAM memory
addresses, but symbols being discussed here. In this example, “display 0” means - display “č”, “display 1”
means - display “ž” etc.
RS = 1 - Bits D0-D7 are addresses of the characters to be displayed. LCD processor addresses one character
from the character map and displays it. The DDRAM address specifies the location on which the character is to
be displayed. This address is defined before the character is transferred or the address of previously transferred
character is automatically incremented.
RS = 0 - Bits D0 - D7 are commands which determine the display mode. The commands recognized by the LCD
are given in the table below:
Execution
Command RS RW D7 D6 D5 D4 D3 D2 D1 D0
Time
Clear display 0 0 0 0 0 0 0 0 0 1 1.64mS
Cursor home 0 0 0 0 0 0 0 0 1 x 1.64mS
Entry mode set 0 0 0 0 0 0 0 1 I/D S 40uS
Display on/off control 0 0 0 0 0 0 1 D U B 40uS
Cursor/Display Shift 0 0 0 0 0 1 D/C R/L x x 40uS
Function set 0 0 0 0 1 DL N F x x 40uS
Set CGRAM address 0 0 0 1 CGRAM address 40uS
Set DDRAM address 0 0 1 DDRAM address 40uS
Read “BUSY” flag (BF) 0 1 BF DDRAM address -
Write to CGRAM or DDRAM 1 0 D7 D6 D5 D4 D3 D2 D1 D0 40uS
Read from CGRAM or DDRAM 1 1 D7 D6 D5 D4 D3 D2 D1 D0 40uS
I/D 1 = Increment (by 1) R/L 1 = Shift right
0 = Decrement (by 1) 0 = Shift left
01 Clear Screen
02 Return Home
04 Shift Cursor to left (decrement cursor)
05 Shift display right
06 Shift cursor to right (increment cursor)
07 Shift display left
08 Display off, Cursor off
0A Display off, Cursor on
0C Display on, Cursor off
0E Display on, Cursor on
0F Display off, Cursor blinking
10 Shift cursor position left
14 Shift cursor position right
18 Shift the display position left
1C Shift the display position right
80 Cursor to begin from 1st line
C0 Cursor to begin from 2nd line
38 2lines, 5x7 Dot matrix display
Table: LCD Command codes
LCD Connection
Depending on how many lines are used for connecting the LCD to the microcontroller, there are 8-bit and 4-bit
LCD modes. The appropriate mode is selected at the beginning of the operation. This process is called
“initialization”. 8-bit LCD mode uses outputs D0-D7 to transfer data in the way explained on the previous page.
The main purpose of 4-bit LCD mode is to save valuable I/O pins of the microcontroller. Only 4 higher bits
(D4-D7) are used for communication, while other may be left unconnected. Each data is sent to the LCD in two
steps: four higher bits are sent first (normally through the lines D4-D7), then four lower bits. Initialization
enables the LCD to link and interpret received bits correctly. Data is rarely read from the LCD (it is mainly
transferred from the microcontroller to LCD) so that it is often possible to save an extra I/O pin by simple
connecting R/W pin to ground. Such saving has its price. Messages will be normally displayed, but it will not be
possible to read the busy flag since it is not possible to read the display either.
Fortunately, there is a simple solution. After sending a character or a command it is important to give the LCD
enough time to do its job. Owing to the fact that execution of the slowest command lasts for approximately
1.64mS, it will be sufficient to wait approximately 2mS for LCD.
LCD Initialization
The LCD is automatically cleared when powered up. It lasts for approximately 15mS. After that, the display is
ready for operation. The mode of operation is set by default. It means that:
1. Display is cleared
2. Mode
o DL = 1 Communication through 8-bit interface
o N = 0 Messages are displayed in one line
o F = 0 Character font 5 x 8 dots
3. Display/Cursor on/off
o D = 0 Display off
o U = 0 Cursor off
o B = 0 Cursor blink off
4. Character entry
o ID = 1 Displayed addresses are automatically incremented by 1
o S = 0 Display shift off
Automatic reset is in most cases performed without any problems. In most cases, but not always! If for any
reason the power supply voltage does not reach ful value within 10mS, the display will start to perform
completely unpredictably. If the voltage supply unit is not able to meet this condition or if it is needed to provide
completely safe operation, the process of initialization is applied. Initialization, among other things, causes a
new reset enabling display to operate normally.
Refer to the figure below for the procedure on 8-bit initialization:
Example program: This program display the message “vasundhara Technologies” on 16x2 LCD display.
#define TRUE 1
#define FALSE 0
delay(1000);
lcd_command_write(0x38); /* 8-bit interface, two line, 5X7 dots. */
lcd_command_write(0x38);
lcd_command_write(0x38);
lcd_command_write(0x10); /* display shift */
lcd_command_write(0x0C); /* display on */
lcd_command_write(0x06) ; /* cursor move direction */
lcd_command_write(0x01) ; /* cursor home */
delay(1000);
}
/************************************************************************************
Function Name : lcd_command_write()
Description :
Input :
Output : Void
************************************************************************************/
void lcd_command_write( unsigned char command )
{
unsigned int temp=0;
temp=(command << 15) & LCD_DATA_MASK;
LCD_DATA_CLR |= LCD_DATA_MASK;
LCD_DATA_SET |= temp;
LCD_CTRL_CLR |= LCDRS;
LCD_CTRL_SET |= LCDEN;
delay(5);
LCD_CTRL_CLR |= LCDEN;
delay(5);
}
/************************************************************************************
Function Name : lcd_data_write()
Description :
Input :
Output : Void
************************************************************************************/
void lcd_data_write( unsigned char data )
{
unsigned int temp=0;
temp=(data << 15) & LCD_DATA_MASK;
LCD_DATA_CLR |= LCD_DATA_MASK;
LCD_DATA_SET |= temp;
LCD_CTRL_SET |= LCDEN | LCDRS;
delay(5);
LCD_CTRL_CLR |= LCDEN;
delay(5);
}
/************************************************************************************
Function Name : lcd_clear()
Description :
Input :
Output : Void
************************************************************************************/
void lcd_clear( void)
{
lcd_command_write( 0x01 );
}
/************************************************************************************
Function Name : lcd_gotoxy()
Description :
Input :
Output : Void
****************************************************************************** ******/
int lcd_gotoxy( unsigned char x, unsigned char y)
{
unsigned char retval = TRUE;
if( (x > 1) && (y > 15) )
{
retval = FALSE;
}
else
{
if( x == 0 ) lcd_command_write( 0x80 + y );
else if( x==1 ) lcd_command_write( 0xC0 + y );
}
return retval;
}
/************************************************************************************
Function Name : lcd_putchar()
Description :
Input :
Output : Void
************************************************************************************/
void lcd_putchar( unsigned char c )
{
lcd_data_write( c );
}
/************************************************************************************
Function Name : lcd_putstring()
Description :
Input :
Output : Void
************************************************************************************/
void lcd_putstring( char *string )
{
while(*string != '\0')
{
lcd_putchar( *string );
string++;
}
}
/************************************************************************************
Function Name : lcd_putstring16()
Description :
Input :
Output : Void
************************************************************************************/
void lcd_putstring16( unsigned char line, char *string )
{
unsigned char len = 16;
lcd_gotoxy( line, 0 );
while(*string != '\0' && len--)
{
lcd_putchar( *string );
string++;
}
}
/****************************************************************************
Function Name : delay()
Description :
Input :
Output : void
********************************************************************************/
void delay(unsigned int count)
{
int j=0,i=0;
for(j=0;j<count;j++)
{
for(i=0;i<120;i++);
}
}
Basically, an LED display is nothing more than several LEDs molded in the same plastic
case. There are many types of displays composed of several dozens of built in diodes which
can display different symbols.
Most commonly used is a so called 7-segment display. It is composed of 8 LEDs, 7 segments are arranged as a
rectangle for symbol displaying and there is an additional segment for decimal point displaying. In order to
simplify connecting, anodes and cathodes of all diodes are connected to the common pin so that there are
common anode displays and common cathode displays, respectively. Segments are marked with the letters from
A to G, plus dp, as shown in the figure on the left. On connecting, each diode is treated separately, which means
that each must have its own current limiting resistor.
Displays connected to the microcontroller usually occupy a large number of valuable I/O pins, which can be a
big problem especially if it is needed to display multi digit numbers. The problem is more than obvious if, for
example, it is needed to display two 6-digit numbers (a simple calculation shows that 96 output pins are needed
in this case). The solution to this problem is called MULTIPLEXING. This is how an optical illusion based on
the same operating principle as a film camera is made. Only one digit is active at a time, but they change their
state so quickly making impression that all digits of a number are simultaneously active.
Here is an explanation on the figure above. First a byte representing units is applied on a microcontroller port
and a transistor T1 is activated at the same time. After a while, the transistor T1 is turned off, a byte representing
tens is applied on a port and a transistor T2 is activated. This process is being cyclically repeated at high speed
for all digits and corresponding transistors.
The fact that the microcontroller is just a kind of miniature computer designed to understand only the language
of zeros and ones is fully expressed when displaying any digit. Namely, the microcontroller doesn't know what
units, tens or hundreds are, nor what ten digits we are used to look like. Therefore, each number to be displayed
must be prepared in the following way:
First of all, a multi digit number must be split into units, tens etc. in a particular subroutine. Then each of these
digits must be stored in special bytes. Digits get familiar format by performing “masking”. In other words, a
binary format of each digit is replaced by a different combination of bits in a simple subroutine. For example, the
digit 8 (0000 1000) is replaced by the binary number 0111 111 in order to activate all LEDs displaying digit 8.
The only diode remaining inactive in this case is reserved for the decimal point. If a microcontroller port is
connected to the display in such a way that bit 0 activates segment “a”, bit 1 activates segment “b”, bit 2 segment
“c” etc., then the table below shows the “mask” for each digit.
Example Program1: This Program counts up and down with two keys (UP and Down) are pressed up to
00 to 99 with 2digit seven segment Display is connected to LPC 2148
while(1)
{
if (!(KEY_CTRL_PIN & INC)) //INC key pressed
{
if (count == 99) goto disp;
count++;
goto disp;
}
if (!(KEY_CTRL_PIN & DEC)) //DEC key pressed
{
if (count == 0x00) goto disp;
count--;
}
disp:
qot = count / 10;
rem = count % 10;
for (i=0; i < 200; i++) //change to inc/dec speed of count
{
seg7_data_write (dig [qot]); //display quotient on digit1
SEG7_CTRL_SET |= DIG2;
for (j=0;j<500;j++); //change to inc/dec brightness of display
SEG7_CTRL_CLR |= DIG2;
}
/****************************************************************************************
Function Name : seg7_data_write()
Description : Function to write data on the cathode segment lines
Input :
Output : Void
****************************************************************************************/
void seg7_data_write( unsigned char data )
{
unsigned int temp=0;
temp=(data << 15) & LED_DATA_MASK;
LED_DATA_CLR |= LED_DATA_MASK;
LED_DATA_SET |= temp;
}
Example Program2: This Program counts up and down with two keys (UP and Down) are pressed up to
0000 to 9999 with 4digit seven segment Display is connected to LPC 2148
while(1)
{
if (!(KEY_CTRL_PIN & INC)) //INC key pressed
{
if (count == 9999) goto disp;
count++;
goto disp;
}
if (!(KEY_CTRL_PIN & DEC)) //DEC key pressed
{
if (count == 0x0000) goto disp;
count--;
}
disp:
qot = count / 1000;
rem1= count % 1000;
}
/****************************************************************************************
Function Name : seg7_data_write()
Description : Function to write data on the cathode segment lines
Input :
Output : Void
****************************************************************************************/
void seg7_data_write( unsigned char data )
{
unsigned int temp=0;
temp=(data << 15) & LED_DATA_MASK;
LED_DATA_CLR |= LED_DATA_MASK;
LED_DATA_SET |= temp;
}
The hex keypad is a peripheral that is organized in rows and Columns. Hex key Pad 16 Keys arranged in a
4 by 4 grid, labeled with the hexadecimal digits 0 to F. An exampl e of this can been seen in Figure 1,
below. Internally, the structure of the hex keypad is very simple. Wires run in vertical columns (we call
them C0 to C3) and in horizontal rows (called R0 to R3). These 8 wires are available externally, and will
be connected to the lower 8 bits of the port. Each key on the keypad is essentially a switch that connects a
row wire to a column wire. When a key is pressed, it makes an electrical connection between the row and
column. The internal structure of the hex keypad is shown in Fig
10k Array
3.3V
ROW1
ROW2
ROW3 S1 S2 S3 S4
ROW4
S5 S6 S7 S8
ROW1
ROW2
ROW3
ROW4
init_lcd();
Construction
Permanent Magnet Rotor ,Also Called the Shaft, Stator Surrounds the Shaft, Usually Four
Stator Windings Paired with Center-Tapped Moving the Rotor
Single-Coil Excitation - Each successive coil is energised in turn.
0 0
0 0
0 0
0 0
0 0
Step Angle
Arc Through Which Motor Turns With ONE Step Change of the Windings
Varies With Model of Stepper Motor(Depending on the number of teeth on stator and rotor)
Normally in Degrees
Step angle = 360/No. of Steps per Revolution
Commonly available no. of steps per revolution are 500, 200, 180, 144, 72, 48, 24
Revolutions per Minute (RPM)
60 Steps per Second
rpm
Steps per Re volution
The top electromagnet The top electromagnet The bottom The left electromagnet (4) is
(1) is turned on, (1) is turned off, and the Electromagnet (3) enabled, rotating again by 3.6°
attracting the nearest right electromagnet (2) is energized; another (1.8’). When the top
teeth of a gear shaped is energized, pulling the 3.6° (1.8’) rotation electromagnet (1) is again
iron rotor. With the nearest teeth slightly to occurs. enabled, the teeth in the sprocket
teeth aligned to the right. This results in a will have rotated by one tooth
electromagnet 1, they rotation of 3.6° (1.8’) in position; since there are 25(50)
will be slightly offset this example. teeth, it will take 100(200) steps to
from electromagnet 2. make a full rotation in this
example
Example program:
DC Motor Interfacing:
Unlike stepper motor, the DC (direct current) motor rotates continuously. It has two terminals positive and
negative. Connecting DC power supply to these terminals rotates motor in one direction and reversing the
polarity of the power supply reverses the direction of rotation.
The speed of the DC motor is measured in revolution per minute (RPM). The speed of the DC motor increases
with increase in the supply voltage. However, we cannot exceed supply voltage beyond the rated voltage.
UNIDIRECTION CONTROL:
Figure shows the DC motor rotation for clockwise (CW) and counterclockwise (CCW) rotations. It also
shows how DC motor changes its direction of rotation when the polarity of power supply reverses.
BIDIRECTIONAL CONTROL
By using switches for changing the power supply polarity we can control the direction of the rotation of the DC
motor. This is illustrated in the below figure.
H-Bridge Is Simplest Method
– Uses Switches (Relays Will do)
Below table shows some of the switch configurations.
SW3 SW2 SW1 SW0 MOTOR ROTATION
OPEN OPEN OPEN OPEN OFF (FIG A)
CLOSED OPEN OPEN CLOSED CLOCKWISE (FIGB)
OPEN CLOSED CLOSED OPEN ANTICLOCKWISE(FIG C)
CLOSED CLOSED CLOSED CLOSED INVALID(FIG D)
The speed of the DC motor also depends on the load. At no-load speed is highest. As we increase the load, the
speed decreases. The speed of Dc motor can maintained at a constant speed for a given load by using “Pulse
Width Modulation (PWM)” technique. By changing the width of the pulse of applied to dc motor, the power
applied is varied thereby DC motor speed can be increased or decreased. Wider the pulse Faster is the Speed,
Narrower is the Pulse, and Slower is the Speed.LPC 2148 has built in PWM. For microcontrollers without PWM
circuit we generate different duty cycles using software’s.
Example1. Program to control the direction of the DC motor according to the status of bit P0.7
Asuume port pins P1.16, P1.20, P1.17 and P1.21are connected to keys to start, stop, speed increase and speed
decrease.
Every ARM instruction is listed on the following pages. Each instruction description shows:
• The instruction encoding
• The instruction syntax
• The version of the ARM architecture where the instruction is valid
• Any exceptions that apply
• An example in pseudo-code of how the instruction operates
• Notes on usage and special cases.
General Notes
These notes explain the types of information and abbreviations used on the instruction pages.
Syntax abbreviations
The following abbreviations are used in the instruction pages:
(immed n) This is an immediate value, where n is the number of bits. For example, an 8-bit immediate value is
represented by: (immed 8 )
(offset n) This is an offset value, where n is the number of bits. For example, an 8-bit offset value is represented
by:(offset 8)
The same construction is used for signed offsets. For example, an 8-bit signed offset is represented by: (signed
offset 8)
Encoding diagram and assembler syntax
For the conventions used, see Assembler syntax descriptions.
Architecture versions
This gives details of architecture versions where the instruction is valid. For details, see Architecture versions and
variants.
Exceptions
This gives details of which exceptions can occur during the execution of the instruction. Prefetch Abort is not
listed in general, both because it can occur for any instruction and because if an abort occurred during instruction
fetch, the instruction bit pattern is not known. (Prefetch Abort is however listed for BKPT, since it can generate a
Prefetch Abort exception without these considerations applying.)
Operation
This gives a pseudo-code description of what the instruction does. For details of conventions used in this
pseudo-code, see Pseudo-code descriptions of instructions.)
Information on usage
Usage sections are included where appropriate to supply suggestions and other information about how to use the
instruction effectively
.
ADC Add with Carry
Description The ADC (Add with Carry) instruction adds the value of (op1) and the Carry flag to the value of
Rn and stores the result in Rd. The condition code flags are optionally updated based on the
result.
Usage ADC is used to synthesize multi-word addition. If register pairs R0, R1 and R2, R3 hold 64-bit
values (where R0 and R2 hold the least significant words) the following instructions leave the
64-bit sum in R4, R5:
ADD Add
Operation (cc)(L): LR PC + 8
(cc): PC PC + (offset0
Syntax B (L) (cc) (offset)
Description The B (Branch) and BL (Branch and Link) instructions cause a branch to a target address, and
provide both conditional and unconditional changes to program flow. The BL (Branch and
Link) instruction stores a return address in the link register (LR or R14).
The (offset) specifies the target address of the branch. The address of the next instruction is
calculated by adding the offset to the program counter (PC) which contains the address of the
branch instruction plus 8.
The branch instructions can specify a branch of approximately ±32MB.
Usage The BL instruction is used to perform a subroutine call. The return from subroutine is achieved
by copying the LR to the PC. Typically, this is done by one of the following methods:
• Executing a MOV PC, R14 instruction.
• Storing a group of registers and R14 to the stack on subroutine entry, using an instruction of
the form:
STMFD R13!,{(registers),R14}
and then restoring the register values and returning with an instruction of the form:
LDMFD R13!,{(registers),PC}
Condition Codes
The condition codes are not affected by this instruction.
Notes branching backwards past location zero and forwards over the end of the 32-bit address
space is UNPREDICTABLE.
CMP Compare
EOR Exclusive OR
Operation if (cc)
IA: addr Rn
IB: addr Rn + 4
DA: addr Rn - (#(registers) * 4) + 4
DB: addr Rn - (#(registers) * 4)
for each register Ri in (registers)
IB: addr addr + 4
DB: addr addr - 4
Ri M(addr)
IA: addr addr + 4
DA: addr addr - 1
(!): Rn addr
Syntax LDM(cc)(mode) Rn(!), {(registers)}
Description The LDM (Load Multiple) instruction is useful for block loads, stack operations and procedure
exit sequences. It loads a subset, or possibly all, of the general purpose registers from sequential
memory locations. The general purpose registers loaded can include the PC. If they do, the word
loaded for the PC is treated as an address and a branch occurs to that address. The register Rn
points to the memory local to load the values from. Each of the registers listed in (registers) is
loaded in turn, reading each value from the next memory address as directed by (mode), one of:
IB Increment Before
DB Decrement Before
IA Increment After
DA Decrement After
The base register writeback option ((!)) causes the base register to be modified to hold the
address of the final valued loaded. The register are loaded in sequence, the lowest-numbered
register from the lowest memory address, through to the highest-numbered register from the
highest memory address.
If the PC (R15) is specified in the register list, the instruction causes a branch to the address
loaded into the PC.
Exceptions Data Abort
Condition Codes
The condition codes are not effected by this instruction.
Notes If the base register Rn is specified in (registers), and base register writeback is specified ((!)),
the final value of Rn is UNPREDICTABLE.
Usage Using the PC as the base register allows PC-relative addressing, which facilitates position
independent code. Combined with a suitable addressing mode, LDR allows 32-bit memory data
to be loaded into a general-purpose register where its value can be manipulated. If the
destination register is the PC, this instruction loads a 32-bit address from memory and branches
to that address. To synthesize a Branch with Link, precede the LDR instruction with MOV LR,
PC.
Condition Codes
The condition codes are not affected by this instruction.
Notes If (op2) specifies an address that is not word-aligned, the instruction attempts to load a byte. The
result is UNPREDICTABLE and the LDRB instruction should be used. If (op2) specifies base
register write back (!), and the same register is specified for Rd and Rn, the results are
UNPREDICTABLE.
If the PC (R15) is specified for Rd, the value must be word aligned otherwise the result is
UNPREDICTABLE.
MOV Move
ORR Bitwise OR
Operation if (cc)
IA: addr Rn
IB: addr Rn + 4
DA: addr Rn - (#(registers) * 4) + 4
DB: addr Rn - (#(registers) * 4)
for each register Ri in (registers)
IB: addr addr + 4
DB: addr addr - 4
M(addr) Ri
IA: addr addr + 4
DA: addr addr - 4
(!): Rn addr
Syntax STM (cc)(mode) Rn(!), {(registers)}
Description The STM (Store Multiple) instruction stores a subset (or possibly all) of the general-purpose
registers to sequential memory locations. The register Rn specifies the base register used to
store the registers. Each register given in R registers is stored in turn, storing each register in the
next memory address as directed by (mode), which can be one of:
IB Increment Before
DB Decrement Before
IA Increment After
DA Decrement After
If the base register writeback option ((!)) is specified, the base register (Rn) is modified with the
new base address. (registers) is a list of registers, separated by commas and specifies the set of
registers to be stored. The registers are stored in sequence, the lowest-numbered register to the
lowest memory address, through to the highest-numbered register to the highest memory
address. If R15 (PC) is specified in (registers), the value stored is UNKNOWN.
Exceptions Data Abort
Usage STM is useful as a block store instruction (combined with LDM it allows efficient block copy)
and for stack operations. A single STM used in the sequence of a procedure can push the return
address and general-purpose register values on to the stack, updating the stack pointer in the
process.
Condition Codes
The condition codes are not effected by this instruction.
Notes If R15 (PC) is given as the base register (Rn), the result is UNPREDICTABLE.
If Rn is specified as (registers) and base register writeback ((!)) is specified:
• If Rn is the lowest-numbered register specified in (registers), the original value of Rn is stored.
• Otherwise, the stored value of Rn is UNPREDICTABLE.
The value of Rn should be word alligned.
SUB Subtract
SWP Swap
Table b.2 ARM Instruction Operand1 field table for data Access
ARM Instructions
Add with Carry ADC(cc)(s) Rd, Rn, (op1) (cc) : Rd = Rn + (op1) + CPSR(C)
Add ADD(cc)(s) Rd, Rn, (op1) (cc) : Rd = Rn + (op1)
Bitwise AND AND(cc)(s) Rd, Rn, (op1) (cc) : Rd = Rn ^ (op1)
Branch B(cc) (offset) (cc) : PC = PC + (offset)
Branch and Link BL(cc) (offset) (cc) : LR = PC + 8
(cc) : PC = PC + (offset)
Compare CMP(cc) Rn, (op1) (cc) : CSPR = (Rn - (op1))
Exclusive OR EOR(cc)(s) Rd, Rn, (op1) (cc) : Rd = Rn _ (op1)
Load Register LDR(cc) Rd, (op2) (cc) : Rd = M((op2))
Load Register Byte LDR(cc)B Rd, (op2) (cc) : Rd(7:0) = M((op2))
(cc) : Rd(31:8) = 0
Move MOV(cc)(s) Rd, (op1) (cc) : Rd = (op1)
Move Negative MVN(cc)(s) Rd, (op1) (cc) : Rd = (op1)
Bitwise OR ORR(cc)(s) Rd, Rn, (op1) (cc) : Rd = Rn _ (op1)
Subtract with Carry SBC(cc)(s) Rd, Rn, (op1) (cc) : Rd = Rn - (op1) - CPSR(C)
Store Register STR(cc) Rd, (op2) (cc) : M((op2)) = Rd
Store Register Byte STR(cc)(s) Rd, (op2) (cc) : M((op2)) = Rd(7:0)
Subtract SUB(cc)(s) Rd, Rn, (op1) (cc) : Rd = Rn - (op1)
Software Interrupt SWI(cc) (value)
Swap SWP(cc) Rd, Rm, [Rn] (cc) : Rd = M(Rn)
(cc) : M(Rn) = Rm
Swap Byte SWP(cc) B Rd, Rm, [Rn] (cc) : Rd(7:0) = M(Rn)(7:0)
(cc) : M(Rn)(7:0) = Rm(7:0)
APPENDIX C
ARM7TDMI -Instruction Encoding
The ARM7TDMI uses a fixed-length, 32-bit instruction encoding scheme for all ARM
instructions. The basic encoding for all ARM7TDMI instructions is shown below. Individual
instruction descriptions and encodings are shown in section 4 of this document.
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Move shifted register 0 0 0 Op Offset Rs Rd
Add/subtract 0 0 0 1 1 1 Op Rn/offset3 Rs Rd
Move/compare/add 0 0 0 Op Rd Offset8
ALU operations 0 1 0 0 0 0 Op Rs Rd
Hi register operations/branch exchange 0 1 0 0 0 1 Op H1 H2 Rs/Hs Rd/Hd
PC-relative load 0 1 0 0 1 Rd Word8
Load/store with register offset 0 1 0 1 L B 0 R0 Rb Rd
Load/store sign-extended byte/half word 0 1 0 1 H S 1 R0 Rb Rd
Load/store with immediate offset 0 1 1 B L Offset5 Rb Rd
Load/store half word 1 0 0 0 L Offset5 Rb Rd
SP-relative load/store 1 0 0 0 L Rd Word8
Load address 1 0 0 1 SP Rd Word8
Add offset to stack pointer 1 0 1 1 0 0 0 0 S SWord7
Push/pop registers 1 0 1 1 L 1 0 R Rlist
Multiple load/store 1 1 0 0 L Rb Rlist
Conditional branch 1 1 0 1 Cond Softset8
Software Interrupt 1 1 0 1 1 1 1 Value8
Unconditional branch 1 1 1 0 0 Offset11
Long branch with link 1 1 1 1 H Offset
APPENDIX D
References
ARM7TDMI Data Sheet.
The Insider‘s Guide To The Philips ARM7-Based Microcontroller Published By
Hitex (UK) Ltd.