0% found this document useful (0 votes)
7 views60 pages

History and Binary Representation

This document reviews the history of electronics and the development of microprocessors, highlighting key milestones from the discovery of the diode in 1874 to the founding of Intel in 1968. It also distinguishes between microprocessors and microcontrollers, explaining their functions and packaging. Additionally, the document covers binary representation, fixed-point and floating-point arithmetic, including methods for representing negative numbers and performing arithmetic operations.

Uploaded by

fabio.sipoli
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
7 views60 pages

History and Binary Representation

This document reviews the history of electronics and the development of microprocessors, highlighting key milestones from the discovery of the diode in 1874 to the founding of Intel in 1968. It also distinguishes between microprocessors and microcontrollers, explaining their functions and packaging. Additionally, the document covers binary representation, fixed-point and floating-point arithmetic, including methods for representing negative numbers and performing arithmetic operations.

Uploaded by

fabio.sipoli
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 60

History & Binary Representation

C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul,
RS 91501-970, Brazil.

August 30, 2017

Abstract
In this lesson we will review the history of electronics and the devel-
opment of the first microprocessors.
Keywords— Microcontrollers; Microprocessors; Electronics; Digital.

1 History
Let us begin with the history of semiconductors and contemporary electronics.
Although it started in Germany, it flourished at the Bell Labs in the United
States.
∗ creq@[Link]

1
1874 Diode effect discovered by Ferdinand Braun at the University
of Berlin.
1906 Diode patented.
1925 Bell Labs is founded.
1925 MOS transistor is patented by Julius Lilienfeld.
1929 Walter Brattain joins Bell Labs.
1934 Another MOS patent by Oskar Heil.
1936 Mervin Kelly becomes director of Bell Labs.
1936 William Shockley joins Bell Labs.
1945 John Bardeen joins Bell Labs.
1947 Bardeen and Brattain conceive the Point Contact Transistor.
1948 Shockley invents the Bipolar Junction Transistor.
1953 First transistor computer built at the University of Manchester
by Dick Grimsdale.
1954 Transistors are fabricated in Si by Morris Tanenbaum at Bell Labs.
1956 Nobel Prize for the invention of the transistor.
1956 Shockley found Shockley Semiconductor Laboratory in Mountain
View, CA.
1957 Robert Noyce, Gordon Moore, Jean Hoerni and the other traitorous
eight found Fairchild Semiconductors.
1958 Jack Kilby at Texas Instruments and Robert Noyce at Fairchild
Semiconductors independently develop the fist Integrated Circuit.
1959 Planar transistor developed by Jean Hoerni at Fairchild
Semiconductors.
1968 Robert Noyce and Gordon Moore found Intel Corporation.

Soon after Intel is founded, a new revolution starts by making electronic


circuits mimick the behavior of machines such as Charles Babbage’s difference
engine from 1822, Alan Turing’s a-machine from 1936, and John Atanasoff and
Clifford Berry’s automatic electronic digital computer from 1942. Soon after in
1946, John Brainerd at the University of Pennsylvania develop the Electronic
Numerical Integrator and Computer (ENIAC). The first transistorized computer
appeared in 1955 at the University of Manchester under the leadership of Tom
Kilburn. It took another 15 years for the development of integrated processors.

2
Figure 1: DIP, PLCC and PGA packagings.

Model Year W/Mem. [bits] [MHz] MIPS Applications


Intel 4004 1971 4 BCD/12 .74 .056 Calculators
Intel 8008 1972 8/14 .80 .12 Calc./Robots
Intel 4040 1974 4 BCD/13 .74 .060 Calculators
TI TMS1000 1974 4/8 .4 .050 Calculators
Intel 8080 1974 8/16 3.125 .29 Cash Registers
[Link]. CP1600* 1974 8/16 5 .2 Video Games
Zilog Z80 1976 8/16 8 .40 Video Games
MOS Tech 6502 1976 8/16 8 3.4 Video Games
Intel MCS-48 1976 8/8 11 .5 Controllers
Intel 8085 1976 8/16 6.5 1 Controllers
Intel 8086 1978 16/16 10 .75 PC-XT
Intel 8087 1979 16- 10 50 kFLOPS FPU
Motorola 68000 1979 32/24 7.67 1 Mac/Video Games
Intel 8051 1980 8/16 12 1 Controllers
Intel 80186 1982 16/20 25 1 PC-AT
Acorn ARM1/2 1985 32/26 6 8 Computers
Atmel AVR 1996 8/ 8 8 Controllers
(*) Microchip’s PIC was born from there.

2 Microprocessors vs. Microcontrollers


Microprocessors are units responsible for processing the flow of information
in an eletronic system, whereas microcontrollers are units that incorporate a
processor, a memory and other subunits to perform intelligent operations. Sim-
ple microcontrollers can have packagings as simple as a DIP16 such as the Intel
4004. Most common microcontrollers are found in a DIP40 package, whereas
modern microprocessors are found in packagings such as a 82 PLCC. Some of
these packagings are shown in Fig. 1.

