Saturday, December 12, 2015

Microcontroller Wars - The Ultra-Low End Part 2


This is the second article from a series of articles that shows the differences in selected ultra-low end microcontrollers. The idea of ultra-low end here is to find MCUs that costs less than $0.40 at volume and have 8 or less pins on the package. That spectrum seems to be the last bastion of various 8-bit architectures and has not been overrun by ARM-clones.
After part one that provided some background to this series. It is time to get down to business and put the parts that I sampled to use. Before we look at the RS08, let us start with the PIC10F322.

PIC10F3xx Overview

The PIC10F3xx is the newest chip of Microchips ultra-low end series. It is primarily marketed ASIC fixes, very simple analog control, and disposable medical applications. I wonder how they came up with ASIC fixes and how big the market size for that problem actually is, but the other two target applications are clearly filling a need. The 8-PIN DFN (2x3mm) and 6-PIN SOT-23 (3x3 mm) packages make it a very small solution. The good news is that Microchip also provides free samples for 8-pin PDIP variant that can be bread-boarded easily. The core is an 8-bit architecture with 4 cycles per instruction (more explained below in PICuliarities). The peripherals include enough options to make it versatile enough to satisfy many different applications. Because it has an ADC it actually can satisfy applications that their previous generation cannot satisfy. That said if you are not attached to analog, you can potentially save another $0.08 by going to a PIC10F200.

If this line existed 50 years ago it would be a worthy contender as guidance system for ballistic missiles; now this is more of a contender for disposable pregnancy tests.

PICuliarities (TM) - The Good, Bad, and Ugly Facts of the 8-Bit Architecture

While being one of the oldest Microcontroller vendors the 8-bit PIC architecture has earned Microchip a lot of haters for mid- and high-end applications. The cause of this is probably its age. The history goes all the way back to 1975 when it was first developed as I/O controller for the CP1600. The RISC instruction set varies between 33 and about 80 instructions. 
Except for the high-end variant of that core the instruction set does not include conditional branches instead it has conditional skip conditions. Rather than testing for a positive argument the compiler tests for the negative and skips over an unconditional branch. Most people will use C to program the core and not notice that, but it is a neat thing to be aware of if you ever dive into assembly on that core.

The core itself has a hardware stack that only stores the return address of calls. If you attended my or any other operating systems course in Waterloo, you know that this is a problem. You cannot implement a multi-tasking OS on that core ever. Also the core itself will silently overrun the stack and not indicate in any way what stack level you are on or if you overran it. As a result, the compiler designers have to worry a lot where to function parameters and how to handle function calls. Since Microchip is comprised of smart people, they figured out that instead of maintaining a growing parameter stack they would stick all parameters in fixed locations and call it a compiled stack. That compiler also tracks how many stack levels you go from your main function. If you avoid function calls from interrupts you can avoid nasty surprises there. The good news is that you can statically predict what you stack usage will be at run-time, but that also means you can never use recursion or function pointers. More of the PICuliarities are in the compiler reference manual. If you are bored and want to know more than is described here then it is definitely worth a read and you are not in for nasty surprises. Lastly for fun, there are PICs out there that do not have an interrupt controller. I picked the PIC10F3xx series over the PIC10F2xx because the PIC10F3xx actually has them. 8-bit PICs come in three flavours: Baseline devices, mid-range (extended mid-range), and high-end. They essentially boils down to what the addressable space is, if you have an interrupt vector or interrupts at all, how many stack-levels the hardware stack has, and if this chip has an on-board debug unit. PIC18s actually have options to access the stack, can run a software parameter stack and run an OS. They are not the focus of this comparison; personally I'd always pick a cheaper 32-bit part that does not have the other PICuliarities for mid or high-end microcontroller applications.

I suspect that a lot of hatred against PICs is a result of expecting something that you know from your "other" architectures. That said, I learned those lessons the hard way 10 years ago by trying to be agile and did not turning to the compiler reference manual first. Aside from turning a blind eye to execution performance, RTFM is probably the best remedy not to become a PIC (8-bit) hater in the first place.

In terms of core the PIC10F32x series is what Microchip calls a mid-range device. It has 35 instructions, an 8-level hardware stack, and an interrupt. It comes with 64 bytes of data memory and up to 896 bytes of program memory, and a 128 byte EEPROM (well it is actually emulated using flash). Again read the CPU Overview section in the datasheet to avoid any nasty surprises afterwards.

Minimal Circuit and Programming Interface

The following picture shows the minimal circuit to get the chip running. The diagram next to it highlights the connections. 



In a nutshell:
  • Weak pull-up resistor on MCLR, 10K or 100K should do
  • Small decoupling capacitor (100nF) between Vdd and Vcc
  • The ICSP needs two signal lines, provides the power, and pulls MCLR low
  • Optional Hello World LED with resistor as shown
It should be noted here that this chip has no debugger circuit. In order to get debugging you need to buy a special version of this chip ($$$) that plugs into the PDIP header of your end-product. Since you would not pay extra cost for the debug version in production, Microchip sells you a board that has just that chip and a PDIP header that you can plug into your target board for debugging. This is called "debug header" in Microchips terms. In production you'd put the regular chip that does not have the debug unit. Because these are cumbersome design steps and this requires you to reserve enough space for a separate PDIP header (or a mess of wires to hook it up to your DFN pads) on your target application, I suspect that a lot of Microchip users develop software for that chip the "burn and pray" way (i.e. flash the firmware and hope it is working). If you come from the Arduino world then this is not a problem, but the normal modus operandi. If you worked on safety critical systems like me and like to inspect every register during run-time this causes some grief and needs some time to get used to.



Our friendly Microchip FAE left a "Low Pin Count Demo" board and PICKit-3 behind during his last visit. Unfortunately the PIC10Fxxx series is not pin-compatible with the PIC12Fxxx 8-pin variants. So I had to breadboard it instead of plugging it into the demo board.

Programming Environment


I usually live and breathe Linux for all our other projects. Since we do a lot of BSPs for various client applications, I normally use Linux to develop everything. So having development tools that run on Linux is a big plus. Microchips newest IDE is MPLAB-X which is loosely based on IntelliJ and it comes with full Linux support. The same goes for the XC8 compiler that is needed to build software for the PIC10F32x series. Both are free and not code-size limited. There is a paid version of the compiler that allows you to do some performance optimizations. Honestly, I would pick a different core if I were in for performance so for the context of low-end applications the free XC8 compiler is more than enough.

I start the development by creating a new project and picking the PIC10F template as shown below.


The next step is to configure build environment to only include the XC8 configuration for the PIC10F322 chip.

As part of that configuration, I would make the compiler and linker as verbose as possible. Because space is very limited I would like to dive in to the memory usage for every linker section (or what Microchip calls psect). 

My next thought was to use Microchips highly advertised MCC configuration tool to graphically configure all the peripherals and generate all required code. Unfortunately, it turns out that this chip is not supported by MCC. That means we have to go back to the normal PIC usage mode: RTFM. 


Luckily at least the configuration bits configurator for mid-range PICs worked on that chip. So we could at least generate that file. Those bits are fuses that are set during flashing and persist during resets. Again, RTFM for all options needed.

Clocking

The chip has internal 16 MHz and 32 KHz oscillators. For the purpose of this article we will use the undivided 16MHz clock. 
Since I cannot dive into the clock configuration registers with a debugger during run-time, I hardcode all values with very verbose comments in my code. By using C preprocessor macros you can build maintainable program blocks that do not result in an increase of code size. Even though my commenting style looks obscure, it guarantees that I will see proper bit-field documentation when I run Doxygen.

GPIOs and Delay Cycles

In order to blink an LED we have to configure the LED. I decided to make the PIC the current source in my breadboard. This means we have to write a logical zero to an output pin to switch the LED on. There are three registers involved to configure the PIN functions in that PIC.


The TRISx register configures the I/O direction of the pin. Setting TRIS to zero for a particular pin makes it an output pin. The ANSELx register and WPUx registers configure the analog function and pull-ups respectively. On the PIC10F32x you also have to clear a bit in the options register to get pull-ups to work.


The output is toggled by writing to a latch register. The bit fields of that register are defined macros making them very easy to use in my main loop. The delay macro that the compiler provides hardcodes delay cycles based on the defined clock-rate in the header file.

Usage Profiling and Chip Programming

After we wrote our piece of firmware for the chip, it is probably worthwhile to check how much of the chip we are actually using. Because we configured the compiler as very verbose the compiler will output the required information. Because we only have 64 bytes of SRAM (parameter) stack overflows would be toxic. The compiled stack option actually comes handy now because it predicts the stack depth at compile time. It can be seen that this Hello World demo only consumes a fraction of the resources of that chip. Even though we selected an ultra-low-end part, we still have quite a bit of wiggle room in terms of program and data memory for more complex operations.


After we are happy with the performance figures, we need to flash the firmware. This can be done straight from the IDE. Remember to set the PICKit-3 configuration to provide target power. In order not to incinerate the target device it is probably advised to pick 3.25V. That covers both the normal line as well as the XLP variant of the chip. If everything goes well the LED should blink in one second intervals.



The source-code can be downloaded from here.

In order to get to know the chip, I advise the reader to try interrupt processing, and the wakeup timer. The peripherals included in the chip are fairly similar to what other PIC microcontrollers offer. You will find ample of tutorials for that elsewhere.

Summary

The PIC10F322 is probably a worthy contender for ultra-low end applications. At the time of writing the chip retails for $0.35-$0.37 @ 5k volumes. That pricing is very hard to beat with any ARM-based solution. If you call your Microchip sales person you can probably bring that down further at larger projected volumes. It has ample of peripherals to satisfy many low-end applications. The DFN and SOT-23 packages are small enough for disposable applications. Anyone starting PIC after having learned a different architecture has to relearn, the PICuliarities can be a real cause of grief. On a positive note the whole idea of the compiled stack may not be a problem but a handy feature to avoid stack overflows, if you know what programming patterns to strictly avoid.

I am going to keep the PIC10F322 on the list for low-end applications. Despite my ARM-bias, I may keep templates for low-end, mid-range, and PIC18 microcontrollers on the shelf if a customer insists on using them or needs legacy support.

Next up I will write a piece about the Freescale/NXP RS08.

References

No comments:

Post a Comment