My Pi Description

My Experiences With the Raspberry Pi -- Tracking My Learning -- My Pi Projects

Sunday, August 28, 2016

ATmega328P and the Serial Peripheral Interface

Introduction

This post continues my discussion of register programming of the ATmega328P microcontroller. Specifically, the ATmega's Serial Peripheral Interface, commonly just called SPI. It also continues the discussion of my large LED display from my last blog post.

My Display

I have a five row by ninety column LED display. What would be the best way to deal with the content I wish to display? I could hard code the message in a variable. That's fine if I don't ever want to change the message. I also run into the 2 kbytes SRAM memory limitation of the ATmega328P. I have several different messages to display and would like to add, delete, and edit messages. I also display dynamic messages like the ever changing weather. In fact, if you look at my last post you see I display the current weather and weather forecasts from Weather Underground. I get weather updates every 10 minutes. I don't need to update any more often, and there is a limit to the number of accesses I can make without incurring a charge. Therefore, I need to continuously display the same information until I get an update. The best way to handle all of these issues is to store all messages in another memory device - a nonvolatile memory, of course.
My nonvolatile memory is a 25AA512 serial EEPROM. This eight pin IC contains 64 kilobytes of memory and has builtin SPI. This is perfect, both the serial EEPROM and the ATmega328P have SPI. The Arduino IDE comes with an SPI library that looks pretty comprehensive. But, I just feel more comfortable programming the applicable ATmega328P registers. I have more confidence that I can successfully get the two devices talking to each other. Besides, the Arduino library has limitations.
You can see the serial EEPROM sitting to the right if the ATmega328P on my interface board. Look towards the bottom of my last post.

The SPI

The SPI, or Serial Peripheral Interface is really quite simple. It's not good for long distances but can be reasonably fast. It always involves one master device and one or more slave devices. The master is in complete control. The slaves do not start a conversation, which is just fine when the slave is a serial EEPROM. The master talks to only one slave at a time.
There are four signal lines:
  • SCK, for Serial clock
  • MISO, for Master In, Slave Out
  • MOSI, for Master out, Slave in
  • SS, for Slave Select
The master and all slaves connect to SCK, MISO, and MOSI. However, each slave must receive its own SS connection from the master.
The master contains a clock generator, a shift register, and control circuitry. Each slave has its own shift register. The slave, if it sees its SS line active, uses the clock from the master (SCK) to shift out the data in its shift register onto MISO. At the same time, it shifts in data from the master, on MOSI, into the same shift register. If it does not find SS active it keep its MISO in a high impedance state, allowing other slaves access to MISO.
When the master wishes to write to, or read from, a slave, it brings that particular slave's slave select (SS) line to a logic low. The master will send eight clock pulses to its shift register to shift out the byte of data that was previously stored in its shift register. Each bit appears on MOSI. As each bit is clocked out on MOSI, a bit is simultaneously clocked in from the active slave on MISO.
On the slave side, SS low, allows the SCK clock from the master to be passed to the slave's shift register and takes the shift register output out of a tristate (or open drain). Each clock pulse, clocks out the contents of the slave shift register onto MISO, while clocking data in from the master on MOSI. When the data transfer is complete, the master brings SS high again.
It is possible for multiple bytes to be transferred while SS is low. The clock runs for eight pulses, the shift register is loaded with a new byte and the clock runs for eight cycles again. This is repeated until the entire message is sent or received. The transfer is completed by bring SS high.

SPI Options

There is flexibility built into the SPI. The designer of a device can choose how it's implemented. As stated before, data will be sampled (clocked in), and outputted (clocked out), simultaneously on both MOSI and MISO. The two operations will be done on opposite edges of SCK. The designer can choose to output on the rising edge and sample on the falling edge, or output on the falling edge and sample on the rising edge. The master and slaves must use the same selection.
In SPI parlance, this is controlled by two parameters (not part of the specification, but most manufactures comply with these definitions), CPOL, and CPHA. As follows:
  • CPOL: Polarity of the clock when in an idle state. CPOL = 0, if SCK is low at idle. CPOL = 1, if SCK is high at idle
  • CPHA: Cock Phase. CPHA = 0, if data is sampled on the rising edge of the clock and output on the falling edge of the clock. CPHA = 1 if data is sampled on the falling edge of the clock and output on the rising edge of the clock.
The combination of the clock polarity at idle and the edge to sample and clock out comprises four modes (most manufacturers comply with this):
  • MODE 0: CPOL = 0, CPHA = 0
  • MODE 1: CPOL = 0, CPHA = 1
  • MODE 2: CPOL = 1, CPHA = 0
  • MODE 3: CPOL = 1, CPHA = 1
A diagram is in order:
SPI Modes
Notice that as soon as SS goes low, a bit, either the MSB or the LSB of the master's shift register, and the selected slave's shift register, will appear on MOSI, and MISO respectively. With CPHA = 0, that bit will be the first bit of the requested data. With CPHA = 1, the first bit of requested data does not appear until the first clock transition.
Another Option: Notice in the diagram the bit names like "BIT 0 or 7". Another option the user has is to determine how the bits are shifted out - either LSB (BIT 0) first or MSB (BIT 7) first.
Another option available to the user may be the selection of the clock frequency.

SPI Implementation Using the ATmega328P and the Serial EEPROM

Serial EEPROM Requirements

The 25AA512's SPI bus has definite requirements. You could say that the ATmega328P master is a slave to the slave's requirements. Therefore, the place to start is with the 25AA512's data sheet, as seen here.
The first thing that jumps out at you is that the data sheet does not use the expected pin nomenclature. While they use SCK, there is no MOSI, MISO, or SS. How then do you know that the thing has an SPI? It tell you so. On the first page under "Description" is says, "The memory is accessed via a simple Serial Peripheral Interface (SPI) compatible serial bus.". That's pretty definitive. Their pin definition is as follows: SCK is SCK, MOSI is SI (slave in), MISO is SO (slave out), and SS is CS (chip select).
You don't see the terms CPOL, CPHA, or MODE 0, MODE 1, MODE 2, or MODE 3. This means you have to figure it out for yourself. Luckily, it's obvious. On page 8, Figure 2-1, you see that the clock, SCK, is low when idle, therefore CPOL is 0. The data bits on SI and SO line up with the falling edge of SCK, therefore CPHA is also 0. This equates to Mode 0. The figure also tells you that the most significant bit is available first on SO, and it expects the most significant bit first from the master on SI.
To see the maximum clock speed, you need to look at the AC characteristics and the timing diagrams. The maximum clock frequency is 20 MHz with a VCC of 5V.
There is a lot more information in the data sheet you need to know. For every operation (read, write, erase), there is an instruction that must first be sent to the device. See Table 2-1. Every operation you can do is detailed in the data sheet. You also learn that you can read and write multiple bytes before bringing SS high. However, when writing data you can not cross over to another page when writing multiple bytes.

Programming the ATmega328P