3
3 Binary Representation
Let us begin our study of microcontrollers by reviewing the binary representa-
tion and operations.
A binary number has only two mnemonics. We will use 1 to represent the
high state, and 0 to represent the low state. Thus, we can have a binary number
such as 011001. This can be converted to decimal by:
ÿ
X“ bn 2n
n
“ 1 ˆ 20 ` 0 ˆ 21 ` 0 ˆ 22 ` 1 ˆ 23 ` 1 ˆ 24 ` 0 ˆ 24 (1)
“ 1 ` 8 ` 16
“ 25.
The reverse operation can be constructed by successively dividing a decimal
number by 2 and taking the remainder. For example:

25{2 “ 12 ` rr1s
12{2 “ 6 ` rr0s
6{2 “ 3 ` rr0s (2)
3{2 “ 1 ` rr1s
1{2 “ 0 ` rr1s,
where r[x] is the remainder of the operation. Therefore, 25 can be represented
as 11001.
Now, let’s take number 9 in binary:

9{2 “ 4 ` rr1s
4{2 “ 2 ` rr0s
(3)
2{2 “ 1 ` rr0s
1{2 “ 0 ` rr1s
It needs 4 bits to be represented. We could have reached the same result by
taking Log2 p9q « 3.17 Ñ 4. Thus, we can represent decimal numbers in groups
of four bits. This is called binary coded decimal or BCD. For instance,25 would
be represented as 0010 0101. It requires more bits to be represented but it has
the advantage of simplicity.

3.1 Fixed Point Representation


How do we represent real numbers? There are two possibilities, the first is to use
fixed point The trick here is to apply a binary point. For example, let us take
again number 25 in binary (11001) and apply a point so that we have 110.01.
In this case we have:

4
110.01 “ 1 ˆ 22 ` 1 ˆ 21 ` 0 ˆ 20 ` 0 ˆ 2´1 ` 1 ˆ 2´2
“ 4 ` 2 ` 0.25 (4)
“ 6.25.
In our case both 25 and 6.25 have exacly the same representation in binary. The
only difference is the point.

3.1.1 1’s Complement


And negative numbers? One strategy is to use the 1’s complement by just
negating the expression. For example, for our 25 we would have 011001 and -25
would be 100110 in a 6 bit notation. For a 3 bit representation we would have:

´3 “ 100
´2 “ 101
´1 “ 110
´0 “ 111
(5)
0 “ 000
1 “ 001
2 “ 010
3 “ 011
This has some problems. For example, the 1’s complement of 000000 (0)
is 111111 (-0). Furthermore, arithmetic operations become problematic. Let’s
take for example 3-1 in a 3 bit representation. This would be 011 + 110, which
would produce 001 and a carry-out bit of 1. This has to be added to the result
and we obtain 010, which is the expected result.

3.1.2 2’s Complement


We can improve computations and use a 2’s complement by always adding one.
For example, 3 in a 3 bit representation is 011, thus -3 in 1’s complement is 100.
In 2’s complement we only have to add 1 and obtain 101. Thus, again in a 3
bit representation we would have:

´4 “ 100
´3 “ 101
´2 “ 110
´1 “ 111
(6)
0 “ 000
1 “ 001
2 “ 010
3 “ 011

5
This way, not only we avoid the problem of -0 as we also simplify the arithmetics.
Let’s see that example of 3-1 again now in 2’s complement. This would be
011+111=010=2 with a carry bit that can be completely discarded. In 2’s
complement, overflow can be detected if summing two numbers of the same
sign produces a number with an opposite sign.
Let us now see how this works for signed fixed point numbers:

´2.0 “ 100
´1.5 “ 101
´1.0 “ 110
´0.5 “ 111
(7)
0.0 “ 000
0.5 “ 001
1.0 “ 010
1.5 “ 011

3.1.3 Arithmetic
For fixed point representation, addition and subtraction are exactly the same
operations as we would do for integer numbers. For example:

0.5 ` 1.0 “ 00.1 ` 01.0 “ 01.1 “ 1.5


(8)
1.5 ´ 0.5 “ 01.1 ` 11.1 “ 01.0 “ 1.0
Now let’s see how it works for multiplication. For simplicity let us drop the
radix point and take care of it later.

010
ˆ 001
010
1.0 ˆ 0.5 “ (9)
000
` 000
00010
We must now account for the radix point. Since both multiplicands have points
after the first bit, the result has to have the point after two bits. Therefore,
the result is 000.10. However, our representation includes only one bit for the
fractional part and two for the integer part. We therefore must either truncate
or round the result for the appropriate number of bits. It is simple in this case
to just truncate it to 00.1, which in decimal is 0.5, the result that we expected.
Let us now use two bits for each the integer and the fractional part. Our
correspondence table becomes:

6
0.00 “ 0000
0.25 “ 0001 ´0.25 “ 1111
0.50 “ 0010 ´0.50 “ 1110
0.75 “ 0011 ´0.75 “ 1101
1.00 “ 0100 ´1.00 “ 1100 (10)
1.25 “ 0101 ´1.25 “ 1011
1.50 “ 0110 ´1.50 “ 1010
1.75 “ 0111 ´1.75 “ 1001
´2.00 “ 1000
Let’s multiply 0.25 ˆ ´2.00:

0001
ˆ 1000
0000
0000 (11)
0000
` 1000
1000000
Our multiplicands have two bits for the fractional part. Therefore, the result
should have four bits for its fractional part and we would get 100.0000. Trun-
cating it we get 00.00, which is completely wrong. This happened because we
did not account for the sign. One way to compensate for it is by expanding the
bit sign:

1000
ˆ 0001
111000
0000 (12)
0000
` 0000
0111000
We must place the point four bits from the right hand side end. Therefore, the
truncated result becomes 11.10, which corresponds to -0.5 as expected. Why
did we do this 1 filling operation? Because we are multiplying 1ˆ a negative
number. We therefore must take its 2’s complement. We obtain it by 1 filling.
This is known as sign extension. Let’s calculate it now the other way around:

0001
ˆ 1000
0000
0000 (13)
0000
` 1111
1111000

7
Taking four bits for the radix point and truncating we get 11.10, which is the
expected result. Note, however that we took 2’s complement. This happened
because we are multiplying one argument by the sign bit. It is like multiplying
the argument by -1.
Let’s now take a look at another example: ´0.75 ˆ 0.75:

1101
ˆ 0011
1111101
111101 (14)
0000
` 0000
11110111
Placing the point we get 1111.0111. If we simply truncate the result we get
1101 which corresponds to -0.75. The right result would be -0.5625 and we
have a quantization error which cannot be accounted for in this representation
with a restricted number of bits. For the sake of practice, let’s make the same
calculation the other way around:

0011
ˆ 1101
0011
0000 (15)
0011
` 1101
11110111
Which is exactly the same value.

3.2 Floating Point


With floating point we have a completely different story. In floating point, a
number is represented as:

S E3 E2 E1 E0 M5 M4 M3 M2 M1 M0 , (16)
where S is a bit for the sign, E is the exponent, and M is the mantissa. This
can be represented as p´1qS M ˆ 2E . Typically, in floating point representation,
the mantissa is normalized. For example:

110.100 “ 1.10100 ˆ 22
. (17)
0.00101 “ 1.01000 ˆ 2´3
Also, the exponent is stored with a 127 bias according to IEEE 754 standard.
This means that the exponent is added to 127 (01111111) and then stored.
For example, 12 (01100) is stored as 139 (010001011), and -5 is stored as 122
(01111010).

8
Let us now put it all together. A number in floating point notation is stored
as SIGN EXPONENT MANTISSA. Also, for the mantissa, the 1 at the left
hand side of the radix point is dropped. Let’s look at some examples:

´10.0110 “ ´1.0011 ˆ 21 “ 1 10000000 00110000


´3
(18)
0.00101 “ `1.01 ˆ 2 “ 0 01111100 01000000

3.2.1 Arithmetic
Addition and subtraction are quite simple. We first must put both operands in
the same exponent and them perform a standard sum of the mantissas main-
taining the exponent.
Multiplication and division are also simple. For the mantissa we must per-
form a standard multiplication. We sum the exponents and subtract the bias.
The sign bit are just added and the carry is dropped.
Thus for a floating point representation with 2 bits for the exponent with a
bias 2 and 3 bits for the mantissa we have:

2.5 ` 0.5 “
“ 10.1 ` 0.1
“ 1.01 ˆ 21 ` 1.00 ˆ 2´1
“ 0 11 010 ` 0 01 000
“ 101.00 ˆ 2´1 ` 1.00 ˆ 2´1 (19)
“ 110.00 ˆ 2´1
“ 1.10 ˆ 21
“ 0 11 100
“ 3.0.
´2.0 ˆ 0.25 “
“ ´10.0 ˆ 0.01
“ ´1.00 ˆ 21 ˆ 1.00 ˆ 2´2
“ 1 11 000 ˆ 0 00 000
(20)
“ 1 01 000
“ ´1.000 ˆ 2´1
“ ´0.100
“ ´0.5

9
Computer Architecture
C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul,
RS 91501-970, Brazil.

September 11, 2017

Abstract
In this lesson we will review digital electronics and begin studying
processor architectures.
Keywords— Microcontrollers; Microprocessors; Electronics; Digital.

1 Circuit Blocks
As logical connectives let’s take the dyadics conjunction (^, AND), disjunction
(_, OR), the exclusive disjunction (Ü, XOR), and the unary negation ( ,
NOT). Also, as memory elements let’s take the register. These elements are
shown in Fig. 1.
In a digital system we may have an adder, a subtracter and many other
small blocks. In order for the processor to work, we must have a unit that sends
the appropriate signals for these blocks, that load registers, etc. This is called
control unit. There must be another block that actually make computations.
This block is known as processing unit. Certainly, we must also have registers
and some other components that store information. This is called memory block.
∗ creq@[Link]

A A A
A B A B A B
B B B

D Q
A A
clr Q

Figure 1: Logic gates and their functions.

1
Let us consider a stupid simple architecture that takes two bits and either
add or subtract them. Let us design the adder and the subtracter. If we make
an operation such as 0-1, we must raise a flag to state that we have an un-
derflow. By the same token, if we add 1+1 we must also raise a flag to state
that we have an overflow. For the sake of simplicity, let’s make this flag the same.

b1 b2 add sub flag


0 0 0 0 0
0 1 1 0 1
1 0 1 1 0
1 1 0 0 1

From this truth table we clearly see that add = b1 b b2 , sub = b1 .b̄2 , and flag
= b2 . These operations will be inside the logical and arithmetic unit or ALU.
However, we must select whether we want the ALU to perform an addition or
a subtraction. Let’s say that if the selection bit ’s’ is 0 we add the inputs. The
truth table for this is:

s add sub ALU


00 0 0
00 1 0
01 0 1
01 1 1
10 0 0
10 1 1
11 0 0
11 1 1
With this table we can construct a Karnaugh map:

add/sub

00 01 11 10

0 1 1
S
1 1 1

For LAU we thus have s̄.add ` [Link]. Thus, we have the control unit illus-
trated in Fig. 2.
This block has to perform operations on data and this is stored in registers
or in a memory bank. In our example, let’s use a single register ‘R’ that can

2
ADD
flag

b2 LAU
b1
s
SUB

Figure 2: Logic and arithmetic unit. The dashed boxes correspond to the adder
and subtracter subblocks.

feed the LAU and also store its result. Also, we can also asynchronously set and
reset it. Nonetheless, our operations are dyadic, so we need another element.
Since our circuit works with only one bit, the other element can only be 0 or 1.
This can come from another point of the circuit and we shall call it ‘Y’. At this
point our circuit is as that shown in Fig. 3.

Y
SET R
set
D Q
LOAD R
clr Q
CLEAR R

X Y

S s
flag

Figure 3: 1 bit LAU and register with control signals explicitly shown.

We need now to feed these control signals. We can do it sequentially. For


example, first we send signals for setting the register, then a following command
to add it with 1 and then to store the result in the register. But this is just
a possibility. For some other application we could have a total different order
of commands. The best solution for this problem is to store these commands
in a memory and read them sequentially. In order to do this we will need
the memory itself, a counter that goes over each memory position and some
hardware to interpret the commands. Let’s take a closer look at these elements.
The memory can be a programmable read only memory (PROM) or an elec-

3
trically erasable programmable read only memory (EEPROM). In any case we
need to tell it which position of the memory we want to read. Furthermore we
need to tell it that we want to read that address. In order to do this we will
use a counter, which we shall call Program Counter (PC). Nonetheless, the PC
need signals to increment its status and the memory needs a signal to read the
contents of the corresponding position. This circuit block is illustrated in Fig.
4.

READ
read
INC inc cnt add MEM
data

PC
CODE
Figure 4: Program counter and memory block.

What code can be stored in this memory? Our LAU can do addition and
subtraction. Also, we can set, reset or load the R register. Therefore we can
have a very limited set of instructions. For each one we must assign a different
binary code. We can have something like the instruction set shown in Table 1.

Table 1: Instruction set for the 1 bit architecture.


Instruction Code
Load R register 010
Set R register 001
Clear R register 000
Add 1 101
Add 0 100
Sub 1 111
Sub 0 110

We now need a block that interprets the instructions and sends the appro-
priate signals to the other circuit blocks. This we will call the control unit.
From the table we see that the instructions related to R register have a 0 most
significant bit (MSB). Therefore we must have a C¯3 .C1 for the SET R signal,
C¯3 .C¯2 .C¯1 for the CLEAR R signal, and C¯3 .C2 for the LOAD R signal. The
commands for the LAU have a 0 MSB. Furthermore, the addition instructions
have their second bit always 0, whereas the subtraction instructions have their
second bit always 1. Therefore, we must have C2 for the S signal and C1 for
the Y signal. Finally, we can always read the memory and increment the PC
for each clock signal. Thus, we connect the latter to the CLK signal and the

4
former to logic 1. We finally have the architecture shown in Fig. 5.

1
read
CLK inc cnt add MEM
data

PC

set
D Q
clr Q

X Y

s
flag

Figure 5: 1 bit architecture.

Obviously, this architecture is useless. Nonetheless it illustrates the overall


structure of a processor.

2 Architecture
The architecture of the first microprocessor (Intel 4004) is shown in Fig. 6. For
running this architecture, there were 45 instructions available. This is a good
point to start studying computer architecture. However, we can construct an
even simpler version of this microprocessor to understand basic concepts.
A very simple architecture is shown in the Fig. 7. Here we have the same
elements depicted in the 1 bit architecture but with a few modifications. First,
instead of a single flag, we have now a status register. The register can be fed
from the memory and also from the ALU itself. Furthermore, the memory is
now storing a set of more complex instructions. These are listed on Table 2.

2.1 Harvard vs. von Neumann


Imagine now a slight modification of this architecture where we could store and
read data in the memory. As a first option we could use the same memory and
bus where the code is. This is known as von Neumann architecture. This is
a architecture that requires a simple hardware. Also, all the instructions are
executed sequentially.

5
D0-D3 bidirectional
Data Bus
Data Bus
Buffer

4 Bit internal Data Bus

Temp.
Accumulator Instruction Register
Register
Register Multiplexer
0 1

Flag Stack
2 3
Flip Flops Multiplexer

Index Register Select


Instruction Program Counter 4 5

Stack Pointer
Decoder and
Machine Level No. 1
6 7
Cycle
Level No. 2
Encoding
ALU 8 9
Level No. 3
10 11
Address
Stack
12 13

Decimal 14 15
Adjust
Scratch
Pad
Timing and Control
ROM Control RAM Control Test Sync Clocks
Reset

CM ROM CM RAM 0-3 Test Sync Ph1 Ph2

Figure 6: Internal architecture of the Intel 4004 (By Appaloosa (Own work) via
Wikimedia Commons).

PC MEM
LOAD OP L
INC

CPU

W
STATUS LOAD
LOAD CLR
CLR

OP

ALU

Figure 7: A simple processor architecture. The brown boxes are registers.

6
Table 2: Instruction set for the proposed simplified architecture.
Instruction Binary Code Description
MOVLW 0000 L3 L2 L1 L0 Move literal to W register.
AND 0001 L3 L2 L1 L0 AND between W register and literal. Result in W.
OR 0010 L3 L2 L1 L0 OR between W register and literal. Result in W.
ADD 0011 L3 L2 L1 L0 ADD literal and store in W register.
CMP 0100 L3 L2 L1 L0 Compare literal and W register, Result in STATUS register.
CLRW 0101 0000 Clear W register.
CLRS 0101 0001 Clear STATUS register.
GOTO 0110 L3 L2 L1 L0 Set PROGRAM COUNTER register to literal.
BTFSS 0111 0000 Skip next instruction is STATUS register is set.
NOP 0111 0001 Do nothing.

DATA CODE
MEM
MEM MEM

CPU CPU

Figure 8: LEFT: von Neumann architecture, RIGHT: Harvard architecture.

We can improve the speed of our architecture if while executing an instruc-


tion we are able to process data in the memory at the same time. In order to do
so, we need to separate the code memory from the data memory with separate
buses. This is known as Harvard architecture. The main advantage of this
architecture is this processes known as pipelining that can improve significantly
the speed of the processor. The cost, on the other hand, is more pieces of hard-
ware needed. This architecture is used in microcontrollers such as those of the
PIC family. Both architectures are illustrated in Fig. 8.

2.2 RISC vs. CISC


There was historically a tendency to offer more powerful resources in micropro-
cessors. Thus, architectures such as the x86 incorporated microcodes directly
on its hardware. This means that once a specific instruction in the code was
interpreted by the CPU it triggered some lower level instructions already hard-
wired in the hardware. For example, there could be an instruction like DEV
X,Y. Once received by the interpreter, it would trigger lower levels already store
in hardware: add x and y and store it in z, sub y from x and store it in t, divide
z by t and store it in z. This kind of architecture is known as complex instruc-

7
tion set computer or CISC. It is convenient to the programmer since the code
becomes simpler and smaller. On the other hand the hardware engineer needs
to pack more content into the processor.
Over the years, manufacturers realized that most of the complex instructions
were rarely used and they required a lot of memory used. Furthermore it did not
offer much flexibility to the programmer since the microcode is already stored
in hardware. One solution proposed by some manufacturers was an architecture
based on a reduced instruction set computer or RISC. In this architecture, the
instructions are simpler, executed directly by the hardware without the inter-
mediation of any microcode. Furthermore, several techniques to improve the
access to the memory were pursued such as pipelining.

3 Memory Addressing
There are several ways that a microprocessor can use to access data. For in-
stance, we can include the data directly as the operand of a MOVLW instruc-
tion (move literal to W):

MOVLW W, 0x3F

Here we are assigning the hexadecimal 0x3F to the register W. This is called
Immediate Addressing.
We can also specify in which memory address the data is using a MOVWF
instruction (move content of W register to memory position specified by the
adddress):

MOVWF 0x3F

Here we are putting whatever is in register W into memory address 0x3F .


This is called Direct Addressing.
It is also possible to put the address wherein the information is in another
memory position and use it as a pointer. We can do this typically using a fake
register. For example, we can create a indexing file register (INDF), whose sole
purpose is to serve as a pointer to the address specified in a file select register
(FSR). Let’s study the following example:

MOVLW 0x0C
MOVWF FSR
CLRF INDF
Here we have assigned the value 0x0C to FSR. When we send an instruction
to clear INDF, the microprocessor is actually clearing whatever is in memory ad-
dress 0x0C. This is called indirect addressing. The three addressing mechanisms
detailed here are shown in Fig. 9.
Some microprocessors offer other memory addressing modes such as indexed
and stacked addressing, but these are out of the scope of this text.

8
IMMEDIATE DIRECT INDIRECT

W = 0xA5 W = 0x3F

MOVLW 0x3F MOVWF 0x3F MOVWF FSR

W = 0x3F W = 0xA5 FSR = 0x3F


[0x3F] = 0xA5
CLRF INDF

[0x3F] = 0x00

ADD DATA ADD DATA ADD DATA

0x3F xxxxx 0x3F 0xA5 0x3F 0x00

Figure 9: Immediate, direct and indirect addressing showing the contents of the
registers and memory.

There can be more than one memory element. Moreover, even if there was
only one memory element, we could need more bits for addressing it completely
than our bus allows. In such cases, the logical memory address can be segmented
in several banks. Thus, for accessing a memory position we first must specify
which memory bank we are interested in and then the offset within that bank.
This is called memory segmentation. You may already have encountered a mes-
sage “segmentation fault” in your personal computer. This is typically caused
by a program trying to access an position within a bank that is not allowed.

9
PIC Architecture
C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul,
RS 91501-970, Brazil.

September 19, 2017

Abstract
In this lesson we will review digital electronics and begin studying
processor architectures.
Keywords— Microcontrollers; Microprocessors; PIC.

1 Architecture
The architecture of microcontroller PIC16F877A is shown in Fig. 1
This RISC architecture has a total of 35 instructions that are shown in the
following table.
For this instruction set, f is any memory location, W is the working register,
b is the bit address within the register, d is the destination bit (0: W, 1: f), C
is the carry/borrow bit of the STATUS register, DC is the digit carry bit of the
STATUS register, and Z is the zero bit of the STATUS register.
The memory of this microcontroller is segmented in 4 banks that contain
specific registers. These are listed in Table 2.
In order to switch banks, we must set the appropriate bits in the STATUS
register at 03h, 83h, 103h or 183h depending on the current active bank.
The STATUS register is composed of the bits described on Table 3 and have
the respective interpretations:

IRP (bit 7) is the Register Bank Select used for indirect addressing. 0 corre-
sponds to banks 0 and 1, and 1 corresponds to banks 2 and 3. Some PICs such
as the 16F8X do not use this bit and it should be maintained clear.

RP1:RP0 (bits 6:5) are the Register Bank Select used for direct addressing.
00 corresponds to bank 0, 01 corresponds to bank 1, 10 corresponds to bank 2
∗ creq@[Link]

1
13 Data Bus 8 PORTA
Program Counter
FLASH RA0/AN0
RA1/AN1
Program RA2/AN2/VREF-
Memory RAM
8 Level Stack RA3/AN3/VREF+
File RA4/T0CKI
(13-bit) Registers RA5/AN4/SS
Program
Bus 14 PORTB
RAM Addr 9
RB0/INT
Addr. MUX RB1
Instruction Reg.
RB2
7 Indirect
Direct Addr. 8 RB3/PGM
Addr.
RB4
FSR reg. RB5
RB6/PGC
STATUS reg. RB7/PGD
8
PORTC
RC0/T1OSO/T1CKI
3 MUX RC1/T1OSI/CCP2
Power-up
Timer RC2/CCP1
Instruction RC3/SCK/SCL
Oscillator
RC4/SDI/SDA
Decode Start-up Timer ALU RC5/SD0
&Control Power-on
8 RC6/TX/CK
Reset RC7/RX/DT
Timing Watchdog
W reg.
Generation Timer PORTD
OSC1/CLKIN Brown-out RD0/PSP0
OSC2/CLKOUT Reset RD1/PSP1
In-Circuit RD2/PSP2
Debugger RD3/PSP3
Low-Voltage RD4/PSP4
Programming Parallel Slave Port RD5/PSP5
RD6/PSP6
RD7/PSP7

PORTE

MCLR VDD,VSS RE0/AN5/RD

RE1/AN6/WR

RE2/AN7/CS
Timer0 Timer1 Timer2 10-bit A/D

Synchronous
Data EEPROM CCP1,2 USART
Serial Port

Figure 1: Architecture of PIC16.

and 11 corresponds to bank 3. In PICs that only use RP0 such as the 16F8X,
RP1 should be maintained clear.

/TO (bit 4) is the Time-out bit. This is a read-only bit. It is 1 after power-up,
a CLRWDT instruction or a SLEEP instruction. 0 indicates that a WDT time-
out occurred.

/PDF (bit 3) is the Power-down bit. This is a read-only bit. It is 1 after


power-up or by the CLRWDT instruction, and 0 by the execution of the SLEEP
instruction.

Z (bit 2) is the Zero bit. It is 1 if the result of an arithmetic or logic operation


is zero, and one otherwise. For borrow, the polarity is reversed.

DC (bit 1) is the Digit carry/borrow. It is the carry-out bit from the 4th low
order bit of the result.

C (bit 0) is the Carry/borrow. It is the carry-out bit from the most significant
bit of the result. For borrow, the polarity is reversed.

2
Table 1: Instruction set for PIC16.
INSTRUCTION DESCRIPTION FLAGS CLK
Data Transfer
MOVLW k W=k – 1
MOVWF f f=W – 1
MOVF f,d d=f Z 1
CLRW Clear W Z 1
CLRF f Clear f Z 1
SWAPF f,d Swap nibbles in f – 1
Data Transfer
ADDLW k W=W+k C, DC, Z 1
ADDWF f,d d=W+f C, DC, Z 1
SUBLW k W=k-W C, DC, Z 1
SUBWF f,d d=f-W C, DC, Z 1
ANDLW k W = W AND k Z 1
ANDWF f,d d = W AND f Z 1
IORLW k W = W OR k Z 1
IORWF f,d W = W OR f Z 1
XORLW k W = W XOR k Z 1
XORWF f,d d = W XOR f Z 1
INCF f,d f=f+1 Z 1
DECF f,d f=f-1 Z 1
RLF f,d Rotate left through carry C 1
RRF f,d Rotate right through carry C 1
COMF f,d d = NOT f Z 1
Bit-oriented
BCF f,b f[b] = 0 – 1
BSF f,b f[b] = 1 – 1
Program Control
BTFSC f,b Skip next if f[b] == 0 – 1(2)
BTFSS f,b Skip next if f[b] == 1 – 1(2)
DECFSZ f,d d = f - 1, skip if Z == 1 – 1(2)
INCFSZ f,d d = f + 1, skip if Z == 0 – 1(2)
GOTO k Go to address k – 2
CALL k Call subroutine – 2
RETURN Return from subroutine – 2
RETLW k Return with W = k – 2
RETFIE Return from interrupt – 2
Other
NOP Does nothing –” 1
CLRWDT Clear watchdog timer TO=1, PD=1” 1
SLEEP Enter sleep mode TO=1, PD=0” 1

3
Table 2: Memory banks for the PIC16 microcontroller.
Bank 0 Bank 1 Bank 2 Bank 3
Addr. Name Addr. Name Addr. Name Addr. Name
00h INDF 80h INDF 100h INDF 180h INDF
01h TMR0 81h OPTION REG 101h TMR0 181h OPTION REG
02h PCL 82h PCL 102h PCL 182h PCL
03h STATUS 83h STATUS 103h STATUS 183h STATUS
04h FSR 84h FSR 104h FSR 184h FSR
05h PORTA 85h TRISA 105h WDTCON 185h SRCON
06h PORTB 86h TRISB 106h PORTB 186h TRISB
07h PORTC 87h TRISC 107h CM1CON0 187h BAUDCTL
08h PORTD 88h TRISD 108h CM2CON0 188h ANSEL
09h PORTE 89h TRISE 109h CM2CON1 189h ANSELH
0Ah PCLATH 8Ah PCLATH 10Ah PCLATH 18Ah PCLATH
0Bh INTCON 8Bh INTCON 10Bh INTCON 18Bh INTCON
0Ch PIR1 8Ch PIE1 10Ch EEDAT 18Ch EECON1
0Dh PIR2 8Dh PIE2 10Dh EEADR 18Dh EECON2
0Eh TMR1L 8Eh PCON 10Eh EEDATH 18Eh Not Used
0Fh TMR1H 8Fh OSCCON 10Fh EEADRH 18Fh Not Used
10h T1CON 90h OSCTUNE 110h GPR 96 bytes 190h GPR 96 bytes
.. ..
11h TMR2 91h SSPCON2 . .
12h T2CON 92h PR2
13h SSPBUF 93h SSPADD
14h SSPCON 94h SSPSTAT
15h CCPR1L 95h WPUB
16h CCPR1H 96h IOCB
17h CCP1CON 97h VRCON
18h RCSTA 98h TXSTA
19h TXREG 99h SPBRG
1Ah RCREG 9Ah SPBRGH
1Bh CCPR2L 9Bh PWM1CON
1Ch CCPR2H 9Ch ECCPAS
1Dh CCP2CON 9Dh PSTRCON
1Eh ADRESH 9Eh ADRESL
1Fh ADCON0 9Fh ADCON1
20h GPR 96 bytes A0h GPR 96 bytes
.. ..
. .
7Fh – FFh – 17Fh – 1EFh –

4
Table 3: STATUS register
bit description
7 IRP
6 RP1
5 RP0
4 /TO
3 /PD
2 Z
1 DC
0 C

2 Configuring the CPU


The first thing to include in a program file is a configuration of the CPU. First we
must tell the compiler how we are generating the clock signal. The possibilities
are shown in the table below.

Table 4: Configuration of the CPU.


LP OSC Low power crystal oscillator.
XT OSC External parallel resonator/crystal oscillator.
HS OSC High speed crystal oscillator.
RC OSC RC oscillator.
CP ON/OFF Code protection.
PWRITE ON/OFF Power-up timer.
BODEN ON/OFF Brown-out reset.
WDT ON/OFF Watchdog timer.
LPV ON/OFF Low voltage IC programming.
CPD ON/OFF Data EE memory code protection.

2.1 Clock
The first thing to configure is the oscillator. Some microcontrollers have an
internal oscillator available. For the vast majority we have to setup an external
oscillator. The PIC microcontroller offer three possibilities that are illustrated
in Fig. 2.
For the external generator configuration not much has to be done. In the
hardware, we only need to connect the generator to OSC1 and leave OSC2 open.
In the software we need to tell the microprocessor to operate in HS, XT or LP.
For the crystal oscillator configuration, acceptable values for C1 and C2 are
given in Table 5. We also need to tell the microprocessor to operate in HS, XT
or LP.
For the RC oscillator configuration, Rext should be between 3 kΩ and 100
kΩ, and Cext should be higher than 20 pF. The frequency of operation will be

5
Mode Freq. C1 C2
LP 32 kHz 33 pF 33 pF
LP 200 kHz 15 pF 15 pF
XT 200 kHz 47-68 pF 47-68 pF
XT 1 MHz 15 pF 15 pF
XT 4 MHz 15 pF 15 pF
HS 4 MHz 15 pF 15 pF
HS 8 MHz 15-33 pF 15-33 pF
HS 20 MHz 15-33 pF 15-33 pF

Table 5: Acceptable values for C1 , C2 , and Rs in the crystal oscillator configu-


ration for the clock. The series resistor may be required by AT crystals.

a function of these values and the supply voltage.

2.2 Code Protection


Some microcontrollers such as the PIC offer the possibility of protecting the
code. Setting up this option blocks the user from reading the code externally.

2.3 Power-up Timer


It is possible to protect the data memory against a spurious write that can
happen. We do this by setting up the Power-up Timer. This will prohibit any
write to the data memory for the first 72 ms after powering the device.

2.4 Brown-out Reset


Another possibility to protect the device is by letting it reset if the power has
been fallen bellow a specific voltage (VBOR ) for more than 72 mS. The device
will remain in brown-out reset until the power voltage has been restored.

2.5 Watchdog Timer


Some microcontrollers such as the PIC have an internal stand alone oscillator
that is completely independent on the clock. If enabled, this timer will peri-
odically emits a reset signal. This can be interesting to avoid that the device
enters in an endless loop caused by some spurious condition, for example. If
using this option, the software has to periodically clear the WDTEN bit (bit
2 of the CONFIGURATION word located at 0x2007) by issuing an instruction
clrwdt.

6
3 Writing a Program
It is always a good practice to include comments in our code to make it readable.
We introduce a comment by beginning a line with a semicolon (;). Thus, our
software can begin somewhat like the following:

7
; [Link]

; CPU configuration
; RC oscillator
; Watchdog timer off
; Power-up timer on

processor 16f877a
include ă[Link]ą
config RC OSC & WDT OFF & PWRTE ON

3.1 Program
Next we must tell the compiler where the code will be. In our case let’s put
the code at the address 0:

; Program

org 0

We must configure the direction of the ports we want to use. We do this by


setting the TRIS register. Setting a TRIS register bit to 1 configures the port
as input, and setting it to 0 configures the port as output. The TRISA register,
however is on bank 1. Therefore, we must select it before setting it.

; Select BANK 1
; BSF STATUS, RP0

bsf 0x03, 5

; Set PORTA entirely as output by setting TRISA


; MOVWF TRISA

movlw B’00000000’
mofwf 0x85

; Return to BANK0 if we want to use PORTA


; BCF STATUS, RP0

bcf 0x83, 5

3.2 Data Declaration


For declaring constants in the PIC assembly we use the following conventions:

8
Binary: B‘0001010’
Octal: O‘772’
Decimal: D‘100’ or .100
Hexa: 0x9f or H‘9f’
ASCII: A‘C’ or ‘C’

9
a)
SLEEP PLL Fosc/4

Fosc

OSC1 OSC2

RS

C1 C2

b)
SLEEP PLL Fosc/4

Fosc

OSC1 OSC2

Fosc/4
c) SLEEP PLL

Fosc

OSC1
OSC2

Rext
10
Cext

Figure 2: a) Crystal oscillator, b) External generator, and c) RC oscillator.


