Microcontrollers

From ELC Wiki
Jump to navigation Jump to search

Everything on this page is intended to be a brief introduction to topics. Most of it can be used as keywords to be entered into an internet search to find many existing excellent resources, that explain all of these concepts in great detail. Before reading this page, it would be a good to have a basic understanding of binary data, bits, bytes and the concept of digital logic.

Microcontrollers are a form of integrated circuit(IC), meaning they are devices made up of many tiny discreet components, carefully formed on one piece of semiconductor. Integrated circuits have increased in complexity and performance dramatically in recent years and can now consist of millions, even billions, of individual components. This page will take a quick and basic look at what components are inside, like opening the bonnet of your car and pointing at all the different bits.

Typical System Overview

Core

People often use the words microprocessor and microcontroller interchangeably, myself included, however technically a microprocessor is an IC consisting of just a processing core, whereas a microcontroller has other devices such as memory and peripherals built around it in the same IC. There are many variations in between this broad definition.

The core or central processing unit (CPU) of a microcontroller is like the brain. It carries out instructions in a sequence like reading items on a list. These are normally simply explained mathematical, logical, or logistical, operations like:

  • add this number and this number
  • move this number over there
  • is this number the same as that
  • if this number is greater than this number jump to that instruction

These instructions vary between different processing core types, and are known as the instruction set. Each instruction is actually a specially coded binary number.

The mathematical and logical evaluation operations are normally carried out by sub-section of the core called the "Arithmetic Logic Unit" or ALU.

Back when microcontrollers were invented, people programmed lists of these instructions directly, then in a slightly more human readable language called "Assembly". In special situations were efficiency is critical Assembly programming is still used. Following this the "compiler" was invented, which was a computer program designed to translate modern programming language, of which there are many different forms, into the machine code.

More modern processors have multiple processing cores and are capable of "executing" or "carrying out" multiple instructions simultaneously, which can have a great improvement on "execution time".

Core Systems

As well as a core or CPU, there are several systems and concepts that most if not all microcontrollers must have to fundamentally operate. These come in many different configurations but they still provide more or less the same functionality.

Clocks

The system clock is an essential part of a micro-controller and although it can be used to count time as we understand it, its main purpose is provide a signal which synchronizes the operation of the core similarly to the way a conductor synchronizes an orchestra. Digital information travels through the circuitry of the core at rate of the clock signal, and instructions are executed in accordance with that.

A clock signal in digital electronics is normally considered to be a square wave changing from a logical value of "0" to a logical value of "1", and back again, continuously. In reality this transition from 0 to 1 doesn't happen instantly but it happens very fast. The time it takes from the moment it is a "0" until the moment it returns to being a "0" is known as a complete cycle.

The number of cycles a clock completes every second is a frequency and is therefore measured in Hz. You will have commonly heard this in PC specifications. PCs from 20 years ago were operating at a few hundred MHz, (e.g. 333MHz, which is 3,330,000Hz), whereas modern day processor will operate at a few GHz (e.g. 3GHz, 3,000,000,000Hz). Typically a basic microcontroller will operate somewhere between 1MHz and 100MHz, which is still quite fast!

The core will assess the inputs of an instruction in time with the clock signal, so the underlying circuitry within the IC must be designed so that it reaches a steady state in time for assessment. An IC's ability to do this quickly, and reliably, dictates how fast you can get it to carry out instructions. If we stick with our musical analogy, you can imagine this as the ability of all of the different musicians being able to arrive at different individual notes as quickly as possible. If one musician is slower, the rest of the orchestra must play at his or her speed, otherwise everything will sound like a mess.

Clock signals are distributed around other parts of the microcontroller outside the core and are essential to the operation of most areas of digital electronics for the reasons just described. They are even communicated outside of the IC to enable synchronized digital communications.

Memory

Memory in microcontrollers comes in several different types but we'll just discuss program memory and random access memory, or RAM, as it's commonly referred to. It should be noted that the following definitions, like with many things on this page are very vague definitions and in reality things can be far less clearly cut.