Here is a fragment of code taken from several sketches and distilled down to only reference communicating with the serial EEPROM by the SPI. Here is a link to all the Arduino sketches I wrote for the display.
The sketch only includes some #defines and functions. Looking at the function, initializeSPI(), there is a great deal of information in the comments. You can see the ATmega pin assignments on port B used for SPI. To use the built-in SPI of the ATmega328P, SCK, MISO, and MOSI must use the pins as stipulated in the comments. SS does not necessarily have to be on PB2 if the ATmega is the master. If the ATmega is the slave, then SS must be on PB2. In our case, the ATmega is the master.
There are #defines at the top. The ones under "Serial EEPROM Instructions" come directly from the 25AA512 data sheet, table 2-1 on page 7. SLAVE_SELECT definition relates to the pin on port B, pin PB2 which is the SS pin. .
There are three registers within the ATmega328P related to SPI. See section 23.5 of the ATmega328P data sheet for details of each register:
  • SPCR: SPI Control Register
  • SPSR: SPI Status Register
  • SPDR: SPI Data Register
The comments, "Setting the Control Register, SPCR" shows the choices I made for my project. Notice bits 0, and 1 set SCK frequency to 4MHz.
SPDR is the register that holds the data. Basically, SPDR acts as the shift register. SPSR is the status register. We are only interested in one bit of SPSR, the SPIF bit. This is the SPI interrupt flag. When the transfer of a byte is complete (eight clocks), this bit is set. If enabled (not so in my project), an interrupt will also occur.
The operation of transferring a byte over SPI is contained in my function "SPIoperation()". This function is used for both sending data to the serial EEPROM and reading from the serial EEPROM, Loading a byte of data into SPDR starts the data transfer process. Even if our intention is to read data, we must send send a byte of data. Next, we simply poll SPSR looking for SPIF to be set. When that occurs, we can simply read SPDR to see what was returned from the serial EEPROM. Pretty simple.
The last function "readFromSerialEEPROM()" shows the read process. We send it an address (16 bits) of the location in the serial EEPROM containing the first byte of data we wish to read. We also send it the number of bytes we want to read. We set SS low to start things off. We then write three bytes to the serial EEPROM ignoring what is returned. The first byte is the "READ" instruction. The next two bytes are the upper and lower bytes of the address. After that we simply send something the serial EEPROM will ignore (0xFF) and read a byte from the serial EEPROM. Every time we send 0xFF, the serial EEPROM will increment its address counter and send back a new byte. After reading the number of bytes requested, we bring SS high.
Writing to the serial EEPROM is similar but a little more involved. Note the function "writeToSerialEEPROM(). We send this what we want to store in the serial EEPROM as a String object (my choice here. You can also send it an array of characters). We also send it the number of bytes to store and the starting address in the serial EEPROM. Firs,t we must convert the String to an array of characters.
The memory of the 25AA512 is organized into 128 byte pages. You can write into consecutive addresses, like you can read from consecutive addresses, as is done in my read function. However, unlike a read, you can not cross a page boundary when you write. Taking an example, if you wish to write 129 bytes starting at byte 0, by taking advantage of the consecutive write feature, the 129th byte will not go into address 128, it will go into address 0, overwriting what you put there first.
The write process also starts by bringing SS low. We follow that by write four bytes to the serial EEPROM, WREN (write enable), WRITE, and the upper and lower bytes of the starting address. Next, we can write consecutive bytes, but we have to monitor the address we are going to write to. If that address is a multiple of 128 we are at the page boundary. In that case we must bring SS high, bring SS low, send WREN, WRITE, and the new address, before writing more bytes of data. When you have written the last byte, SS can be brought high again.

Monday, August 1, 2016

ESP8266 - Downloading Weather To LED Display

Introduction

My electronic endeavors, lately, have taken me down two paths. One path was dealing with a salvaged LED display, and the other was the ESP8266. Those paths have now been joined in a challenging project.
Here is a video of the project:

All Design Documentation

All of my design files including schematics, board layout, and all programming sketches are on my GitHub repository. There is an extensive readme file with plenty if details.

The Display

Sometime ago a friend gave me a board with 18 five column by seven row LED matrices, Thanks Mike.
The board was missing the four most critical ICs, namely the microprocessor and two RAM chips. I'm guessing the forth IC was a programmable read only memory used to translate ASCII characters to row and column bit patterns - a character generator.
I probably would have removed those ICs anyway.
Fortunately, I had enough information to reverse engineer the display PCB and was able to design an interface board using an ATmega328P microprocessor. The ATmega device has enough internal SRAM and an internal EEPROM. I built my character generator in the EEPROM. You can see that interface board and its connections to the display PCB as the still shot for the video.
There are 90 columns and the most typical programming scheme would be to start at one end, load the column data for one column, turn that column on, then move down the line doing the same for each column. Each individual LED would be accessed 1/90 of the time. This display PCB divided the columns into six zones. The data for six columns are loaded and all six columns turned on simultaneously. An individual LED is accessed 1/15 of the time. If an LED is meant to be on, it will be six times brighter.
I wrote Arduino sketch for the user to write messages to a serial EEPROM on my interface board, and select one of 28 possible messages stored in the EEPROM to display. I wrote separate sketches to display in four direction:
  • from right to left which I call my Times Square Scroll
  • from left to right. Challenge here was that the letters in each word had to be reversed, otherwise "the" would become "eht"
  • from top to bottom. My favorite. Challenge was to not split up words between lines. See second video in my youtobe video, above.
  • from bottom to top. Like top to bottom with the same challenge
I wanted the display to do more, to be dynamic, to display stuff I did not write - like the weather or latest news.

ESP8266

At the same time, while working on the display, I got on the ESP8266 bandwagon. One of the limitations of the Arduino platform was realistic WiFi access. There Arduino are shields like the Xbee series of boards, but they are pretty expensive.
Along came a tiny 8 pin PCB from China:
This device is a little less than an inch long and a little over one half inch wide. I have seen it being sold for $2.40 USD. The small 32 pin IC is the ESP8266 chip itself. It contains a very capable microcontroller along with the WiFi circuitry - everything but the antenna. The antenna is those wavy lines at the top of the board. I happened to come across a YouTube video from electronupdate where the ESP8266 was photomicrographed. Here is what it looks like inside.
All the red is the logic circuitry for the microcontroller. All the rest is for the Wi-Fi. You can recognize inductors in the picture - those oval items. The eight pin device is a 8 Mbit serial Flash Memory with an SPI.
Although this module is commonly called an ESP8266, its proper name is the ESP-1. It has a couple of limitations. There is only one useful I/O pin and it's not RFI shielded. The pins do have a 0.1" pitch which is nice for mounting on vectorboards.
There are newer generations using the same ESP8266 integrated circuit. The latest seems to be the ESP-14, but the most common seems to be the ESP-12, of which the ESP-12f is the latest flavor. I'm familiar with the ESP-12e, so will not talk about the ESP-14 (same WiFi as in ESP8266 but another microcontroller). the advantages of the ESP-12 are seven fully useful I/O pins, and FCC certified RFI shielding. It does have 2mm pitch castellated pads though. While designed for surface mount placement, I have been able to solder 24AWG solid wire through the holes to connect to other circuitry. I have seen a price of $2.50 USD for the ESP-12e. I'm still going to use the term ESP8266 for all the members of the family.

What's the Big Deal With the ESP8266