Digital I/O Ports
C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul,
RS 91501-970, Brazil.

September 22, 2017

Abstract
In this lesson we will study how to use the digital input and output
ports in microcontrollers.

Keywords— Microcontrollers; Microprocessors; Electronics; Digital; I/O.

1 Hardware
Imagine that we want to use a pin to output and input digital data to and into
a data bus. We may additionally want to use this pin to eventually input analog
data into an analog to digital converter (ADC). Therefore, it is convenient to
set the circuit responsible for the digital I/O into a tri-state configuration. We
can achieve this with PMOS and NMOS transistors as shown in Fig. 1. It works
according to the truth table described in Table 1. If register TRIS is set, then
the port enters in a tri-state configuration. Otherwise, data is sent to the pin if
a command to write the port is issued or data is read from the pin if a command
to read the port is issued.

PORT TRIS Out P N


0 0 0 1 1
0 1 Z 1 0
1 0 1 0 0
1 1 Z 1 0

Table 1: Truth table for the digital I/O circuit.

We can see from this table that the logic function that drives the PMOS
transistor is simply:
∗ creq@[Link]

1
D Q
WR Q
PORT

D Q I/O Pin
WR Q
TRIS

DATA BUS
Q D
Q

RD
PORT

Figure 1: Internal circuit for digital I/O ports in the PIC microcontroller.

