Reflow soldering typically makes use of solder paste, which is fairly easy to work with but has a short shelf life and can only be reasonably purchased in quantity (read: I can’t justify buying any). I performed a very loose experiment this weekend in using the more traditional coiled solder for reflow.

I’d seen two important articles whose advice I sought to combine. One was for the concept of performing the reflow itself using plain solder and a hot air station. I have no hot air station; what I do have is a reflow skillet,  but that article deals in solder paste.

With these concepts in mind, and with a fresh supply of SMT components purchased in anticipation of building my Bus Pirate, I decided on an extremely simple circuit, an LED and resistor in series, and got to work.

Please note that mistakes were made; don’t try any of this until you’ve read the whole thing and know what not to repeat.

I started by scratching out a PCB. I used a box knife instead of etching because I didn’t want to delay the experiment with an uncertainty and, given my more recent failures, it seemed like etching was more likely to be a waste of time than I could allow. In this case, I scratched the outline of a trace roughly 3mm wide across the length of the board, and sliced across it in two places, one for each component.

I colored all of that side of the board except the six points that needed to remain exposed with a Sharpie, thinking it might work as a solder mask. (It didn’t. Read on.)

I used my soldering iron to apply solder to each of the six points I left uncovered; this would be the solder to be reflowed.

0309141748

Sharpied and soldered. Only one of these was a good idea.

After it cooled enough to handle, I placed the components atop the now-solid solder on their pads. Both components were 0603[1], roughly the size of a sesame seed, and nudging them around without flipping them over is difficult, especially with my unsteady hands. One also must take care that the part stays in place instead of sticking to the tweezers. This was a trial of patience.

At this point it was necessary to apply flux; the original flux in the core of the solder itself would have already dissipated when soldered the first time. The flux itself exposed the main two errors that I made in this process:

  • Components should probably be placed after the flux. I had expected the flux to be liquid like in the videos, but at somewhat below room temperature (the temperature of the workspace), it is most sincerely a paste, and it is easily stiff enough to knock the already tenuously-placed components out of place. Bigger components are probably less of a problem since they are already easier to place.
  • Sharpie does not work as a solder mask, at least for reflow; flux readily dissolves the ink. Actually, the ink did seem fairly effective when I was applying the solder with the iron, but it started to lift with the paste, and once the flux was warm enough to flow the whole board was a tacky, blue mess. It naturally follows that the solder wicked all the way up the traces, as evident from the picture, but in this case that wasn’t a problem.

Once everything was relatively ready, I put the board in the pan[2] and turned it up to 375°F, which is reportedly slightly above the melting point for my solder. The board was placed off-center in the ring-shaped area directly over the heating element. The flux quickly turned liquid. After only a couple of minutes, the solder liquefied as well, and once it all seemed thoroughly reflowed, I turned off the heat, leaving the board in the pan as it cooled[3].

0309141821b

Nice board, if you like your flux tinted.

I brushed off the excess flux and scratched through the remaining film to the contact spots I made for power to the board. I connected up the gator clips and powered up. Nothing in either direction. Then I realized that I’d left the plane on the far side of the board untouched, causing the clips to be shorted. Whoops.  Touching the clips to the points on the top side of the board allowed it to function properly.

It can be done!

Stuff I’ll keep in mind for next time:

  • If more than a little solder ends up on a pad, it should probably be wicked off. A little is necessary; a lot can be problematic for placement.
    • I’ve also read that, for small enough parts, unevenness between the pads can cause the component to stand on end instead of soldering properly, called “tombstoning”. Let’s try to avoid the parts that are especially prone (the hard-to-imagine-ly small 0402 and 0201 parts).
  • Flux before placing. It may help keep the components in place.
  • Experiment with mask materials before attempting to use one again.

Thanks to Club Cyberia for being a place other than my garage where I can make this stuff happen.

  1. [1] 0.06 by 0.03 inches
  2. [2] To be perfectly honest, the board was in and out of the pan at least twice as I noticed things I’d forgotten to do, but was only allowed to fully heat when ready.
  3. [3] Cooling or quenching it suddenly is likely to damage the components or reduce the structural integrity of the connections.

Will try to leave the extraneous details out so that this actually gets posted.

The Steel Sandwich hasn’t been touched since December, but a test at 450°F, wrench-tightened, for 30 minutes gave the best transfer yet—except that the copper was so oxidized as to be purple. But I didn’t try to etch it. It might have still worked. Will pick that one up at some point.

I got a credit for the Dangerous Prototypes free PCB drawer and snagged a bare Bus Pirate 3.8 board. If you haven’t heard of the Bus Pirate, look it up—it’s a fine digital exploration, analysis, and prototyping tool.

I have an order in for all of the parts, plus a couple of hand tools I needed and some parts that I think will be useful for the universal PIC ICSP adapter thing I keep touching on here. I hope I can keep my hand steady enough to solder all of those surface-mount parts.

I’ve also ordered a few of the PIC16F527, a relatively recent addition to the PIC 12-bit line, which is only a small amount more expensive than the PIC16F57 (the current cheapest 16F) and has more I/O pins and an onboard precision 8MHz oscillator. That last bit means saving a couple of cents from omitting the external RC, improving the viability in timing-sensitive applications, and simplifying PCB layout. The additional I/O also means that, in some cases, a shift register (like 74HC595) or port expander can be eliminated. Overall, probably worth the extra 19 cents.

