Wednesday, March 27, 2013

Introduction to MPLAB X, First Project

In the first blog post we downloaded and installed MPLAB X and the XC8 compiler.  We will now use these to set up our first project, using an I/O pin on the PIC12F629 to turn on a light emitting diode.  Since this is our first project, there's quite a bit to cover here, so this lesson will be a little long in order to cover a lot of "basics".

In addition to the software, you will need the following hardware:

1 Battery or Voltage Source 9-12V
1 PIC12F629 Microcontroller
1 LED with a forward current ~20-24mA
1 10K Resistor
1 Current Limiting Resistor for LED
1 0.1uF Capacitor
1 LM7805 Voltage Regulator IC
1 Normally-Open Momentary Switch
1 Breadboard
Jumper Wires

Creating a New Project

Figure 1

Upon opening MPLAB X IDE you will see the program's Start Page as shown in figure 1.  Under the Dive In section of the start page, click "Create New Project".  Alternatively, you can click File>Create New Project.  In the new project window you should see that under the categories column "microchip embedded" is selected and "standalone project" under the projects column is selected, click next.  We'll now select our device (the MCU we're using).  On the family drop down menu, select "Mid-Range 8-bit MCUs", and then "PIC12F629" under the device drop down menu.  Click next.  The next step will ask you to select a Supported Debug Header which we will leave selected to "None", then click next again.

The next step is to select a tool.  This is where we select which programmer we're going to use.  I have the PICkit 2, which I have selected for my project.  Click next.  The next screen asks us to choose a compiler and you should see the XC8 compiler listed there.  XC8 only appears in this menu after you have installed the compiler, so if you don't see it, make sure that you installed the XC8 compiler software.  After selecting XC8, click next.  Finally, we need to name our project.  Let's name our project "learn_c", and click finish.

We should now see our projects in the top-left portion of the IDE, as seen in figure 2.  This is a blank project (there are no files associated with it), so we need to add a file before we can start writing a program.
Figure 2
Click the file menu and select "New File".  Under categories, highlight "C" then under file types highlight "C Source File" and click next.  Let's name our source file the same as our project "learn_c" and set the file extension to ".c".  The .c file extension is associated with c source code files.  Click finish.  We should now have a new window within the IDE open as seen in figure 3.1.
Figure 3.1
If your .c file within the projects window is placed somewhere other than in the "Source Files" drop-down, we should drag the .c file into the Source Files, as shown in Figure 3.2.

Figure 3.2

Our First C Program

Our first program is very simple.  It will teach you the basic input/output interface by illuminating a light emitting diode when we press a button.  The LED will remain lit for as long as we're pressing the button, and will extinguish when we release the button.  The main purpose is to show how to read an input, and how to place data on an output.

The first thing we're going to want to do is plan out what I/O pins we want to use for the button and the LED.  Planning the hardware in advance is necessary for programming.  The PIC12F629 datasheet contains the pin diagram for the MCU as seen in figure 4.
Figure 4
Each pin of the MCU and the associated functions available on those pins are described in the datasheet's pinout description section.  As a brief rundown though, VDD is +5V, VSS is ground, and pins 2 through 7 are the General Purpose I/O pins.  There are additional functions which reside on these pins, such as analog to digital converters and comparator modules, but we're only interested in the I/O function right now.

Reading through the datasheet, we discover that the GP3 pin is an input only port, which means that we cannot use it to output data.  Let's use GP3 (pin 4) for our button input.  We'll select GP0 (pin 7) as the output for our LED.  A schematic and breadboard image of this project is at the bottom of this post so you can build it and follow along.

Let's have a look at the program now, then we'll walk through it.

Figure 5
In reference to figure 5, please view my post which corrects an error made here.

As we can see at the very top of the program, I have made use of the ability to place comments in the code.  It is good practice to place a description of the program at the top of each program we write.  Following the comments, we need to include the xc header file.  As stated before, the header files contain a bunch of stuff that the compiler needs in order to generate code.  The xc.h file automatically includes the MCU specific header file so that all of the definitions and addresses of the special function registers are there.  Remember to place the file name within the <> symbols.  I have made use of comments to describe what the program is doing, and also to break up sections of the software to make it easier to read.  I haven't just done this for the sake of making it easier for the learner to look at the software, I always do this.  As you start writing longer pieces of software, you will really appreciate breaking up the code like this.

Now, let's take a slight detour for just a moment.  One of the the things that always bothered me about reading books that were supposed to teach you MCU programming in C is that they would do one of two things.  They would show you an example first program and not include this section on the CONFIGURATION WORD, or they would have that section in the code, but never explain it until later in the book.  The configuration word is SUPER important and will most likely be used in every program you write, so why wouldn't you explain it right away?  Well I suppose because it's a long-winded explanation, but I'll try to keep it short and to the point.

Configuration Word

Microcontrollers have special options in their program memory separate from the Special Function Registers called the Configuration Word.  The configuration word cannot be accessed during program execution, so they must be set during programming of the device (with the compiler).  The configuration word allows the user to define certain configurable features of the microcontroller.  We will talk briefly about those features now, focusing only on those that are currently relevant.  Section 9.1 of the datasheet shows the PIC12F629 configuration word register (figure 6).

Figure 6
Under the configuration word register in figure 6 is a legend.  This legend is useful when looking at any register because it tells you how you can manipulate the bits, and what their default status is.  In the case of the configuration word bits, they show "R/P - 1" which means they are readable bits (can be read in program memory), they must be set during programming, and their default status is 1 (which means "set").

The datasheet defines each bit and it's available settings.
Bits 13 and 12 control the Bandgap Calibration.  These bits are set at the factory and are used partly to calibrate the MCU's internal oscillator.  We wont be messing with them.
Bits 11 through 9 are unimplemented.
Bits 8 and 7 are used to enable Code Protection for EEPROM data and program data respectively.  Code protection is a means of keeping your software safe from theft.  Basically, if you are a company producing a product, and you want to help keep someone from stealing the code off your MCU and using it to produce a "knock-off", code protection helps.  We will always keep code protection disabled because once it's set, you cannot read from or write to your MCU anymore.
Bit 6 controls Brown-Out Detection, an internal trigger that shuts down the MCU when operating voltage drops below a threshold.  It is useful for situations where the embedded system runs off batteries.  The Brown-Out Detection (BOD) circuit will reset the MCU when voltage is restored above the threshold.
Bit 5 controls the Master-Clear Reset (MCLRE).  The MCLRE function is used to externally reset the MCU.  When enabled, the MCLRE pin must be provided with positive voltage for the MCU to operate.  The MCU is held in reset as long as this pin is low (no voltage), and restarts the MCU from the reset vector when voltage is restored.  MCLRE can be turned off so that the MCLRE is internally tied to the VDD pin.  We will explore using the MCLRE function in later projects.
Bit 4 controls the Power-Up Timer (PWRTE).  The power up timer is disabled by default, but is used to hold the MCU in reset mode upon power up.  This feature allows time for the power supply to stabilize before program execution begins.  The power up timer's delay is a nominal 72 milliseconds.  We will always use this feature, since there is little reason not to.
Bit 3 is the Watchdog Timer (WDT) bit.  Many times, embedded systems operate without human intervention, and in places that access by humans would be impractical.  If for some reason during program execution the device get's hung up, the WDT will reset the device.  The WDT must be periodically cleared in software in order to prevent the device from resetting during normal operation.
Bits 2 through 0 are used to select the Oscillator mode.  Microcontrollers use an oscillator for all timing operations, including normal program execution.  Precise timing operations require a more precise oscillator, using a crystal or resonator.  Less precise operations may utilize a less expensive Resistor-Capacitor (RC) oscillator.  Many MCU models include an internal RC oscillator, but not all.  We will dedicate a lesson later specifically to the MCU's oscillator clock and modes.

To view the configuration word settings for a PIC chip, you can view them in the chips html files located at:
C> Program Files> Microchip> xc8> version #> docs> chips.  Scroll down to the chip you're using, such as the 12f629.html file and open it. All of the options are listed under the "#pragma config Settings" header.

Back to our Program

We left off in the Configuration Word section.  The configuration bits are set using the preprocessor directive #pragma.  The pragma directive is a method of providing additional information to the compiler.  It tells the compiler to do something, set some option, take some action, override some default, etc.  We use it here to set the configuration bits during programming.  The format of using #pragma is #pragma keyword options where in our case the keyword is "config" since we're setting the configuration options, and then the actual option we want.  In my program I have strung all of my options together using commas, but you could indicate them separately if you chose, for example:
#pragma config BOREN = OFF
#pragma config MCLRE = OFF
#pragma config PWRTE = ON
And so on.  You can find the configuration word options in the device's chip file.  Chip files are located in: program files>microchip>xc8>version#>docs>chips.  Looking in this document for the PIC12F629, we can find the options listed at the bottom.  We do not need to specify bits we're not going to change from their default.  For example, Code-Protection is disabled by default, so we don't need to specify CPD = OFF since it's already off.  For this program, I have specified in my configuration word to turn off the BOD, MCLRE, and WDT; turn on the PWRTE; and am using the internal RC oscillator with I/O function on the clock-in and clock-out pins.

After the configuration word our main function begins.  We're not passing any information into or out of the main function, hence the void keyword and the use of empty parenthesis.  The following line opens our main function group with the left brace.  Program execution begins with the main function and the entire executable program resides within it.

We use the TRISIO register to set the data direction of our I/O bits.  Setting a TRISIO bit (=1) will make the corresponding GPIO pin an input, while clearing a TRISIO bit (=0) will make the corresponding GPIO pin an output.  I have specified the entire TRISIO byte (8 bits) using a hexadecimal number.  All hexadecimal numbers are preceded by a zero and lower-case x "0x" to indicate to the compiler that you're using a hexadecimal number.  Since GPIO pin 3 is the only input we're using, and unused pins should be outputs, our TRISIO byte is 00001000.  I have used a Binary to Hexadecimal Converter to convert this into a hexadecimal number.  In reference to the preceding paragraph, I have made an error. Please see my blog post, which corrects this error.

After specifying port direction, I have cleared the GPIO port (turned all the pins off).  We do this at the beginning of a program in case the device gets reset while a GPIO pin is on.  It's good practice to do that, as not doing so could cause your embedded system to not operate properly.

The next line is the conditional function while( ).  A while loop checks a condition and, if the condition is true, executes the loop for as long as the condition remains true.  The loop is everything within that function's set of braces {}.  If the condition is false, the loop will not execute.  The condition to test resides within the parenthesis.  The first while loop we use is a simple one that pretty much every program we write will contain, the while(1) loop.  We place a 1 within the parenthesis to ensure our condition is always true, thus the program will continue to execute over and over again.  Without this loop, we are depending on the compiler to assume we want the main function to execute repeatedly, and that doesn't always happen, so a while(1) function is a safety net.

Following while(1) is a second while loop.  Here we have asked the program to check the condition of the GPIO3 pin that our button is connected to.  When we press our button, it applies VDD to GP3, thus placing it in a logic high state (pin reads 1).  When we release the button, no voltage reaches the pin and the logic state is low (pin reads 0).  The operator "==" is the conditional operator.  In plain English, while(GP3==1) says "while GP3 pin reads 1, do this..."  The "this" is whatever is inside the function braces.

The C language differentiates between a single equals sign, and two equals signs.  Example: GP0=1 means "make the GP0 pin equal to 1", whereas GP0==1 means "if the GP0 pin is equal to 1".  Getting these confused causes problems in your code.

Okay, so our while function says that while we're getting a logic high on GP3, do whatever is inside the braces.  In this case, there is only has 1 instruction (statement), GP0=1;  This turns on the GP0 pin, which turns on our LED.  Then the function is ended with the right brace.  When we press the button, GP3 is evaluated and is at logic high, so the condition GP3 is equal to 1 holds true, which in turn allows the function to be executed and GP0 is turned on.  This loop continues to repeat until we release the button and GP3 is no longer 1.

If the button is not pressed, GP3 is evaluated to be 0 and the while loop condition operator is false, therefore the loop is not executed.  Then the default instruction GP0=0; is instead executed, which turns the LED off.

Our program ends by closing up our open functions.  Adding a right brace for each open function, in this case the while(1) and the main functions, will end the function loops.

Compiling our Program

Okay, our program is written, now we need to turn it into a hexadecimal file (.hex) that the PIC can read.  Refer to figure 7.
Figure 7
Label A shows the location of the "build" button.  This button will compile our program into a .hex file, which is the file that we flash into our PIC.  Before we can press the build button, we need to add the xc.h file into our project so the compiler knows where to find it.
Label B shows where I have added the xc.h file into the IDE.  Right click on "Header Files" and select "Add Existing Item..."  This file is located in Program Files>Microchip>xc8>version#>include, be sure to add xc.h and not xc.inc.  Once you have added the xc.h file, we can press Build.
A new Output window (label C) will pop up, and you'll see some text popping up within it.  When the compiler has finished, you should see the words BUILD SUCCESSFUL.  If something is wrong about your code, you would see BUILD FAILED here.  This would indicate that there is some kind of mistake in your code, and the output window will show you what kind(s) of error(s) you have using a blue link.  For instance, if you had forgotten to place a semicolon after a statement, the compiler would say "learn_c.c:22: error: ";" expected".  If you click on this text it will point you to the location of your error(s).  The number 22 within the error is the Error Code, and you can find a list of all the error codes and what they mean in the compiler manual, which is in the XC8 directory in the "docs" folder.
Finally, label D shows how much memory your program has taken up of the memory available in your PIC chip.  Our program has only used 24 bytes out of 1024 available, or 2% of total memory.

Our program is successfully compiled now, so let's find the .hex file it generated.  A .hex file is a hexadecimal file that we flash into the PIC.  The .hex file get's put into your project folder by the compiler, which is located at: C:>users>(your name)>MPLABXProjects>learn_c.x>dist>default>production.  Yea, I know that's a bit of a long directory, it's buried deep.  You'll see your .hex file in there, learn_c.X.production.hex.

Flashing the Microcontroller

Alright, the project is compiled and we know where our .hex file is, now we need to get it inside the microcontroller.  Break out your PIC Programmer, in my case, the PICkit 2.  The PICkit 2 (and presumably the PICkit 3) come with their own software interface, and they flash the microcontrollers with what's called In Circuit Serial Programming (ICSP).  The setup is fairly easy, and when properly set up you can flash your PIC without having to remove it from the project circuit.  Microchip provides a lot of information on ICSP, and it is well covered in the PICkit 2 or 3 documentation.

Figure 8
Figure 8 shows the breadboard setup for programming our chip, be sure that the PICkit is aligned properly.  These connections are taken straight from the PICkit user guide.  Plug your PICkit into the computer's USB drive and open the programmer software.  Remember that I'm using the PICkit 2, if you're using something different, you'll need to attempt to find the comparable operations.  Figure 9 shows the PICkit 2 software interface.  If your PICkit is plugged into the computer you should see the message "PICkit 2 found and connected" in the message window.  If you have already built the connections to the ICSP and are connected to the PIC12F629, you will also see the message "PIC Device Found".  Let's load the .hex file into the programmer by clicking File and then "Import Hex".  Browse to the .hex location and select the file.  Your screen should now appear as in figure 9.  After you have made all the connections from the PICkit programmer to the PIC microcontroller, pressing the "Write" button will flash the PIC chip.  The message window will change to green and display "Programming Successful" when the operation is complete.  We're ready to build and test our project!
Figure 9
Project 1 Hardware

The project schematic and breadboard layout images are below.  When your project is assembled, you can test the program in action.  Pressing the button will illuminate the LED and releasing the button will extinguish it.
IMPORTANT NOTES: Do not exceed 5V input to the MCU as doing so will destroy the device.  There is a tolerance to about 5.5V but it is safest to use 5V, hence the use of the LM7805 voltage regulator.  Also, the current limit of each MCU I/O pin is 25mA thus, be sure to use an appropriately sized current limiting resistor on the LED.  My schematic shows the use of a 270 Ohm 1/4W 10% resistor.  Voltage output on the I/O pin is VDD (5V) when turned on, thus using Ohm's law provides that current sourced from pin 0 to the LED is 5V/270R = 18.5mA.  DO NOT EXCEED VOLTAGE OR CURRENT LIMITS!

Project 1 Schematic
Project 1 Breadboard Layout


November 25, 2014: Post edited to direct the reader's attention to an error in the text. Links have been added to allow a direct-open to the correction. The original information was left intact because I felt that the information provided, which instructs how to use a hexadecimal number in a C program, and a link to a hexadecimal converter were still useful.

Friday, March 22, 2013

A Crash Course Introduction to C

Previously, I mentioned the Assembly programming language.  Assembly is a great tool for writing programs which directly control the system hardware.  The problem with assembly is that, as programs become more complex, assembly gets hard to manage.  Program flow becomes difficult to control and errors are difficult and tedious to find.
Enter C.  C is a high-level language, which means that it's easier for humans to understand.  C also has clearly defined rules and is considered "portable".  Not in the sense that you can pick C up and take it with you to the bar after work (although... I suppose you could in a way) but rather, a program we write for one microcontroller can be easily installed into a different microcontroller with only minimal adjustments to the program (if any).  A program written in Assembly however, is written for a specific MCU and cannot be ported to another without significant changes.  After we write our program in C, an intermediary computer (your desktop) is used to translate C into machine code via a Compiler, in our case Microchip's XC8 Compiler.

Introduction to the C Language

 The C language is made up of a number of elements including Keywords, Variables, Operators, Functions, Statements, and Preprocessor Macros.  Each will be explained, and figure 1 below shows some examples.
Figure 1
Keywords are words whose meanings have already been declared to the C compiler to define data types, or for use in loops.

A variable is a name we give to a certain memory location which can hold various values.  All variables must be declared before they can be used.  There are different variable data types which we will learn and become familiar with later.

Operators are basically used to perform some operation on a variable, such as arithmetic or a comparison between two variables.

A preprocessor macro is a command given to the compiler (XC8) rather than our C program.  They are not actually part of the C language, but accepted as such because of their use and familiarity.  Preprocessing is a separate step from compilation and happens before compiling begins.  The most common preprocessor macros are #define and #include.  Preprocessor macros allow the programmer to include text from other files, such as header files (used in every C program), define macros which reduce programming effort and improve readability of the program code, and issue compiler specific directives to optimize compilation.

A function is a set of instructions that can be used more than once in a program.  Functions are also referred to as subroutines or procedures.  Functions are the basic building blocks of C, and all statements must be within a function.  As programs are written, and functions are developed to perform a specific task, they can be used again and again, and even saved in a separate file and called to other programs using the #include preprocessor macro.

Statements are used to control the flow of your program.  Statements allow your program to move from function to function so long as certain conditions are met, which is why you can see them referred to as Conditional Statements.

To aide in making program code more readable to humans, we have the ability to insert comments into our program.  Any comments you wish to write in your code must be preceded by a double forward slash "//".  Additionally, a forward slash and an asterisk "/*" can precede a comment so long as an asterisk and a forward slash "*/" follows the comment.  We will see more examples of comments used shortly, but it is important to remember that anything you write in a program will be considered part of the program by the compiler unless you tell the compiler to ignore it.  Using the slashes and asterisks is how you instruct the compiler to ignore your comments.

Looking at our First C Program

Below is a very simple example of a C program that does pretty much nothing, but it will introduce us to the structure of a C program.  Let's take a look.

Figure 2

Lines 1 through 3 show some examples of comment usage, using both the double slash and slash-asterisk combinations.  You'll notice that we skip line 4.  Skipping lines in the IDE is okay, the compiler will just ignore blank lines, and using them can help break up a wall of code to make reading it easier.  It's important to keep your program code as readable as possible using blank lines, indents, and comments.

Line 5 shows our first example of the usage of a preprocessor macro, #include, followed by another comment.  The #include preprocessor macro tells the compiler to include a file named "xc.h", which is a header file.  We place the name of the file inside the <> symbols to indicate to the compiler what the file name is.  Header files are very important in C, as they include all the definitions for all the special function registers and their bits in each PIC chip.  The xc.h header file is something of a catch-all for header files, as it directly includes the chip specific header file for the MCU you're programming for.  All of the header files associated with the XC8 compiler can be found in the XC8 directory on your hard drive: program files>microchip>xc8>version#>include.  The include directory is full of all the header (.h) and include (.inc) files.  These files can be opened with notepad and are pretty interesting to look through.  We'll dig through some of them in later lessons to get you familiar with how they can be useful.

Line 7 shows our first function, the "main()" function.  Every program we write in C must have this function.  Program execution begins and is contained within the main function.  Functions allow data to be passed to them from the program, and also allow data to be returned from the function back into the program.  In the case of the main function, the entire program resides within main, so there is no data to be passed.  The C keyword void is used in front of the main function name to indicate that no return data is expected.  The set of parenthesis is where our arguments would go, which are a type of conditional operator.  In other words, data that we want to pass to the function.  Again, in the case of main, there are none, so we can either leave the parenthesis blank, or we could have written void inside of them, for example, void main (void).

Following the main function on line 8, we see the usage of a left brace "{".  The braces are used to group the instructions that belong inside a function.  Each function has a set of braces, so as you write a C program, especially one with many functions, your number of braces will grow rapidly.  Many functions can reside within another function and yet inside another function.  When one function resides within another, it is called "nesting".  To help keep track of where one function ends and another function begins, it is good practice to indent each set of braces so that the opening brace lines up with the closing brace vertically.  The nice thing about MPLAB X is that it will do this for us.

In line 9, we define a variable and give it a decimal value.  In this case, I have defined the variable "name" and assigned it the "char" (short for character) data type.  We'll talk about data types in just a minute, but for now, just understand that "char" is a keyword which defines a type of data.  The name of the variable, "name" can be anything we want it to be as long as it is not a C keyword.  For instance, if I wanted to define a variable to keep track of a number counter, I could name my variable "number_counter" to help me remember what it's for.  The use of spaces in a variable name is not allowed, so we must use the underscore instead.  After I defined the data type "char" and gave my variable a name "name", I have used the operator "=" (the equal sign) to indicate that I want to assign a value to my variable.  As indicated, that value is zero.  So basically what this line is telling the program is that I want a char data type variable named "name" and I want it to equal the decimal number 0.  Since defining a variable is a statement, it must be ended with a semicolon.  All statements end in a semicolon just like all sentences end with a period.  If you don't use the semicolon, the compiler won't know it's a statement.

Line 11 is another function.  This function resides within the main function, so it can be considered a nested function.  Notice my second set of braces are indented further to help me keep track of my functions.  This is a while function, and basically says that "while a condition is true, do this function".  Most applications need to run continuously until the processor is turned off or reset.  The program will run through a loop to the end and then start over again.  The while function offers a means of doing this.  There are 2 conditions that a while loop can have, either true, or false.  False is always 0, and true is any number but 0.  The condition for continuing to repeat the while function is contained within the parenthesis following the while keyword.  The function block is repeated continuously as long as the value, or result of the expression in the parenthesis is not zero.  In the case of our example, placing a "1" inside the parenthesis ensures that the result is always true, and therefore repeats forever.

Line 12 is simply the function block beginning brace for the while function.

Line 13 is nothing but a semicolon.  This is completely useless code as it contains no statement.  It's basically saying "do nothing".  However, the example is there to show where instructions within a function would go.  The block of statements (instructions) for the endlessly repeating while loop would go here.

Lines 14 and 15 contain the right braces "}" to close the while function and main function respectively.  Remember to keep track of your braces, and always close your function blocks.  One of the nice things about the MPLAB X IDE is that when you place a left brace to add a function block, the IDE will automatically add a closing brace for you.

Data Types

Variables are defined as a specific data type depending on how big a number we need our variable to hold.  If we want a variable that we can use to simply set as either a zero or a one, we would want to use a different data type than if we wanted to use a variable to count from 1 to 1,000.  We could use a data type that is capable of holding the number 1,000 to simply set 1 or 0, but this would waste memory space inside the MCU because 1,000 requires more space than 1.  Let's look at the table in figure 3 to see the different data types.
Figure 3
The table in figure 3 shows the data type definitions, the name of the type, the size required in memory for the data type in bits and (bytes), and finally the decimal range the type is capable of storing.  Why am I saying decimal range when most of these are whole numbers?  Because in C, we use binary numbers, hexadecimal numbers, octal numbers, and decimal numbers.  Personally, I've never used octal numbers in any of my programs, but I have used the other three types.  The last data type on the list is the Floating Point.  This is the data type used for calculations that require fractions of numbers, in other words, numbers with decimal points.  We're not going to see any of these for a while, so I'll hold off on the rather complex explanation until later.

In our next lesson, we'll introduce you to the programming environment (the IDE) and start setting up for our first project.  As always, comments are welcome if you care to share.  Thanks for reading.

Monday, March 18, 2013

A Brief on How PIC Chips Work

In this post, we'll talk a little bit about what a PIC microcontroller is, how they're organized, and how they work.  I'm going to save in depth discussions about features for when we actually start using them.  Remember, this blog is about learning one step at a time, so I don't want to flood you with information you're not going to need for a while.

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
C language generally eliminates the need to learn assembly and frees the user from managing all the details.  That being said though, I have found that I am better off in understanding what exactly it is that I'm doing when I write a program in C because I know a little bit about Assembly.  Assembly gives you the opportunity to learn the structure of the PIC architecture and memory organization, which can be very useful.

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
Notice that underneath each register is "bit 7" on the far left, and "bit 0" on the far right.  The PIC12F629 has 6 GPIO pins (Figure 2.2), so the two most significant bits (7 and 6) of the registers' bytes are blanked out.  These blanked out bits are called "unimplemented" bits and are read as "0".  The pinout (arrangement of the device's pins) are shown in Figure 2.2, which is taken from the datasheet. Figure 2.3 shows a photograph of a PIC12F629 MCU. Notice that the device has a small indent on the upper left corner. This indent on all microchip MCUs indicates the location of pin number 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
Since all RAM memory registers are 8-bits wide, all data being exchanged is of the same width.  All the programs written for these MCUs will be stored in the microcontroller internal ROM (program memory) after being compiled to machine code.  ROM locations however, are not 8-bits wide, but 12, 14, 16, etc. bits wide.  The CPU needs to know what to do with the 8-bit wide RAM data, and the extra bits of the program data are the instructions for doing just that.  Figure 4 shows the four different types of 14-bit instruction words.  Remember that bits start at 0, so 14 bits is bit 0 through 13.
Figure 4
The OPCODE (Operation Code) is the portion of the instruction that specifies the operation to be performed.  The other bits specify the program memory address and data on which the operation should be performed.

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
We know from earlier that a microcontroller operates by processing instructions.  The program we write into the MCU is made of up individual instructions that are executed one at a time and reside in the program memory.  Think of the program memory as a sheet of lined paper.  In the case of the 12F629, our lined paper has just over 1,000 lines and each line can hold one instruction.  When we power on the MCU, instruction execution begins at line 0.  The instruction on line 0 will be executed, and then the instruction on line 1 will be executed, then line 2, line 3, and so forth.  At the top of figure 5, we see the top box is labeled PC <12:0>.  This is the Program Counter, and it is 13 bits wide (bits 12 through 0).  The job of the program counter is to direct the MCU on which instruction to execute next, and generally speaking it will start at the first line and just run down the list of instructions until there aren't anymore to execute.

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.