Besides the price, this little device can act as a TCP/IP or UDP server or client. It can connect to your WiFi router, and, as a server, contains its own access point. It's often called the "Internet of Things" device.
I have used it as a client where the server is a Raspberry Pi. I employed two in a remote control project, one as a client, the other a server. I utilized the access point in the server device so it does not need my my WiFi router. The access point has an SSID and a password you choose.
If you do a search on the ESP8266, and search YouTube videos, most often you find projects involving the internet. And, indeed, my weather project uses the ESP8266 as a client to get the weather from weatherunderground.com. Other common projects fall into the "internet of Things" category. I have not explored this, myself.
"Internet of Things" projects use the ESP8266 as a server. It's connected to some device you wish to control - your front door electronic lock, for example. You call up the ESP8266's IP address on your browser from anywhere in the world. Let's say you wrote a little javascript in your ESP8266's program to create "Lock" and "Unlock" buttons. These appear in your browser window. Push a button and control your lock. Next project, perhaps (though not control my front door lock).
One of the best things about the ESP8266 is how you program it. There are several options including issuing AP commands and using the Lua interpretive language. I'm not going to discuss those but will talk about what I use - writing C code within the Arduino IDE. I've been using the Ardino IDE for quite some time, writing Arduino sketches. My LED display uses the same microcontroller as used on the Arduino Uno, and I use the Arduino IDE to write all the firmware to control the display.
Two wonderful things happened. The Arduino IDE was opened up to other devices, and the people at NodeMCU provided the functionality for writing ESP8266 firmware using the Arduino IDE. I now had one platform for writing code to both the ATmega328P and my ESP8266. Many of the same libraries as used for Arduino devices were adapted for use on the ESP8266. NodeMCU adapted the existing Arduino WiFi shield library to become the ESP8266WiFi library.

Putting the ESP8266 together With My Display

Here is my interface board that connects to the rear of my display
Above is the layout of the breadboard PCB that controls my display - my interface board. Until recently, there was nothing to the right of the serial EEPROM. The ESP8266 came later. My ESP8266, the ESP-12e version, exists on a development module designed by NodeMCU. It's $8.79 USD from Amazon. Bit more expensive but adds an USB to serial chip for programming, a voltage regulator (5V to 3.3V) and fits nicely on the breadboard PCB having pins on a 0.1" pitch. It's worth every penny. The TXB0104, between the serial EEPROM and the ESP8266 translateS voltage levels of two signals between the ATmega328P, operating at 5V, and the ESP8266, operating at 3.3V.
I'm not going to go into a lot of detail here. The readme file on GitHub explains a lot, and the sketches have lots of comments. I will say that the ESP8266 connects to the weatherunderground api every 10 minutes. It retrieves two .JSON files - one with the current weather conditions and the other, eight forecasts. It signals the ATmega328P via an interrupt that new data is ready. In the meantime, the ATmega328P is reading the weather data from the serial EEPROM and writing it to the display. I functionally divided the serial EEPROM's 64K memory into 2 kbyte blocks. The first 28 of these blocks are for static messages I write that I wish to display. The weather data sits in the next 2 kbyte space. Once the ATmega328P has written all the weather data to the display, it looks to see if the ESP8266 has sent the interrupt. If, not, it simply repeats the same weather information. If the interrupt occurred, the ARmega328P and the ESP8266 talk to each other using a pseudo SPI handshaking scheme that sends the new data to the ATmega328P. The data in the .JSON file is parsed for the desired information, and along with other text, is written to the serial EEPROM.

Friday, April 22, 2016

Arduino Uno Register Programming and Pulse Width Modulation - Continuous Servo

Introduction

This is a continuation of my last post. I have been discussing the virtues of what I call Arduino "Register Programming". This is all about using the Arduino IDE to program the ATmega328p"s internal registers directly. This is my forth post in the series. The last post, of which this is a continuation, talked about using the ATmega328P's internal timer/counters to control a small DC servo. The servo is a good example because it requires pulse width modulation to do anything and the timer/counters are ideal for that application. That last post got pretty long, thus this continuation.

The Continuous Servo

In my last post, I used the noncontinuous servo as an example. The output shaft of this servo only rotates when a change of shaft position is called for. When the new position is reached, the servo stops and holds that position. You can envision this servo controlling the steering of a model car. Only when the steering wheel is moved will the wheels of the car change the direction of travel.
The output shaft of the continuous servo, on the other hand, continues to rotate even if the control signal is constant. Changing the control signal changes the speed and direction of the shaft. An application could be a winch where you can control how fast it turns and whether the cable plays out or pulls in.
I put together a little video that further explains the differences between the two devices and how to program them. The video's Arduino sketch (the same for both types of servos) is very short. The comments, the same as in the sketch in my last post, take up most of the sketch.
I had a thought while playing with the continuous servo. I wondered how fast the shaft was turning particularly when I tried to balance the speed between CW and CCW rotation with the screw driver. I could only go by the sound it was making to judge speed. The same timer/counter circuit could be used to create a timing light type of tachometer. The flashing rate of a bright LED is controlled by a potentiometer. You illuminate the rotating device by the LED and rotate the potentiometer until the motion of the rotating device appears to stop. In this application, the configuration of the timer/counter will be opposite as used by the servo. The pulse width remains constant while the pulse repetition changes. The potentiometer connects to an A>D converter input of the ATmega328P and the digital output of the A>D is used to program the pulse repetition frequency. A digital display rounds out the equipment controlled by an ATmega328P microcontroller. An interesting, future project.
Here is a timing diagram like the one in the last post but this is actually to scale:

Sunday, April 17, 2016

Arduino Uno Register Programming and Pulse Width Modulation

Introduction

My last two posts concerned, what I call, Register Programming of the ATmega328P microcontroller of the Arduino Uno. My last post discussed the expanded capability of interrupts, over and above the functions in the Arduino IDE's reference language. This post concerns the use of the ATmeta328P's counter/timers to manage pulse width modulation (PWM). Pulse width modulation is used to control such things as the light intensity of LEDs and the speed of small DC motors when the intensity or speed is to be changed during operation. If the light intensity or the motor speed is to be constant, supplying the device with a constant DC voltage is sufficient. Some devices such as servos, require PWM just to operate. The repetition rate of the pulses, or PWM frequency is normally kept constant. The variation in light intensity or speed is achieved by varying the width of the pulses (changing the duty cycle). PWM controls these devices by rapidly turning then on and off.
While it is certainly possible to use the Arduino IDE's analogWrite() function, to control LED brightness and motor speed, forget about controlling a servo by this method. The servo requires pulses of a specific frequency. The function analogWrite() produces a fixed PWM frequency of 490Hz or 980Hz depending upon which arduino pin used. Servos I am familiar with requires 50Hz - a big, big difference.
Knowing how to use the ATmega's counter/timers, and how to program the various, associated, registers will give you much better control in any project.

How I Am Going To Cover The ATmega328P's Timer/Counters

