Comparison between Microchip PIC and Atmel AVR microcontrollers
Thursday, September 8, 2011 9:00:00 PM
What is PIC?
PIC is a family of microcontrollers produced by Microchip Technology. This family is very well known for 8-bit microcontrollers.
I've used PIC16F870 mostly because the college lab already had a lot of them. If you are going to start new projects, please consider using another model (Microchip itself recommends PIC16F883).
Glossary (AVR/PIC terminology)
- VCC and Vdd both mean the main positive power supply (usually, +5V)
- GND and Vss both mean the "ground", or negative power source (usually 0V)
- RESET and MCLR are the "reset" or "master clear" pin, that triggers a chip reset/reboot when driven low.
- PA0 and RA0 both mean the pin 0 from the port A.
Comparison between PIC and AVR
Note that this comparison is based on my knowledge about PIC16F870 and ATmega8. This comparison should be valid for most PIC16xxxx devices, as well as most ATmega and ATtiny devices. PIC18xxxx have different features, and this comparison won't apply to them.
ROM/Flash memory
Both microcontrollers are based on Harvard architecture, where the instructions (the program) is stored in a different memory space than variables. The program (firmware) is stored into a ROM memory, implemented as flash.
In AVR, each instruction takes up 16 bits (2 bytes). Thus, the flash memory space is addressed in words of 16 bits. That's nice and round, and 2 bytes fit perfectly into each address. Very simple concept, and it is very easy to store arbitrary (binary) data.
In PIC, each instruction takes up 14 bits. The flash memory space is addressed in words of 14 bits. That's a quite weird number, and it makes difficult to store arbitrary binary data. You can either store a pair of 7-bit values (but still need to shift bits around after reading from Flash), or waste 6 bits by storing just one 8-bit value.
This weird PIC design, however, was made so it would be easier to write lookup tables using RETLW instruction. Too bad it is inefficient for storing other kinds of data.
Memory and registers and instruction operands
AVR has 32 general-purpose registers, and many instructions can access all of them. Other instructions can only access half of those registers, while a few others have further limitations. Still, considering you have 32 registers, it's easy to fit all the data needed for a subroutine.
According to the number of operands, AVR can be considered a 2-operand machine, as most instructions operate on a pair of arbitrary registers and store the result into one register from the pair.
In addition to those 32 general-purpose working registers, it also has 64 I/O registers for controlling all microcontroller features. Finally, ATmega8 also includes 1024 bytes of SRAM (other AVR devices have different amounts of RAM). All RAM and registers are directly available, no tricks are necessary.
PIC16F870 (and probably most other devices from the same family) has 1 working register, called W (accumulator). In addition to that, it has a somewhat confusing memory space that is called register file.
This register file has 512 addresses divided in 4 banks of 128 bytes each. In each bank, the first 32 addresses are mapped to I/O registers, while the other 96 addresses are for general-purpose "registers":
- The first bank has 96 general-purpose registers.
- The second bank has 32 general-purpose registers. In addition, the last 16 addresses map to the same registers as the first bank.
- The 96 general-purpose addresses from the third bank are mapped to the same registers as the first bank.
- The 96 general-purpose addresses from the fourth bank (of which only 32+16 are valid) are mapped to the same registers as the second bank.
So, this PIC can be seen as having 1+96+32=129 general-purpose registers and no SRAM, or as having 1 register and 128 bytes of RAM. However, due to bank-switching, not all of that is available directly.
According to the number of operands, PIC is between 1-operand and 2-operand machine. The instructions always operate on the W (accumulator) and another register (from the register file), and save the result on either W or that other register.
Stack
AVR has a pair of registers (SPH, SPL) that work as stack pointer. This pair of registers hold a SRAM address corresponding to the program stack. Not only function calls use the stack, but the user can also run PUSH/POP instructions to store variables. This behavior is very similar to CPUs from desktop computers.
PIC, on the other hand, has a dedicated 8-word stack that can hold up to 8 addresses from function calls or interrupts. This stack is not accessible by the user and cannot be used for other purposes. There is no PUSH/POP.
AVR approach is much more powerful: it allows an arbitrary number of nested function calls, and temporary values can be saved on the stack. Not only it makes the life of the programmer easier, but also simplifies the implementation of a high-level compiler.
PIC approach, on the other hand, is very limited. While it is possible to implement a user-level stack using the register file, it requires a lot of work and a lot of overhead, due to limited addressing modes.
Clock cycle and instruction timing
AVR has a 2-stage execution pipeline that allows fetching the next instruction in parallel to executing the current one. Thus, in the best case, it can execute one instruction on each clock cycle, which means up to 1 MIPS per MHz.
In AVR, the instruction timing can be summarized as:
- Most branching instructions spend 1 or 2 cycles of clock, with a few of them spending at most 3 cycles, and the RET/RETI instructions requiring 4 cycles.
- Instructions that access the SRAM memory require 2 cycles.
- Instructions loading data from the program memory (ROM/Flash) require 3 cycles.
- Instructions operating on a 16-bit value stored on a pair of registers (ADIW, SUBIW) require 2 cycles.
- Multiplication instructions require 2 cycles.
- Almost all other instructions require only 1 cycle.
PIC instruction timing is a lot more simple and less powerful. Each instruction requires 4 clock cycles. Branching instructions might require additional 4 cycles if the program counter is changed. When compared to AVR, it's a lot easier to (manually) determine the amount of time spent on a piece of code. However, this is the only advantage I can see, and even so I'm not sure if it's really important.
AVR devices can have clocks up to 8MHz, 16MHz, and sometimes 20MHz. This PIC16F870 has a clock up to 20MHz. But, when we compare the actual instruction throuput, an AVR device running at 8MHz can achieve around 4 to 8 MIPS (or 8 to 16 MIPS when running at 16MHz); while a PIC16F870 at 20MHz can reach at most 5 MIPS. This clearly shows that an AVR with a slower clock can run more instructions than a higher-clocked PIC.
This difference is aggravated when we observe that accessing most registers in PIC might require bank-switching, which means setting one or two bits (and thus adding one or two instructions) before being able to access the desired position. Things get even worse when we remember that all instructions must use the W (accumulator) register, which means we must spend more time moving values around.
Contrast this to AVR, that allows accessing any of those 32 general-purpose registers or any I/O register in only one cycle, without bank switching. At most, due to limitations of certain instructions, you might need one extra instruction to move values to another register.
All of this means that, at the same clock rate, AVR microcontrollers can run more instructions than PIC, and each AVR instruction is more "powerful" (or more "useful") than PIC instructions.
Reading/writing 16-bit timer value
Both microcontrollers have 3 timers (two of them are 8-bit, and one is 16-bit) that can be used for whatever purpose. Since they are 8-bit microcontrollers, accessing the 16-bit value from the timer may pose some challenge, as it must be done in two separate instructions.
In PIC, in order to read the 16-bit timer value, you must read the lower byte, and then you read the higher byte. However, the timer didn't stop, and between those instructions the lower byte might have overflowed, which means the high byte might have been incremented since reading the lower byte. In order to detect this event, you must read the lower byte once again, and compare it against the previous reading. [Note: now I'm not sure which byte you should read first... So, if you are actually implementing this, you might need to read high-low-high, instead of low-high-low.]
What's more, since PIC requires using W (accumulator) register and you need to read 2 (or 3) values, you need an additional instruction to store each byte to the register file.
In total, how many instructions do we need? I don't know! Maybe 2 for each reading, which means 6 instructions, plus a few others for comparing the first and the third reading, plus some extra code to deal with that...
Similar care might be needed when writing the 16-bit value.
Now let's take a look at how AVR implements the access to the 16-bit timer: it has a temporary 8-bit buffer for storing the high byte, which greatly simplifies this 16-bit reading/writing logic.
Upon reading the value from the low byte, AVR automatically copies the high byte to the temporary buffer. Thus, when you read the high value, you will get the exact value the time had when you did the reading of the low byte. Yeah, just this. You read two bytes using two instructions. Yeah, it is this simple.
And how about writing a 16-bit value to the timer? You write the high byte, which will be stored in the temporary buffer instead of the actual register. Then you write the low byte, and AVR will then store both bytes at the same instruction cycle.
Software development tools
Both AVR and PIC have a Windows-only IDEs. Microchip's MPLAB v8.76 IDE is around 125MB of download, while Atmel's AVR Studio 5 is 602MB (or 387MB if you already have some componentes). They're huge, and they are completely useless for me, as I don't use Windows.
AVR has a lot of open-source cross-platform (Windows/Linux/Mac) community-written tools:
- avr-gcc (and WinAVR for Windows): C/C++ and assembly compiler
- avr-libc: C library for AVR
- tavrasm and avra: assemblers
- avrdude (or the older uisp): for uploading/downloading the firmware
- simulavr: AVR simulator, not sure if it works
The size of all of these together? Less than 50MB. Okay, they are command-line tools, and not a full-featured IDE, but they work very well and have that "Unix" feeling. In addition, the Arduino IDE is based on these tools. Se my previous posts (part 1 and part 3) for details about the AVR software tools.
PIC, on the other hand, doesn't have tools with such active community around them. After searching a lot, I found all tools I needed:
- gputils: assembler and library (and a few other tools) [16.5MB]
- sdcc: C compiler (not just for PIC, but also for many other processors) [68.4MB]
- gpsim: PIC simulator [15MB]
- picp: firmware uploader for use with PICSTART Plus (see my comments below about hardware tools) [120KB]
- PIC Burner: firmware uploader that supposedly supports multiple programmers
- Picprog: another firmware uploader
- piklab: outdated IDE that does not work anymore on current systems
Due to limitations in PIC design, it is a lot more difficult to write a high-level compiler. AVR is not as limited, and because of that we can use our familiar GCC (and binutils).
Hardware development tools (chip programmers)
You can buy many different kinds of AVR programmers, and avrdude appears to support most of them. Not only that, but you can easily build a low-cost parallel-port AVR programmer, or even a USB one. And you can buy a USBasp from eBay for around 6 dollars. Read my previous posts part 2 and part 2.1 for more information.
Building a PIC programmer, on the other hand, is not as trivial as building an AVR programmer. Feel free to try building usbpicprog USB programmer or Pickit 2 clone USB programmer. They require a lot more components and take up a lot of space.
You can also try building a simpler in-circuit PIC Serial Port Programmer or even a super-cheap PIC programmer. I don't know if they work, as I haven't built them.
If you still want to build one, it seems this JDM Programmer Variant (based on Jaakko Hyvätti Picprog documentation) is supported by Picprog software.
But there is another issue here: every PIC programmer requires its own specific software in order to work. Have you built your own PIC programmer? Great! Now try finding an open-source and cross-platform software that works with it. Good luck!
At the college lab we had 2 different kinds of third-party PIC programmers (and one AVR programmer), but they were completely useless for me, as they required proprietary software only available on Windows. One of them was this huge USB PIC programmer:

The others were a pair of parallel port PIC and AVR programmers. At first look, they seemed nice, as they had both ZIF socket for inserting the chip and in-circuit serial programming interface (that flat cable at the bottom of the device). However, since computers nowadays (my laptop included) don't have parallel port, these programmers are useless. In addition, they require Windows-only proprietary software.

Fortunately, a friend had an official Microchip's PICSTART Plus programmer that I borrowed for some time, and then I found the open-source picp software to use together with the programmer. With them, I could successfully upload the firmware to PIC16F870. On the other hand, if I had to buy this piece of hardware, it would cost me around 200 dollars (plus shipping).

Even so, this Microchip PICSTART Plus is quite bulky, and requires an external 9V supply. Compare it to my older parallel port AVR programmer and my new USBasp AVR programmer.

I know that in-circuit programmers can be built a lot smaller than stand-alone programmers, but the difference is extreme! This USBasp is almost the size of the ZIF socket, maybe a bit smaller. And it doesn't require an external 9V power supply.

Conclusions
As I said before, my experience is limited to PIC16F870 and ATmega8.
And based on what I what I have researched and learned, my opinion is that AVR microcontrollers are far better than PIC.
For me, it is very clear that it is a lot cheaper to start using AVR microcontrollers, and they are a lot more attractive for hobbyists than PIC.
AVRs are more powerful and easier than PICs
AVRs can run more instructions per second than PICs. Even an AVR with a slower clock can still run more instructions than a higher-clocked PIC.
The assembly from AVR microcontrollers seems more powerful than PIC. Each instruction seems more useful, which means less data juggling and more work done. It is also easier to write by hand.
The lack of a general-purpose stack in PIC makes it more difficult to write code (either in high-level or in low-level languages).
And AVRs have many registers available, as well as a lot of RAM, and no bank-switching is required. When we compare this to PIC, it means less run-time overhead and less development-time headaches.
AVRs have better software tools than PICs
There is a lot of community-written open-source and cross-platform tools for AVR. You can easily start developing for AVR in you Windows, Mac or Linux, using the exact same tools.
Not just that, but due to compiler-friendly architecture, it is possible to write code in C or C++ (and maybe other languages also supported by GCC). Arduino project only exists because of these features.
AVRs have better/cheaper hardware tools than PICs
It's very easy to build an AVR programmer, and it will just work.
Or maybe you would prefer to buy USBasp on eBay for around 6 dollars (shipping costs included). It is a simple, cheap and tiny AVR programmer with open-source hardware and software. And it will work on whatever operating system you have.
Compare it to 200 dollars (plus 20 dollars for a power supply, plus shipping costs, plus a USB-to-Serial adapter if your computer doesn't have a serial port) that is required for the only PIC programmer that I've managed to work. Or maybe you would prefer to buy a cheap PIC programmer on eBay, and then find out there is no software that works with that programmer on your operating system.
Bonus feature: You can upload USBaspLoader to the boot section of your AVR microcontroller, and then you will have an embedded version of USBasp that can be used to self-update the microcontroller firmware without the need of an external programmer hardware.
Other links
Here are some pages about PIC that I have bookmarked, but I haven't read all of them.
- Programming PIC Microcontrollers under Linux
- Using PicStart Plus under Linux
- Intro to Programming PIC Microcontrollers in Linux
- PIC Microcontroller Hacking with Linux (Wayback Machine mirror)
- Development Tools for PIC programmers (Wayback Machine mirror)
- Getting started with PIC 16F84 on GNU/Linux
- Getting Started With Programming PICs (or similar products)
- PIC18F4550 C-compiler that's open-source & cross-platform?
- Why are Atmel AVRs so popular?
- PIC / Ubicom Dev'rs
- Gooligum Electronics - PIC Tutorials
Don't forget to read my series of posts First contact with ATmega8 microcontroller.








Mad Scientistqlue # Friday, September 9, 2011 4:16:29 PM
Denilson Figueiredo de SáCrazyTerabyte # Friday, September 9, 2011 4:26:05 PM
Mad Scientistqlue # Friday, September 9, 2011 5:31:18 PM
It may be the solution I've been looking for.
I've been working on the development of a control circuit for a laser engraver. I've run into the problem of requiring an inherently parallel system that can provide proportional control of two stepper motors. (x-axis/y-axis)
Of course, the Arduino Uno that I initially bought for this project will not, by itself, be able to manage the timing and parallel nature of the task. So my options are;
A. Build a dedicated hardware circuit that is controlled via the Arduino.
B. Use an FPGA to implement said circuit. (expensive and complicated since there is no easy off the shelf kits that work with Linux.)
C. Use multiple microcontrollers.
Now, using multiple Arduino boards was just going to be too prohibitively expensive.
I did briefly consider using some PIC12's as dedicated motor controllers, but the difficulty of learning to program them together with the additional hardware needed for the task made me reconsider.
But now, since I can get loose AVRs a lot cheaper than a full Arduino board, I can possibly implement planC using homebrew versions of METAboard.
I'm already familiar with the Arduino IDE, so I'll be able to work with familiar territory.
Denilson Figueiredo de SáCrazyTerabyte # Friday, September 9, 2011 6:20:25 PM
Remember you still need an AVR programmer in the first place (either the parallel port one or USBasp or any other), because you need to write the USBaspLoader onto the microcontroller.
Mad Scientistqlue # Friday, September 9, 2011 7:04:45 PM
Good point.
But what it will help me with is in it's compatibility with the Arduino IDE. Using a programmer still requires writing of software. It will be easier to work with what I'm familiar with. But this still gives me new ideas and alternative options.
Once I've finalised my designs, I'll do a post (or a series of posts)documenting the final project.
At the moment, I don't have anything concrete. Of course, this is typical for me. I usually do a large amount of planning in my head, and once I'm 90% sure of what I'm going to do, it all just flows out as if I'm just following a recipe.
Mad Scientistqlue # Friday, September 9, 2011 7:10:25 PM
(the article I read this in showed how to use the Arduino board as a joystick hid device.)
Denilson Figueiredo de SáCrazyTerabyte # Friday, September 9, 2011 7:24:13 PM
If you use a modified board that connects the USB port directly to the ATmega, then you can implement a USB HID device, or any kind of device.
Mad Scientistqlue # Friday, September 9, 2011 7:31:49 PM
I'll research my options. I've rested the project for long enough now. It's time for me to get back to it anyway.
Unregistered user # Monday, December 5, 2011 11:49:23 PM