Sunday, March 17, 2013

Introduction, Expectations, and Requirements

Welcome to the first blog post on what I hope will be the road to learning a bit about how to work with PIC microcontrollers.  Without a formal education on the subject, it can be daunting to take your electronics hobby to the level of embedded systems.  There are many many books on the subject, some of which are very good, some of which are very poor, and many more than one person could ever read in a lifetime.  I have "read" about 3 (more skimmed through as reference material than actually read) and I find them boring.  Have you ever found yourself interested in something yet bored every time you try to read up on it?  That's me when it comes to microcontrollers.

Why?  Well because every book you pick up as a beginner starts with endless pages of the history of, the structure of, the architecture of, etc.  When you finally get to the parts that could be useful, it's loaded with assumptions of things that you should know when you don't.  Let me break it down for you.  Some guy somewhere who has made a career in embedded systems decides to write a book for beginners.  What they all seem to forget is that they've been doing this for 40 years, and you (the reader) have not.  So all the little things they take for granted as being trivial are not so trivial to you and me.  Where does that leave us?  Well, here at this blog I guess, so read on young one, let's learn from the ground up together.

A Brief History

Is this guy serious?  He just said he's bored with books because they all start off with "A Brief History".  Okay, I did, but this isn't so much a history as it is a quick disclaimer about me, the author of this blog.  I have been dabbling in electronics for about 8 years, about half of which has been in microcontrollers.  Am I any good?  No.  I have built no grand inventions, am not rich from a grand career in embedded systems.  I am a hobbyist.  That being said, I have no formal schooling in programming, my methods may not be the "right way" or the "wrong way" for that matter, but they work.  I do this for the personal education and satisfaction of saying "Hey, I did that".  Take it or leave it buddy.  I very much welcome corrections or alternatives if anyone has them, just leave a comment.  We can all learn together.