Finally, for Valentine’s Day, my wife initiated my membership to Club Cyberia, the only hackerspace I’ve ever heard of in this vicinity. I’m interested to see what difficulties this might help alleviate.

A simple one-directional level shifter is easy to build out of an NPN transistor and two resistors in the common-emitter topology, if the application doesn’t need to sink as well as it sources—that is, if a significant output impedance is acceptable when the output is high. If low impedance is needed for high output, an additional PNP transistor and two resistors[1] can be added, again in common-emitter topology, to re-invert the signal, but then the output low has the impedance instead.

To both source and sink with comparably low impedances, the obvious solution, if you’re properly equipped, is probably CMOS: Two complementary MOSFETs configured to pull the output either up or down, with similarly low impedance either way—or, more likely, a CMOS logic IC that does the same thing, but in a more compact fashion.

Still, there are some possible issues:

  • If you don’t keep a stock of (fairly well matched) N-channel and P-channel FETs around, you can’t really build a CMOS inverter out of them.
  • If all you have are 74HC-series ICs, the output voltage must be from 2V to 6V. If your output voltage is, say, 13V, this is a no-go.[2].
  • If the input high voltage is too much lower than the output voltage, a logic high may not register properly. A preliminary low-to-high shifter (such as the single-sided NPN thing from before, 3 parts) would be needed for each input.
  • If the input high voltage is too much higher than the output voltage, a logic high may do some damage to the IC. A preliminary high-to-low shifter (such as a resistive divider, 2 parts) would be needed for each input.

Incidentally, constructing a CMOS-like complementary output using discrete bipolar transistors is not advisable;  even short input transitions can cause high and low transistors to be on simultaneously for a non-trivial amount of time, a condition called shoot-through, which results in a massive current spike likely to damage both transistors and possibly other components. One way to avoid this condition is to add a resistance between the high and low sides, but then we’re back to the original problem. Shoot-through is evidently less of a concern with CMOS, partly because the FETs involved have better tuned and matched thresholds, and partly because a MOSFET is less subject to self-destruction via thermal runaway than a BJT.

Wanting to prototype something with an oddball push-pull 3.3V-to-13V switch led me to concoct an experiment using only stuff available at a reasonably well-stocked Radio Shack[3], with particular attention to ICs that provide push-pull outputs. So far I’ve tried configurations based on the original 555 timer[4] and the TL082 op amp.

My first experiments with the TL082 in Schmitt trigger configuration were not promising, but I’m suspicious something may have been connected wrong; the logic low never went below 1.15V, which happens to have been the reference voltage, half of 3.3V. Either way, the supply voltage had to read 17.3V for a high output of 13V.

In contrast, the 555-based Schmitt trigger appears to be a workable solution, as long as you can drive the chip 1.5V higher than the desired high output.

555 shifter

555 as a level shifter in just two parts (not including the load). Output is a roughly fixed amount below Vcc.

The output stage of the 555 is a push-pull output, but it is implemented with bipolar transistors in a traditional style, meaning both high and low sides are NPN transistors. This works, but at the cost of about 1.5V from Vcc. If you can pay that cost, it should work nicely.

In my experiments with the pictured circuit, using 1K for the load, the output was 12.5V for a 14.0V input. Similarly, it went up to 13.0V for 14.5V input, and 5.0V for 6.5V.

Apart from the 555, there is a diode to set the control voltage. The CV pin is essentially the top split of a 5K:5K:5K resistive divider from Vcc to ground. The splits of this divider set the high and low thresholds of the Schmitt trigger; they are CV (default 2Vcc/3) and CV/2, respectively. A silicon rectifier diode is added from the CV pin to ground, forming a crude shunt regulator with the internal resistors. This sets CV to about 0.6V and the low threshold to about 0.3V. This is suitable to make the input accept a clean signal directly from a 3.3V or 5V CMOS logic output. Adding a second diode in series with the first would double those levels, making input from a somewhat noisy source or from 5V TTL practical. CV could similarly be set using a Zener diode (in reverse) or by constructing a voltage buffer, but at that point you may just want to order a more suitable part.

So, there you have it—an imperfect but still practical low-impedance level shifter in just two parts.

  1. [1] or one resistor, with caveats I haven’t fully investigated
  2. [2] If you have the older CD4000-series ICs, however, up to about 18V is possible, as long as the inputs are brought within range.
  3. [3] For those of us who don’t have 24 hours to wait for progress.
  4. [4] Not the TLC555 they also carry, which may work better or worse.

(Continued from Part I.)

I lead with two developments that required an additional shopping trip—on Hack Friday, no less.

First, I discovered that there could be some situations in which the holes on the two opposing corners of the plates turn out to be insufficient. In particular, the board may need to be of a minimum size and placed symmetrically across the line between the two bolts; otherwise the pressure over the surfaces of the board may be uneven. One remedy for this could be to restore balance with a spacer of the same thickness, such as a scrap piece of the same copper-clad.

