PIC Chips
There are a number of different microcontroller companies out there, Atmel, Microchip, Intel, etc. We could spend forever talking about the differences between them, and why use one over the other. Deciding which MicroController Unit (henceforth MCU) type to use is something of a religious experience for many, and they'll argue to the death. I chose to learn on the PIC chips because they are abundant, available from many suppliers in small quantities, have all different kinds of chips with all kinds of different features, are available in DIP (dual inline package) which is the only packaging you can really use with a breadboard, they are cheap (about $1-$5 each depending on what you get), and the list goes on, you get the idea. Why not use Microchip PICs? Well I don't know, and I don't care, I never gave much thought to it.
PIC originally meant Peripheral Interface Controller. Today, PIC is more or less just a name, and it applies to pretty much any MCU. Microchip now uses the PICmicro name for their PIC chips. We will pretty much just keep referring to them as PICs or PIC chips, etc.
The PIC chips we will use on this blog, the PIC12F629 and the PIC16F628A have an operating voltage range of 2.0V to 5.5V and 3.0V to 5.5V respectively. In all of our experiments we will use an operating voltage of +5V.
The "F" designation in the name of the PIC chip tells us that these PICs have Flash-type memory, meaning that they are erasable and programmable via electric signal using a programmer (the PICKit).
MCUs are very complicated little devices, and many books have been written about all their inner workings. Because they are so complex, and since I'm not an expert on microcontrollers, I'm really not qualified to teach you about them with regards to specific details. So, what I have decided is that rather than plowing over books and just rewriting information that's already out there, I would leave it up to you to get the information yourself. Sorry, but it's really just better that way since it's not the scope of this blog to teach these things. Listed below are a couple of texts that I am familiar with and have been used well to write this blog. The first listed is quite a handy reference to have on your bench, regardless of whether you read it cover to cover or not, and at over 900 pages, it's full of information.
PIC Microcontrollers: Know It All (Newnes Press)
Programming 8-bit PIC Microcontrollers in C: with Interactive Hardware Simulation (Newnes Press)
Languages
Microcontrollers are traditionally programmed in assembly language, which translates directly into machine code. Machine code, also called binary, is the ones and zeroes language (10010001). Assembly language is found in a lot of microchip's documentation, including datasheets and reference manuals. Is it necessary to know assembly language? No, not really, but it helps quite a bit, especially when trying to look up information in the microchip datasheets or from some other sources. The first text listed above, PIC Microcontrollers: Know It All is what I used to learn assembly, and it does this quite well.
Each PIC chip has a set of instructions, written in assembly, which can be found in the device datasheet. These instructions are basically everything that the MCU can do broken down into simple instructions. The baseline PICs use a 12-bit instruction word, which has 33 instructions. The mid-range family uses a 14-bit instruction word, which has 35 instructions. Then, the 16-bit instruction word microcontrollers, at the high end of the PIC MCU family, have 58 instructions. We'll talk in just a minute about bits, so don't worry if you don't know what I'm talking about right now. Both of our chips are mid-range MCUs and have 35 instructions. The table below, taken from the PIC12F629 datasheet shows the 35 instructions. Assembly uses Mnemonics as instructions. A mnemonic is a memory aide, like Every Good Boy Deserves Fudge to remember the musical scale E-G-B-D-F. The first instruction on the list is ADDWF, and it means mathematically add the Working register to F (a literal, such as a number). I know that probably goes over your head, and that's okay, I'm just making a point that there's a logic behind the instructions.
Figure 1 |
The other thing to note about C vs. Assembly is that, Assembly takes up far less space in the PIC's program memory than a piece of software written in C. Adversely though, C takes far less time to write, and is infinitely easier to read when you have to go back to a program and make some changes, so it tends to be a trade-off between time and ease of writing vs. data space used.
Memory types found on MCUs
Microcontrollers have different types of memory inside them, program memory, data memory, and data EEPROM memory (some chips).
Program memory is where the program we write gets stored when we "flash" it onto the chip. Program memory size is dependent on the device being used. Program memory is non-volatile memory, meaning that the information stored on it remains intact when power to the device is lost.
Data memory is a RAM (Random Access Memory) memory type which contains "Registers". A register is a place inside the microcontroller that can be written to, read from, or both. Think of a register as a piece of paper in the MCU. There are two types of registers that we will be concerned with, Special Function Registers (SFRs) and General Purpose Registers (GPRs).
Special Function Registers are the registers that control special functions of the MCU, like timers, Input/Output peripheral controls, etc.
General Purpose Registers are registers where we store temporary data that we want to save for later.
Data memory is Volatile memory, meaning that any data we put there will be lost when the device loses power.
Data EEPROM memory is like a general purpose register in that we get to use it like paper for writing down variables and reading them later when we need them. The difference is that EEPROM memory is non-volatile, meaning that the information is saved even when the device loses power. This is useful for things like storing the access code of an electronic lock. Not all devices have EEPROM, but both of the devices we'll use in this blog do. EEPROM stands for Electronically Erasable-Programmable Read-Only Memory.
Bits, Bytes, and Words
I mentioned before that assembly translates down to machine code. Well, so does C in a manner of speaking. All MCUs operate solely on machine code. The program you write gets "compiled" (the purpose of a compiler, in our case the Microchip XC8 compiler) down to ones and zeroes which are executed through the chip.
Each 1 or 0 is a bit, and 8 bits is a byte. A byte is the 8 bits from 0 through 7. It's important to remember that a byte is not 1 through 8, but rather 0-7 with 0 being the "least significant bit" and 7 being the "most significant bit". A bit confused? We'll clear it up for you in just a second.
You're going to think a lot in bits and bytes when you start programming. There are a lot of registers inside a PIC, and each of these registers has a control to set up the feature associated with the register. These controls are a string of ones and zeroes, typically a byte in length which are user-set to either a 1 or a 0 depending on the options desired. Let's take a quick look at an example to help make this more clear.
In one of our first example projects, we're going to turn a LED on and off using the PIC12F629 MCU. In order for the MCU to do this, we utilize one of the Input/Output (I/O) pins to complete the circuit to the LED. We need to access two registers inside the MCU in order to do this, the TRISIO register, and the GPIO register. These two registers work together to tell the MCU what to do with I/O pins. The TRISIO register controls whether a specific pin is an input or an output, and the GPIO register controls whether the pin is turned on or turned off. Let's open up the PIC12F629 Datasheet. For other PIC datasheets when you need them, they can be searched for on Microchip's website at www.microchip.com.
Section 3.0 in the datasheet covers the GPIO (General Purpose Input Output) Port. Figure 2.1 below shows the bits associated with the TRISIO and GPIO registers from the device datasheet.
Figure 2.1 |
Figure 2.2 |
Figure 2.3 |
Let's say that we are going to use pin number 4 of the device (indicated on the pinout as GP3) to hook our LED up to. Since a LED is an output device (it outputs light), we need to setup pin 4 as an output in the TRISIO register, and for the sake of this example we'll set all other GPIO pins as inputs. Remember that the TRISIO register controls the port direction (sets input or output). Setting a bit to 1 sets it as an input, and setting a bit to 0 sets it as an output, therefore our TRISIO bits would be 00110111. Read in order from left to right, these would be bits 76543210, and is a byte. Remember that bits 7 and 6 are unimplemented and read as 0. For the sake of clarity, PIN 4 of the device is associated with the GP3 bit, as determined by referencing figure 2.2.
The GPIO register sets whether the GPIO pins are turned on or off. A bit set to 1 is on, and a bit set to 0 is off. Therefore, when the LED is off, each bit would be set as 0, and the byte would look like 00000000. When we want to turn the LED on via its connection to pin 4, we set the GP3 bit to 1, and our byte would look like 00001000. Again, a byte is read from the most significant bit (7) on the left to the least significant bit (0) on the right.
Now let's talk about Words real quick. Words, instructions, bits, bytes... it's all kind of a confusing mess, but can be summarized like this: Different MCUs come in different word sizes. There are 12-bit instruction words, 14-bit instruction words, 16-bit instruction words, etc. Both the PIC12F629 and PIC16F628A have 14-bit instruction words. The internal architecture of the PIC chips (called Harvard Architecture) has three sections, RAM, the Central Processing Unit (CPU), and the Program Memory (figure 3). There are 8 data buss lines between the RAM and CPU. Each line is a bit, so the 8 lines corresponds to 1 byte worth of data transfer lines. The connection between the CPU and the program memory however, is 12, 14, 16, etc lines depending on the size of the instruction word. In our chips there are 14 data transfer lines (14-bit) between these two components.
Figure 3 |
Figure 4 |
I realize that this is all confusing and can be difficult to grasp, but I wanted to make sure and cover it so that when you're browsing around at other information on-line and in books, and you start seeing things about bits and bytes and words, that you had something of a basis to start on. To make matters worse, despite the fact that the instruction words on mid-range PIC chips is 14-bits wide, they are still considered 8-bit microcontrollers because that's the width of the RAM memory.
How the PIC Processes Instructions
Figure 5 |
Certain instructions however, will tell the MCU to go to a specific location in the program memory and execute that instruction next rather than proceed in order down the list. As a matter of fact, the very first instruction in a program typically does just that, because as shown in figure 5, the first line that gets executed on reset is line 0, but program memory doesn't start until line 5. Therefore, the first program instruction will typically be an instruction that tells the program counter to skip down to line 5. To summarize the program counter, it is a device which holds the memory location of the next instruction to execute. The bit-width of the program counter corresponds to the number of bits required to address all of the available space in the program memory.
Lastly, looking at figure 5 again, we see the stack, labeled as Stack Level 1 through 8. What is the stack? Certain instructions will interrupt normal program flow and instead execute a subroutine. In order for the program to return to the location it left off from when the subroutine is completed, the program address needs to be saved so that it can be called later. The purpose of the stack is to store this program address. The stack tends to be several layers deep so that multiple subroutines and interrupts can be called without losing the normal program's place. Going to multiple subroutines or interrupts in succession, in other words a program flow which would take MCU operation from Regular program flow, into a subroutine, then from that subroutine into another subroutine and so forth without first returning to the normal program flow is called "nesting". Care must be taken by the programmer that the program doesn't go deeper into the stack than the number of stacks you have available, otherwise the address needed to return to normal operation will be lost. We don't need to worry about this at all right now, so we won't cover it any further.
Conclusion
Wow, okay what a post huh? I know there's a lot of information in there, but it will make more sense the more we learn about programming and using PIC chips. The nice thing is that when using C language to program PICs, the compiler pretty much takes care of everything so we don't need to watch the finer details too much. I presented the information here because I feel that these are basic things you should know in order to be a better programmer, and to help understand certain things when designing a program.
Thanks for reading, and I'll see you on the next post!
November 25, 2014: Post edited for clarity.
Great tutorial!
ReplyDeleteJust one point I don't get. When you say the output to the LED is on pin 4, do you mean port4? As pin 4 is port3 on a PIC12F629.
FANTASTIC BLOG
When I reference a PIN number, such as pin 4, I am referring to the actual pin number as used on the device's data sheet. If you look at page 4 of the PIC12F629's datasheet from microchip, http://ww1.microchip.com/downloads/en/DeviceDoc/41190G.pdf you can see that the pins are numbered starting from the top left (pin 1) and working down the left side to 4. So PIN 4 is labeled as "4" and also labeled as GP3/MCLR/VPP. What this tells us is that PIN 4 is capable of functioning as a General Purpose Input/Output number 3, the Master Clear/Reset, and it is the pin to which programming level voltage is applied when we are programming the device with the programs we write for it.
ReplyDeleteAnonymous pointed out an issue with the clarity of my description regarding the connection to PIN 4/Port 3. This post has been edited to simplify this description.
ReplyDelete