The PIC24 is Microchip’s 16-bit microcontroller intended to offer better performance than their PIC16 or PIC18 8-bit parts. But the way Microchip pitches the PIC24, it seems intended to be a shot across the bow of the Texas Instruments MSP430. I evaluated the PIC24F16LK100, which has the following specs:

  • 32 MHz operation (via internal 8 MHz oscillator and 4x PLL)
  • 4K of flash, 512B of RAM
  • Two 16-bit timers, one 8-bit timer
  • Two capture/compare/PWM channels
  • Analog comparator
  • Separate UART and SPI/I2C interfaces

…and that’s it. Like the MSP430, this series of MCUs is extremely expensive when compared to most other parts in this round-up. My $1 budget precluded me from purchasing a part that even had an analog-to-digital converter.

Peripherals & Core

The PIC24 is a modified Harvard architecture 16-bit CPU with two-cycle instruction timing. It has a 17×17 single-cycle multiplier as well as a 32-by-16-bit hardware divider. There are 16 general-purpose registers, and its RISC architecture made the architecture more suitable for C development. The PIC24 has close lineage to the dsPIC DSP-endowed microcontrollers.

The PIC24 is named for the 24-bit instruction width used by the architecture; like the other PIC parts, the PIC24 does an instruction fetch and execution in a single cycle, regardless of instruction (except for branches and double-word moves).

The PIC24 has a vectored exception system similar to ARM microcontrollers; there’s also a seven-priority interrupt controller with up to 118 interrupt sources.

There’s an internal 8 MHz oscillator with an optional 4x PLL, along with a 500 kHz oscillator and 31 kHz internal low-power RC oscillator. Like other PIC parts, the PIC24 uses configuration fuses to select many options; however, many of these values can be changed during runtime.

There are 12 GPIO pins. Of those, 11 can be used for input-change notification interrupts. Unlike lower-end PIC parts, the PIC24 has a separate register that allows GPIO pins to be configured as true open-drain outputs; there’s also configurable pull-up or pull-down internal resistors.

The MSSP master synchronous serial port supports SPI and I2C operation — in SPI mode, it can operate in master or slave mode; in I2C mode, it supports master, multi-master, and slave mode — with both 7-bit or 10-bit addressing. The peripheral supports clock speeds up to one-fourth the system clock speed.

The UART module supports full-duplex operations with hardware flow-control and  IrDA support. The UART has a built-in baud-rate generator and a two-level-deep FIFO buffers for both TX and RX. The maximum baud rate for this part is 4 Mbps; the minimum is about 15 bps. I wish the baud-rate generator were fractional, allowing dialing in better precision (at the expense of range — but does anyone need 15-baud communication?)

Timer1 is a 16-bit auto-reload timer and counter. Timer2 is an 8-bit auto-reload timer — its output can be routed to the PWM or MSSP module. Timer3 is a 16-bit counter without an auto-reload (“period”) register; it has a single-pulse one-shot gate option that the other times don’t have.

The two CCP modules each support 16-bit input-capture, 16-bit output-compare, and 10-bit PWM generation. There are routing capabilities which allow you to trigger other peripherals on a capture or compare event.

Development Environment

I’ve done a full write-up of MPLAB on the main review page. There’s really no PIC24-specific information to add to this assessment.

Peripheral Libraries & Code Generator Tools

There’s a legacy PIC24 PLIB package available, but this peripheral library does not abstract the underlying hardware very much — it’s also not recommended for new designs.

Unfortunately, the Microchip Code Configurator — a lovely code-gen tool built into MPLAB X — does not support this particular PIC24. In fact, there’s a lot of devices it doesn’t support, which is problematic because MCC supported device lists aren’t widely available on the web when selecting parts.

Here’s what MPLAB X looks like with the processor halted when the code was compiled with -O1. Note that even the disassembly view is empty — this is absolutely unheard of in any microcontroller architecture reviewed.

Debugging Experience

The moment you turn the optimizer on, you can no longer debug code on the PIC24. I don’t mean “it’s a lot harder, because you jump around a lot” — no, it’s actually flat-out impossible. The disassembly view is totally blank, and the C source view doesn’t even attempt to determine where it is — it’s as though the compiler builds the program without any debugging metadata in the binary file. I didn’t experience anything like this with the PIC16 (which uses Microchip’s XC8 compiler), or the PIC32 (which also uses a GCC-derived compiler, the XC32, which is similar to PIC24’s XC16)



Bit-wiggling was not good — the PIC24 took 10 clock cycles to toggle a pin, as there is no “toggle” register; here’s the disassembly that XC16 spit out:

mov	_LATAbits,w0
lsr	w0,#2,w0
com	w0,w0
and	w0,#1,w0
sl	w0,#2,w0
mov	_LATAbits,w1
bclr	w1,#2
ior	w0,w1,w1
mov	w1,_LATAbits
bra	.L2


The 16-bit architecture (with hardware multiplier) makes the PIC24 well-suited for this task; it turned in a biquad processing rate of 838.46 kSPS, and used 10.74 mA, turning in an efficiency score of 42.27 nJ/sample. Given its effective clock speed of 16 MHz (due to its 2T architecture), it performed better than expected: it was only about half the speed of the 48 MHz 32-bit ARM Cortex-M0 parts running three times faster than it.

DMX Receiver

The minimum frequency I could run the CPU at is 2 MHz — while the UART can run in a 4x-sampling high-speed mode, its peripheral clock is the instruction clock of the processor; not the system oscillator speed — and the PIC24 is a 2T architecture, necessitating a 2 MHz system oscillator speed to achieve a 250 kbps baud for the UART receiver.

The PIC24 had good power consumption figures for the DMX-512 receiver project — pulling in 667 µA. However, there was a variety of 8-, 16-, and 32-bit parts that eclipsed it, including most notably the lower-cost, better-endowed PIC32MM — which beat it by a long shot (493 µA versus 667 µA).

Bottom Line

The PIC24 is an expensive microcontroller, but provides good per-cycle performance, and decent low-power operation. I wouldn’t recommend using this particular variant in designs, but larger, more modern parts may be useful to applications that need good sleep-mode power consumption while waking up for duty-cycle processing. But even staying inside the Microchip umbrella, it’s hard not to look at the PIC32MM parts, which offers similar performance, even lower power consumption in run-mode, and better peripheral options for the same cost.

Comments (3)

XC compilers without paid optimizations seem to be just inserting instructions without any meaning, to bloat the code and make it larger and slower. I really don’t understand why is Microchip allowing this. It makes their PIC cores looks extremely un-optimized and less likely to be picked by a new developer.

Here’s how a simple bit toggling looks like in MikroE dsPIC/PIC24 C compiler: https://pastebin.com/uRmBHsWA

Basically, you can toggle any I/O with just 1 machine instruction!

The 16-bit PIC core is very well optimized for C code. On the inside it’s similar to AVR. What makes them fall behind is a lack of good compilers. XC16 is too expensive for students and small scale developers, MikroE compilers have a bloated uncomfortable IDE that looks like it’s from 2001 (but produce very good code for the price), and neither gcc nor sdcc support PIC24/dsPIC targets.

Hope this helps!

Here two tone is generating. I want to assign two pin for this two tones. So that I can detct the timing of 2 tones by 2 channel of Osciloscope. Atthe same time I will measure the EEG signal by OpenBCI.

Please see the attached file. I want to assign pins to see “Beep” and “Boop” in two channel.

} // SineTest
#define DELAY 25000000UL / 256/8
unsigned v;
void main( void )

while( 1 )
MP3Init( MP3_MODE_TEST); // TEST MODES enabled
testMP3Sine( 0x69); // tone1
DelayMs( 100);

MP3Init( MP3_MODE_TEST); // TEST MODES enabled
testMP3Sine( 0x44); // tone2

} // main loop


Sounds like an interesting project; good luck!

Leave a comment