Another fix could be to forget about the holes and secure the board more evenly (for example, on each of the four corners) with some sort of clamps. This might be more generally applicable since it could be adapted to larger plates that do not already have holes. So, I had to identify something that would be useful as a clamp that is also inexpensive and capable of surviving being baked. A small steel beam clamp in the electrical section of Chain Home Improvement Store seemed like it could fit the bill for under $1 apiece.

Second, my wife vetoed my use of the oven in the kitchen. This is completely understandable—we use it for food, and the hardware I’ll be heating, not being graded for food safety, could potentially produce all sorts of unfriendly gases and residues. This is a job for a garage oven, and that means a toaster oven. Fortunately, a fancy one isn’t necessary—an arbitrary box that semi-steadily holds its content at a set temperature is all we need. Much-Maligned Chain Department Store stocks a $15 firestarter model. They were out of stock, so I upgraded to the $20 firestarter model.

Supplies

The ragtag bunch of misfits. Clockwise from top: Toaster oven, steel beam clamps, steel electrical work box cover plates, USB mini-B breakout board patterns on baking parchment, double-sided copper-clad PCB blanks.

So, on to the first experiments executed this evening.

I started by printing the layout of Sparkfun’s USB mini-B breakout board several times over on baking parchment paper. I selected this board because it’s small and thus suitable for repeated trials. (As a bonus, I actually need one; I’ve got a couple of the connectors collecting dust in a drawer.)

Parchment

Left to right: A freshly cleaned piece of copper-clad, a nicely printed pattern on parchment, and one that didn’t come out so nicely.

Printing on parchment is tricky. It is something that you can get to work, but it may take a few tries. Parchment paper is coated with silicone, making it difficult to stick anything to. The fact that the paper releases easily is a desirable property for a toner transfer backing, but it does its job perhaps a little too well. Traces printed this way may not stick long enough to fuse correctly, resulting in smears and runs. When a pattern does take correctly, it must be handled somewhat delicately, as it can scratch or flake off without much of an impact. Still, since someone has gotten it to work[1], I think this can be a reasonably useful medium if you have some patience, and it’s certainly priced to sell (sold by the roll in your grocery store of choice).

I may include the other common media (magazine paper, inkjet glossy photo paper) in future experiments.

Incidentally, any sort of slick tape appears to be a bad choice for attaching the medium to ordinary paper; it being all I had at the moment, it caused more paper jams than I’ve ever encountered with this printer. I’ve had more success with matte tape[2].

I cut the copper-clad for the board and gave it a light cleaning with a soft abrasive[3] before building the apparatus around it.

Patterns, board, and one plate

Copper-clad between two patterns on top of the bottom plate.

One copy of the pattern was placed on either side of the board. The registration wasn’t given too much attention because that isn’t the point of the current experiment (I’ll work on it once I have the adhesion process working), and because the patterns are both the same rather than flip sides of a double-sided board. To conserve the clearly printed copies of the pattern, a misprinted copy of the pattern was used on one side.

Apparatus with top plate

All of the above plus the top plate.

The board and patterns were laid down onto one of the steel plates, then the other plate was placed on top.

Apparatus with clamps

Clamps are added to press everything together.

The steel clamps were added to the edges of this sandwich and the bolts tightened.

Apparatus in oven

The smell of fresh-baked productivity. (But seriously, try not to inhale any fumes.)

The full apparatus was then placed on the top rack of the preheated oven (there are two heating elements situated at the top and bottom, so the bake should be fairly even regardless) and baked for a specified amount of time.

Quenching the assembly

If lowered into the water slowly, there is audible boiling. If dropped quickly, as shown, you end up with a watery mess. Some sort of middle ground is probably a good idea.

Afterward, the assembly is removed from the oven and immersed in cool to tepid water, bringing it to a safe temperature for handling.

The results are examined immediately. The medium is removed without any special degree of care; any toner dislodged by normal handling cannot be considered to have adhered properly.

The variables I’m currently seeking to study are:

  • Bake time
  • Bake temperature
  • Clamp pressure

For tonight’s experiments, I decided on:

  • Trials of 10 and 30 minutes
  • Temperature of 350°F (setting of the oven, not measured temperature)
  • Clamp pressure resulting from tightening the bolts as far as I could using only my fingers, rather than a wrench.

10-minute trial, proper side.

10-minute trial, misprint side.

30-minute trial, proper side. Note that the extra time has discolored the copper somewhat.

30-minute trial, misprint side.

Put briefly, neither result was quite satisfactory, but I believe I’m on the right track. The 10-minute trial gave a better result than I’ve achieved with an iron and parchment. The 30-minute trial was somewhat better, but not so much so that I think adding more time is the key. The toner that did transfer was clear and crisp with no real smudging, which to me indicates that we could afford to apply more pressure. So, it’s likely that the next experiment will be a repeat of tonight’s, except using a wrench to tighten the clamps a little harder.

  1. [1] Refer to the Instructable by dustinandrews.
  2. [2] “magic” or “invisible” tape
  3. [3] Bar Keepers Friend soft cleanser.

While lying in bed last night, I was going over in my head everything I could recall having learned about getting a PCB[1] layout out of my computer and onto a piece of copper clad.

