Saphum

Programming PIC from Mac OS X

August 24, 2009 | 9 Minute Read

My Mac OS X development tool chain for PIC is now complete. I successfully assembled my Ifos project (and by extension, my Modbus and Framework projects) on the Mac using GPUTILS, then programmed it over ICSP using pp and a K150 programmer. This was not a painless process.

Choosing the software

I have a perfectly good K150 USB programmer I’ve used for a couple of years, and the MicroPro software that came with it is full-featured and fast. Unfortunately, it’s also PC-only and closed-source. Google turned up a few potential substitutes:

  1. George Caswell’s (tetsujin) pic_programmer Python script, picpro.py
  2. Thomas Parslow’s picprogrammer (derived directly from tetsujin’s picpro.py, with fixes)
  3. Brandon Fosdick’s QProg, a native Mac app built on Qt
  4. Rick Altherr’s pp command-line tool, written in C

A few others popped up, but these four generated the most board buzz. I tried them all.

  1. Failed with “Data too large for PIC ROM”, no matter how small the hex file I used.
  2. Transferred the data, but always failed to verify the ROM afterward (which, not surprisingly, never worked).
  3. Always produced an infinite beach ball, requiring a forced quit.
  4. Simply hung.

Ok, a not-so-great start. QProg was particularly disappointing since it was the only one specifically targeted to the Mac AND it forced me to install 180MB of Qt framework before its epic fail.

tetsujin’s script seemed well-written, but my Python is pretty thin, so I wasn’t too keen on wading in and trying to debug it (although in retrospect, it would have been a good opportunity to improve my Python skills, and the interactive shell would have made debugging pretty easy). Instead I started looking at pp.

pp not ready for 16-bit prime time

I dropped in a few printf() calls and found pp would hang when trying to access the serial port. When I looked at the code, it was clear why: the open() call would block until carrier was detected—common enough with “real” serial devices like modems, but my USB-to-Serial cable would never simulate it. The general solution is to open in non-blocking mode (just to obtain a file handle, we can reset the non-blocking flag later), then disable the modem controls with the CLOCAL flag (see §3.6 of the Unix Programming FAQ). Relevant lines:

From serial.c:

fd = open( port, O_RDWR | O_NOCTTY | O_NDELAY );
fcntl( fd, F_SETFL, fcntl( fd, F_GETFL, 0 ) & ~O_NONBLOCK );

With the above changes in place, I was able to successfully clear my PIC18F242 over ICSP. Cool, but will it program?

peter@McMullen ~/Documents/saphum/PIC/pp-0.1 $ ./pp -d 18F242 -p /dev/ttyK150 -w ../ifos/ifos.hex
Writting to a 18F242 from ../ifos/ifos.hex. . .
Segmentation fault

Evidently not. I can live with the misspelling, but the segmentation fault is a little more problematic.

Long story short, pp had a bunch of problems I had to resolve before I could get anywhere. The INHX32 parser, in particular, had several serious errors, mostly due (probably) to a lack of need/opportunity to use it with any 16-bit PICs. Here’s a quick run-down of the problems I found:

  • ihx32.c
    • config and eeprom addresses treated as word offsets instead of byte offsets, leading to the segfault (gpdasm makes the same mistake, though it doesn’t segfault)
    • config data words swabbed on load, even though they’re already little-endian (this is messed up; an easy mistake to make)
    • eeprom data read as words, then swabbed, even though they are fundamentally bytes
    • array index error in calculation of ULBA (later operations corrected the result, but only through sheer luck)
    • not really a bug: element-by-element initialization of arrays everywhere—blech, let C do its thing!
    • not really a bug: strtol() calls everywhere, kinda overkill when parsing hex nybbles
  • devConfig.c
    • sscanf() failed on space-delimited list of blank fuse values in pp.conf, causing error in chip-specific fuse count calculation
  • pp.c
    • ROM image always initialized to 0x03ff, rather than chip-specific value (this also caused image length calculation to fail)
    • fuse values swabbed (this would have been necessary to counteract the effect of the parsing bug, above)
    • fuse values never actually written on 18Fxxxx devices (this requires a separate command in the P018 protocol)
  • programmer.c
    • no support for P018’s “echo” command (important later on; see below)
    • no support for P018’s “write 18Fxxxx fuses” command (as previously mentioned)
    • broken logic when identifying actual image size (separate from ROM fill value problem, above)
    • ROM writing routine looked for “YP” completion string, instead of just “P” (with this fix, typical programming time dropped from ~9 minutes to 15 seconds, a 3500% speed up)
    • EEPROM writing routine announced too many bytes available (caused first byte to be overwritten—_very annoying_)
    • not really a bug: more element-by-element array initialization
    • not really a bug: for() loops and element assignment to clear memory

