An Overview of Assembly Language for Programming Microcontrollers

Introduction

Software is the term used for the instructions that tells a microprocessor or microcontroller what to do. The collections of instructions that a microprocessor will recognize is its instruction set. The form of the instruction set depends on the microprocessor focused on.

Microprocessors operate in binary code. The instructions written in binary code are referred to as being in machine code. Writing a program in binary code i.e. a series of zeros and ones is not easy, nonetheless, we can use an easy to understand form of shorthand code referred to as mnemonic code (memory-adding code) for example in Freescale microcontrollers, the code: STAA $0011 copies data in accumulator A to location 0011. Assembly language is the term used to describe such a code. Writing programs in assembly language (using mnemonics) is easier because they are abbreviated version of the operation performed by the instruction. Additionally, since the instructions describe the program operations, they can be easily comprehended, and less prone to error than binary patterns of machine code programming. The assembler language has to be converted into machine code for the microprocessor to recognize it. The computer software used to convert assembly language program to machine code is referred to as assembler programs.

To use a microcontroller in say a mechatronic system design, software must be written, tested and stored in the ROM of the microcontroller. Normally, the software is written and compiled using a PC and then downloaded to the microcontroller ROM as machine code. If the program is written in assembly language, the PC must have software referred to as a cross-assembler that generates machine code for the microcontroller. An assembler is software that generates machine code for the microprocessors in the PC, while a cross-assembler generates machine code for a different microprocessor, in this case the microcontroller.

An Overview of Assembly Language for Programming Microcontrollers

Assembly Language Basic Elements

Generally, assembly language programs contain the following five basic elements:

  1. Directives
  2. Labels
  3. Instructions
  4. Operands
  5. Comments

Directives

Directives are similar to instructions, but unlike instructions, they are independent on the microcontroller model, and represent a characteristic of the assembly language itself. Directives (pseudo-instructions) give directions to the assembler. Assembler directives define data and symbols, set assembler and linking conditions, and specify output formats.

Directives do not generate any machine code and are used only by the assembler.

Example of a directive:

  ORG

Origin defines the starting memory address of the part of the program as illustrated below:

ORG 0H   ; start (origin) at location

For the microcontroller to function properly, you need to define a number of microcontroller parameters prior to the start of the writing of your program. These parameters may include:

  • Whether watchdog timer is turned ON.
  • Type of oscillator
  • Whether internal reset circuit is enabled

Details on these parameters can be found on the datasheet for that specific microcontroller.

For example, all the three parameters aforementioned are defined by the directive:

_CONFIG_CP_OFF&_WDT_OFF&PWRITE_ON&XT_OSC

Labels

A label is a textual designation for a line in a program, or section of a program where the micro can jump to or even the beginning of set of lines of a program. It can also be used to execute branching such as Goto and the program may have a condition that must be met for the Goto instruction to be executed.

Examples of labels:

    Start

    End

   -end

Instructions

These are assembly language instructions for the operation of the microcontroller. Assembly language instructions tell the CPU what to do. The way the instructions are written is referred to as instruction “syntax”.

Example of instructions:

Goto Start

Operands

Operands are the instruction elements for the instruction being executed. They are usually registers or variables or constants.

In the instruction movlw H“FF”, the operand is H“FF”

Comments

A comment is added to explain the function of instructions and directives. It is placed after an instruction, and must begin with a semicolon “;”.  In other words Comment is a series of words that a programmer writes to make the program more clear and legible.

Headers

To inform the assembler program which microcontroller it is dealing with, and which file to use for information about the microcontroller, headers are used with programs. For instance, with a PIC microcontroller, this could be:

include “c:\pic\p16c54.inc”

Or with AVR Mega microcontroller:

include “M32DEF.INC”

Writing Assembly Language Programs

An assembly language program is usually a series of instructions to an assembler which will then produce the machine code program. A program written in assembly language consists of a sequence of statements, one statement per line. A statement contains from one to four sections or fields:

Label Op-code Operand Comment

The start or end of a field is indicated by Freescale microcontrollers by spaces. With Intel microcontrollers there is a colon after a label, a space after the op-code, commas between entries in the address field and a semicolon before a comment. In general, a semicolon is used to separate comments from the operand. As an example, the following illustrates statements in Intel program:

DATA1: DB 28  ;DECIMAL (1C in Hex)

DATA2: DB 00110101B  ;Binary (35 in Hex)