At this point in history I’ve managed to successfully iron a toner pattern onto a board only about three times, and each success came at the cost of around ten failures. The glossy photo paper is the only thing I’ve gotten to work; with magazine paper the image was too smudged to use, while with parchment paper hardly any of it stuck (though what did stick was high-fidelity). What has really been frustrating in this whole process is that there are too many variables and not enough correlation. I don’t know whether I haven’t been using enough pressure, waiting enough time, executing the correct motions, or using the right setting on the iron. For all I know, I could just have a crappy iron!

And everyone seems to have something different to try, with the most consistent results apparently from either (a) using a modified laminator for the toner transfer or (b) equipping for photoresist boards. Of the two, I would surely choose the photoresist, in part because it produces truly sharp results but mostly because the failure/success ratio seems to be lower. But both options involve buying new equipment (and in one case ruining it) with no guarantee of out-of-box success, and given the laser printer and copper-clads already in my possession, I’m already well in.

Anyway, I suddenly had an idea that, if it works, combines the even heat and pressure of a laminator with extremely low (new) equipment cost and increased controllability, the latter of which translates into more meaningful experiments and, when an experiment succeeds, more repeatable results.

What I decided was necessary is as simple as this:

  • The patterns are printed in reverse on the medium of choice—for me, it will be parchment paper since it already exists in my house.
  • The board is placed in alignment with the patterns on one or both sides.
  • The board and patterns are placed between two flat plates of rigid metal, such as steel.
  • The plates are bolted together and tightened at least to the point that nothing slides around.
    • Here, the sustained flatness of the plates is important so that the pressure remains fairly even across the entire pattern.
    • If you have any way to gauge it, take note of the tightness or pressure of the plates on the board. This is possibly one of the variables.
  • The oven is set to the target transfer temperature.
    • To be truly scientific about it, use an oven thermometer to ensure the knob is telling the truth.
    • The temperature is certainly one of the variables.
  • The oven is allowed to preheat until up to temperature.
    • My hypothesis is that a consistent result is probably easier to obtain from a preheated oven due to variances in rise time.
  • The plate apparatus is placed in the oven near the heat source.
    • If the apparatus can be hung sideways from the rack, do so allowing equal heat exposure to the two sides.
    • If the oven has a convection mode, it might be worth using.
  • A prescribed amount of time passes.
    • Another variable.
  • The apparatus is removed from the oven.
  • The apparatus is allowed (as by air) or forced (as by water) to cool to a safe temperature for handling.
    • Maybe another variable.
  • The apparatus is disassembled and the results are examined.
    • An effective transfer should stick well enough that it does not lift or flake when the medium is pulled away. Therefore, the medium can be pulled away without being exceedingly gentle.
    • If the result is unsatisfactory, a hypothesis is formed as to why that relates to one of the variables. The variable is adjusted and another attempt is made.

With this basic process in my head, I went to Chain Home Improvement Store to seek something I could use for the plates. What I found was square steel covers for electrical work boxes, in a flat variety with no punchouts. They already have holes for fasteners at two of the corners, and it was only $1 for the pair. I also got #10-24 stainless steel bolts and wingnuts which themselves totaled $4. This setup should adequately accommodate boards up to about 3 by 4 inches (for comparison, the standard Arduino footprint is 2.7 by 2.1 inches).

I now have all the equipment I think I’ll need to give this a shot, and that could happen as early as this weekend (and I’ll try to take photos). I really hope it works, not just because it would be convenient for me, but because it has the potential to lower the blood pressure of many other frustrated hobbyists.

  1. [1] printed circuit board

ICSP in general

From the perspective of actual information to be transferred, an ICSP (in-circuit serial programming) programmer for a PIC microcontroller is not terribly complicated. As with a CPU, there are operands and instructions that must be issued in a particular order.

ICSP

General pinout of PIC ICSP connector

As with a serial shift register or SPI device, there are two lines—one data line (pin 4, ICSPDAT) to carry the information plus one clock line (pin 5, ICSPCLK) to indicate when that information is valid. In ICSP, the data line is bidirectional so that the programmer can read memory from the target PIC; the programmer should be prepared for that.

There are also the Vpp (pin 1) and Vdd target (pin 2) lines. Vpp must be able to assert either 0V or the programming voltage (13V for most targets). Similarly, Vdd must be able to assert either 0V or the target Vdd (often 5V, but may vary). The switching times must be kept to a minimum; for example, a 16F88 target specifies a Vpp rise time of 1µs.

Vss (pin 3) exists but is not usually switched.

Finally, there is AUX (pin 6), a plain output pin from the programmer to indicate LVP (low-voltage programming) instead of supplying the high voltage on Vpp. Programmers not supporting LVP tie this to ground via a resistor.

The application circuit itself, when presenting an ICSP header, must isolate the pins of the header from excessive capacitance or other interference so that the voltages and rise/fall times are as specified. If possible, the pins used for ICSP should be dedicated. If one or more of these pins is needed for I/O in the application, the circuit should be designed to give the ICSP higher priority (such as by connecting the ICSP header directly but connecting the application circuit via a resistor). If Vpp is connected to an RC slow start circuit (as /MCLR), it can also be isolated using a resistor or a Schottky diode.

Production programmers

The documentations for ICSP differentiates a prototyping programmer from a production programmer as follows:

A production programmer is capable of performing the verification step (i.e., reading back the contents of the target device’s memory as written) with target Vdd set to the minimum and maximum specified voltages of the application circuit.