I am learning at the same time you are, and we are learning by doing.  By which I mean we will build simple projects to highlight certain features of the microcontrollers.  We will tackle some things one at a time, and then put several things together to make something slightly more complex, but the point is, you're gonna need some hardware and software if you want to follow along.

My Expectations of You

The only things I expect from you are, a general understanding of electronics, and basic ones at that.  We're not going to be building rockets to the moon.  I expect that you know Ohm's law and how to select the proper current-limiting resistor for a LED.  I expect that you know what a LED is.  I expect that you know how to use a breadboard.  I expect that you know how to use a computer.  This blog will cover none of these things.  If you don't know one or more of them, go learn those first, then come back.  Lastly, I expect that if you don't like my blog, you leave.  Don't sit and post comments about how my blog sucks, it does none of us any good.  If you're so smart, go write your own blog instead of cutting down every one else's.  We good?  Okay, let's continue.


Requirements (Things you Need)

These items are minimal equipment to follow along:
MPLabX IDE - Free software from Microchip, Inc. An integrated Development Environment (more on this later).
MPLAB XC8 Compiler - Software from Microchip, Inc. A C language compiler (more on this later also).  The link for the download is on the left side of the page (circa 2013) under XC8.  This is a "costs money" software, but it has a free mode that is fully functional, with the exception that the code it generates isn't all that optimized, meaning it will take up more space on the microcontroller.  For our purposes, it's not a big deal.
You will need a programmer.  What does a programmer do?  It takes the code (the software) that you write and puts it into the microcontroller.  I use the Microchip Corporation PICKIT 2, but the current model is the PICKIT 3. Both PICKITs are available with a demo board, which I've never used but you might want.  Have a look around the microchip website, see what you like.  You can also probably nab one of these on the cheap at ebay.
If you don't have one, you'll need a breadboard.  A quick search on amazon.com for "breadboard" will reveal many.
You'll need a PIC12F629 microcontroller, and later on a PIC16F628A.  Both models are available on mouser.com and digikey.com.  You should not buy microcontrollers on amazon, the prices are ridiculous.
Finally, download a copy each of the PICmicro Mid-Range MCU Family Reference Manual, the PIC12F629 Datasheet, and the PIC16F628A Datasheet.
Got all that?  Ok good.

Conclusion

In the next post, we'll start learning about the microcontroller.  While I did say earlier that a lot of texts go into depth about histories, and architectures, etc., and I said I thought that stuff was boring, we do need to learn a couple things about the chips themselves so that we can understand how to make them work.  It's like saying, you don't need to know how a car is constructed in order to drive one, but you do need to know what the steering wheel does.  We'll cover that stuff next.