P “ P ORT ^ T RIS
P “ pP ORT ^ T RISq
(1)
P “ P ORT _ T RIS
P “ P ORT _ T RIS
The logic function that drives the NMOS transistor is simply P ORT ^
T RIS.
The diodes shown in the figure help to avoid electrostatic static discharges
(ESD). The latches store the values present in the data bus, the Schmitt trigger
buffer works as a signal conditioning stage to ensure that the input signal is
treated digitally by the circuit. Finally, the tri-state buffer is used to organize
the access to the data bus and avoid short circuits.

2 Software
The affected registers used in the digital I/O in the PIC microcontroller are
shown in Table 2.
First we must select the correct memory bank by setting RP0:1, then we
must configure the direction of each digital I/O pin by setting the TRIS register.
Finally, we must again select the correct memory bank and write or read the
appropriate port. We end up with a code similar to this:

2
bit STATUS PORT{A:E} TRIS{A:E}
(03h,83h) (05h:09h) (85h:89h)
7 IRP PORT7 TRIS7
6 RP1 PORT6 TRIS6
5 RP0 PORT5 TRIS5
4 /TO PORT4 TRIS4
3 /PDF PORT3 TRIS3
2 Z PORT2 TRIS2
1 DC PORT1 TRIS1
0 C PORT0 TRIS0

Table 2: Registers involved in digital I/O.

Software

org 0x00

bcf 0x03,6
bsf 0x03,5 ; Select bank #1: RP = 01.

movlw 0x0F ; Pins 4:7 are output, pins 0:3 are input.
movwf 0x85

bcf 0x83,5 ; Back to bank #0.

movlw 0x20
movwf 0x05 ; Pin 5 is high.

3
Interrupts
C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul, RS 91501-970, Brazil.

October 2, 2017

Abstract
In this lesson we will study how to handle interrupts in microcontrollers.

Keywords— Microcontrollers; Microprocessors; PIC; interrupts.

1 Introduction
Imagine that you need to follow an event and whenever it happens you take an appropriate action. One way of
doing this is my constantly polling the agent responsible for this event to check if it has started. This, however,
takes significant computing resources from a CPU that could be doing something else. A better way for doing this
is by asking the agent to warn the CPU whenever it happens. This is called an interrupt. One example in personal
computers is when the keyboard is pressed and it sends a signal to the CPU to process this event. There can be,
nonetheless, interrupts also caused by software. For instance, the processor may start a procedure to write some
data to an external memory and then generate an interrupt when it is done.

2 Hardware
The circuit responsible for handling interrupts in the PIC microcontroller is shown in Fig. 1 It is possible to block
all interrupts by resetting the General Interrupt Enable register (GIE). If this register is set, then both high and
low priority interrupts will be accepted by the CPU. The Peripheral Interrupt Enable register (PEIE) enables or
disables the low priority interrupts. Both the low and high priority interrupts have an enable register (E) and a flag
register (F). High priority interrupts are shown in Table 1, whereas low priority interrupts are shown in Table 2.

Flag Description
T0IF TIMER0 overflow interrupt.
INTF Universal external interrupt through pin RB0.
RBIF Interrupt caused by a change of state in one of RB4:7.