A prototyping programmer…doesn’t.

This verification is intended to ensure that each memory location in question was either written or erased with a sufficient combination of voltage, current, and time to be reliably recovered.

As implemented by Ardpicprog

Ardpicprog is a project that specifies an ICSP-compatible prototyping programmer using an Arduino for the host computer connection and most of the programming logic.

On the one hand, if the application circuit is simple enough, or if you use the ZIF socket configuration instead of ICSP itself, the programmer circuitry could not get much less complicated, constructed only of three resistors and a single transistor, plus whatever 13V supply you have handy for Vpp[1]. If you’re in a hurry, this could be your pick.

Ardpicprog switching

Switching circuitry for Ardpicprog (not shown: 13V linear regulator for Vpp_SRC, indicator LEDs, ZIF socket for non-ICSP use)

However, there are some issues that may prevent it from being generally applicable, at least for ICSP:

  • ICSP_Vdd is driven directly from an Arduino I/O line. For non-in-circuit programming and for the very slightest of application circuits this is fine. But the absolute maximum DC current rating for that pin (ATmega168) is 40mA, so the  Vdd pin on the application circuit might need to be extremely well isolated in order not to harm anything.
  • ICSP_Vpp has a somewhat high impedance (R2) when outputting high. This might not be a problem in most situations, since the target’s Vpp pin is fairly high-impedance itself, but when programming I noticed that this line was closer to 12V when turned on.
  • The programmer’s logic high voltage is the only target Vdd supported.
    • If the programmer is 5V but the application circuit is designed for 3.3V (some PICs can do this), incomplete isolation on the application side could result in damage.
    • If the programmer is 3.3V (some Arduinos and copycats can do this) but the application circuit is designed for 5V, programming would probably fail unless Vdd to the PIC device is well isolated and the PIC is of a model that supports 3.3V (such as 16LF88—note the L).
    • The programmer is not properly buffered for a self-powered target. For one example, a 3.3V programmer with a self-powered 5V target would probably sustain damage from the current sunk by the ICSP_Vdd pin.
    • Naturally, the programmer is not for production.
  • LVP is permanently disabled. (This isn’t necessarily a bad thing; I’ve read that actually getting LVP to work is difficult.)

As implemented by PICkit 2

Microchip’s own PICkit 2 is a mostly production-capable PIC ICSP programmer. The designs for this 18F2550-based programmer aren’t free (in the sense of liberty), but the firmware and schematics have both been published and clones of the device are plentiful.

Pickit2 switching

Switching circuitry for PICkit 2

While not nearly as simple as Ardpicprog, the switching for the PICkit 2 is not utterly complex, either.

  • The Vpp switch uses a sort of push-pull, allowing both high and low voltages to come through with fairly low impedance. This is controlled by two lines, and the firmware must prevent both from being on at the same time to avoid shoot-through.
  • The Vdd switch is similar, but uses MOSFETs, presumably to reduce voltage drop, and a Schottky diode to prevent reverse current from a self-powered target.
    • A self-powered target is supported by turning off both push and pull in firmware.
    • Whether self-powered or not, the actual target Vdd appears on ICSP_Vdd.
  • The data, clock, and AUX lines are clamped, using PNP transistors, to be no higher than ICSP_Vdd. (The 18F2550 correctly reads 3.3V-level highs and lows even at 5V).

Perhaps the most interesting characteristic of the PICkit 2 is the onboard boost regulator.

Pickit2 boost

PICkit 2 Vpp boost regulator

Using a PWM output[2] (PK2_Vpp_PUMP) with an inductor, the programmer is able to produce and regulate the high Vpp voltage (Vpp_SRC) without a second supply. A resistive divider feeds back to an ADC input (PK2_Vpp_FEEDBACK), allowing the firmware to make adjustments to the PWM duty cycle.

This is by no means an original circuit, nor is it specific to PIC (I’ve gotten one working on an Arduino), but it is a useful inclusion.

What makes this a more-or-less production-capable programmer is its built-in adjustment for Vdd.

Pickit2 Vdd buffer

PICkit 2 Vdd buffer

A PWM output[3] (PK2_Vdd_TGT_ADJ) is used as a rough DAC by passing it through an RC lowpass (R22 and C2), resulting in a steady analog level. The op amp is configured to double the input, so the DAC must output half of the intended voltage. The PFET in the feedback loop increases the current capacity of the amp output.

The maximum target Vdd is less than the programmer’s Vdd due to drops that exist within the programmer. One workaround is to make the target self-powered; all of the lines are set up such that even a 6V target shouldn’t harm a programmer running at 3.3V[4]. By self-powering like this (with any programmer), it becomes more difficult to enter program mode with some targets: The timing requirements vary from device to device, but several of them require Vpp to rise a very short time[5] after Vdd initially rises. When the target is self-powered, ICSP_Vdd cannot be driven low by the programmer. There might be some secret to making this work that I just haven’t read yet.

It would also work to patch in a higher voltage (maybe 6-7V) to the source of the PFET instead of Vdd. For an actual PICkit 2, this would involve some messy hacking that would more likely ruin the device than improve it.

My own ideas