The label is the name by which a particular line in the program can be referred to make the code easier to read, such as, LOOP, to indicate the line in a program which the program will later have the instruction to loop back to. Labels may consist of letters, numbers, and some other characters; however, the label must not use any of the names that are reserved for registers, instruction codes or pseudo-operations. All labels within a program must be unique. If there is no label, then a space must be included in the label field. With Freescale, an * in the field indicates all the entire statement is a comment.

The op-code or operand specifies how data is to be manipulated and is specified by its mnemonic such as LDA A. These mnemonics are typically listed in the instruction sets for microprocessors. The op-code is the only field that can never be empty. In addition it may contain directives to the assembler. These are referred to as pseudo-operations because they appear in the op-code field but are not translated into instructions in machine code. They may define symbols, assign programs, and data to certain areas of memory generate fixed tables, and data, indicate the end of the program, etc. Some of the commonly used assembly language directives are:

ORG Origin defines the starting memory address of the part of the program that follows such as:

 ORG $E000

The ORG instruction can be used more than once in a program, the code following an instruction then starting at the specified location.

EQU Equates is used to define the location for an item. For instance, with the following we can write NUM and the program assembler will see it as being file register $00, so enabling a symbolic name to be used in place of a number and making the program more legible.

 NUM EQU $00

A list of equates is usually placed at the beginning of a program.

END The END defines the last statement of the program. Nothing beyond END is processed by the assembler.

The information included in the operand field depends on the mnemonic preceding it and the addressing mode used. It provides the address of the data to be operated on by the process specified by the op-code. Hence it is usually referred to as the address field. This field may be empty if the instructions given by the op-code do not need any data or address. Numerical data may be binary, hex, octal, or decimal. Generally, in the absence of any indicator, the assembler assumes the number is decimal. With Freescale microcontrollers, a number is indicated by the prefix #; a binary number is preceded by % or followed by B; an octal number is preceded by @ or followed by O; a hexadecimal number is preceded by $ or followed by H; and a decimal number requires no indicating letter or symbol. With Intel microcontrollers, numerical values must be preceded by # to indicate a number and by B for binary, O or Q for octal, H or h for hexadecimal and D or nothing for decimal. With PIC microcontrollers, the header file has R 5 DEC for decimal to be default. The binary is enclosed in quotation marks and preceded by B and for hex by H. For Atmel microcontrollers, binary numbers are preceded by b, hex numbers by 0x or $, and if nothing is in front then the number is a decimal.

The comment field is optional and is usually used by the programmer to make the program understandable and legible by adding comments. The comment field is ignored by the assembler during the production of machine code.

Common Instruction Sets used with Microcontrollers

The instruction set is a list of instructions that may be used with a microprocessor or microcontroller. Such instruction sets usually contain data transfer and movement instructions, arithmetic instructions, logical instructions and program control instructions.

Examples of instructions that you are likely to encounter include:

Data Transfer/Movement Instructions

1.  Load

This instruction reads the contents of a specified memory location and copies it to a specified register location in the CPU. For instance, with Atmel AVR microcontrollers, the instruction LDS (load direct from data space) can be used, e.g. LDS R5, 0x200 this loads R5 with the contents of location 0x200.

In a similar way, with Freescale microcontrollers, LDAA $0010 loads accumulator A with contents of memory location 0010.

2.  Store

This instruction copies the current contents of a specified register into a specified memory location. For instance, with Freescale microcontrollers STAA $0011 copies data in accumulator A to location 0011.

3.  Move

This instruction is used to move data into a register or copy data from one register to another, such as with PIC microcontrollers, MOV R5, A.

In Intel microcontrollers, an instruction to move data could be MOV A, #3Fh to move the data value 3F, in hexadecimal notation, into register A. As mentioned earlier, the # is used to indicate a number and h to indicate that it is in hexadecimal notation.

A similar instruction in Atmel AVR microcontrollers could be mov Rd, Rr to make a copy of register Rr in Rd.

4.  Clear

Clear instruction resets bits to 0, for example, to clear all bits with Freescale microcontroller: CLRA to clear accumulator A. In the same manner, with PIC CLRF 06 instruction clears file register 06. Other clear instructions are available to clear individual flags.

5.  Logical Shift (Left or Right)

These instructions involve moving the pattern of bits in the register one place to the left or right by moving a 0 into the end of the number. For instance, for logical shift right a 0 is shifted into the most significant bit and the least significant bit is moved to the carry flag in the status register as demonstrated below:

Illustration:

Before instruction: Accumulator with data 0011

After instruction: Accumulator with data 0001

                               Status register indicates Carry 1

