Electronic – Reccomendations of PIC microcontrollers

microchipmicrocontrollerpic

Since some of you may already read some of my posts here where I wrote that I preferred AVRs/ARMs may wonder why now I want to know something about PICs.

Though one may like them or hate them, they offer many advantages at [very] low prices (CANbus and Ethernet, RTCC, many I2C & SPI & UART ports).

Finally they seem to be among some of the most widely MCUs used in the industry (beside for instance the 8051 which although old is still widely used), so learning them might be positive for a job.

Therefore I wanted to ask: what MCU architecture would you choose among the many available?
PIC16/PIC18/PIC24F/PIC24H/dsPIC30/dsPIC33/PIC32?

I ask that because it seems to me that their architectures is very different one from the other. Therefore assembly instructions will differ significantly. I don't really if in C these differences are less important.

I know you can't really give me a "general" answer since each MCU is best suited for one specific application, but I hope you can give me tips to maybe avoid using some deprecated MCUs and choose newer ones for ~ the same price.

This is AFAIK where they'd be better suited for:

  • PIC12/PIC16/PIC18: basic circuits (LED controls, switchs, basic ADC, DAC, SPI&I2C&UART), 8 bits [basically what you do with any AVR] (very cheap)
  • PIC24F/PIC24H: more complex circuits, ethernet MAC, 16 bits
  • dsPIC30/dsPIC33: operations involving digital signal processing (I don't plan doing those at the moment)
  • PIC32: most complex circuits, CAN/CANbus, ethernet MAC, 32 bits (relatively expensive)

Since I already have some projects in mind I'll illustrate what I'd chose for some small applications, so that you may prove me I'm wrong 🙂

  • Energy meter: PIC32, since with SPI/I2C it will communicate to a power meter IC, while CAN/CANbus will pass the measured informations to a host (basically a distributed energy meter system with on meter on each [significant] plug)
  • DC/DC converter, battery charger, …: PIC12/PIC16/PIC18/PIC24F/PIC24H, basically to do a PWM and negative feedback with ADC

I'll accept any statement on which MCUs to prefer/avoid for one particular application.
I know some of you may want to use AVRs/ARMs/MSP430 and each MCU has its own application field. And, BTW, I'm not saying I only on using PICs. Just that for starters it may be better to use not all architectures at once.

For instance in my opinion:

  • I'd take a MSP430 for low-power applications or for integrated >= 16 bits ADC
  • I'd take an AVR for very fast instruction set (most are 1 cycle instructions)
  • I'd take an ARM for more advanced features and speed/memory

However since PICs are usually the cheapest and with most periferals, I think it's best to know the characteristics of each PIC family. I don't know if nowadays PIC12/PIC16 are deprecated, expecially since I heard some bad things about their "complicated instruction set", but AFAIK nowadays that's a bit better.

Best Answer

Aesthetically, my favorite architecture in many was is the 14-bit series. The 16-bit PIC18Fxx architecture improves some things, but I find somehow the design less aesthetically pleasing. Which architecture you'll like better probably depends upon your design aesthetic, the extent to which your find yourself wishing things were designed differently, and the extent to which such wishing detracts from your enjoyment working with them.

From a design perspective, there's no particular reason why code addresses and data addresses need to be the same. One thing I like about the 14-bit PICs is that adding a number to an instruction address advances by that many instructions. By contrast, on the PIC18X, each instruction takes two addresses. Consequently, computed jumps using an 8-bit selector are confined to a range of 128 instructions rather than 256. It's a small detail, but having a program counter whose lowest bit is non-functional seems unaesthetic.

Also, the PIC18xx parts add a single-cycle hardware multiply, but unfortunately since it requires one operand to be in W but puts the results in a fixed pair of other registers, it can't be used very effectively for multi-precision operations. If I had my druthers, there would be two types of multiply instructions:

  1. Simple multiply -- Store W into multiplier register, and store op*W into PRODH:W
  2. Multply-add --Store PRODH+op*multiplier register into PRODH:W

With such a pattern, a 16x16 operation would be rendered as:

  movf  OP1L,W
  mul   OP2L
  movwf RESULT0
  mula  OP2H
  movff OP2L,MULTR
  mula  OP2L
  movwf RESULT1
  mula  OP2H
  muvwf RESULT2
  movff PRODH,RESULT3

Further, arbitrary-length multiplies could be done with an average cost of a little over two cycles per 8x8 partial product, using the repeated pattern:

  mula   POSTINC0,c
  addwfc POSTINC1,f,c

That pattern would multiply one multi-byte number times an 8-bit value and add the result to another multi-byte number.

As it is, I think the best one can do for an extended multiply is to do the multiply to a destination buffer without doing a built-in add, at a cost of six cycles per 8x8 partial product, and then spend another two-cycles per partial product adding that result to the previous 8xN partial result.

  movf   multiplier,w
  mulwf  POSTINC0,c
  movf   PRODL,w,c
  addwfc POSTINC1,w
  movff  PRODH,INDF1

Four times as long as what could be achieved with a slightly different instruction set. I don't know that I've seen any processor which included a function to compute PRODH+Op1*Op2 but it would be a very simple feature to include in shifter-based multiplies, and it facilitates computing arbitrary product widths with fixed hardware cost. Actually, since the PIC takes four hardware clocks per instruction, the hardware required to allow a 16xN or 32xN multiply would be pretty modest; when computing big products, a 16xN or 32xN multiply with suitable register usage would offer a 2x or 4x speedup.