Table 1: High priority interrupts.

3 Software
The interrupt flags and enable bits can be accessed by the registers listed on Table 3. The memory organization
of the PIC microcontroller has two special positions. The Reset Vector is the position where the program counter
points to after a reset is placed. This vector is located at 00h in the program memory. The Interrupt Vector is
the position where the program counter points to after an interrupt is called. This vector is located at 04h in the
∗ creq@[Link]

1
Low Priority

EEIF
EEIE

PSPIF
PSPIE High Priority
ADIF
ADIE T0IF
T0IE
RCIF
RCIE INTF
INTE 4

TXIF Wake-up
RBIF (if sleeping)
TXIE
RBIE
SSPIF 11
Interrupt
SSPIE GIE
PEIE
CCP1IF
CCP1IE

TMR2IF
TMR2IE

TMR1IF
TMR1IE
CCP2IF
CCP2IE

BCLIF
BCLIE

Figure 1: Circuit responsible for handling interrupts in the PIC microcontroller.

Flag Description
EEIF Writing to EEPROM or Flash memories has completed.
PSPIF Reading/writing to Parallel Slave Port (PSP) - PORTD has completed.
ADIF A/D conversion has completed.
RCIF USART has received information through RCREG register.
TXIF TXREG register is empty and USART is ready to transmit data.
SSPIF Interrupt caused by the Master Synchronous Serial Port (MSSP) module.
CCP1IF Interrupt caused by the Capture/Compare module.
TMR2IF End of counting by TIMER2.
TMR1IF Overflow of TIMER1.
CCP2IF Interrupt caused by the Capture/Compare module.
BCLIF Interrupt caused by the MSSP module.

Table 2: Low priority interrupts.

program memory. Now, in order to use interrupts we must write appropriate commands in these two positions. One
possibility is to write ‘goto’ instructions to move the program counter to a specific subroutine. This is shown below:

Software for handling interrupts

org 0x00
goto Main ; Start at Main.

org 0x04
goto Interrupt ; Go to Interrupt after an interrupt call.

Now at the ‘Main’ subroutine we must configure the appropriate registers to handle the interrupts. So let’s say
we want to be interrupted only by a signal at RB0. We must set this pin as input and also enable interrupts.
Therefore, we have:

2
Bit INTCON PIE1 PIR1 PIE2 PIR2
(0Bh - All Banks) (8Ch - Bank 2) (0Ch - Bank 1) (8Dh - Bank 2) (0Dh - Bank 1)
7 GIE PSPIE PSPIF – –
6 PEIE ADIE ADIF CMIE CMIF
5 T0IE RCIE RCIF – –
4 INTE TXIE TXIF EEIE EEIF
3 RBIE SSPIE SSPIF BCLIE BCLIF
2 T0IF CCP1IE CCP1IF – –
1 INTF TMR2IE TMR2IF – –
0 RBIF TMR1IE TMR1IF CCP2IE CCP2IF

Table 3: Main registers used for handling interrupts.

Main: bcf 0x03, 6


bsf 0x03, 5 ; Select bank #1: RP = 01.

movlw 0x01
movwf 0x85 ; RB0 is input.

bsf 0x8B, 7 ; Enable GIE.


..
.
goto Fim ; End software.

Finally, we must write the interrupt subroutine. Here we have to check what caused the interrupt, reset the
corresponding flag and treat the event:

Interrupt: btfss 0x8B, 1


retfie ; Check if it was caused by INTF.
bcf 0x8B, 1 ; Clear INTF.
..
.
retfie

3
Timers & Counters
C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul,
RS 91501-970, Brazil.

November 16, 2017

Abstract
In this lesson we will study how to use timers and counters in micro-
controllers.
Keywords— Microcontrollers; Microprocessors; Electronics; Digital; Timer.

1 Timer0
PIC has the circuit shown in Fig. 1 that is used for timer/counter 0.

0
fosc/4
1

1 2 CYCLE
DELAY
T0CLK 0
PRESCALE

TMR0

T0SE T0CS PS2 PS1 PS0 PSA T0IF

OPTION_REG RBPU INTEDG T0CS T0SE PSA PS2 PS1 PS0


0x01 BANKS 1,3

7 6 5 4 3 2 1 0

INTCON GIE EEIE T0IE INTE RBIE T0IF INTF RBIF


0x0B ALLBANKS

Figure 1: Timer/counter circuit inside the PIC microcontroller, and correspond-


ing registers (green).

In PIC, the interrupt vector is located in the code memory position 0x04.
The interrupt vector is an instruction that the microcontroller executes every
∗ creq@[Link]

1
time an interruption occurs. Therefore, the first thing we must to do is to place
a ‘goto’ command in that position:

org 0x00
goto init
org 0x04
goto routine

Next, we must configure the circuit to work as a timer. For this, firstly T0CS
has to be set to 0. Next we must set the frequency of operation by setting the
PS registers. By setting PSA, our oscillator will work with a quarter of the
external oscillator. On the other hand, we can use fractions of this frequency
by resetting PSA and setting PS2:PS0 according to Table 1.

Table 1: PS2:PS0 register configuration.


PS2:PS0 Prescale PS2:PS0 Prescale
000 1/2 100 1/32
001 1/4 101 1/64
010 1/8 110 1/128
011 1/16 111 1/256

Let’s say that we want the timer to operate at fosc /16. Then OPTION REG
has to be B‘00000011’. Next, we must enable the microcontroller to accept in-
terrupts related to this timer. We can do this in PIC by first setting the timer
0 overflow interrupt enable register (T0IE). The code now evolves to:

org 0x00
goto init
org 0x04
goto routine
init: movlw B‘00000011’
movwf OPTION REG
movlw B‘00100000’
movwf INTCON

Now, the timer 0 overflow flag register (T0IF) will set every time TMR0
transits from 0xFF to 0x00 and the program will call the sub-routine located at
routine. We can do a further adjustment to the frequency by always starting
TMR0 with a specific value, let’s say 0x10. Also, we must enable the micropro-
cessor to accept interrupts in general by setting global interrupt register (GIE).
We end up with:

2
org 0x00
goto init
org 0x04
goto routine
init: movlw B‘00000011’
movwf OPTION REG
movlw B‘00100000’
movwf INTCON
movlw 0x10
movwf TMR0
bsf INTCON, 7
main: goto main

Finally, we must take care of the interrupt sub-routine. There we must


restart TMR0 and clear the T0IF flag. Therefore we have:

routine: movlw 0x10


movwf TMR0
bcf INTCON, 2
retfie

2 Timer1
Timer 1 on PIC can be used as: i ) a synchronous timer, ii ) a synchronous
counter, or iii ) as an asynchronous counter.
Independent on the mode of operation, the general program can be:

org 0x00
goto Main ; Go to main function.
org 0x04
goto IVEC ; Go to interrupt vector.

Main:
call CFG XX ; Configure appropriate mode of operation.
call CFGI ; Enable interrupts.
...

For all configurations, the prescaler can be set to 1:1 (00), 1:2 (01), 1:4 (10),
or 1:8 (11).

Synchronous Timer

For using it as a synchronous timer, we simply reset TMR1CS. In this con-


figuration the status of /T1SYNC has no effect.

3
T1OSCEN
0
fosc/4
1 CCP
T1OSC PRESCALE
1 TMR1
CLR
0
SINC: TMR1H TMR1L
DET

T1OSI T1OSO TMR1CS TMR1ON TMR1F


T1CKPS<1:0> T1SYNC

7 6 5 4 3 2 1 0

INTCON GIE EEIE T0IE INTE RBIE T0IF INTF RBIF


0x0B ALLBANKS

T1CON -- -- T1CKPS1 T1CKPS0 T1OSCEN T1SYNC TMR1CS TMR1ON


0x10 BANK 0

PIR1 TMR1IF: Bit position may


0x0C BANK 0

PIE1 TMR1E: Bit position may


0x8C BANK 1

TMR1L
0x0E BANK 0

TMR1H
0x0F BANK 0

Figure 2: Internal circuit for oscillator 1.

CFG ST:
bcf T1CON, TMR1CS ; Select f osc/4 as source.
bcf T1CON, T1CKPS1
bcf T1CON, T1CKPS0 ; Prescale 1:1.
bsf T1CON, T1SYNC ; Synchronization has no effect.
bsf T1CON, TMR1ON ; Enable TMR1.
return

Synchronous Counter

For using it as a synchronous counter, we turn off the T1 oscillator by reset-


ting T1OSCEN. In this case we must also set TMR1CS. Although it has little
effect, it is possible to synchronize the counter to the internal oscillator with a
built in PLL by resetting /T1SYNC.

4
CFG SC:
bcf T1CON, T1OSCEN ; Turn off the T1 oscillator.
bsf T1CON, TMR1CS ; Select the counter as source.
bcf T1CON, T1CKPS1
bcf T1CON, T1CKPS0 ; Prescale 1:1.
bcf T1CON, T1SYNC ; Synchronize counter with internal oscillator.
bsf T1CON, TMR1ON ; Enable TMR1.
return

Asynchronous Counter

In this configuration, /T1SYNC must be set. Moreover, T1OSCEN can be


enabled, and TMR1CS must be set. In this configuration the device can run
real time applications even in sleep mode. Every time TMR1 saturates it emits
an interrupt that is still treated by the microprocessor. Care must be taken
to read and write the TMR1H and TMR1L registers when Timer 1 is running
in asynchronous mode. It is recommended to stop the timer when performing
these operations.

CFG SC:
bsf T1CON, T1OSCEN ; Turn on the T1 oscillator.
bsf T1CON, TMR1CS ; Select the counter as source.
bcf T1CON, T1CKPS1
bcf T1CON, T1CKPS0 ; Prescale 1:1.
bsf T1CON, T1SYNC ; Do not synchronize counter with internal oscillator.
bsf T1CON, TMR1ON ; Enable TMR1.
return

For all configurations, we must enable interrupts:

CFGI:
clrf TMR1L ; Initial value for TMR1.
clrf TMR1H
call BANK2 ; PIE is on bank #2.
bsf PIE1, TMR1IE ; Enable TMR1 interrupts.
bsf INTCON, PEIE ; Enable low priority interrupts.
bsf INTCON, GIE ; Enable general interrupts.
return

And we must treat the interrupt:

5
IVEC:
call BANK1 ; PIR is on Bank #1.
btfss PIR1, TMR1IF ; TMR1 interrupted ?
retfie
bcf PIR1, TMR1IF
...
call BANK0 ; TMR1 is on Bank #0.
bcf T1CON, TMR1ON ; Stop counter temporarily.
clrf TMR1L ; Restart TMR1 with a specific value.
clrf TMR1H
bsf T1CON, TMR1ON
retfie