In general:

  • Program memory is memory that "remembers" even when power is removed from the device, and is generally used to hold the instructions or "program" that the microcontroller is "programmed" to do. Due to the physical type of memory (at a circuit level) that this memory is made of in microcontrollers, it is commonly referred to as Flash memory. Flash is also typically more difficult to store information in, i.e. it takes even longer than reading it back out, and consumes a lot of power, so it is normally only used for information that doesn't need to change often or at all.
  • Random Access Memory (RAM) will generally "forget" when power is removed. This type of memory is used more directly by the core of the microcontroller because of its main benefit over Flash memory, which is that it is much faster to access. It also is much easier to store information in, and can be rewritten many times before it begins to fail. It also happens to be more expensive to produce per unit size.

We refer to storing things in digital memory as writing, and reading things from digital memory as... reading.

Due to the speed benefits of RAM, and its read/write flexibility, it is used to store information that the core may have calculated, and also sometimes to store parts of the program being executed, all in the name of improving the execution time.

Registers

Registers are similar to memory in that they hold data, but these are special because the data held in them can have a more directly physical effect on what the processor is doing. The core itself, and most peripherals (which we are yet to discuss), have registers that control their operational parameters, and also to hold information that is more immediately required than the information stored in RAM. If we go back to our car analogy, and the car had registers, then these registers might hold:

  • the current value of speed
  • the current fuel level
  • the state of the turn signal switch
  • the value of the selected gear

and any other important operational parameter.

Registers are even faster to read/write than RAM, and behave in many different and specific ways. Some can be written to and changing the value actually changes some setting. In our car, you might write a new value to the window wiper speed setting register to change the wiper speed. Some registers are read only and simply provide information about the current state of the microcontroller, such as the speedometer register in our car.

Moving back to microcontrollers, we can look at a couple of the important core registers that all microcontroller processing cores have.

  • Program Counter register holds the address in memory of the current program instruction. When the instruction completes, this value is incremented or sometimes altered depending on the result of the instruction.
  • Stack Pointer register. This holds the address of the area of RAM that's currently being used. We'll talk a little more about the Stack soon.

Address Space

Address space is quite an important part of microcontrollers and processing cores in general. The thing that both types of memory, and registers all have in common is that they hold certain amounts of data, and they do this in a binary format. You can imagine them like a huge wall full of mailboxes. Some mailboxes hold program instructions, some hold data values, these being the memory "mailboxes". Some mailboxes hold operational parameters and settings values, these are the register mailboxes. Just for the record, we don't actually refer to them as mailboxes, however, the thing this allows us to do is to assign an address to each piece of memory and each register in a similar format. This is very useful because it becomes as easy for the user/program/core to refer to any memory location or any register with one type of address. So we just number them all.

This brings us on to Address Space, which is another very useful concept. You can imagine that if different types of memory and different registers were numbered randomly it would be very difficult to find the information you're looking for so the addresses are assigned based on types. A simple example:

  • If its program memory, the address will be somewhere between 0 and 10
  • If its RAM, the address will be somewhere between 50 and 60
  • If its a core register its address will be somewhere between 120 and 150
  • if its a peripheral register, the address with be somewhere between 200 and 250

In reality the address numbers themselves are slightly different from this, but the concept is the same. We call these ranges of addresses, address regions and they help to organize our microcontroller, and make operation easier to understand. It's worth noting that some addresses remain unused, and if you try and read or write to these addresses bad things will happen, like opening a mailbox that someone left a very old sandwich in, or posting your car keys into a mailbox that nobody has the key for.

Interrupt System

An interrupt system is another essential part of a microcontroller, as it allows external events to interrupt normal program execution. Let's use another analogy; you're busy making a nice tasty cake and you put it in the oven. You then go and sit down to watch a movie while it bakes. Unfortunately, something goes wrong and the kitchen catches fire.

Now, if you didn't have an interrupt system, you would wait the cooking time of your cake and then go back to the kitchen and take it out of the oven, but, in this situation if you did that your house might burn down. Luckily you do have an interrupt system, so whether or not you have a smoke alarm, or you can smell burnt cake, this event makes you interrupt your movie. You press pause, go and save the cake, and the kitchen. Once everything is under control again, you can go back to your movie and press resume.

Back in the world of microcontrollers, this is more or less what happens. Most microcontrollers have complex interrupt systems that are triggered on many different events from many different inputs.

These event signals or interrupt signals can be linked to special sets of instructions which are executed if one of these events occurs, which are known as interrupt service routines or ISRs.

Peripheral Devices

In the world of microcontrollers, peripheral devices are pieces of circuitry or "hardware" within the IC but external to the core. They are capable of carrying out specialized tasks very well and come in many different shapes, sizes and complexities.

Some of them help the microcontroller to interact with the outside world and some carry out specific calculations more efficiently than a standard processing core. The complexity of a peripheral device, will dictate how much the processing core, and program instructions, will need to interact with the peripheral's registers to get a job done. If the peripheral is an advanced design, it may be able to carry out very complex tasks autonomously without the need for what is known as processor intervention. This is beneficial for the core because it reduces its workload, rather like having highly skilled staff members in a company.

Timers

Timers are one of the most basic and useful peripherals on a microcontroller, as they allow the processor to keep track of time in a more similar way to the way humans do than the clocks we were talking about earlier. They essentially count clock cycles for the processor. If you know how frequent the clock cycles occur, you can calculate how much actual time has passed.

Timers come with many different features and complexity. Commonly, they can generate an interrupt signal after a certain number of cycles has passed, or they can be used to trigger other peripherals without the need for the core to become involved at all.

A simplified application for this might be in a digital watch, where the core needs to be notified to update the screen once every second.

Timers can be very useful in saving power as well because they are simple circuits. In our digital watch example with the screen being updated once a second, the core might not have much to do after updating the screen for millions of cycles until a second has passed. The timer peripheral will use significantly less power than the processor core, so you can put the processing core in a low power state, and get the timer to "wake it back up" when it has work to do.

Other applications for timers include:

  • Generating pulse-width modulation signals (good for driving motors, LEDs, MOSFETs, buzzers)
  • Generating clock signals of different frequencies
  • Measuring the time between signals on digital input

General Digital Input/Output(GPIO)

This is the most basic form of peripheral device connecting the microcontroller to the outside world. General purpose Input/Output, or GPIO as it is commonly known, gives the microcontroller the ability to perform basic digital operations with the external pins of its IC. These operations are:

  • Read a digital input i.e. is the pin at voltage potential of "logic 1" or "logic 0"
  • Set a digital output i.e. make the pin move to the voltage potential of "logic 1" or "logic 0"

and also in addition to this, but not always:

  • generate an interrupt signal when the voltage potential of a pin changes logic value.

These 2 or 3 features can provide very versatile functionality. In the simplest situations, they can be used to read the state of a switch or be used to control the state of another more basic IC, like the address lines of a multiplexer. In digital systems, many different types of ICs interact with each other through manipulation of GPIO pins.

When connecting a GPIO pin to an external circuit or IC, it is important to make sure the external circuit is compatible. This is because setting up a GPIO pin incorrectly can leave the microcontroller in a vulnerable state. There are a number of ways this can happen but here is one; imagine you connect your GPIO pin to the 0V rail because you want it to always read a "logic 0". If your microcontroller pin is configured as an "input", this is fine because the pin appears to be a very high impedance to the outside world, therefore any voltage you apply to it will cause negligible current to flow into or out of the pin. If you somehow accidentally configure the pin to be a digital output, and accidentally try to set the digital output value to a "logic 1", the microcontroller will then do everything it possibly can to lift the voltage on that pin up to "logic 1" potential. Unfortunately, as the pin is connected to the 0V rail, this would require it to pass a very very large current, much larger than the pin could physically handle, and certainly much larger than the internal circuitry of the IC can handle. If you're lucky the microcontroller will have protection systems for this, but if not, you'll need a new microcontroller.

The ability for a GPIO pin to pass current (known as sinking or sourcing current) varies between devices. A good estimate might be around 10mA per pin, but it can be less and it can be more. The maximum current value will be given in the datasheet of the microcontroller.

GPIO pins are normally arranged in ports and normally assigned a letter. E.g. GPIO PORT A, GPIOB, GPIO C etc. and each pin in the port is normally designated a number. E.g. GPIO Port B Pin 3.

Each port will have a set of registers within the microcontroller that control its operation. The available registers will vary between different microcontrollers but typically you have a register for each port and each bit in the register will control settings for an external pin. The bit number in the register will correspond with the number of the port I/O label number. But be careful, pin numbering on ICs is separate to pin labeling. i.e. pin number 1 on an IC, does not have anything to do with a GPIO port label number. Registers that are commonly available are:

  • data direction - is the pin an input or an output
  • data value - if the pin is an input, what logic value is it now
  • data output value - if the pin is an output what value should it be set at

More complex microcontrollers have additional settings and features for each pin, such as interrupt signal setup, internal "pullup" or "pulldown" resistors, or variable drive strength, which would vary the current capabilities of that pin.

Analogue to Digital Convertors (ADC)

Most things in the digital world are either "0" or "1", but often when systems need to interact with the real world, this is not enough and we need to be able measure a continuously variable input with a certain level of accuracy.

An ADC will take a measurement of an input voltage, which must lie within a certain range, e.g. 0V and 3.3V. It will then convert this voltage value into a number which is scaled between 0 and the maximum digital value of the ADC, or the full scale value. The amount of numbers in between 0 and the maximum digital value of the ADC is known as the resolution. As with many things in digital electronics, this is normally a number based on powers of 2.

E.g. you might refer to an 8-Bit ADC. This means the number of values it has to approximate the input voltage to is 2^8=256

So, if we have an analogue input range of 0-3.3V and an 8-bit ADC, with an analogue input of 0V it will return "0", with an analogue input of 3.3V it will return 255. If we remember we always start counting from 0 in the digital world.

There are a few different ways of physically achieving this operation, for those interested a couple of research starting points are "Successive Approximation Register" or "Sigma-Delta".

Comparators

It is worth mentioning compactors at this point which can themselves often be one or more separate peripheral devices within a micro-controller, but they can be seen as the most basic form of analogue to digital converter. They have two analogue inputs labeled positive (+) and negative (-), and one digital output. If the positive input is greater than the negative input the output will be "logic 1" and vice versa.

Digital to Analogue Convertors (DAC)

As you can probably imagine, Digital-to-Analogue (DACs) do the opposite of ADCs. The will take a digital value between 0 and the maximum digital resolution of the device, and produce an analogue output voltage (or current) that is a proportion of its "full scale" value.

DACs can be useful for generating complex wave forms, probably the most common example of which is generating music from digital audio files.

Communication Interfaces

In modern day electronics there are numerous different communication interfaces and standards. Most of us will know about a few of them with even knowing we do, like HDMI, USB, Ethernet. These examples are mostly used to communicate between different devices, however there are also several well know digital communication interfaces used between ICs on the same circuit board or for shorter range communications.

Many microcontrollers are equipped with internal circuitry (peripheral devices) that can carry out the basic functionality of these communications systems to reduce the workload of the core, and reduce the complexity of the programming. You can image this peripheral as a personal assistant who handles and organizes receiving your mail and phone calls, so you can just look at the relevant information when you have the chance.

On a hardware level, these peripheral devices use variants of digital input/output circuitry, the requirements can be quite different between different interfaces. Some interfaces are able to transmit and receive data using the same electrical connection, sometimes referred to as a line. Others have a dedicated line to send and a dedicated line to receive.

In terms of format, digital communication interfaces could categorized as serial or parallel. As the data that we are transmitting is stored as bytes or groups of bytes, this refers to how the data is transmitted.

  • Serial Communication sends and receives data 1 bit at a time over one electrical connection.
  • Parallel Communication sends and receives data multiple bits at a time over several electrical connections. This can be increased to transmit 1 or more complete bytes of information simultaneously, if you have enough electrical connections. This provides a considerable communication speed increase an the expense of more complex electrical circuitry.

We won't go into detail on parallel communication in this page but it is commonly used in the most data intensive environments where efficiency is crucial such as communication with external memory or display hardware.

UART

Universal Asynchronous Receiver Transmitter, or UART as it is commonly referred to is a communication interface that has been in use for many years. It is one of the most basic forms of serial digital communication. If someone is talking about "serial comms" they probably mean UART

There are various "hardware standards" that dictate the voltage levels used to indicate a "logic 0" or "logic 1" such as Transistor-Transistor Logic (TTL Serial), or RS-232, and again people sometimes talk about serial communication directly by the hardware protocol name. There is an abundance of info on the internet about serial communications and the various standards associated.

The most common arrangement for communication between ICs on the same circuit board is to use TTL logic levels and a minimum of 2 electrical connections (lines). Typically these will be labelled at each IC:

  • Tx - Transmit
  • Rx - Receive

Normally, you will connect the transmit pin of one IC to the receive pin on the other IC and vice versa in what's known as "crossover" configuration. In addition to this, 2 lines are commonly (but not always) added to this for communication stability known as:

  • CTS - Clear to send
  • RTS - Request to send

These two lines are used for a more "polite" form of communication and give the transmitting/receiving devices an opportunity to notify the other if they are available to transmit data. This is known as hardware flow control.

The thing about this interface that is strange compared to the other two interfaces we will discuss, is that no "clock" signal is transmitted along with the data. We noted the importance of clock signals at the top of this page, so how does this interface transmit data successfully without one?

The answer is that both communicating devices will have an internal clock operating at an agreed frequency known as the Baud rate. As activity occurs on the electrical lines, this internal clock will be synchronized with the activity. From this point on, technically you have the same clock, a little bit like synchronizing your watch at the start of a race. In reality, there will be very slight differences between the internal clock speeds of each device and so this re-synchronization process happens quite frequently. This lack of need for clock transmission is also where the "asynchronous" in the name comes from.

SPI

Serial Peripheral Interface (SPI) is commonly used to communicate between one or more ICs that require typically higher data rates. It is a system that uses a master-slave hierarchy, where there is one master (normally the microcontroller), and the master's role is to initiate communication between one or more "slave" devices. It is a relatively hardware efficient method of achieving communication between multiple devices as 3 of the electrical lines are shared between all of the devices on the "bus". There is also an individual electrical line between the master and each slave device, the job or which is to indicate to the slave that the master is "talking" to them.

The electrical line configuration is as follows:

  • MOSI - Master Out Slave In - This line is used to transmit data from the master to the slave devices
  • MISO - Master In Slave Out - This line is used to transmit data to the master from the slave devices
  • SCL/CLK - Serial Clock - This line is used to transmit a clock signal from the master to the slave devices
  • NCS/SS - Not Slave Select - There can be multiple NCS/SS lines depending on the number of slaves in the system. The "Not" indicates that it is inverted logic. i.e. a "logic 0" means it is selected, "logic 1" means not selected. The polarization of this line is sometimes configurable but most commonly inverted.

I2C

If you want to interface to a large number of devices and your microcontroller doesn't have many pins, or you can put up with slightly slower data rates, you can use an I2C interface. This interface uses only 2 lines which are shared between all devices on the bus. Typically as with SPI there is a master device that initiates all communication with the slave devices, but some systems do support "multi-master" operation where the master role can be exchanged between the devices.

The lines are referred to as:

  • SDA Serial data. This line is used to transmit or receive data depending on the state of the current transaction.
  • SCL Serial Clock. This line is used to transmit a clock signal from the master to the slave devices.

Special conditions can be indicated to the slave devices by manipulating both of the lines in an specific way with respect to each other. For example, a "Start" condition which indicates the beginning of a new transaction is indicated to the slaves by bringing SDA to "logic 0" while SCL is "logic 1.

Although during normal operation it shouldn't happen, the internal microcontroller hardware in I2C systems is cleverly designed to cope with "bus fights" where two or more devices try to use the bus simultaneously by using an "open collector" topology. For this reason in order for it to operate properly, a "pullup" resistor must be connected between each line and the digital power supply. This holds the lines in a "logic 1" state. When a device wants push data onto the bus, it alternates between connecting the line to ground, pulling the line low to "logic 0", and releasing it to let it be pulled back to "logic 1". If more than one device tries to pull the line low at once there is no problem because the current is limited by the pullup resistor. A common part of microcontroller I2C hardware is to automatically detect this condition.

More information about the I2C bus can be found on the specification website: https://i2c.info/i2c-bus-specification