For Freescale microcontrollers, the instruction LSRA will shift to the right and LSLA for a shift to the left. With Atmel microcontrollers, the instruction lsl Rd for logical shift left and lsr Rd for shift right.

6.  Arithmetic Shift (Left or Right)

These instructions involve moving the pattern of bits in the register one place to the left or right but reserve the sign bit at the left end of the number, for example, for an arithmetic shift right with Freescale instruction ASRA as illustrated below:

Illustration:

Before instruction: 1011

After instruction: Accumulator with data 1001

                                Status register indicates Carry 1

7.  Rotate (Left or Right)

These instructions involve moving the pattern of bits in the register one place to the left or right and the bit that spills out is written back into the other end, for example, for a rotate right, Atmel instruction ror Rd, and Intel instruction RR A, this illustrated below:

Illustration:

Before instruction: Accumulator with data 0011

After instruction:   Accumulator with data 1001

8.  Arithmetic Instructions

Add

This instruction adds a number to the data in a register, for example, for Intel microcontrollers; ADD A, #10h instruction to add to accumulator A.

Illustration:

Before instruction: Accumulator A with data

After instruction: Accumulator A plus 10 hex

Decrement

This instruction subtracts 1 from the contents of a specified location. For instance, with Intel, DEC R3 as illustrated below:

Before instruction: Register R3 with data 0011

After instruction: Register R3 with data 0010

Increment

This instruction adds 1 to the contents of a specified location. For example an instruction with PIC microcontroller incf 06 to increment data in register 06 by 1.

Compare

This instruction indicates whether the contents of a register are greater than, less than or the same as the contents of a specified memory location. For example, for Freescale microcontrollers, CMPA is used for comparison of the contents of ACCA to the contents of a register and sets the condition flags N, Z, V or C as per the result. Atmel instruction cp r3, r4 compares register r3 with r4 and flags H, S, V, N, Z or C are set.

9.  Logical Instructions

AND

This instruction carries out the logical AND operation with the contents of a specified memory location and the data in some register. The AND operation is applied bit by bit, for example, with Freescale, ANDA %1001:

Before instruction:  Register A with data 0011

                                   Memory location with data 1001

After instruction: Accumulator A with data 0001

For Intel, ANL is used for logical AND operation, for example, ANL A, #3Bh to apply AND operation to contents of register A with the hexadecimal number 3B.

OR

This instruction carries out the logical OR operation with the contents of a specified memory location and the data in some register, bit by bit, for example, with Intel, ORL A, #3Fh will OR the contents of register A with the hexadecimal number 3F.

EXCLUSIVE-OR

This instruction carries out the logical EXCLUSIVE-OR Operations with the contents of a specified memory location and the data in some register, bit by bit, such as with PIC microcontrollers, xorlw 81h (81 hexadecimal in binary in 10000001):

Before instruction: Register w with 10001110

After instruction: Register w with 00001111

The XOR operation with a 0 leaves a data bit unchanged while with a 1 the data bit is inverted. For Intel, XRL is used for the EXCLUSIVE-OR operation, for example, XRL, A, 3Bh.

10.                 Program Control Instructions

Jump or Branch

This instruction changes the sequence in which the program steps are carried out. Usually the program counter causes the program to be carried out sequentially in strict numerical sequence. But, the jump instruction causes the program counter to jump to some other specified location in the program. Unconditional jumps occur without the program testing some condition to occur. For PIC microcontrollers, a jump instruction will be GOTO POINTA, with Intel, LJMP POINTA.

No operation NOP

This is a single-byte instruction the causes only the program counter to be incremented. No other registers are affected. This instruction is usually used to produce a time delay before the next operation is carried out. For instance, in Atmel programs, it is utilized to carry out a wait while data direction register is configured following an instruction to set bits as inputs or outputs.

Halt/stop This instruction stops all further microprocessor activity.

Bottom Line

To sum up, it is clear from some of the examples I have given above that, to write a program in assembly language, you need to have some understanding of the microcontroller/microprocessor architecture you are working with. Assembly language programs interact with the hardware, therefore, having knowledge on the computer architecture is paramount, i.e. take some time to learn the registers, memory organization, memory addressing, etc. of the microcontroller/microprocessor you are focused on before embarking on learning to program it in assembly language.

Please follow us and share:

Author: John Mulindi

John Mulindi has a background in a technical field and he writes on topics ranging from automation, computer systems, embedded systems, mechatronics to measurement and control.

4 thoughts on “An Overview of Assembly Language for Programming Microcontrollers”

Leave a Reply