I’m not actually complaining about these problems, mind you. The original author of pp made it clear that it was an early release, and I’m just happy he sat down and cranked out the code. Fixing a few bugs was a lot less work than writing the whole thing from scratch. I’m just listing the issues here in case anyone else runs into trouble with pp and 16-bit PIC chips. Evidently there used to be an SVN repository off the main project page, but I wasn’t able to access it, either to check for these fixes in later versions or contribute my own changes1.

pp is working! (why isn’t my program?)

With fixes in place for all the known issues, pp was operating perfectly. Well, except for the fact that nothing I programmed actually worked on the PIC. Out came more printf() calls (what data exactly was being written to which memory exactly?), and sure enough, the fuses always came back blank—even though I had explicitly inserted the correct P018 command. What gives?

First of all, I ran a simple test program (everyone loves blinky) through my old PC-based tool chain, just to ensure I had a working hex file. I assembled and linked, then programmed the PIC all from the PC with no problems—blinky lived up to its name. Next I took that hex file and programmed it from the Mac using pp. No joy.

Returning to the PC, I used USB Snoopy (what a life-saver!) to watch the interaction between the K150 and MicroPro, then compared that to the behavior of pp. I found two very interesting items:

  1. MicroPro sprinkled echo commands liberally throughout the communication session, usually sending ‘V’, ‘v’, or both between other commands.
  2. The “write 18Fxxxx fuses” command (0x11) (re)sent the block of fuse data.

I had a couple of theories about #1. They might be for timing purposes. They might be some undocumented hand-shake necessary for normal operation. They might be simple, “Are you still there?”” queries at logical checkpoints. Of these, the last seemed most likely. As for #2, the observed behavior was definitely at odds with the published specification, which clearly asserted no fuse data was to be sent with command 0x11.

I went ahead and modified pp to match the behavior of MicroPro and lo and behold, blinky started working whether it was programmed from the PC or the Mac.

Now gpasm output fails? Seriously? Why does this have to be so hard?

Programming from the Mac was working, but building on the Mac was still untested, so the next step was to produce blinky using GPUTILS there. Unfortunately, the resulting binary would not run on the device. Drat.

A quick comparison of the hex output from both tools showed two major differences. First, the instruction offsets did not match, leading me to discover that the linker files provided with GPUTILS differed from those included with MPLAB (at least for the PIC18F242). The default version included a dedicated area for “vectors” in low memory, so I copied it to the GPUTILS file and rebuilt. blinky remained DOA, however, which wasn’t totally unexpected.

The second difference was a little more unsettling. For some reason, MPLAB inserted a nop instruction just ahead of the retfie in the ISR. Hmmm… Ok. Time to check all errata sheets for the chip… Nope, nothing there. Ok, well—let’s put it in and see what happens.

That did it. Here are the original binaries, for comparison (as disassembled by gpdasm).

Disassembly comparison

Code on left generated by GPUTILS — Code on right generated by MPLAB

Ifos moves to Mac

So finally, after many hours debugging other people’s code, sniffing USB data packets, and examining disassembly files, I have a working PIC development tool-chain on the Mac. Hooray! I did have to incorporate the mysterious nop instruction into Ifos, but that appears to be the only change required. GPUTILS is working great, and pp is working. That’s all I need!

Update:

Source update: I went ahead and created a project on GitHub to track my version of the pp tool. You can find it at http://github.com/pheinrich/PIC-pp and get a copy using something like:

peter@McMullen ~ $ git clone git@github.com:pheinrich/PIC-pp
  1. Unpack pp-0.1.tar.gz, move to the directory created, then patch -b -p1 < pp.patch.