Friday, March 2, 2012


Introduction to C and the PIC Microcontroller

In this lab you will be introduced to the programming language C, and the PIC16F873, a popular and very widely used m-controller (read micro-controller). m-controllers find use in devices that needs some intelligence but not a huge amount of processing power (eg, fancy graphical interfaces, massive computing needs). You can find these devices in cars (engine control, anti-lock brakes...), in appliances, etc... There are many ways to program these devices, but you will be using C to program the PIC to perform some fairly simple tasks. C is often used with m-controllers because of its small size, high speed, and the access it allows to the real-world. This week you will get a short introduction to C as well as a brief look at some of the capabilities of the PIC.
A good resource for help with the PIC programmed with the CCS C-compiler is given at http://www.ccsinfo.com/forum/.
The PIC microcontroller comes in a wide range of variants.  You can check them out in data books that are in the lab, or at the MicroChip web site.  A m-controller is distinguished from a m-processor in that it has many capabilities useful for real-world interfacing built into the chip.  The PIC has a RISC-based Harvard architecture with separate memory for data and program.  The one we will be using is the PIC16F873  (link to data sheet)   It has an on-board RAM (Random Access Memory), EPROM (Erasable Programmable Read Only Memory), an oscillator, a couple of timers, and several Input/Output (I/O) pins, serial ports and 8 channel A/D convertor (if you don’t know what all of those things are don’t worry; suffice it to say there can be an impressive array of peripherals built into the chip). However, the m-controller is less computationally capable than most m-processors due to the fact that they are used for simple control applications rather than spreadsheets and elaborate calculations. As an example, the PIC16F873 has 4096 words of memory for program, and only 192 bytes of RAM, and can only operate with clocks up to 20 MHz on 8 bits of data (compared to megabytes of RAM, Speeds of a GHZ or more and 32 or even 64 bits of data for many desktop systems).  It also has no facilities for floating point numbers... A pinout of the PIC16F873 is shown below.
There are several pins that are used to power the device.   Many of the other pins have multiple uses depending on how the device is programmed. 
This week, and the next, you will be using a m-controller in the lab. These laboratories will serve as a brief introduction to the processor and to programming in C.

Getting started with C.

