CrazyTB's blog

Comparison between Microchip PIC and Atmel AVR microcontrollers

, , , , ,

Earlier this year, I had contact with a PIC microcontroller as part of a college course. I'm documenting here everything I learned, and also making a comparison between PIC and AVR.

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:

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.

Don't forget to read my series of posts First contact with ATmega8 microcontroller.

First contact with ATmega8 microcontroller - part 2.1Nvidia bug when rendering windows smaller than 32x32

Comments

Mad Scientistqlue Friday, September 9, 2011 4:16:29 PM

The irony for me is that AVRs are not as readily available as PICs around here. awww.

Denilson Figueiredo de SáCrazyTerabyte Friday, September 9, 2011 4:26:05 PM

Mad Scientist: the same here...

Mad Scientistqlue Friday, September 9, 2011 5:31:18 PM

The mention of USBasploader is a good 'nice to know'. up.
It may be the solution I've been looking for. party.
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. faint.
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. left.
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. yes.
I'm already familiar with the Arduino IDE, so I'll be able to work with familiar territory. up.

Denilson Figueiredo de SáCrazyTerabyte Friday, September 9, 2011 6:20:25 PM

Mad Scientist: I still don't see how USBaspLoader will help you. You can do what you have said without even USBaspLoader.

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

sherlock.
Good point. left.
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. up.
Once I've finalised my designs, I'll do a post (or a series of posts)documenting the final project. up.
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. p.

Mad Scientistqlue Friday, September 9, 2011 7:10:25 PM

P.S: I'll have to search for it, but I seen to recall that there is a way to use a modified Arduino board to upload a different bootloader to an ATmega chip. sherlock.
(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

Arduinos used to have a USB-RS232 chip between the ATmega chip and the USB port. Not sure if this is still true for newer versions.

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

the Uno uses a smaller ATmega chip to implement the USB to serial conversion. sherlock. Although there are also project in the Arduino Wiki for using an Arduino as an in-system programmer for a second AVR. left.
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. p.

Unregistered user Monday, December 5, 2011 11:49:23 PM

Anonymous writes: PIC needs 1059 usec, AVR just 130 usec to run the same code Are 8 bit PIC and AVR even comparable? From what I have read in a table that intends to compare the performance of an accelerated 8051 to PIC and AVR, I soon realized that PIC is about 8 times slower than AVR, as long as for the same frequency it needs 1059 usec to complete the attached test code while AVR finishes it in just 130 usec (see the table). TABLE, Comparison PIC - AVR PIC16F77 ----- 12MHz -- 1059us -- 132 bytes code -- 105 bytes data -- MPLabIDE ATMEGA164P - 12MHz -- 130us ---- 198 bytes code -- 100 bytes data -- AVRStudio http://www.edaboard.com/thread233202.html

How to use Quote function:

  1. Select some text
  2. Click on the Quote link

Write a comment

Comment
(BBcode and HTML is turned off for anonymous user comments.)

If you can't read the words, press the small reload icon.


Smilies

May 2012
S M T W T F S
April 2012June 2012
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31