If we want to read TMR1 in some place of the code we must pay attention
to the fact that between reading the low and high bytes, the counter may roll
over. Therefore a good way of reading the registers is:

movf TMR1H ; Read Timer1 registers.


movwf High
movf TMR1L
movwf Low
movf TMR1H ; Read Timer1H again.
subwf High,W
btfsc STATUS,Z ; Do they have the same value?
return
movf TMR1H ; No. It has rolled over.
movwf High ; Reading it again will result
movf TMR1L ; in a good value.
movwf Low
return

3 Timer 2
Timer 2 is an 8-bit counter with a single source. It has both pre- and post-
scalers and overflows every time it reaches the same value indicated by the
Period Register (PR2). When this happens, TMR2 is reset and an interruption
is called through PIR1:TMR2IF. This is a counter simple to use and is commonly
associated with pulse width modulation (PWM) as we will soon see. A simple
way to program it is:

6
RESET

PRESCALE
fosc/4 TMR2
1:1, 1:4, 1:16
POSTSCALE
TMR2IF
1:1 - 1:16

PR2
2
4

T2CKPS<1:0> TOUTPS<3:0>

7 6 5 4 3 2 1 0

INTCON GIE EEIE T0IE INTE RBIE T0IF INTF RBIF


0x0B ALLBANKS

T2CON -- TOUTPS3 TOUTPS2 TOUTPS1 TOUTPS0 TMR2ON T2CKPS1 T2CKPS0


0x12 BANK 0

PIR1 TMR2IF: Bit position may vary.


0x0C BANK 0

PIE1 TMR2E: Bit position may vary.


0x8C BANK 1

TMR2
0x11 BANK 0

PR2
0x92 BANK 1

Figure 3: Internal hardware associated with Timer 2.

...
clrf T2CON ; Pre and postscale are 0. Counter is disable.
clrf TMR2 ; Start counter with 0.
bsf T2CON,TMR2ON ; Start counter.
call Bank1
bsf PIE1, TMR2E ; Enable interrupts from TMR2.
movlw 0x1A ; Value to be compared to.
movwf PR2
call Bank0
bsf INTCON, PEIE ; Enable peripheral interrupts.
bsf INTCON, GIE ; Enable general interrupts.
...
IVET:
btfss PIR1, TMR2IF
retfie
bcf PIR1, TMR2IF
... ; TMR2 does not need to be cleared!
retfie

3.1 Pulse Width Modulation


A simple way to output a signal that can be converted to analog is by using the
so called pulse width modulation. This consists of producing a digital output

7
DT

vPWM

0 T

Figure 4: (red) Desired analog output, and (blue) PWM modulation. The inset
shows the concept of duty cycle: A pulse occupy only D% of a period T.

with a constant amplitude by modulating its duty cycle according to the analog
amplitude we want to obtain. Figure 4 illustrates this process.
If this signal is averaged, by an LC circuit, for example, we obtain:
"ˆ ˆ T #
DT
1
v̄ = vmax dt + vmin dt
T 0 DT
1 (1)
= [vmax DT + (1 − D)T vmin ]
T
= vmax D + vmin (1 − D)
Typically, vmin is 0. Therefore, v̄ = Dvmax and the output is directly propor-
tional to the duty cycle.
The software necessary to make the PWM work is very similar to that used
for Timer2. The first difference is that it does not use interrupts. Also, the
register CCP1CON has to be configured to operate as PWM by setting its bits
CCP1M3 and CCP1M2.

bcf T2CON, T2CKPS1 ; Prescale 1:1.


bcf T2CON, T2CKPS0
movlw 0x0B ; Example: CCPR1L,CCP1CONXY = 0x0B[11].
movwf CCPT1L
bsf CCP1CON, CCP1CONX
bsf CCP1CON, CCP1CONY
bsf CCP1CON, CCP1M3 ; Set CCP1CON to operate as PWM.
bsf CCP1CON, CCP1M2
call BANK1
movlw 0x1A ; Example: PR2 = 0x1A.
movwf PR2
bcf TRISC,2 ; RC2 will be used for PWM output.
call BANK0
bsf T2CON, TMR2ON

8
10 bits

CCPR1L CCP1CON <X:Y>

CCPR1H TRISC <2>

R Q
RC2/CCP1
fosc/4
PRESCALE
TMR2
S Q
1:1, 1:4, 1:16

2
PR2

T2CKPS<1:0>

7 6 5 4 3 2 1 0

INTCON GIE EEIE T0IE INTE RBIE T0IF INTF RBIF


0x0B ALLBANKS

T2CON -- TOUTPS3 TOUTPS2 TOUTPS1 TOUTPS0 TMR2ON T2CKPS1 T2CKPS0


0x12 BANK 0

PIR1 TMR2IF: Bit position may vary.


0x0C BANK 0

PIE1 TMR2E: Bit position may vary.


0x8C BANK 1

TMR2
0x11 BANK 0

PR2
0x92 BANK 1

CCPR1L
0x15 BANK 0

CCPR1H
0x16 BANK 0

CCP1CON -- -- CCP1X CCP1Y CCP1M3 CCP1M2 CCP1M1 CCP1M0


0x17 BANK 0

Figure 5: Internal hardware associated with the PWM.

The period of the PWM will be (PR2+1)·4·Tosc ·PS, whereas the duty cycle
will be CCPR1L:CCP1CON<5:4> ·Tosc ·PS. The CCPR1L and CCP1CON<5:4>
registers can be written at any time, but will only be fetched to CCPR1H after
the next time TMR2 = PR2.

9
Analog to Digital Converters
C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul, RS 91501-970, Brazil.

November 30, 2017

Abstract
In this lesson we will study how to use analog to digital converters in microcontrollers.
Keywords— Microcontrollers; Microprocessors; Electronics; Digital; ADC.

1 Sigma-Delta Converters
The most used analog-to-digital converters (ADC) have the so-called Sigma-Delta architecture. This
is structure is shown in Fig. 1 and is composed basically of five blocks. First the difference (delta)
between the input signal and a reference signal is obtained. This difference signal is integrated so that
an average is computed. This average then goes to an 1-bit ADC that can be fabricated with basically
a comparator and a flip-flop. This 1-bit signal then is used as the the input of a digital-to-analog
converter (DAC) and its output is the initial reference signal. Because of the negative feedback, the
input signal and the average output of the DAC will be approximately the same. Therefore, the number
of times the ADC outputs 1 will be proportional to the input signal. Thus, the only block missing is
a digital counter to count the number of 1’s in a period. The oversampling also has the advantage of
reducing the noise amplitude and pushing it to higher frequencies where it is filtered by the integrator.
This process is known as noise shaping.

2 Aliasing
If there is any component in the input signal that contains frequencies higher than the allowed band-
width, they will be mapped by the converter to the appropriate range. The effect is known as aliasing
and distorts the desired signal to be digitally converted. One example of this effect is the appearance
of a wheel rotating slowly or backwards, or even a stroboscopic effect. In order to avoid it, anti-aliasing
filters are used at the input of the ADC converter. This is a filter that allows only frequencies below
the Nyquist frequency to input the converted. For instance, if we are interested in audio frequencies (f
leq24 kHz), then the sampling rate has to be at least 48 samples per second and a filter cutting at 24
kHz has to be included in the input.

3 Circuit
PIC has the circuit shown in Fig. 2 that is used for the analog to digital converter (ADC). For converting
an analog value into digital we must specify the range within this voltage is. The maximum voltage is
∗ creq@[Link]

1
1 bit ADC

vi(t)
∫ D Q
counter
clk Q
vd(t)
oversampling

1 bit DAC

Figure 1: The general schematic of a Delta-Sigma ADC converter.

` ´
described by Vref , and the minimum voltage is Vref . For a converter that works with n bits, we can
achieve a resolution of:
` ´
Vref ´ Vref
R“ . (1)
2n ´ 1
` ´
For example, if Vref “ `5V, Vref “ 0V, and we use a 10 bit ADC, we get a resolution of:
5´0 5
R“ V “ “ 4.8876 mV. (2)
210 ´ 1 1023
This behavior is illustrated in Fig. 3

4 Registers
There are basically four registers involved with the AD converter as depicted in Fig. 2: ADRESH,
ADRESL, ADCON0, and ADCON1. Let’s analyze each one of them:

Both ADRESH and ADRESL contain the result of a conversion.

ADON (ADC On bit - ADCON0[0]): 1 = ADC module is operating, 0 = ADC module is shut-down
and consuming no energy.

GO/DONE (ADC Conversion Status bit - ADCON0[2]): 1 = ADC conversion in progress, 0 = ADC
conversion not in progress and automatically cleared when the conversion is done.

CHS (Channel Select - ADCON0[3:5]): Selects the input multiplexer for an AD conversion.

2
VREF+
ADCS2:0 PCFG3:PCFG
RE2/AN7 111 GO/DONE
RE1/AN6 110
RE0/AN5 101
RA5/AN4 Justification
RA3/AN3/VREF+
100

011
A/D ADFM
RA2/AN2/VREF- 010 ADRESH ADRESL
RA1/AN1 001 ADON 0x1E (0) 0x9E (1)
RA0/AN0 000

PCFG3:PCFG
VREF-

CHS2:CHS0

RW RW RW RW RW RW RW

ADCON0 ADCS1 ADCS0 CHS2 CHS1 CHS0 GO/DONE ADON


0x1F BANK 0

7 6 5 4 3 2 1 0

ADCON1 ADFM ADCS2 PCFG3 PCFG2 PCFG1 PCFG0


0x9F BANK 1
RW RW RW RW RW RW

Figure 2: Analog to digital converter circuit inside the PIC microcontroller, and corresponding registers
(green).

ADCS (AD Conversion - ADCON0[6:7], ADCON1[6]): An AD conversion needs at least 1.6 µs to


complete. Therefore, the operation has to be chosen so that it accommodates this period. The opera-
tion is shown in Table 1.

Table 1: AD Conversion Clock. (Tosc is the time period of the device clock.)
ADCS 2:0 Operation Maximum Freq.
000 2 Tosc 1.25 MHz
100 4 Tosc 2.50 MHz
001 8 Tosc 5.00 MHz
101 16 Tosc 10.00 MHz
010 32 Tosc 20.00 MHz
110 64 Tosc 20.00 MHz
x11 RC TAD „2-6 µs.

PCFG (ADC Configuration Control - ADCON1[0:3]): Configure the hardware pins as analog inputs,
digital I/O’s or as voltage references according to Table 2.

ADFM (ADC Result Format Select bit): The result of an ADC conversion has 10 bits. Setting ADFM
results in the 6 Most significant bits of ADRESH being 0 (000000XX XXXXXXXX). Resetting ADFM
results in the least significant bits of ADRESL being 0 (XXXXXXXX XX000000).