A simple C program
A very simple C program is shown below.
/*simple.c -- sets a pin low, then high*/
#INCLUDE <16F873.h>
#USE DELAY (CLOCK=4000000)
void main() {

 output_low(pin_C1);
 output_high(pin_C1);
}
This program has many common features of C programs. The first line is a comment that is ignored by the compiler.  It is simply there to document what the program code does.  A comment is anything that occurs between a "/*" and the subsequent "*/".  The next line is a "directive".  All directives begin with a "#" and are used to convey information to the compiler.   The directive in this program tells the compiler to include a header file ("16F873.h") which is necessary when using the microcontroller’s input and output capabilities.   The next two directives tell it how to configure the device, and how fast it goes.  The next line tells the compiler that this is the "main" program, and that everything between the opening brace, {, and the matching closing brace, , constitutes the main program. The main program itself is only two lines.   The first  line (not a comment) is a call to the "output_low" function, which sets output pin pin_C1 low, and a call to output_high, which sets it high. . Note that after every program statement there is a semi-colon. This is very important.

Variables
Almost all programs will use variables which are simply units of information stored in the computers memory. The standard C language has a wide variety of variable types available, however the dialect we will be using is more restricted. The version of C that we will be using has a quite unstandard set of variable types that are suited to its architecture.
Type SpecifierSizeRange
unsigned8 bit unsigned0 to 255
unsigned int
int
char
int8
long16 bit unsigned0 to 65535
long int
int16
signed8 bit signed-128 to 127
signed int
signed int8
signed long16 bit signed-32768
to 32767
signed int8
int3232 bit unsigned4*109
signed int3232 bit signed±2*109
float32 bit floating point±0.5*2-128 to 1-(2-15)*2128
shortone bit0 to 1
short int
int1
The program below shows how variables are used.
#INCLUDE <16F873.h>
#USE DELAY (CLOCK=4000000)
void main() {
   char i, j, k; /* declare characters */
    i=2;
    j=3;
    k=i+j;
}
Again we have a fairly simple program that shows many different features of C. Note the semicolon after every program statement. We declare 3 char’s, "i", "j" and "k".   A char is simply an 8 bit variable.  You should use chars whenever possible because the PIC is designed to work on data 8 bits at a time.

Numerical manipulations
C has a variety of built in operations for performing math. These are listed below along with an example where a=0x03, and b=0x11:
 Name of OperandSymbolExampleResult a=0x03 b=0x11
Binary Operators (Two Operands)
Addition
+a+b0x14
Subtraction
-b-a0x0E
Multiplication
*a*b0x33
Division
/b/a0x05
Modulus
(remainder)
%b%a0x02
Bitwise and
&b&a0x01
Bitwise or
|b|a0x13
Bitwise xor
^b^a0x12
Shift right
>>b>>a0x02
Shift left
<<b<<a0x88
Unary Operators (One Operand)
increment
++++a0x04
decrement
----a0x03
negate
--a-0x03
logical complement
~~a0xFC

Logical Expressions
In addition ot manipulating numbers, C is also capable of handling logical expressions. When using these expressions TRUE is taken to be anything that is not zero, and FALSE is always equal to zero. Again, a=0x03, and b=0x11:
Binary operators (two operands)
Name of Operand
Symbol
Example
Result
a=0x03 b=0x11
Binary OperatorsGreater than>a>bFALSE
Less than
<a<bTRUE
Equal
==a==bFALSE
Greater than or equal
>=a>=bFALSE
Less than or equal
<=a<=bTRUE
Not equal
!=a!=bTRUE
Logical AND
&&a&&bTRUE
Logical OR
||a||bTRUE
Unary operators (one operand)
Logical complement
!!aFALSE


Manipulating addresses (somewhat advanced topic, may be skipped)
There are two operators used for manipulating addresses and you have already been briefly introduced to one of them, the indirection operator, *. The other one is the address operator &. If you have an address k, the value stored at that address is *k. If you have a variable j, the address of the variable is given by &j. Therefore it is obvious that *(&j)=j.

I/O (Input/Output) Ports
It is possible with with a PIC to interact with the real world.   This is done thourgh the use of I/O ports.  The PIC16F873 has 3 I/O ports, labeled "a", "b" and "c".  We will use Port A for analog input, though it has other uses. Ports B and C will be used for digital I/O.  On the schematic the pins are labeled RB0 through RB7, but the compiler refers to them as pin_B0 through pin_B7.   Likewise for port C.  The pins can be used for either input or output. 
Your circuit has the pushbutton switch connected to RB0, and the LED's to pins RC0 through RC7.
Digital Output
There are several functions that are used for output from the PIC.   A full listing is in the PCB manual.  Four commonly used functions are:
  • Output_high(pin)
    Sets the specified pin to a logic 1 (about 5 volts).
  • Output_low(pin)
    Sets the specified pin to a logic 0 (about 0 volts)
  • Output_float(pin)
    Sets the specified pin to a high-impedance (or tri-state) state.  In this state it is as if the pin has no connections to the chip.  Current can neither go in or out of the pin.
  • Output_bit(pinvalue)
    This function sets the specified pin to the specified value (which must be 0 or 1).
Digital Input
There is only one input function you will need for the PIC.
  • Input(pin)
    Reads the value on a specified pin.  The value is returned in a short int.   A proper use of the function would be something like:

        while( !input(pin_B0)) { ... }
    which would repeat the commands in the braces as long as RB0 was low.
"High level" I/O
If the PIC is connected to the PIC C development software via the debugger it is possible to do some higher level input and output.  These  interactions take place via the debugger's "Monitor" window.
You specify that IO is to take place through the debugger by properly defining serial connections (usually in your codes header file):
#use rs232(DEBUGGER)
You can then print to the monitor window by using "putc()" which sends a character to the monitor window, "puts()" which sends a string, or "printf()" which sends a formatted string.  The "printf()" command is most useful, but also the most complicated (and takes the most memory).
The syntax of printf is the following:
printf(format-string, [arg_1] , ... , [arg_N] )
This is best illustrated by some examples.

Printing Examples

Example 1: Printing a message. The following statement prints a text string to the screen.
printf("Hello, world!\n");
In this example, the format string is simply printed to the screen.
The character \n at the end of the string signifies end-of-line. When an end-of-line character is printed, the LCD screen will be cleared when a subsequent character is printed. Thus, mostprintf statements are terminated by a \n.
Example 2: Printing a number. The following statement prints the value of the integer variable x with a brief message.
printf("Value is %d\n", x);
The special form %d is used to format the printing of an integer in decimal format.
Example 3: Printing a character. The following statement prints the ascii equivalent of the integer variable x with a brief message.   Here is an ascii table.
printf("Value is %d, ascii = %c\n", x, x);
Example 4: Printing a number in binary. The following statement prints the value of the integer variable x as a binary number.
printf("Value is %b\n", x);
The special form %b is used to format the printing of an integer in binary format. Only the low byte of the number is printed.
Example 5: Printing a floating point number. The following statement prints the value of the floating point variable n as a floating point number.
printf("Value is %f\n", n);
The special form %f is used to format the printing of floating point number.
Example 6: Printing two numbers in hexadecimal format.
printf("A=%x  B=%x\n", a, b);
The form %x formats an integer to print in hexadecimal.

Formatting Command Summary

%d
Type: int Description: decimal number
%x
Type: int Description: hexadecimal number
%b
Type: int Description: low byte as binary number
%c
Type: int Description: low byte as ASCII character
%f
Type: float Description: floating point number
%s
Type: char array Description: char array (string)
Format CommandData TypeDescription
%dintdecimal number
%xinthexadecimal number
%bintlow byte as binary number
%cintlow byte as ASCII character
%ffloatfloating point number
%schar arraychar array (string)

Your circuit has the pushbutton switch connected to RB0, and the LED's to pins RC0 through RC7.
Input
Unfortunately, you can only receive input from the keyboard one character at a time using the getc() command.  Be aware:
  • getc() returns the ascii equivalent of the character entered into the keyboard.
  • the keyboard I/O is implemented in software on the PIC.  That means, it won't receive input from the keyboard unless it is explicitly looking for it.  Therefore, your program must stop in order to look for input from the keyboard.  (Hardware communications could receive a character in the background, without requiring software support).
As an example, the following code gets the ascii value in k, converts to a number, and prints the number.
k=getc();                %Get ascii value of keyboard input.
k=k-'0';                 %Subtract value of '0' to convert to number.
printf(" ... k=%d\n",k); %print the number.
Control of Flow
What you have learned up to this point has been useful but is of limited utility because it does not allow for decision making capabilities by the computer. C has a variety of mechanisms to control the flow of a program. These are listed below:
The if...then construct
if (logical expression) {
    ...statements...
}
If the logical expression is true then evaluate the statements between the braces. The following code sets RC1 if a is even.
if ((a%2) == 0) {
   Output_high(pin_C1);
}
The if...then...else construct
if (logical expression) {
   ...if statements...
}
else {
   ...else statements...
}
If the logical expression is true then evaluate the "if" statements between the braces, otherwise execute the "else" statements. The following code decides if a number if is even or odd.
if ((a%2) == 0) {
   Output_high(pin_C1);
}
else {
   Output_low(pin_C1);
}
while (logical expression) {
    ...statements...
}
While the logical expression is true, the statments (of which there is an arbitrary number) between the braces is executed. The following code cycles through the even numbers from 0 to 9 (the variables must have been declared elsewhere in the program).
a=0;
while (a<10) {
    ...statements...
    a=a+2;
} 

The for loop
for (initial condition; logical expression; change loop counter variable) {
    ...statements...
}
Set the initial condition, then while the logical expression is true execute the statement between the braces while changing the loop counter as specified once at the end of each loop. This code segment is functionally equivalent to the one for the "while" loop.
for (a=0; a<10; a=a+2) {
    ...statements...
}

The case...switch construct
Case..switch is used in place of a series of "if...else" clauses when a variable can take on several values.  The "default" clause at the bottom takes care of any cases not covered explicitly.
switch (variable) {
   case val1: ...statements 1...
   break;
   case val2: ...statements 2...
   break;
   case val3: ...statements 3...
   break;
   default: ...statements default...
   break;
}

Functions
Often a series of instruction must be repeated over and over again. Instead of repeating the same operations repetitively it is useful to use a function that performs the repetitive operations. For instance to set a value on RC1 and then read from RB0 and set RC0 to that value, and returning the value of RB0 you might use a function called "RB0toRC0".  (Note: this program isn't meant to be particularly useful, but to introduce the syntax for function declaration, and use).
/*simpleFunc.c -- to demonstrate function calls*/
#INCLUDE <16F873.h>
#USE DELAY (CLOCK=4000000)
short int RB0toRC0(RC1val)
short int RC1val;
{
   Output_bit(pin_C1, RC1val);  /*Set RC1 to the specified value*/
   if (input(pin_B0)) {         /*Read RB0*/      
      Output_high(pin_C0);      /*If RB0 is high, RC0 set high*/
   } 
   else {
      Output_low(pin_C0);       /*else set RC0 low*/
   }
   return(input(pin_B0));       /*Return RB0*/
}
void main() {
   short int b;

   b=RB0toRC0(1);
   b=RB0toRC0(0);
}
This program introduces some new constructs. The most obvious is the function "RB0toRC0" which is at the top. The first line of the function declares that the function returns a short int, and has one argument. The type of the argument is given before the function's opening brace. The body of the function (between the braces) outputs a value to RC1, and reads from RB0 and echos to RC1.  The last line tells that compiler to return the value of RB0 to the calling function.
The function is called in the main program with different arguments.   The first call would set RC1 high, and return the current value of RB0 to the variable "b".  The next line would set RC1 low, and return the value of RB0 to the variable "b".

How to make PCBs at home in 1 hour

If you take your electronics hobby seriously, I guess you already feel the need for a simple and fast technique for making your own printed-circuit boards (PCB). Here I’m going to show how to make simple single-sided PCBs in a snap, using widely available materials. This technique works reliably for thin tracks down to 10 mils, and is suitable for most surface-mount parts.

What you need

 
Required materials
I used…
Where to find
Magazines or advertising brochures 
(More on this later).
IEN magazine / TV programme magazine
Mail-order catalogue
Travel agent's brochures
Free in your mailbox
Laser printer Alternately, a photocopier should work
Samsung  ML1710 with original toner cartridge.
Inkjet printers/copiers don't work.
Attached to your PC
Household clothes iron
Tefal Acquagliss 70s
(dismissed unit, vapour was broken)
Ask mummy
Copper clad laminate
FR4 laminate 1.6 mm thick (35um copper)
Radio Shack
Etching solution
Ferric chloride solution,
about 1 liter/ 0,26 gallons
Radio Shack
Kitchen scrubs
Spontex “Azione Verde”
Grocery store
Thinner (e.g. acetone)
Nail polish remover.
Most solvents used in painting will do.
Grocery store
Plastic coated wire
Plastic insulated copper wire, 1 mm diameter solid core (about 1 meter/3feet)
Electrical store
You need also: a blade cutter, scotch tape, sandpaper, kitchen paper, cotton wool, vice, hacksaw.

How it works

Laser printers and photocopiers use plastic toner, not ink, to draw images. Toner is the black powder that ends up on your clothes and desk when replacing the printer cartridge. Being plastics, toner is resistant to etching solutions used for making PCBs - if only you could get it on copper!
Modifying a printer for working with copper is out of question, but you can work around it with the toner-transfer principle. Like most plastics, toner melts with heat, turning in a sticky, glue-like paste. So why not print on paper as usual, place the sheet face-down on PCB copper, and melt toner on copper applying heat and pressure?
Almost right. Right now you got paper toner-glued to PCB copper. Last step is to find a way to remove paper leaving toner on the copper, and you’re done.
I must credit Thomas Gootee for finding a solution putting glossy, inkjet photo paper in his laser printer. He found that the glossy coating dissolves in water. As most of the toner does not penetrate the glossy surface, you can easily remove the paper support with water: the gloss dissolves and you can remove paper.
Clever, isn’t it?

Unfortunately, the kind of paper used by Thomas is being replaced by new, improved, WATERPROOF (!) photo paper. This is good for your photo prints, but doesn't work anymore for PCBs.

While searching for more information on the subject, I found a newsgroup thread that suggested replacing expensive inkjet photo paper with glossy paper recycled from magazines. Magazines use ink, not toner, for printing, so previous printing shouldn’t affect the process. Another great idea! I tried it and worked so well that I decided to spread the word. Read on for a complete tutorial and my hands-on tips.

Finding the right paper

The perfect paper should be: glossy, thin, and cheap. The kind of stuff that looks lustrous and shiny when new, but so cheap it quickly turns into pulp when wet. If you ever found a mailbox full of squashy mail on a rainy day, you already know the answer: paper used for most mail advertising and magazines fits perfectly the requisites. I tried pages from the free advertising magazine IEN,catalogues , travel agent’s brochures, TV programme magazine, and all worked well. I don’t expect great difference using paper from most magazines. As a rule of thumb, if humidity in your bathroom turns your magazine in bad shape, it should be OK. If the humidity on your fingertips is enough to feel a sticky sensation while touching its gloss coating, it should be OK. Feel free to experiment: almost any glossy magazine paper will work. I like thin paper over thick one, and prefer recycled paper over new paper.

Paper preparation

I discard pages heavily printed, preferring pages with normal-size text on white background. Although ink usually does not transfer on the PCB, heavy print of headlines sometimes accumulate so much ink that some gets on copper.
Cut the paper to a size suitable for your printer. Try to get straight, clean cuts, as jagged borders and paper dust are more prone to clog printer mechanism. An office cutter is ideal, but also a blade-cutter and a steady hand work well.
Be careful to remove all staples, bindings, gadget glue or similar stuff, as they can damage printer’s drum and mechanisms.

Printer setup

Laser printers are not designed for handling thin, cheap paper, so we must help them feeding the sheets manually instead of using the paper tray. Selecting a straight paper path minimizes the chances of clogging. This is usually achieved setting the printer as if it were printing on envelopes.

You want to put as much toner on paper as possible, so disable “toner economy modes” and set printer properties to the maximum contrast and blackness possible. You want to print your PCB to exact size, so disable any form of scaling/resizing (e.g. “fit to page”). If your printer driver allows, set it to “center to page” as it helps to get the right position using a non-standard size sheet. 

Printing

Disclaimer: your laser printer is not designed to handle this kind of paper. Feeding your printer with paper other than special laser printer paper could damage it and potentially voids the warranty. So you are warned: do it at your own risk.
Print your PCB layout as usual, except you must setup the printer as described above and you must print a mirrored layout.
This is my PC thermometer circuit printed on IEN magazine paper. Notice that it is a mirror image of the circuit (the word PCTHERM is reversed). Placing some text helps recognizing when the layout is mirrored. Text will read straight again once the image is transferred on copper. If you look it very closely, you can see that toner is not opaque enough to 100% cover the words underneath, but this won’t affect etching.

How to cut raw material

PCB material is fibreglass like, and a trick to cut it effortlessly is to score a groove with a blade cutter or a glass cutter. The groove weakens the board to the point that bending it manually breaks it along the groove line. This method is applicable only when cutting the whole board along a line that goes from side to side, that is you can’t cut a U or L shaped board with it.
For small boards, I lock the PCB material in a vice, aligning vice edge and cut line. I use an all-aluminium vice which is soft and doesn’t scratch copper, if you use a steel vice protect copper surface with soft material.
Using the vice as a guide, I score BOTH board sides with a blade cutter (be careful) or another sharp, hardened tool (e.g. a small screwdriver tip). Ensure to scratch edge-to-edge. Repeat this step 5-6 times on each side.
Bend the board. If groove is deep enough, the board will break before reaching a 30 degrees bend. It will break quite abruptly so be prepared and protect your hands with gloves.
To make paper alignment easier, cut a piece of PCB material that is larger (at least 10mm/0,39 inch for each side) than the final PCB.

Cleaning the board for transfer

It is essential that the copper surface is spotlessly clean and free from grease that could adverse etching. To remove oxide from copper surface, I use the abrasive spongy scrubs sold for kitchen cleaning. It’s cheaper than ultra-fine sandpaper and reusable many times. Metallic wool sold for kitchen cleaning purposes also works. Thoroughly scrub copper surface until really shiny. Rinse and dry with a clean cloth or kitchen paper. 

Preparing for transfer

To make paper alignment easy, cut excess paper around one corner (leave a small margin though). Leave plenty of paper on the other sides to fix the paper to the desk. As the board is larger than the final PCB, there is large margin for easy placement of paper on copper.
Turn the iron to its maximum heat (COTTON position) and turn off steam, if present. While the iron warms up, position the materials on the table. Don’t work on an ironing board as its soft surface makes it difficult to apply pressure and keep the PCB in place. Protect table surface with flat, heat-resistant material (e.g. old magazines) and place the board on top, copper face up. Lock the board in place with double-adhesive tape. Position the PCB printout over the copper surface, toner down, and align paper and board corners. Lock the paper with scotch tape along one side only. This way, you can flip the paper in and out instantly.

Iron it!

Flip out the paper, and preheat copper surface placing the iron on top of it for 30 seconds. Remove the iron, flip back paper into its previous position over the copper. It is essential that paper does not slip from its position. You can also cover with a second sheet of blank paper to distribute pressure more evenly. Keep moving the iron, while pressing down as evenly as you can, for about one minute.
Remove the iron and let the board to cool down.

Peeling


This is the fun part. When the board is cool enough to touch, trim excess paper and immerge in water. Let it soak for 1 minute, or until paper softens.

Cheap paper softens almost immediately, turning into a pulp that is easy to remove rubbing with your thumb. Keep rubbing until all paper dissolves (usually less than 1 minute). Don’t be afraid to scratch toner, if it has transferred correctly it forms a very strong bond with copper.

The board with all paper removed. It is OK if some microscopic paper fibres remain on the toner (but remove any fibre from copper), giving it a silky feeling. It is normal that these fibres turn a little white when dry.

Magnified view of the tracks, these are 1206 pads and SO8 SMT pads, connected by 20 mils tracks. Some white fibres show up on the black toner surface.

The hanger tool

.
The optimal way to etch is keeping the PCB horizontal and face-down (and possibly stirring). This way dissolved copper gets rapidly dispersed in the solution by gravity. Stirring keeps its concentration even, so the solution close to the PCB does not saturate and etching proceeds quicker. Unfortunately it is not easy to keep the PCB in place in an highly corrosive acid. This hanger is my best attempt to solve the problem. I made it with plastic-insulated copper wire. The wire must have a rigid core, but must be also easy enough to adapt to the board by hand without tools. Core diameter of 1 to 2mm is fine. Give it the form of an “arm” (the handle) ending with 4 “fingers”.
Each finger has a ring tip that fits a corner of the board. Close fingers around board corners: now you can use the handle to splash the board into the etching solution, stir, and inspect how etching proceeds.

Etching

There are many alternatives for etching liquids, and you can use the one that suits your taste. I use ferric chloride (the brown stuff): it’s cheap, can be reused many times, and doesn’t require heating. Actually, moderate heating can speed up etching, but I find it reasonably fast also at room temperature (10…15 minutes).
The down side of this stuff is that it’s incredibly messy. It permanently stains everything it gets in contact with: not only clothes or skin (never wear your best clothes when working with it!), but also furniture, floor tiles, tools, everything. It is concentrated enough to corrode any metal – including your chrome-plated sink accessories. Even vapours are highly corrosive: don’t forget the container open or it will turn any tool or metallic shelf nearby into rust.
For etching, I place the container on the floor (some scrap cardboard or newspaper to protect the floor from drops). I fit the board on the hanger, and submerge the PCB. Stir occasionally by waving the hanger.


First impression may be that nothing happens, but in less than 10 minutes some copper is removed, making first tracks to appear. From now on, stir continuously and check often, as the process completes rather quickly. You don’t want to overdo it, otherwise thinner tracks start being eroded sideways. As a rule of thumb, stop 30 seconds after you don’t see any copper leftovers over large areas.


Rinse the board with plenty, plenty, plenty of water
I store the etching solution in the same plastic box used for etching. When the job is done I just put the hermetic lid on. To further minimize risks of leakage, I put the container inside the bigger one I use for rinsing, put the second lid, and store it in a safe place.

Finishing touches


A few drops of thinner (nail polish remover works well) on a pinch of cotton wool will remove completely the toner, bringing back the copper surface. Rinse carefully and dry with a clean cloth or kitchen paper.
Trim to final size and refine edges with sandpaper.

You will like it

The best thing about this method is that it makes possible to start with a great idea at 11:00 pm and have your prototype working by midnight. It is so straightforward that you will use it more often than you think.
The second great thing is that this method is good enough for larger SMT parts. Actually, once you get some practice soldering, SMT parts are easier to work/experiment with, and don’t require drilling the holes.
So far, results are comparable with what I was used to get with UV sensitive boards. The board in this tutorial had 20 mils wide tracks: the word “PCTHERM” is 40 mils high and made from 10 mils tracks, and the three pads in the middle are spaced only10 mils apart.
I don’t know how the method scales to large board sizes, as I make only small boards.
 ---aneoena