Atmel equipped the ATmega328P (and the other microcontrollers in the family) with a very robust set of capabilities for it's timer/counters. There are three independent, different, timer/counters. Each timer/counter has many modes, and many options. Rather than trying to cope with all of these variants, now, I am going to present how PWM is created in very general terms. Then, I will include enough of the details to demonstrate controlling a servo. Finally, I will discuss all of those modes and options.
You should certainly download the datasheet for the device. There are four chapter associated with timer/counters. Here is a link to the datasheet. I'm going to use the language of the datasheet as much as possible.

Determining the Repetition Rate of the Pulses (PWD Frequency)

We know we are going to create a string of pulses of a particular frequency. What in the Arduino already has a repetitive characteristic? How about the 16MHz clock that drives the ATmega328P? That clock will work but may be a little fast and is invariant. The timer/counters use that clock, but we usually feed that clock into divider circuits to produce lower clocks frequencies. There are five or six outputs from these dividers, called prescallers, in the Atmega documentation. Each precaller divides the 16MHz clock by a different power of 2. The prescallers may slow the clock down sufficiently to be useful, but they only give a choice of five or six different PWM frequencies. What if we want something different? Something like 50Hz is impossible from any prescaller, alone. That is where the timer/counters come in to play.
The timer/counter takes the output of the chosen prescaller and further divides the frequency. This divider is not limited to a power of two. It can divide by any whole number from 1 to a maximum number which is determined by the number of bits in the physical counter within the ATmega328P, or by a programmed value.
The timer/counter simply counts the clock pulses it receives from the prescaller. With each clock pulse, the counter increments by one. When it reaches it maximum value, or the number programmed into an associated register, it will count down with the next clock, decrementing by one until it reaches 0. The next clock pulse starts the counter incrementing again.
If we plot the count against time, we get what is commonly called a triangle waveform. The significance of this waveform is that its frequency will correspond to the pulse repetition frequency. It is obvious that this frequency depends upon three factors: the Arduino's 16MHz clock frequency, the prescaller selected, and the count we choose for our timer/counter. Later, we will put all of that together and generate a formula.

Determining the Pulse Width (Duty Cycle) and Generating the Pulses

Now that we know how to determine the pulse frequency, let's move on and determine the pulse width and generate the pulses themselves. This is really one operation. We introduce two more elements: a comparator circuit, and the comparator register. For our present discussion, we are going to say that the comparator is part of the circuit that drives one of the Arduino's I/O pins.
The comparator compares two values: the value programmed into the comparator register, and the current value in the timer/counter. Here is were we make our pulses: When the comparator detects that the two values are equal, it changes the logic level of the I/O pin. Let's assume that the current logic level of the I/O pin is high, and that the timer/counter is at 0. The timer/counter counts up and when it reaches the value programmed into the comparator register the comparator will flip the I/O pin low. The counter/timer continues to count up until it reaches the maximum count we have selected. The counter now counts down and when it, again, reaches the value programmed into the comparator register, the comparator flips the I/O pin High. We now continue to count down to zero, which is where we started. This cycle continues for as long as we let it. To produce pulses, the value of the comparator register must be lower than the value programmed into the timer/counter's register. If the comparator register has a value equal or higher than the timer/counter register, or has a value of 0, the I/O pin's logic level will not change. Here is a diagram of the operation:
It should be obvious that if we lower the line labeled "Pulse Width" (corresponds to the value programmed into the comparator register), the positive portion of the pulses get narrower, while the negative portion gets wider, thus lowering the duty cycle. The frequency will not change. Note that the center of the positive pulse is centered on the peak of the triangle wave. The center of the low pulse is centered upon the count of zero. This has some significance as we will see later when we discuss other modes of operation.

What's a Servo

A servo is a device used by radio control models (planes, cars, boats), in robotics, and in other applications where something has to be moved. Something, like the wheels that steer a car, the ailerons of a plane, or the fingers of a robotic hand.
There are industrial servos, usually run by AC. I'm not talking about those (I don't know anything about them). I'm only considering the dc types like in the picture. The photo shows a "standard" size servo. There are smaller ones available. Check out Adafruit and Sparkfun. Also, there are two types: continuous and non-continuous. The following discussion, and my code example, is for the non-continuous servo. I'll discuss the continuous servo in another post.
The non-continuous servo rotates through a 180° arc. It consists of a motor connected to a potentiometer (a variable resistor) via a series of gears. The potentiometer shaft also serves as the output shaft that drives your device. When the motor changes the potentiometer setting, it changes a voltage that is fed into a feedback circuit. There is a second voltage feeding the feedback circuit, a voltage derived from pulses from an external device like the PWM output of your Arduino Uno.
The motor rotates until the voltage out of the potentiometer equals the second voltage. When that that happens, the motor stops. The width of the input pulses determine the position of the output shaft. Saying it another way, the motor turns only when the pulse width changes, making the two voltages unequal. When the voltages become equal, again, due to the turning of the potentiometer, the motor stops. The gears greatly reduce the rotational speed of the motor. The torque at the output shaft is increased in the same proportion as the speed is decreased. The beauty of this device, is the motor can turn, and hold fast, against a good deal of applied torque.

Controlling a Servo

I have a non-continuous servo I experiment with. I previously discussed this in my post: Gertboard - Pulsewidth Modulation - Servo Control. The Gertboard is an attachment for the Raspberry Pi.
The servo has three connections: ground, power, and control. Ground and power connect to an external voltage source. I used 6V worth of AA batteries. Ground and control connect to the Arduino Uno. I used Uno pin 10 for the control signal.
The control signal is a string of pulses of 50Hz - a pulse every 20ms. The servo will be at -90° if the pulse width is 0.5ms, at +90° if the pulse width is 2.5ms. and at zero, if the pulse width is 1.5ms. My understanding is there is some variability in the specifications for different servos. The pulse repetition frequency of 50Hz. seems to be standard, as is the pulse width of the zero position (1.5ms.). It's the maximum and minimum pulse width, at the extreme clockwise and counterclockwise positions, that may vary with the device. Some trial and error may be required. I would start at 1.0ms. and 2.0ms. and see how far your device turns.

Timer/counter, and the Output and Input Registers