I’ve been toying with an idea to make a production-capable (or nearly-production-capable) programmer based on the principles of these designs plus some of my own ideas.

  • Arduino implementation.
    • This is partly because I think it’s funny, but mostly because it caters to impatience: If you suddenly need a PIC programmer, nobody sells a PICkit retail but at least RadioShack and Fry’s have some variation of Arduino for sale.
  • Full support for any combination of 3.3V or 5V programmer and target.
    • Some Arduinos and other development boards are pushing for 3.3V logic. I say, sure, why not?
  • Push-pull switching for Vpp and Vdd.
    • I think the Vpp switch on PICkit 2 would be a good model for both Vpp and Vdd. I don’t dislike MOSFETs, but I have a zillion PNP and NPN devices and only a very small number of FETs.
    • Using the PK2 Vpp switch for Vdd would allow use of e.g. 5V target with 3.3V programmer. Q2 and Q3 serve as a sort of level shifter.
  • Full level shifting for I/O lines.
    • A level shifter I’ve been playing with in a simulator[6] starts with a buffered 1V supply (2 silicon diodes, 1 Schottky diode, 1 NPN, and input voltage of 2V or higher) through 470 ohms to the base of an NPN. The input is the emitter of that transistor, and the output is the collector, which is pulled up to the desired output voltage.
    • A bidirectional variation of this[7] is to use 2 NPNs with the bases tied together (to the same 1V through 470 ohms) and cross couple each collector to the other emitter, finally pulling up each side to the desired voltage.
      • Unlike the common 1-NFET bidirectional shifter, this design does not require the advance knowledge of which side will be higher, so the target is allowed to be either higher or lower than the programmer.
    • Since these shifters pull up rather than down, firmware or other circuitry expecting pull-down behavior would need to be adapted.
  1. [1] Several are listed, the simplest being a 13V linear regulator based on an adjusted 7812.
  2. [2] Configured to 150kHz.
  3. [3] Again, configured to 150kHz.
  4. [4] But don’t quote me on that.
  5. [5] Less than a small number of ms
  6. [6] Not an original creation.
  7. [7] Also not an original creation.
2-channel-power-Pch

If it works as intended, this circuit should allow an Arduino to control 2 different output voltages via PWM.

(EDIT: The above is the second revision.[1] Note also that the above will not work as-is, except perhaps in the NPN or N-channel variants; it doesn’t account for the fact that the op amp outputs peak well below the voltage necessary to turn off a PNP or P-channel transistor.)

Out of nowhere I just happened to find an 18V wall wart in my junk box. The lack of such a thing makes it necessary for a PIC programmer to produce its 12-14V programming voltage some other way, such as with an adjustable regulator and a pair of 9V batteries or with a boost converter. Even so, a programmer for production-quality output must be able to adjust its own programming voltage as well as its own output supply voltage.

Read More

  1. [1] This version uses P-channel MOSFETs instead of PNP, and better explains the power requirements.
piculear Suite

A suite of pieces that just might comprise a working PIC programmer when connected to an Arduino.

Years ago, while frustrated with my Microchip PICkit 2, which I only bought because of two failed attempts at building serial-port-based PIC programmer designs, I considered the possibility of a somewhat more open design that still had solid USB-based communications and the 5-to-13V boost converter, which was still kind of mysterious to me at the time.

Read More

On Facebook, I recently posted the following:

Inspiration of the moment: I hate voicemail. If I don’t have an opportunity to chat right away, a voicemail is every bit as inconvenient. So my idea is this: Record a message whose first five seconds are “please email or leave a text instead of voicemail” and whose remaining 25 seconds are an unlistenable cacophony of screeching, blaring noise. That would at least keep it down to machines and the ultra-dedicated.

This got a few Likes, so I decided to start working on something. Attached to this post is a tame first draft of the voicemail message. It doesn’t include the 25-second ear horror (which I’d like to make later to test any skills I may have as a cacophonist), but does have a creepy voice[1] telling human listeners to leave a text or send an e-mail instead and to “please hang up”, plus error tones[2] to confuse some machines and repetition to discourage humans from waiting for the actual record tone.

Use at your leisure (and, of course, your own risk) and do share stories of any good (or bad) results.

Download

  1. [1] “Tom”, a text-to-speech voice whose unsettlingness partly comes from its use in NOAA weather radio and some areas’ Emergency Alert System notices.
  2. [2] Specifically, Special Information Tones (SIT) such as those used by TeleZapper that indicate to some kinds of auto-call machinery that the line has been disconnected.

(ANTLR users searching for an answer, you might skip the prose and head to the listings. They’re meant to be readable outside full context.)

What follows is a toy grammar, a gross oversimplification of one I’ve been working on, used to explore a fairly simple but rather underdocumented possibility in ANTLR: Having a single lexer rule emit multiple tokens (or zero tokens, or an altogether different token than specified by the rule).

Synopsis

This language is called “SomeSx”, and it consists of dumbed-down S-expressions with a special “sigil” modifier, as follows:

  • A document consists of zero or more elements delimited by whitespace.
  • An element is an atom, a list, or a sigiled item.
  • An atom is an unquoted string of letters and digits.
  • A list is zero or more elements delimited by whitespace, surrounded by ( and ).
  • A sigiled item is a $that is either
    • followed directly by an element (with no whitespace between), which is then its topic, or
    • not followed directly by an element, in which case it has a special empty topic.