3
Digital
Output R

111
110
101
100
011
010
001
000
Analog
- + Input
VREF VREF

Figure 3: Analog to digital conversion curve.

5 Software
Let’s say we want to have two analog input, the lowest input voltage is zero and the maximum voltage
is given externally. Therefore, according to Table 2, we must set PCFG3:0 as 0101. Our operating
frequency is 20 MHz, thus Tosc is 5 ˆ 10´8 s.
Since the ADC converter requires at least 1.6 µs for a conversion, we have 1.6 ˆ 10´6 {5 ˆ 10´8 “ 32.
Thus, according to Table 1, ADCS2:0 should be set as 010.
It is more convenient for my application that there are 0’s in the most significant byte. Therefore,
ADFM should be 0.
With this information, the ADCON1 register should be configured to 00000101 = 0x05.
Let’s start measuring channel 0, so CHS2:0 should be 0x00. Finally, let’s turn the ADC on, so
ADON should be 1. Therefore, ADCON0 register should be configure to 10000001 = 0x81.
Our code should then be:

org 0x00

CONFIG: bcf 0x03,6 ; Set bank 1


bsf 0x03,5 ; RP1:RP0 = 00

movlf 0x05 ; Set ADCON1


movwf 0x9F

bcf 0x83 ; Set bank 0

movlf 0x81 ; Set ADCON0

MAIN: bsf 0x1F,2 ; Start a conversion


LOOP: btfsc 0x1F,2 ; Wait until done
goto LOOP

4
Table 2: ADC Configuration Control (A: Analog input, D: Digital I/O).
PCFG 3:0 AN 7:4 AN3 AN2 AN 1:0 VREF+ VREF-
0000 AAAA A A AA VDD VSS
0001 AAAA VREF+ A AA AN3 VSS
0010 DDDA A A AA VDD VSS
0011 DDDA VREF+ A AA AN3 VSS
0100 DDDD A D AA VDD VSS
0101 DDDD VREF+ D AA AN3 VSS
011x DDDD D D DD – –
1000 AAAA VREF+ VREF- AA AN3 AN2
1001 DDAA A A AA VDD VSS
1010 DDAA VREF+ A AA AN3 VSS
1011 DDAA VREF+ VREF- AA AN3 AN2
1100 DDDA VREF+ VREF- AA AN3 AN2
1101 DDDD VREF+ VREF- AA AN3 AN2
1110 DDDD D D DA VDD VSS
1111 DDDD VREF+ VREF- DA AN3 AN2

6 Comparator Module
The analog inputs can also be used in two comparator modules as shown in Fig. 4. The comparators
can be used in eight different configurations controlled by the CM bits of the CMCOM register. The
configurations are given in Table 3.
The nine possible configurations are shown in Fig. 5. All input pins not used are set as digital.

6.1 Digital-to-Analog Converter


The voltage reference (VREF) is set by an internal digital-to-analog converter (DAC). The PIC micro-
controller implements it with a 4-bit resistive network as shown in Fig. 6. The parameters of the DAC
are set through the CVRCON register. CVREN bit enables or disables the module, CVROE enables
the output of the DAC to the RA2 pin. CVRR couples and decouples a 8R resistor to the network.
When it is enabled, the range of the module is between 0 and 0.75 VDD in steps of VDD/24. When it
is disabled,the range is between 0.25 and 0.75 VDD with a step of VDD/32. Bits CVR3:0 control the
voltage value.

5
CM2:CM0/CIS

AN0

CM2:CM0

C1OUT RA4

AN3

CM2:CM0/CIS
VREF

C2OUT RA5
AN2

CM2:CM0

AN1

CM2:CM0/CIS

7 6 5 4 3 2 1 0

CMCON C2OUT C1OUT C2INV C1INV CIS CM2 CM1 CM0


0x9C BANK 1
R R RW RW RW RW RW RW

Figure 4: Internal circuit of comparator module.

Table 3: Configutation of the comparator module.


CM2 CM1 CM0 CIS V1- V1+ V2- V2+ C1OUT C2OUT
0 0 0 0 AN0 AN3 AN1 AN2 GND GND
0 0 0 1 AN0 AN3 AN1 AN2 GND GND
0 0 1 0 AN0 AN3 GND GND RA4 GND
0 0 1 1 AN0 AN3 GND GND RA4 GND
0 1 0 0 AN0 AN3 AN1 AN2 – –
0 1 0 1 AN0 AN3 AN1 AN2 – –
0 1 1 0 AN0 AN3 AN1 AN2 RA4 RA5
0 1 1 1 AN0 AN3 AN1 AN2 RA4 RA5
1 0 0 0 AN0 AN3 AN1 AN3 – –
1 0 0 1 AN0 AN3 AN1 AN3 – –
1 0 1 0 AN0 AN3 AN1 AN3 RA4 RA5
1 0 1 1 AN0 AN3 AN1 AN3 RA4 RA5
1 1 0 0 AN0 VREF AN1 VREF – –
1 1 0 1 AN3 VREF AN2 VREF – –
1 1 1 0 GND GND GND GND GND GND
1 1 1 1 GND GND GND GND GND GND

6
CM2:0 = 000, CIS = X CM2:0 = 011, CIS = X CM2:0 = 110, CIS = 0

AN0 AN0 AN0

AN3 C1OUT AN3 C1OUT RA4 C1OUT

AN2 AN2 VREF


C2OUT C2OUT RA5 C2OUT

AN1 AN1 AN1

CM2:0 = 001, CIS = X CM2:0 = 100, CIS = X CM2:0 = 110, CIS = 1

AN0 AN0 AN3

AN3 C1OUT RA4


AN3 C1OUT C1OUT

VREF
C2OUT C2OUT C2OUT

AN1 AN2

CM2:0 = 010, CIS = X CM2:0 = 101, CIS = X CM2:0 = 111, CIS = X

AN0 AN0

AN3 C1OUT AN3 C1OUT RA4 C1OUT

AN2
C2OUT C2OUT RA5 C2OUT

AN1 AN1

Figure 5: Nine comparator configurations.

7
CVREN

8R

16x

R
VREF

RA2/AN2/VREF-
CVRR 8R CVROE

CVR3:0
7 6 5 4 3 2 1 0

CVRCON CVREN CVROE CVRR CVR3 CVR2 CVR1 CVR0


0x9D BANK 1
RW RW RW RW RW RW RW

Figure 6: DAC Module.

8
Digital PID Controller
C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul, RS 91501-970, Brazil.

November 30, 2017

Abstract
In this lesson we will learn how to implement a PID controller in a 8-bit microcontroller using
integer math.
Keywords— PID controller.

1 Introduction
A PID controller is composed of three components: i) one that gives an output proportional to the
difference between a setpoint and the actual output (error), ii) one that gives an output integral to
this difference, and iii) another that gives an output differential to this difference.
For the error we have:

e(t) = x(t) − y(t)


(1)
en = xn − yn .
For the proportional component we have:

y(t) = kp e(t)
= kp x(t) − kp y(t)
y(t)(1 + kp ) = kp x(t) (2)
kp
yn = xn
1 + kp
yn = ξp xn (3)
For the integral component we have:
ˆ t
y(t) = ki e(t)dt
0
ˆ t
(4)
= ki (x(t) − y(t))dt
0
yn = ki ∆T Sn ,
∗ creq@[Link]

1
for X
Sn = (xn − yn )
n (5)
Sn = Sn−1 + xn − yn .
Therefore,
yn = ki ∆T (Sn−1 + xn − yn )
yn (1 + ki ∆T ) = ki ∆T Sn−1 + ki ∆T xn
(6)
ki ∆T
yn = (Sn−1 + xn )
1 + k i ∆T

yn = ξi (Sn−1 + xn )
Sn = Sn−1 + xn − yn (7)
S−1 = 0

Finally, for the derivative component we have:

∂e(t)
y(t) = kd
∂t

= kd (x(t) − y(t))
∂t
∂x(t) ∂y(n)
= kd − kd
∂t ∂t
kd kd
yn = [xn − xn−1 ] − [yn − yn−1 ] (8)
∆T ∆T
∆T
yn = xn − xn−1 − yn + yn−1
kd
 
∆T
yn + 1 = yn−1 + xn − xn−1
kd
kd
yn = (yn−1 + xn − xn−1 )
kd + ∆T

yn = ξd (yn−1 + xn − xn−1 ) (9)

1.1 ξ Factors
The ξ factors are given by:
kp
ξp = ,
1 + kp
ki ∆T
ξi = , (10)
1 + ki ∆T
kd
ξd = .
∆T + kd
One interesting aspect of these factors is that they are restricted to values between -1 and 1. Therefore,
we can write them as:
ξp = αp /K0 ,
ξi = αi /K0 , (11)
ξd = αd /K0 ,

2
where K0 can be conveniently chosen to be 2n , and this would imply just n bit shifts. Also, the α
factors are now simple integers.
Finally we get an expression for the PID controller:

αp + αi + αd αd αi
yn = xn + (yn−1 − xn−1 ) + Sn−1
K0 K0 K0
Sn = Sn−1 + xn − yn (12)
S−1 = 0

Now using a 2-complement representation and operations for bit shift, addition and multiplication
we can implement the PID controller.

3
Serial Communication
C. R. da Cunha∗1
1
Instituto de Fı́sica, Universidade Federal do Rio Grande do Sul, RS 91501-970, Brazil.

December 14, 2017

Abstract
In this lesson we will study how the serial coomunication of the PIC microcontroller works.
Keywords— PIC, Serial, USART.

1 USART
The heart of the Universal Synchronous/Asynchronous Receiver-Transmitter (USART) is a shift register
that converts a set of bits of a word into a sequential set of bits to be transmitted or the other way
around. Once in a serial format, the communication can be simples if it is unidirectional, one equipment
only sends information and the other only receives. It can also operate in half duplex mode where there is
also only one channel available and both equipments take turns in sending and receiving information in
a master/slave configuration. This protocol is also known as synchronous. Finally, serial communication
can also happen in a full duplex mode wherein both devices are able to send and receive information
at the same time. This is also known as asynchronous.
The serial protocol maintains its line typically in a high state to indicate that the line is active. To
start a communication, first a start bit is sent (low state). Next, 8 data bits are transmitted from the
LSB to the MSB. After that, some devices implement an extra parity bit. Finally, there is a stop bit to
signal the end of transmission in a low state.
The PIC microcontroller operates with 1 start bit, 8 data bits, an optional extra bit that can be
used for parity check via software, and a stop bit. This is slightly different from the standard RS232
where there is only 8 data bits and no parity bit. In this last case, for instance, it takes exactly 10 bits
to transmit a word. For a bit rate B, the word transmission rate is consequently B/10.
Furthermore, the PIC microcontroller serial module operates in a non-return to zero level (NRZ-L)
protocol where the logic level 1 corresponds to VDD and the the logic level 0 corresponds to GND. Both
occupy the whole period of the clock and there is no rest condition. Again, this is slightly different from
the RS232 protocol where the logic 1 corresponds to a voltage within +5V and +12V, and the logic 0
corresponds to a value within -12V and -5V. This is typically overcome with level converters such as
the MAX232.
The main registers associated with the USART operation are:

Address Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0


TXSTA 0x98 CSRC TX9 TXEN SYNC – BRGH TRMT TX9D
RCSTA 0x18 SPEN RX9 SREN CREN ADDEN FERR OERR RX9D
SPBRG 0x99
∗ creq@[Link]

1
In order to use the PIC USART, the first thing that we must do is specify whether it will operate
in synchronous or asynchronous mode.

1.1 Synchronous Mode


For the synchronous mode we must set the SYNC bit on the TXSTA register (0x98 on bank #1) and
the baud rate will be given by:
fosc
BR “ , (1)
4pSPBRG ` 1q
where SPBRG is a register on bank #1 at 0x99.

1.2 Asynchronous Mode


For the asynchronous mode, we must clear the TXSTA:SYNC bit, and the baud rate will be given
by:
fosc
BR “ p3´TXSTA:BRGHq
. (2)
4 pSPBRG ` 1q

1.3 Asynchronous Write


For sending a word asynchronously through the USART, we must first specify the asynchronous mode
and set the baud rate:

bcf TXSTA, SYNC ; Set the mode to asynchronous.


bsf TXSTA, BRGH ; High speed mode.
movlw BAUD RATE ; Specify the baud rate.
movwf SPBRG

The TX pin is shared with PortC, so we must set it to work with the USART. Next, we must turn the
USART on and enable transmission.

bsf TRISC, 6 ; RC6 becomes TX.


bsf RCSTA, SPEN ; Turn the USART on. where RCSTA is a register on bank #0 at
bsf TXSTA, TXEN ; Enable transmission.

0x18.
The PIC microcontroller allows us to use a ninth bit for parity check. However, the check has to be
done by the user in software.

bsf TXSTA, TX9 ; Enable 9th bit.


bsf TXSTA, TX9D ; 9th bit will be 0.

At this point we can write the word to be sent to the USART and wait until it is fetched to its
internal register TSR.

2
movlw WORD
movwf TXREG ; Send word to be transmitted.

Loop: btfss PIR1, TXIF ; Ready to send next?


goto Loop

It is also possible to check if the data was transmitted by the USART by reading TXSTA:TRMT.

Table 1: Registers related to an asynchronous write.

Address Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0


TXSTA 0x98 CSRC TX9 TXEN SYNC – BRGH TRMT TX9D
RCSTA 0x18 SPEN RX9 SREN CREN ADDEN FERR OERR RX9D
SPBRG 0x99
TXREG 0x19
PIR1 0x0C PSDIF ADIF RCIF TXIF SSPIF CCP1IF TMR2IF TMR2IE
PIE1 0x8C PSPIE ADIE RCIE TXIE SSPIE CCP1IE TMR2IE TMR1IE
INTCON 0xXB GIE PEIE T0IE INTE RBIE T0IF INTF RBIF

1.4 Asynchronous Read


For receiving data asynchronously using the USART, first we must configure the baud rate as before:

bcf TXSTA, SYNC ; Set the mode to asynchronous.


bsf TXSTA, BRGH ; High speed mode.
movlw BAUD RATE ; Specify the baud rate.
movwf SPBRG

Next we must configure the PORTC, turn the USART, say if we want a ninth bit and enable
reception.

bsf TRISC, 7 ; Bit 7 becomes RX.


bsf RCSTA, SPEN ; Turn USART on.
bsf RCSTA, RX9 ; Enable 9th bit.
bsf RCSTA, RCEN ; Enable reception.

Finally, we can either set an interrupt vector or pool the USART to wait for the data.

Loop: btfss PIR1, RCIF ; Wait until data is received.


goto Loop

The received data will be on RCREG and on RCSTA:RX9D. If an error occurred, we must also
clear RCSTA:RCEN. This could be for example an overrun error indicated at RCSTA:OERR.

1.4.1 Addressable Mode


It is possible to active an address detection mode wherein the device only receives data if it is addressed
to it. The way we do it is by using the ninth bit to specify that the incoming data corresponds to an

3
Table 2: Registers related to an asynchronous read.

Address Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0


TXSTA 0x98 CSRC TX9 TXEN SYNC – BRGH TRMT TX9D
RCSTA 0x18 SPEN RX9 SREN CREN ADDEN FERR OERR RX9D
SPBRG 0x99
RCREG 0x1A
PIR1 0x0C PSDIF ADIF RCIF TXIF SSPIF CCP1IF TMR2IF TMR2IE
PIE1 0x8C PSPIE ADIE RCIE TXIE SSPIE CCP1IE TMR2IE TMR1IE
INTCON 0xXB GIE PEIE T0IE INTE RBIE T0IF INTF RBIF

address word. The code is very similar, but we must also tell the microcontroller that we are interested
in this mode by setting the ADDEN register.

bcf TXSTA, SYNC ; Set the mode to asynchronous.


bsf TXSTA, BRGH ; High speed mode.
movlw BAUD RATE ; Specify the baud rate.
movwf SPBRG

bsf TRISC, 7 ; Bit 7 becomes RX.


bsf RCSTA, SPEN ; Turn USART on.
bsf RCSTA, RX9 ; Enable 9th bit.
bsf RCSTA, ADDEN ; Set address detect.
bsf RCSTA, RCEN ; Enable reception.

Loop: btfss PIR1, RCIF ; Wait until data is received.


goto Loop

movf RCREG
xorwf ADDRESS,W ; Is it my address?
btfss STATUS,Z
goto NOPE
bcf RCSTA, ADDEN ; Ok, I’ll receive data now, not only addresses.
..
.

2 Synchronous Mode
SYNC = 1 CSRC = 1: Master, 0: Slave Reception: SREN = 1 (single word) ou CREN (continuous
word)
TX becomes Clock RX becomes Data

3 Master Synchronous Serial Port (MSSP) Module


The MSSP is another serial module used for communicating the microcontroller with other devices that
operate with a serial peripheral interface (SPI) or an inter-integrated cicuit (I2 C).

4
3.1 SPI
The SPI mode was developed by Motorola in the 1980’s. It allows for transmitting synchronously 8
bits of data both in and out of the microcontroller. It uses four wires for transmitting data. The
master sends the clock signal through the serial clock (SCLK) line and data through the master output
slave input (MOSI) line. The slave sends data through the master input slave output (MISO) line.
Moreover, there is an slave activation bit through slave select (SS) line.
In order to use the MSSP module in the SPI mode we must specify whether we will use the micro-
controller in master mode or in a slave mode. This is controlled by the SSP Mode Select (SSPMx3 : 0y)
bits of the MSSP control register (SSPCON1). Table 3 shows the possible configurations:

SSPMx3 : 0y Configuration
0000 Master Mode, clock = Fosc {4.
0001 Master Mode, clock = Fosc {16.
0010 Master Mode, clock = Fosc {64.
0011 Master Mode, clock = TMR2 Out/2.
0100 Slave Mode, SS pin enabled.
0101 Slave Mode, SS pin disabled.

Table 3: Configuration of the SPI module.

In this mode, the transmission is performed bitwise with the MSB being the first to be transmitted.
Furthermore, during communication the master sends a bit that has to be read by the slave and then
it sends a bit that has to be read by the master. This has to occur even it the transmission is purely
unidirectional. This happens in a circular configuration where bit after bit the registers of the master
and the slave devices exchange their words.
Other parameters can be set. For example, we can specify the the polarity of the idle state through
the SSPCON1:CKP register, we can enable or disable the SSP through the SSPCON1:SSPEN
register, and set if we want the transmission to occur during the transition from low to high or the
other way around through the SSPSTAT:CKE register. The completion of a reception can be verified
through the SSPSTAT:BF register, and the data is read from or written to the SSPBUF register.
The complete specification of the registers is shown in Table 4.

Table 4: Registers related to the SPI mode.

Address Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0


SSPSTAT 0x94 SMP CKE D/A P S R/W UA BF
SSPCON1 0x14 WCOL SSPOV SSPEN CKP SSPM3 SSPM2 SSPM1 SSPM0
SSPBUF 0x13

In slave mode, the SSPIF flag is raised when the last bit of a word is received.

3.2 I2 C
A competitor of SPI is the Inter-Integrated Circuit (I2 C) invented in 1982 by Philips Semiconductors.
The main advantage over SPI is the use of only two lines: a Serial Data Line (SDA) and a Serial Clock
Line (SCL). Both lines are driven by open drain MOS transistors and thus have to be pulled up with
resistors („ 4.7 K). It operates within 3.3 V and 5 V, and can operate up to 400 kbit/s. The biggest
drawback of this mode is that in order to use fewer lines, its programming is more complex.

5
Transmitting data with the i2 c protocol is based on the concept of condition events. For example,
the equivalent of a start bit is the start condition (S) that is represented by the SDA transitioning
from high to low while the SCL is kept high.
The stop condition (P) is characterized by the opposite path. The SDA transitions from low to
high while the SCL is kept high.
There is also an acknowledge condition (A) where the device brings SDA low during the 9th
clock pulso of SCL. This can also be a negative acknowledge condition (N) if the device sets the
SDA up instead.
Finally, it is possible to send a restart condition (R), which is a stop condition followed by a start
condition. The SCL is kept high and SDA transitions from low to high. Then, SCL is lowered, set up
again and SDA transitions to low. Finally, SCL goes back to low.

Writing

For writing data on a device, the microcontroller must have the data bit valid on the raising edge
of the SCL. The communication starts with the microcontroller emitting an S condition followed by a
control in byte to tell the controlled device what it should do. The device answers with an A condition.
Next, the microcontroller sends an address byte. Again the controlled device answers with an A. The
microcontroller then emits the data, which is once again answered by an A. The communication is
finalized with the controller sending a P.

Master S Control In Address Data P


Slave A A A

Reading

For reading a device, the microcontroller sends an S condition followed by the control in byte. The
device answers with an A. Next the address by is sent and answered with another A. Next, the mi-
crocontroller sends an R and a control out byte. The device answers with an A and the data. The
microcontroller answers with an N condition and a P condition to finalize the communication.

Master S Control In Address R Control Out N P


Slave A A A Data

I2 C allows for an interesting situation to occur. If the device receives a command but is not ready
to transmit the data, it can hold the SCL low until it is ready. This is known as clock stretching.
The LSB of the control byte is 0 for writing and 1 for reading. Words between 0x00 to 0x07 and
0x78 to 0x7F are reserved.

You might also like