Now we get play with the ATmega328P's timer/counters within the ATmega328P, There are three of these: Timer/counter0, Timer/counter1, and Timer/counter2. I use Timer/counter1. The registers in Timer/counter1, and in the timer/counter itself, are 16 bits long. We need the 16 bit resolution - Timer/counter0 and Timer/counter2 use 8 bit timer/counters and registers.
Hopefully, you can match the following detailed discussion with the non-specific discussion at the beginning of this post. As I said before, there are a lot of options available. To wit, Timer/counter1 has 15 modes of operation, 12 of which are for pulse width modulation. Table 16-4 of the datasheet lists these modes. We will be using mode 9, "PWM, Phase and Frequency Correct". I'll explain what that means later, when discussing the other modes. Remember, from before, we need to program a register to contain the value of the highest timer/counter count to establish the pulse repetition rate. In the parlance of the datasheet, this value is called "TOP". There is a formula below that comes from the datasheet. That formula uses "max value" to describe the same thing. We also will need a register to determine the width of the pulses.
Now would be an excellent time to look at the block diagram in Fig. 16-1 of the datasheet. You can replace all of the small "n"s, like in "TCNTn" with a "1", because this is Timer/counter1. "TCNTn" becomes "TCNT1", ect.
On the left of the diagram, you see the timer/counter itself: "TCNT1". Below "TCNT1" are two output control registers, "OCR1A" and "OCR1B", and one input control register, "ICR1". The output control registers connect, to "other circuitry" discussed in the next paragraph. I'll discuss "ICR1" pin functionality later.
Let's talk about that "other circuitry". The mode we select controls the interconnections between the various blocks in the block diagram. The output control registers each connect to comparators, depicted as rectangles with equal signs inside. These two comparators also connect to the timer/counter. When the value of the timer/counter equals the value stored in an output control register, a signal is sent to perform some action. In my project, when the comparator between the timer/counter and output control register "OCR1A" reach the same value, the "equal" signal will migrate to the "Control Logic" block (connection set by the mode selection). The result will be that the timer/counter will count down at the next clock from the prescaler. "OCR1A" is programmed with the highest value we want the timer/counter to reach "(TOP", or max value), and, obviously, is used to control the pulse repetition frequency. When the timer/counter reaches zero, called "BOTTOM" in the datasheet, it will count up at the next clock.
The output of the comparator between the timer/counter and output control register "OCR1B" connects to the block called "Waveform Generation". The "Waveform Generation" block connects to the ATmega328P pin "OC1B" (via a programming selection). When the output of this comparator signals equality, "Waveform Generation" circuitry will change the logic state of the pin. Whether it changes from "Low" to "High" or "High" to "Low" depends on whether the timer/counter was counting up or down at the time. It also depends on how we program one of the control registers not shown on the diagram.

Programming the Registers

Now is the time to discuss how we determine the value of max count to program into "OCR1A". There is a formula in the datasheet:
pulse repetition freq = clock speed / (2 * prescaler * max count)
Substituting the known values:
50 = 16,000,000 / (2 * prescaler * max count)
Rearranging and simplifying:
max count = 160,000 / prescaler
We have a choice of fixed values for prescaler: 1, 8, 64, 256, and 1024. We want to choose the lowest value of the prescaler to give us the highest value of max count. The larger max count, the greater resolution we will have when programming the pulse width. We can't use the prescaler of 1 because that would give us a max count of 160,000. A 16 bit counter can only count up to 216 -1, or 65536. Choosing the next prescaler value, 8, gives us a max count of 20,000. This will do nicely. There is also the happy coincidence that 20,000 is exactly the time between pulses in microseconds. Therefore, when we go to programming the pulse width, of say, 1.5ms., it will be attained by programming a value of 1500.

Generating The Code

I have a sample sketch below. All it does is slew the servo in 10° steps from +90° to -90° and back again. It runs continuously with 500ms. between steps. Registers "OCR1A" and "OCR1B" can be written to, directly, as can be seen in the sketch. "OCR1A", once set to 20,000 will not change - because the pulse repetition frequency will not change. "OCR1B" changes every time we wish to change the pulse width.
We have four more programming steps to attend to: Selecting the timer/counter mode 9, setting the prescaler to 8, selecting how we want the output pin to change logic state, and making the output pin, "OCP1B", an output. The first three of these will be done by programming two ATmega328P control registers, "TCCR1A" and "TCCR1B"
When I wrote the code below I included lots of comments that describe the programming of the control registers. No sense of being redundant so have a look at the code. Please look at tables 16-3. 16-4, and 16-5 of the datasheet for further details of the programming of these two control registers.
There is a lot more to discuss, including:
  1. The other PWM modes
  2. Non-PWM modes
  3. Input control register
  4. Waveform generator modes
  5. Timer/counter0 and Timer.counter2
  6. The continuous servo
  7. Generating and using timer/counter interrupts
  8. Some other uses for the timer/counters
I'm going to deal with these issues in my next post or posts.

Friday, March 11, 2016

Interrupts and the Arduino Uno

Introduction

This post is a logical follow-up on my last post: "Programming the ATmega328P Registers From the Arduino IDE". This discussion is about using the Uno's interrupts. You have two ways to monitor the Uno's I/O pins (to monitor switches, for example). You can poll for inputs to change state, or you can use interrupts to sense when a change of state occurs.
Polling means you are just going to check the state of Uno I/O pins. In a simple system this if fine. Polling means your sketch does nothing else while you check the state of pins. Interrupts are a way to check pins without your sketch diverting its attention from its main tasks.
Here is an example taken from a project I have been reporting on in this blog: I have an enclosure that accepts a large number of temperature sensors. Measurements are made and the results are transmitted to a Raspberry Pi for storage and graphing. The enclosure has a 2 line by 16 character display. I use the first line to display a sensor's description, and the second line to display the sensor's latest temperature measurement. Since the display can only show one sensor at a time, I installed a switch that allows me to switch the display between sensors.
I first handled the switch by polling. I included a small routine in my code in a convenient location. This routine looks at the logic level of the pin connected to the switch, and if low, causes the display to go to the next sensor. A lot goes on in my main code, so the routine to check the switch repeats after several seconds have passed. If I'm not pressing the switch when the routine looks, the routine misses the change of state.
The operation just felt awkward. I now monitor the switch by interrupt. Whenever the switch is pressed, an interrupt occurs so my routine in the loop just looks to see if an interrupt occurred, not if my finger is on the switch. Much better operation.
When the condition for an interrupt occurs, a small function, you write, will run immediately. When that function has done all it needs to do, operation is returned to the task your sketch was doing at the time before the interrupt. Since you don't know when the interrupt will occur, you have to look closely at your sketch to assure there are no instances when an interrupt will impact some critical timing. There are ways to handle that situation. Interrupts can be turned on and off at any place in your sketch.

Interrupts and the Uno

If you want to use the Uno's interrupts, the Arduino Language Reference states there are only two pins, pin 2 and pin 3 you can use. I'm here to tell you it is possible to generate an interrupt from every I/O pin on the Uno. Unless you are using pins 2 and/or 3, however, you will not be able to use the Arduino IDE functions attachInterrupt() and detachInterrupt(). You can, however, use Register Programming to program interrupts on any I/O pin.
The interrupt capabilities of pins 2 and 3 are, however, more robust. All of the external interrupts, when enabled, will trigger an interrupt whenever a change of logic level is detected. Pins 2 and 3 have three additional capabilities.
The four capabilities available for pins 2 and 3:
  1. trigger an interrupt whenever the logic level of the pin changes (high to low or low to high).
  2. only trigger an interrupt whenever the logic level changes from a low to a high.
  3. only trigger an interrupt whenever the logic level changes from a high to a low.
  4. trigger an interrupt whenever the logic level of the pin is low.
Every pin operates with choice 1. Only pins 2 and 3 have the additional three choices.
If you are designing a new project, and you know you are going to use interrupts to monitor sensors or switches, certainly plan to use pins 2 and 3. If you need to utilize interrupts from other pins, or would like to learn the advantages of register programming interrupts, read on.

A Little Review