One might think of a sigiled item as one that represents either a nullary (if the topic is empty) or unary (otherwise) function. The source

alpha $bravo $ (charlie $() delta $(echo foxtrot) golf $) $

might transliterate, as an example, to the following JavaScript-like expression:

top(
	"alpha",
	$("bravo"),
	$(),
	[
		"charlie",
		$([]), // Note: not the same as empty topic
		"delta",
		$(["echo", "foxtrot"]),
		"golf",
		$()
	],
	$()
)

Parser

The parser grammar is straightforward enough. (I nerfed the ever-loving stuffing out of it to make it that way.)

// Parser

start : elementsOpt ;

elementsOpt : element* ;

element : atom | list | sigiled ;

atom : Atom ;

list : Down elementsOpt Up ;

sigiled : Sigil sigilTopic ;

sigilTopic : element | emptyTopic ;

emptyTopic : EmptyMarker ;

Do note how sigiled is matched: There’s always a Sigil token and then a topic. That topic is either a normal element or some special EmptyMarker to indicate that there is no topic.

This is the problem, of course: In the language described above, the fact that a topic is empty doesn’t correspond to a token but to what regexp fiends would call a zero-width assertion. Before we get to why that’s a problem, I’ll sidestep it for a moment by presenting a lexer for a slightly broken version of the language.

Lexer, makeshift/broken demo version

Imagine that the language described above, instead of determining an empty topic by detecting that whatever follows a sigil is not an element, just has an explicit empty topic token ~. The above input sample would then be written

alpha $bravo $~ (charlie $() delta $(echo foxtrot) golf $~) $~

which is easy to write a lexer for:

// Lexer, with explicit empty token marker

Space :
	( ' '
	| '\t'
	| '\r'
	| '\n'
	) {$channel=HIDDEN;}
	;

fragment Dollar : '$' ;

Down : '(' ;
Up : ')' ;
Atom : ('a'..'z'|'A'..'Z'|'0'..'9'|'_')+ ;

EmptyMarker : '~' ;

Sigil : Dollar ;

This works delightfully; alas, it doesn’t lex the language as specified. No, for that to happen, EmptyMarker would have to match not ~ but the empty string (a big no-no for any eventually deterministic lexer), and to only match it in well defined places.

One way to make a lexer rule in ANTLR that matches in exactly this way is to make it a fragment; we could use a syntactic predicate to cause the zero-width token to match only if whatever follows the sigil doesn’t look like the start of an element. It’s actually very easy.

Or not. The rule’s fragment-ness is a double-edged sword in this regard: Matching it does not emit any sort of token that can be used by the parser. Therefore, we’ll have to convince the lexer rule containing the fragment to emit it alongside any token it might have produced anyway.

And it can be done. There’s just some plumbing to do first.

Lexer support for arbitrary numbers of tokens per rule

Little aside. (And again, do skip it if you’re in a hurry. It’s hypocritical; I’m providing unnecessary information into an article I wrote out of frustration with information overload.)

Emitting arbitrary numbers of tokens from a lexer rule is actually a well-known problem in the ANTLR world, if not only because Python is so popular. In that language, the braces one would see in a C-like language are eschewed in favor of indentation changes. While that’s nice for the user (ymmv), it’s tricky for the lexer, which has to be able to spit out all sorts of made-up “indent” and “dedent” tokens resulting from monitoring the indentation state.

After running into much information overload on the subject, I flipped open my dead wood copy of The Definitive ANTLR Reference and found this gem around pages 110-111:

Note that, for efficiency reasons, the CommonTokenStream class does not support multiple token emissions for the same invocation of nextToken(). Read the following from class Lexer when you try to implement multiple token emission:

When I read this, I truly had to fight the urge to throw the tome hard across the room. ANTLR’s finest documentation, lovingly crafted by the creator, is unfortunately (but justifiably) not free information. I have the thing itself in my hands, and it not only tells me that I’m going to have to override some methods to get it to work the way I want, but then has the nerve not to offer a concrete implementation and that I’m just going to have to “try to implement” it.

Additionally, a comment in the code snippet offers this:

Currently does not support multiple emits per nextToken invocation for efficiency reasons.

It might not need to be default, but I’d think this is a common enough thing that it might be simple (and more descriptive and easier to carry across target platforms) to have some settable flag for multiple emit support rather than requiring ugly ad hoc overrides.

Of course, this was at the end of a night of fruitless searching for an answer, and it’s a wonder nobody was killed.

Fortunately for humanity itself, I was finally able to extract the core nugget of knowledge from a wiki page that had quite a bit of unrelated (to me, anyway) surrounding information hiding it from plain sight.

Near the end of the text itself was the treasure: The overrides for emit(Token) and nextToken() that I needed. Sadly, it was for an earlier version of Java and of ANTLR, but I was able to port code from a more recent post by a user of the C# target.

Without further ado, the very simple guts of a multi-emitting lexer, for Java 1.6 and ANTLR 3.4:

// Without this code, or something similar, lexer rules emitting multiple
// tokens will not work correctly. (Try it if you don't believe me.)

@lexer::header {
	import java.util.Deque;
}
 