From my last post, we will need knowledge of the ATmega328P's datasheet, the AVR library for the ATmega328P, and how we handle pin names. To use register programming, we shift our focus from the Arduino Uno to the ATmega328P, itself. Indeed, you can remove a programmed ATmega328P from your Arduino and use it on a circuit board of your own design. With an FTDI adaptor, you can program the ATmega328P while it is on your circuit board.
To use register programming, we will not be using the pin numbers printed on the Uno (like pins 2 and 3). We will use the pin nomenclature found on the ATmega328P microcontroller datasheet. I'm going to repeat a graphic from my last post. Its a partial schematic showing how the Uno's pins connect to the ATmega328P:
All of the ATmega328P pins that connect to the Uno I/O pins have multiple functions. For example, the ATmega328P pin 2 has this label inside the graphic for the chip: "PD0 PCINT16/RXD". That means this pin has three functions:
  1. PD0 - Standard I/O function, Port D, Pin 0
  2. PCINT16 - External Interrupt Number 16. One of 24 External Interrupts. ATmega documentation calls them Pin Change Interrupts
  3. RXD - UART Receive Pin. For Serial Input From External Devices

External Interrupt Register Programming - Register Definitions From the ATmega328P DataSheet

I cobbled together the following from the ATmega328P datasheet:
Pin Change Interrupt Control Register, PCICR: As I described in my last post, the ATmega328P has three ports, Port B, Port C, and Port D. PCICR lets you to enable or disable interrupts on any of the three ports. You can enable interrupts on more than one port. To enable interrupts on a specific port, write a "1" to the applicable bit in the PCICR register. Writing a "0" disables interrupts on the applicable port. Use the following when writing to PCICR:
  • PCIEO (bit 0) controls the interrupts on Port B, pins PCINT0 - PCINT7. PCINT6 and PCINT7 are not available as those pins connect to the crystal.
  • PCIE1 (bit 1) controls the interrupts on Port C, pins PCINT8 - PCINT14. PCINT14 is not available as it reserved for the RESET function.
  • PCIE2 (bit 2) controls the interrupts on Port D, pins PCINT15 - PCINT23.
Pin Change Mask Registers, PCMSK0, PCMSK1, PCMSK2: These three registers let you enable or disable individual pins in a port whose interrupts have been enabled with the PCICR register.

External Interrupt Register Programming - The ATmega328P Arduino Library

As mentioned in the last post, you do not have to consult the library. I include it to show how the datasheet, pin names, and the library come together to help you to write your sketches. The "#defines" in the library show what names you can use in your sketches. These names relate directly to the names in the datasheet register definitions and the ATmega328P pin names, as shown in the datasheet.

Examples Using Interrupts

From my setup in my last post, I'm going to use the red and green switches, and the Arduino Uno. I/m not using the LEDs. If a switch is pressed, a message to the serial monitor will appear.
In my first script, below, I will connect the green switch to PC4 (PCINT12, Uno Pin A4), and the red switch to PC5 (PCINT13, Uno pin A5). In this example, both switches connect to the same port. In setup you can see where I have setup my registers. Remember, from my last post I use the ATmega328p's internal pull-up resistors. They are enabled in line 28. Lines 32 and 33 enable interrupts for the two switches. That should be self-explanatory from the preceding discussion.
Here is where the magic happens: Note lines 13 to 20. This function is called the "Interrupt Service Routine" or ISR. Most of the time we will be in the while loop in setup. If either switch is pressed, processing diverts to the interrupt service routine. When this routine is done, processing goes back to where it was in the while loop.
It is important that you write line 13, the function definition, exactly as shown in my sketch (except for the comment, of course). This ISR will react to any enabled interrupt on port C. If you enabled interrupts on port B, or port D you would substitute "(PCINT0_vect)", or "(PCINT2_vect)", respectively, for "(PCINT1_vect)".
You want your interrupt service routine to be as short as possible. Do not use delay() in the ISR, delay(), itself, uses interrupts. If you use millis() in your code, millis() will not continue to increment while you are in the ISR, resulting in errors.
Any variable declared outside of the ISR, but changed inside the ISR should be declared with the modifier "volatile". This changes where the values of these variables are stored within the ATmega328P. Declaring them as volatile assures the values will be stored in RAM and not in a register - more important is the fact the values will not be lost. In our case that refers to the variasbles "data" and "foundInterrupt".
What does the ISR do? First, it reads PINC (the port C input register), masks out all bits but those related to PC4, and PC5, and stores the value in the variable "data". Second, it disables the port C interrupts - this is a way to debounce the switch (further key presses will not trigger an interrupt). Lastly, it makes the Boolean variable "foundInterrupt" true. When it has done all of these things, it exits back to the while() loop.
Back in the while()n loop, The first "IF" statement will now be true. We now look at the variable "data" to see which switch was pressed (The bit will be low for the switch that was pressed). Variable "foundInterrupt" is set to false and the masked value of PINC is check. If neither switch is pressed, the interrupt for port C is enabled again. This last is another way to effect switch debounding. This assures that only one message will be displayed for each switch press. In this scenario, it is not possible to detect if both switches are pressed at the same time.
The sketch below illustrates connecting the two switches to different ports. The green switch connects to PB0 (PCINT0, Uno pin 8). The red switch connects to PC5 (PCINT13, Uno pin A5). As with the last sketch, look at setup() to see how the ports, pullup resistors, and interrupts are setup.
Since we would like to detect interrupts on both the B and C ports, we need an interrupt service routine for both ports. The two ISRs are very simple. When a switch is pressed, variable "foundInterrupt_PortB", or "foundInterrupt_PortC", is made true. Also, the interrupt for that port is disabled. This is for switch debounce to avoid multiple interrupts (without this provision, an interrupt would occur whenever the switch is pressed and whenever the switch was released).
I think the code in the while() loop is pretty clear. Note that this sketch allows the possibility to detect both switches pressed. Since the while() loop has a 2 second delay, if both switches are pressed within the same two second period, the serial monitor will show that both are pressed. To avoid that situation, you should disable both interrupts in the two ISRs. The last part of the while() loop enables the two interrupts if both switches are released.

Thursday, January 7, 2016

Programming the ATmega328P Registers From the Arduino IDE

Please Note:

Because I have no experience with other Arduino boards, I'm going to confine my comments to the Arduino Uno and the Atmel ATmega328P microprocessor.

Introduction

If you desire to do something beyond the Arduino programming language, like program an interrupt for any Uno I/O pin, do more precise control of pulse width modulation, or write to the EEPROM within the ATmega328P, you need to learn about the ATmega328P's internal registers. If you are studying someone else's code and see something like:
     PORTD |= (1 << PORTD1);
and you wondered what that meant, read on. By utilizing what I call "Register Programming", besides the examples above, you can more efficiently program the three I/O ports, use the ATmega328P's internal timers, program it's SPI, I2C, and serial interfaces, and make better use of the Analog to Digital converter pins, and the analog comparator.
I would not attempt to control a servo with the AnalogWrite() function. You need more resolution than 1 part in 256. Also, the frequency is wrong. AnalogWrite() gives you a frequency of 490Hz or 980Hz depending on the pin. The very common servo I am familiar with requires a frequency of 50Hz. Register programming gives you the opportunity of using an ATmega328P counter that gives you one part 65536 resolution rather than 256. You can also set the frequency exactly to your needs.
What are these registers? They are eight bit bytes of SRAM memory within the ATmega328P. These registers can be accessed through programming via the Arduino IDE. If you write "digitalWrite(13, HIGH);" in your code, you are writing to one of these resisters. The ATmega328P has 224 of these registers, but most are reserved for future use. I count 86 that are useful. All of these have particular purposes.