@lexer::members {
	// Substitute any compliant Deque implementation to taste
	Deque<Token> tokens = new java.util.ArrayDeque<Token>();
	
	@Override
	public void emit(Token token) {
		state.token = token;
		tokens.addLast(token);
	}

	@Override
	public Token nextToken() {
		super.nextToken();
		if (tokens.isEmpty())
			return Token.EOF_TOKEN;
		return tokens.removeFirst();
	}
}

Modifying the lexer to produce the marker token on cue

Here, we just follow through with the modification ideas from earlier: Have the Sigil token perform as before if, and only if, it detects that it is immediately followed by an element. If not, have it match a zero-width fragment token, then emit the Sigil followed by the EmptyMarker tokens. The details are provided inline:

// Lexer changes for implicit empty topic

// EmptyMarker is changed to match a zero-length string. In ANTLR (at least), a
// zero-width lexer rule is practically useless (it could match anywhere, and
// it's unclear where it's supposed to) unless it is a fragment. As a fragment,
// it matches exactly where we put it. But as a fragment, it doesn't emit a
// token...without some effort (read on).
fragment EmptyMarker : ;

// This fragment reflects the beginning of any explicit sigil topic: the first
// token in an atom, list, or sigiled. Used in a syntactic predicate, we can
// determine whether a token we're matching is followed by an explicit,
// non-empty topic.
fragment StartOfNonEmptyTopic : Down | Atom | Sigil ;

Sigil : d=Dollar
	// The Sigil token is changed to do what it did before as long as the token
	// appears immediately before what looks like a non-empty topic. 
	( (StartOfNonEmptyTopic)=> // already does the right thing; add nothing.
	
	// But if no such token follows, we have to output the sigil (as normal)
	// but then also insert a zero-width EmptyMarker afterward.
	| z=EmptyMarker // not followed by explicit topic; insert an empty one
		{
			// The tokens are fairly fluid; several of their properties can be
			// changed at will. In this case, the type of a token can be
			// changed while retaining its text content, line and column
			// numbers, and so forth.
			
			// From what I can tell, using emit(Token) directly will prevent
			// any token being emitted by the rule itself. So, if you use it
			// once for a fake token, be prepared to use it for the real one as
			// well.
			
			$d.setType(Sigil);
			emit($d);
			
			// You might have noticed that $z is already a EmptyMarker. Why set
			// the type? From looking at the generated lexer code, it appears
			// that a matched *fragment* rule creates a token with not the
			// named type but an unmatchable dummy token type. However, the
			// fragment token type (or any other token type) can be stuck back
			// onto it to make it work.
			$z.setType(EmptyMarker);
			emit($z);
		}
	)
	;

Peripheral caveats

Mostly not specific to this issue, but in general for ANTLR: Mind your generated code. Lots of stuff that might be wrong with your lexer will produce useless, misleading, or even absent diagnostic information. It’s not your fault, and fixing it might only require some changes in convention. For example:

  • I think I’m going to stick with CamelCase lexer rules, if only because ANTLR itself reserves a few all-caps ones such as DOWN and UP.
  • The aforementioned wiki page contains the phrase d=DIGITS r='..'; when I tried to match the dollar sign as a quoted string (i.e. d='$') the resulting variable in the generated lexer was an int rather than a Token. If you were curious why Dollar is its own fragment, this is the reason. (Perhaps double quotes would have worked—it wasn’t the first thing I tried, so I didn’t.)

Finally, I have to make sure to meditate and do my best not to be quick to anger toward Terence Parr et al. Language makes for really, really difficult computational problems, and despite the vast collection of warts in JARs, I do think ANTLR really is the best we’ve got, and I hate to consider the needless loss of life were I to attempt much of what I try to do with flex and bison.

The whole thing

Here is how everything fits together. Most comments have been removed to drive home how simple this whole thing is really supposed to be.

grammar SomeSx;

@lexer::header {
	import java.util.Deque;
}
 
@lexer::members {
	Deque<Token> tokens = new java.util.ArrayDeque<Token>();
	
	@Override
	public void emit(Token token) {
		state.token = token;
		tokens.addLast(token);
	}

	@Override
	public Token nextToken() {
		super.nextToken();
		if (tokens.isEmpty())
			return Token.EOF_TOKEN;
		return tokens.removeFirst();
	}
}


// Parser

start : elementsOpt ;

elementsOpt : element* ;

element : atom | list | sigiled ;

atom : Atom ;

list : Down elementsOpt Up ;

sigiled : Sigil sigilTopic ;

sigilTopic : element | emptyTopic ;

emptyTopic : EmptyMarker ;


// Lexer

Space :
	( ' '
	| '\t'
	| '\r'
	| '\n'
	) {$channel=HIDDEN;}
	;

fragment Dollar : '$' ;

Down : '(' ;
Up : ')' ;
Atom : ('a'..'z'|'A'..'Z'|'0'..'9'|'_')+ ;

fragment EmptyMarker : ;

fragment StartOfNonEmptyTopic : Down | Atom | Sigil ;

Sigil : d=Dollar
	( (StartOfNonEmptyTopic)=> // normal
	| z=EmptyMarker // insert empty token
		{
			$d.setType(Sigil);
			emit($d);
			
			$z.setType(EmptyMarker);
			emit($z);
		}
	)
	;