Resources

To do Register Programming you need three basic resources:
  1. Comparison between Arduino I/O pins and ATmega328P pins
  2. ATmega328P datasheet
  3. AVR libraries on your computer

Arduino Pins and the ATmega328P

The following partial schematic represents the ATmega328P and the Arduino Uno's pins as printed on the device and as used in the language reference:
The graphic of ATmega328P looks really messy. That is because, all the I/O pins, except power and grounds, have multiple functions. For the moment, we will concentrate on the ATmega328P's pin nomenclature closest to the border of the graphic, namely PB0 to PB7, PC0 to PC6, and PD0 to PD7. All but three of these pins connect to Arduino Uno I/O pins. PC6 does not because it is used by the Uno as a reset to the ATmega328P. PB6 and PB7 connect to the 16MHz crystal so can not be used as I/O pins. The other pins make up three ports, B, C, and D. Each port is controlled or monitored by three ATmega328P registers.

ATmega328P Datasheet

The next resource is the Atmel datasheet for the ATmega family of microcontrollers. Here is a link to that document.
Every function and every register is clearly presented and explained in the datasheet. You can learn a lot and do a lot by reading this document. Besides the control of the port registers, I have used the timer registers to precisely control motors and servos (better than using the Arduino's analogWrite() function). I have also used the registers for writing to and reading from the ATmega328P's internal EEPROM, and I have used them to utilize external interrupts.

ATmega328P Port Registers

Let's create an example using one of the three port registers. We will use all eight pins of port D. Four LEDs will connect to PD0 to PD3. These correspond to pins labeled 0 to 3 on the Uno. We will connect four switches to PD4 to PD7. These correspond to pins labeled 4 to 7 on the Uno. Here is the partial schematic:
The following is copied directly from the datasheet for the ATmega328P. It details the three registers devoted to Port D:

AVR Libraries On Your Computer

Here is the final resource. YOU DO NOT NEED TO CONSULT THESE LIBRARIES TO PROGRAM YOUR DEVICES. I include this discussion to show why the Arduino IDE compiler allows you to use the Atmel register and register bit names in your code.
Atmel has supplied libraries for a large number of their microcontrollers to the Arduino development suite. If you have a PC, more than likely, you will find these libraries here:
     C:\Program Files (x86)\Arduino\hardware\tools\avr\avr\include\avr.
There are 285 library files in this directory. No matter what version of the Arduino you have, you only need to know of one these libraries: io.h. You insert "#include <avr\io.h>" at the top of your code. The Arduino IDE, when compiling, will look at this file and knowing the specific Arduino you are using, will go to the appropriate library file. For the Arduino Uno, that library is iom328p.h. Wish I could print out the entire file here, but it is quite long.
iom328p.h consists of many, many #define statements. There is a #define for each of the ATmega328P's registers, and #define statements for each bit of each register. I never counted them, but I would think all 86 registers are addressed. All the nomenclature in the library is taken directly from the data sheet. PORTD in the data sheet is PORTD in the library. Consequently, you can write "PORTD" in your code.
Here is the portion of the library that deals with the three PORTD registers. Note the text corresponds exactly to the text in the data sheet:

Putting It All Together and Writing Code

While the text in the library conforms to the text in the data sheet register descriptions, the text on the schematic (also taken from the data sheet) does not. For example, the schematic pin labeled PD7 corresponds to PORTD7 in the PORTD register, PIND7 in the PIND register, and DDD7 in the DDRD register.
Now that we know that we can use the register names, like DDRD, and the register individual bit names, like DDD2, how do we write code? There are two basic ways I do it. If I want to specify all eight bits in a register (initializing a register), I will write something like this:
  PORTD = 0; //writes 0 to all eight bits.
  PORTD = 0b11110000; //top 4 bits high, lower 4 low.
If, however, I wish to simply change one, or more bits, without effecting the other bits in a register, I will do something like this:
  PORTD |= (1 << PORTD2);
This will make the logic level of I/O pin PD2 high, without effecting any of the other seven bits of PORT D. Rather than explain how this works here, I'll let you read further down this post where it will be explained.
Finally, it is time to discuss the functions of the three registers and how to used them in your code. We will make use of those four switches and four LEDs of our example circuit in our discussion.

The Data Direction Registers - DDRB, DDRC, and DDRD

The ATmega328P needs to know how you are using its pins. Are they inputs or outputs? That is the purpose of the data direction registers. You write a 1 to make a pin an output and a 0 to make it an input. In our example, PD0 to PD3 will be outputs, while PD4 to PD7 will be inputs. PD0 corresponds to DDD0 in the DDRD register. The other pins follow the same pattern as PD0. We now have enough information to write a line of code to establish which pins are inputs or outputs:
      DDRD = 0b00001111;
I'm using the binary representation (0b00001111 rather than 15 in decimal) because I can easily see each of the eight bits of DDRD. This is equivalent to using the pinMode() function in the Arduino language. However, using pinMode() you need to write eight lines of code:
      pinMode(0, OUTPUT);
      pinMode(1, OUTPUT);
      pinMode(2, OUTPUT);
      pinMode(3, OUTPUT);
      pinMode(4, INPUT_PULLUP);
      pinMode(5, INPUT_PULLUP);
      pinMode(6, INPUT_PULLUP);
      pinMode(7, INPUT_PULLUP);

Internal Pull-Up Resistors

What's with the PULLUP notation? As shown in the schematic, without further effort, the switches have no useful function. Whether a switch is pressed, or not, a logic 0 will be seen at the switch's pin. There are two ways to make the switches useful. The first is to connect a resistor between each of a switch's I/O pin and 5V. With this "pull-up" resistor connected, a logic 1 is recorded at the pin if the switch is not pressed. Since the switch connects the I/O pin to ground, a logic 0 will be recorded if the switch is pressed.
The second way utilizes a convenient feature of the ATmega328P. Each I/O pin has an internal pull-up resistor that can be connected at the pin. These ATmega328p pull-up resistors are connected by programming. We have seen how that is done using pinMode(). We can do the same, and do it for all four switches, in one statement using register programming. Per our example, we will use the PORTD register.
If you look in the data sheet at the description of the PORT registers, you will find if a pin is declared an input, in the port's DDR register, programming a 1 in the pin's PORT register will turn on the internal pull-up resistor. To make it clear, in our example, PD4 - PD7 have been declared inputs. Therefore, we will program PORTD4, PORTD5, PORTD6, and PROTD7 as 1s. We will do this in one line of code:
      PORTD = 0b11110000;

Port Registers - PORTB, PORTC, and PORTD

We have already seen an example of using the port register for enabling the internal pull-up resistors of input pins. The other obvious use of these registers is to turn on and turn off external components like LEDs. In our example, we have four LEDs. In the line of code above, where we connected internal pull-up resistors, we have also turned the four LEDs off. A logic 0 provides, essentially, ground voltage to the device. A logic 1 provides, essentially, +5V to the device. In our case, 0 volts turns the LEDs off. To turn an LED on, program a 1 to the pin's PORTD register. To turn LEDs D1 and D3 on, and to keep LEDs D2 and D4 off, we can write the following line of code:
      PORTD = 0b11110101;
Note, by writing the line above, we have to keep track of the logic levels of all eight pins in port D. Sometimes, that is not convenient, and not possible. Once we setup those pull-up resistors, we don't want to inadvertently disconnect them by programming. What we need then is a way to write to as few as one pin in the PORTD register without disturbing the logic levels of the other pins. To do that we need to be familiarize ourselves with the logic functions given to us by mathematician George Boole: the bitwise operators.

The Bitwise Operators

What does the following statement do?
     PORTD |= (1 << PORTD1);
This statement will turn on LED D2 without effecting the other seven bits of port D. It utilizes two of the six bitwise operators. Let's list the six operators and the characters that represent them in code:
~ NOT
& AND
| OR
^ EXCLUSIVE OR
<< SHIFT LEFT
>> SHIFT RIGHT
These operators are called bitwise because they operate on individual bits of a byte.

The NOT Operator ~

This is the simplest operator. It will flip all eight bits of a byte. The 1s become 0s and the 0s, 1s. For example, if PORTD = 0b00001111, ~PORTD = 0b11110000.

The AND Operator &

This takes two bytes and results in a third byte. The best way to visualize the operation is to place one byte over the other and then state the rule. For example:.
      00001111  the first byte
      01000010  AND with the second byte
      00000010  the resulting byte
We compare the two bits, in the same bit position, of each byte, and come up with the value of the bit, in the same bit position, in the resulting byte. The rule for the AND operation: if BOTH bits are a 1, the resulting bit is a 1. If either bit is, or both bits are, a 0, the resulting bit is a 0.

The OR Operator |

This also takes two bytes and results in a third byte. For example:.
      00001111  the first byte
      01000010  OR with the second byte
      01001111  the resulting byte
The rule for the OR operation: if EITHER bit is a 1, the resulting bit is a 1. If BOTH bits are a 0, the resulting bit is a 0.

The EXCLUSIVE OR Operator ^

This takes two bytes and results in a third byte. For example:.
      00001111  the first byte
      01000010  EXCLUSIVE OR with the second byte
      01001101  the resulting byte
The rule for the EXCLUSIVE OR operation: if BOTH bits are the SAME, the resulting bit is a 0. If the bits are DIFFERENT, the result is a 1. This also has the useful function of flipping, or not flipping a bit. A logic 1 in a bit position of one byte will flip the corresponding bit in the second byte. A logic 0 in a bit position of one byte will leave the corresponding bit in the second byte unchanged.

The SHIFT LEFT Operator <<

This operator takes a byte and an argument. The argument of the operator indicates how may times we will shift all the bits in the byte to the left. After each shift, a 0 is loaded into the least significant bit position (the bit on the right end). If we have the expression "PORTD << 3;", and PORTD is 0b00001111, the resulting byte is 0b01111000.

The SHIFT RIGHT Operator >>

This operator also takes a byte and an argument. The argument of the operator indicates how may times we will shift all the bits in the byte to the right. After each shift, a 0 is loaded into the most significant bit position (the bit on the left end). If we have the expression "PORTD >> 3;", and PORTD is 0b00001111, the resulting byte is 0b00000001.

Now That We Have The Fundamentals, Let's Light Some LEDs

How would we turn on LED D3 and not effect the other LEDs or the switches? Let's write the line of code and then take it apart:
     PORTD |= (1 << PORTD2);
First, we know that is a compound operation like "A += 1;" is the same as "A = A + 1;" We can expand our expression to:
     PORTD = PORTD | (1 << PORTD2);
Looking at the library we see "#define PORTD2  2". We can replace PORTD2 with 2, as below:
     PORTD = PORTD | (1 << 2);
(1 << 2) indicates a shift left with the argument of 2. The operand is the integer 1 which we can state in binary form as 0b0000000000000001. The operation wants us to left shift this twice putting a 0 in the least significant bit position each time. The result of (1 << 2) is 0b0000000000000100. We can drop the upper eight bits as they will have no impact when next operating on the eight bit PORTD. The result now is 0b00000100.
This now resolves to:
     PORTD = PORTD | 0b00000100;
Let's assume PORTD is 0b11110000. Here is what the operation looks like:
      11110000  the original value of PORTD
      00000100  OR with the second byte
      11110100  the resulting value of PORTD. --- LED D3 TURNS ON.
We turned LED D3 on, now let's turn it off (without effecting the other LEDs or switches. Here is the line of code:
      PORTD &= ~(1 << PORTD2);
Some of the line of code is the same as before. (1 << PORT2) resolves to 0b00000100. However notice the NOT operator, ~. This flips all eight bits resulting in 0b11111011. Now we apply the AND operation as shown below:
      11110100  the original value of PORTD
      11111011  AND with the second byte
      11110000  the resulting value of PORTD. --- LED D3 TURNS OFF.

Writing To Multiple Outputs

What if you wanted to turn on (or off) two or more LEDs? You can string the operations together in one line. Let's turn on LED D1 and LED D4, then turn them off:
      PORTD |= (1 << PORTD0) | (1 << PORTD3);  ON
      PORTD &= ~(1 << PORTD0) & ~(1 << PORTD3);  OFF
You can even mix them. This will turn LED D1 and LED D3 on and LED D2 and LED D4 off:
      PORTD |= (1 << PORTD0) & ~(1 << PORTD1) | (1 << PORTD2) & ~(1 << PORTD3);
For more fun, stick that line above in setup(), and add the following lines in loop():
      PORTD ^= (1 << PORTD0) ^ (1 << PORTD1) ^ (1 << PORTD2) ^ (1 << PORTD3);
      delay(500);
This will toggle the four LEDs at a 1Hz cycle. Try it.

Reading the Logic Level of Input Pins

We Can't Forget Those Switches. Continuing the example, the switches are connected to input I/O pins. To read a pin that has been declared an input we use one of the PIN registers. In our case, that will be PIND. Since we have four switches we need a way to read one switch and ignore the others. To see how this is done, the line of code to evaluate if switch SW1 (connected to PD4) is pressed is:
      PIND &= (1 << PIND4);
The above expression will be logic 0 if SW1 is pressed and not 0, actually 16, if released. The other switches will not effect the result.
I, frankly, don't always use that last method for reading from a register. I usually establish, and apply an eight bit datamask to the value in the PIN register. Like this to read the value of PIND4:
      byte datamask = 0b00010000;
      byte data;
      data = PIND & datamask;
Here is a simple sketch. If SW1 is pressed, LED D1 will light, etc. This is not the best way to do this as it allows multiple LEDs to be lit and there is no switch debouching. The better way is to use interrupts to signal when a switch is pressed. My next blog entry will deal with that exact topic. Interrupts also are best handled with register programming.

One More Thing

Here is a photo of the actual hardware:
I had to Photoshop in the colors of the LEDs. They are of clear plastic and do not photograph well when lit.
Since we have introduced color, why not put that into the program. Here is the sketch carried to the extreme by adding a bunch of #define statements: