About PCB Drill Compensation

About PCB Drill Compensation

There are no great individuals, only great teams. With the team working together, the first-stage PCB CAM automation project for net handling and drill handling is done. Next, we can move on to the PCB rules engine. Here I talk about drill compensation in PCB engineering. As a PCB engineering developer, you should know what it is and why it works. I share the key points about drill compensation below.


1. Why do we compensate drill sizes?

The hole sizes in the PCB files the customer gives usually mean the final hole size. During PCB production, copper is plated inside the holes (or the holes get a surface finish such as HASL, ENIG, OSP, etc.). This makes the hole smaller. To make sure the final hole size meets the requirement, the CAM step corrects the drill size. This is drill compensation.

Real example:
Final hole size: 1.00 mm. Surface finish: ENIG (nickel thickness 2.54 µm, gold thickness 0.0254 µm). Follow IPC Class II and the average plated copper thickness is 20 µm. If we use 0.10 mm as the compensation value, the CAM team will pick a 1.10 mm drill bit.

Real example


2. How do we do drill compensation?

First, be clear about the three key parameters for drill compensation:
(1) Drill bit increment,
(2) Compensation value,
(3) Step-up threshold (advance value).
These three determine how to apply compensation.

1) Drill bit increment

This depends on the drill bits the company buys. The industry common increment is 50 µm. Typical drill sizes range from 0.10 mm to 6.35 mm. The usual smallest step between drill bits is 0.05 mm. So the drill library has sizes like 0.10 mm, 0.15 mm, 0.20 mm, 0.25 mm, and so on.

2) Compensation value

The process team sets the compensation rules based on factory test results. Compensation values do not vary much across the industry. Common rules:

  • Boards with HASL (spray tin): compensate 0.15 mm.

  • Boards without HASL (ENIG, immersion tin, OSP, etc.): compensate 0.10 mm.

3) Step-up threshold (advance value)

The process team also sets the strategy for picking the drill bit, similar to a rounding rule. For example, when the increment is 20 µm, if the remainder after dividing by the increment is ≥ 20 µm, you round up 50 µm; otherwise you keep the lower size.

Example:
Final hole size = 1.025 mm, compensation = 0.10 mm, so compensated size = 1.125 mm. But there is no 1.125 mm drill in the library. Use the step-up rule. The remainder of 1.125 mm when compared to the 0.05 mm step is 25 µm. Since 25 µm > 20 µm, round up by 50 µm and choose a 1.15 mm drill.


Actual drill compensation examples

Assume: drill increment = 50 µm, step-up threshold = 20 µm

Original hole Compensation After compensation Integer part Remainder Drill chosen
1.025 mm 0.10 1.125 mm 1.10 0.025 mm 1.15 mm
1.016 mm 0.10 1.116 mm 1.10 0.016 mm 1.10 mm

How to compute the chosen drill size

Break the compensated hole size into an integer part and a remainder part using the drill increment:

Take 1.125 mm as an example:
1.125 / 0.05 = 22.5 → floor to 22 → integer part = 22 × 0.05 = 1.10 mm.
Remainder = 1.125 % 0.05 = 0.025 mm.

Then compare the remainder with the step-up threshold (for example, 20 µm):

  • If remainder > threshold, drill size = integer part + 0.05 mm.

  • If remainder ≤ threshold, drill size = integer part + 0.00 mm.


Summary about the step-up threshold

When the drill increment is 50 µm, the step-up threshold is critical. It performs a second correction of the compensated drill size. It decides whether to “step up” or “stay.” Changing this threshold directly changes the chosen drill size.

More examples (drill increment = 50 µm):

Original hole Compensation After comp. Integer Remainder Step-up threshold Drill
1.022 mm 0.1 1.122 mm 1.10 0.022 mm 0.02 1.15 mm
1.022 mm 0.1 1.122 mm 1.10 0.022 mm 0.025 1.10 mm

Personal view on setting the step-up threshold

Pros and cons: After compensation, if the final hole is a little larger, at least the part can be inserted. If the hole is too small, the part cannot be inserted. So we usually set the step-up threshold to 20 µm instead of 25 µm. The exact choice should match each process and compensation value.

Combined with compensation value: For boards with HASL where compensation is 0.15 mm, you already “over-compensate” a bit and the final holes tend to be slightly large. In that case, a step-up threshold of 25 µm can also work. Use the “nearest” rule when picking the drill.


3. How to ensure final hole size meets requirements after compensation?

Method 1: Buy special drill bits

Standard drill increment is 50 µm (0.05 mm steps like 1.00, 1.05, 1.10, 1.15 mm). With a PTH tolerance of ±3 mil, a 50 µm drill set can cover the tolerance. If the tolerance is smaller than that, use special drill bits.

Example 1 — Compare 50 µm vs 25 µm increments:
Original hole = 0.922 mm, compensation = 0.10 mm, compensated size = 1.022 mm.

Original Compensation Compensated Increment Drill chosen
0.922 0.10 1.022 0.05 (50 µm) 1.05
0.922 0.10 1.022 0.025 (25 µm) 1.025

Difference: 1.050 − 1.022 = 0.028 mm; 1.025 − 1.022 = 0.003 mm. The smaller difference is better, so 1.025 mm (25 µm increment) is better.

Example 2 — 50 µm vs special drill:
Original hole = 0.611 mm, compensation = 0.10 mm, compensated = 0.711 mm.

Original Compensation Compensated Increment / Type Drill chosen
0.611 0.10 0.711 0.05 (50 µm) 0.70
0.611 0.10 0.711 Special drill 0.711

Difference: 0.700 − 0.711 = −0.011 mm; 0.711 − 0.711 = 0.000 mm. The smaller difference is better. So the 0.711 mm special drill is best.

Method 2: Improve process and equipment

  • Add a second board plating step to reduce uneven thickness from pattern distribution.

  • Use negative photo direct-etching and plate the whole board to reduce uneven copper thickness.

  • Lower the current density (typical is 19 ASF); slightly lower current density can improve plating uniformity but will extend plating time.

  • Upgrade to a horizontal plating line. Vertical plating lines often give thicker copper at the hole edge and thinner copper at the hole center for high aspect-ratio holes. A horizontal line can reduce that issue.

Method 3: Improve CAM strategies

  • For holes in isolated copper areas, apply one extra increment compensation. Isolated areas have less copper, so during plating they get higher local current density and more copper thickness; extra compensation offsets that.

  • For designs with dense traces on one side and sparse on the other (for example, a power board), place the sparse side inward and the dense side outward, and use reversed panelization. During panel plating, areas near the board edge get higher current density and thicker plating. Reversed panelization helps balance plating distribution.

  • When TOP and BOTTOM copper area differ a lot, use positive/negative (yin-yang) paneling. Uneven copper area causes “bell-mouth” vias; the thicker the board and the more copper, the worse the effect; yin-yang paneling helps balance copper distribution.

  • For isolated-area holes near the board edge or slots, add copper “pick-up” areas or copper pads near the edge or slot. Isolated holes can get too much plating thickness and become too small; extra copper near them reduces local current density and balances plating.


4. How much compensation is needed and how is it derived?

Compensation values come from process tests. Below is one set of measured hole size changes after various steps (data from a report):

Process flow: mechanical drilling → immersion copper → electroplating → pattern transfer → etch → AOI → wet film → HASL

Process parameters:

  • Drill: drill bit size 0.95 mm, re-sharpen/regrind 3 times, drill compensation 0.15 mm;

  • Plating: copper thickness ≥ 18 µm, average ≥ 20 µm;

  • HASL: final hole requirement 0.80 mm, tolerance ±0.08 mm (3 mil);

  • Test: 10 panels, corner trimmed, board thickness 2.0 mm.

Hole size changes by step

1) After drilling — hole sizes measured

  • Total 1920 holes tested (10 panels, 384 holes each). Sample: 200 holes (20 per panel). Hole range: 0.93–0.94 mm, average 0.931 mm.
    (Then a long list of sampled values, mostly 0.93 or 0.94.)

2) After patterned plating — copper thickness

  • For each panel, test 10 holes. Copper thickness range 18–31 µm, meeting ≥18 µm and average ≥20 µm.
    (Then many sample copper thickness values.)

3) After patterned plating — hole size

  • Total 1920 holes, sample 200. Hole range: 0.84–0.88 mm, average 0.858 mm.
    (Then many sample values, mostly 0.85–0.88.)

4) After HASL — hole size

  • Total 1920 holes, sample 200. Hole range: 0.82–0.86 mm, average 0.836 mm.
    (Then many sample values.)

Test summary

Step Hole range Average hole
After drilling 0.93–0.94 mm 0.931 mm
After copper plating 0.84–0.88 mm 0.858 mm
After HASL 0.82–0.86 mm 0.836 mm

Conclusion: For HASL boards the drill compensation of 0.15 mm is an “over-compensation” and causes final holes to be larger. The best compensation value in this test is 0.125 mm.


5. Drill compensation code implementation (rules)

  1. Compensation and step-up rules

Aspect Finished hole Surface finish Board thickness Step-up threshold If via copper < 26 µm 26–37 µm 37–47 µm 47–67 µm 67–86 µm
thickness ratio < 12:1 ≤ 1.90 mm HASL (leaded or lead-free) ≥ 3.5 mm 0.01952 5 mil 6 mil 7 mil 8 mil 9 mil
thickness ratio < 12:1 ≤ 1.90 mm HASL (leaded or lead-free) < 3.5 mm 0.01952 4.5 mil 5.5 mil 6.5 mil 7.5 mil 8.5 mil
thickness ratio < 12:1 ≤ 1.90 mm Other finishes / 0.01952 4 mil 5 mil 6 mil 7 mil 8 mil
thickness ratio < 12:1 > 1.90 mm HASL / 0.0246 5.5 mil 6.5 mil 7.5 mil 8.5 mil 9.5 mil
thickness ratio < 12:1 > 1.90 mm Other finishes / 0.01952 4.5 mil 5.5 mil 6.5 mil 7.5 mil 8.5 mil
thickness ratio ≥ 12:1 all holes HASL / 0.0246 5.5 mil 6.5 mil 7.5 mil 8.5 mil 9.5 mil
thickness ratio ≥ 12:1 all holes Other finishes / 0.01952 5 mil 6 mil 7 mil 8 mil 9 mil
  1. Special drill sizes (if tolerance < 3 mil, use special drills or 25 µm increment, use nearest drill rule)

				
					List<double> ContainDrillToolList = new List<double>();
ContainDrillToolList.AddRange(new double[] { 610, 635, 711, 838, 914, 1016, 1320, 3120 });
				
			

3. Drill Compensation Code

				
					///<summary>
/// Calculate the drill bit diameter based on drill compensation parameters
///</summary>
///<param name="ToolInfo">Drill tool basic information</param>
///<param name="UpParam">Drill compensation parameters</param>
///<param name="ContainDrillToolList">Special drill bit diameter list</param>
///<returns>Return 1 if calculation is successful</returns>
public static int getDrillUpSize(Mod_tool ToolInfo, gToolUpParam UpParam, List<double> ContainDrillToolList)
{
    if (ContainDrillToolList == null) ContainDrillToolList = new List<double>();
    gToolUpParamHole UpParamHole = new G_Helper.gToolUpParamHole();
    switch (ToolInfo.type)
    {
        case "via":
            UpParamHole = UpParam.Via;
            break;
        case "plate":
            UpParamHole = UpParam.Pth;
            break;
        case "nplate":
            UpParamHole = UpParam.Npth;
            break;
    }
    ToolInfo.max_tol = Math.Round(UpParamHole.Max_Tol, 0);
    ToolInfo.min_tol = Math.Round(UpParamHole.Min_Tol, 0);
    if (ToolInfo.finish_size < 50)
    {
        ToolInfo.finish_size = ToolInfo.drill_size;
    }
    double DrillSlotLevel = (ToolInfo.shape == "slot") ? UpParam.SlotLevel : UpParam.DrillLevel;  //Drill step interval: Round holes have two levels (25/50μm), slot holes have one level (50μm)
    double UpLevel;
    if (UpParam.DrillLevel > 49) //When the step interval is 50μm, do not use special drill bits
    {
        ContainDrillToolList = new List<double>();
        UpLevel = UpParamHole.UpLevel;
    }
    else
    {
        UpLevel = UpParam.DrillLevel * 0.5;   //Select drill bit by half of the step interval
    }

    double Drillfinish_size = ToolInfo.finish_size + (ToolInfo.max_tol - ToolInfo.min_tol) * 0.5;  //Average the upper and lower tolerance
    int DrillLevelCount = (int)(Math.Floor((Drillfinish_size + UpParamHole.UpVal) / DrillSlotLevel)); //Drill step count
    double DrillsizeInt = DrillLevelCount * DrillSlotLevel; //Round down to the nearest drill step
    double DrillsizeFloat = (Drillfinish_size + UpParamHole.UpVal) % DrillSlotLevel;//Remainder of drill size after step division
    double DrillsizeLevel = (DrillsizeFloat > UpLevel) ? DrillSlotLevel : 0;//Determine whether to round up the remainder

    //Check if special drill bits are included
    int ContainDrillIndex = ContainDrillToolList.FindIndex(tt => (int)(Math.Floor(tt / DrillSlotLevel)) == DrillLevelCount);
    if (ContainDrillIndex > -1)
    {
        double ContainDrillFloat = ContainDrillToolList[ContainDrillIndex] % DrillSlotLevel;//Remainder of special drill bit size after step division
        if (DrillsizeFloat > UpLevel) // e.g. 38 > 20
        {
            double diff1 = Math.Abs(DrillsizeFloat - DrillSlotLevel);   //e.g. 40-50
            double diff2 = Math.Abs(DrillsizeFloat - ContainDrillFloat);  //e.g. 40-38
            DrillsizeLevel = (diff1 < diff2) ? DrillSlotLevel : ContainDrillFloat;
        }
        else //if (ContainDrillFloat < UpLevel)
        {
            double diff1 = Math.Abs(DrillsizeFloat - 0);  //e.g. 12-0
            double diff2 = Math.Abs(DrillsizeFloat - ContainDrillFloat);  //e.g. 12-16
            DrillsizeLevel = (diff1 < diff2) ? 0 : ContainDrillFloat;
        }
    }
    ToolInfo.drill_size = DrillsizeInt + DrillsizeLevel;

    double DiffDrillSizeUp = ToolInfo.drill_size - ToolInfo.finish_size;
    if (ToolInfo.shape == "slot") // Slot length compensation
    {
        if (UpParam.isSlotUpLevel) //Whether to round the slot length to step interval
        {
            Drillfinish_size = ToolInfo.slot_len + (ToolInfo.max_tol - ToolInfo.min_tol) * 0.5;  //Average the upper and lower tolerance
            DrillLevelCount = (int)(Math.Floor((Drillfinish_size + UpParamHole.UpVal + UpParam.SlotLengthUp) / DrillSlotLevel)); // Drill step count
            DrillsizeInt = DrillLevelCount * DrillSlotLevel; //Round down to the nearest drill step (50μm)
            DrillsizeFloat = (Drillfinish_size + UpParamHole.UpVal + UpParam.SlotLengthUp) % DrillSlotLevel;//Remainder of slot length after step division
            DrillsizeLevel = (DrillsizeFloat > UpParamHole.UpLevel) ? DrillSlotLevel : 0;//Determine whether to round up the remainder
            ToolInfo.slot_len = DrillsizeInt + DrillsizeLevel;
        }
        else
        {
            DrillsizeInt = Math.Floor((ToolInfo.slot_len + DiffDrillSizeUp) / 10) * 10; // Round down to the nearest 10μm
            ToolInfo.slot_len = DrillsizeInt;
        }
        ToolInfo.drill_size += UpParam.SlotEndNumber;  // Add suffix number for slot drill bit segmentation
    }
    ToolInfo.bit = Math.Round((ToolInfo.drill_size * 0.001), 3).ToString();
    return 1;
}

public class gToolUpParam
{
    /// <summary>
    /// Compensation parameters for VIA holes (in μm)
    /// </summary>
    public gToolUpParamHole Via { get; set; } = new gToolUpParamHole();
    /// <summary>
    /// Compensation parameters for PTH (Plated Through Hole) (in μm)
    /// </summary>
    public gToolUpParamHole Pth { get; set; } = new gToolUpParamHole();
    /// <summary>
    /// Compensation parameters for NPTH (Non-Plated Through Hole) (in μm)
    /// </summary>
    public gToolUpParamHole Npth { get; set; } = new gToolUpParamHole();
    /// <summary>
    /// Step interval for round drill holes (in μm)
    /// </summary>
    public double DrillLevel { get; set; } = 50;
    /// <summary>
    /// Step interval for slot drill holes (in μm)
    /// </summary>
    public double SlotLevel { get; set; } = 50;
    /// <summary>
    /// Suffix number for slot drill bit segmentation
    /// </summary>
    public int SlotEndNumber { get; set; } = 0;
    /// <summary>
    /// Additional compensation value for slot length (in μm)
    /// </summary>
    public double SlotLengthUp { get; set; } = 0;
    /// <summary>
    /// Whether to round the slot length to step interval
    /// </summary>
    public bool isSlotUpLevel { get; set; } = false;
}

public class gToolUpParamHole
{
    /// <summary>
    /// Compensation value (in μm)
    /// </summary>
    public double UpVal { get; set; } = 100;
    /// <summary>
    /// Step interval threshold for rounding up (in μm)
    /// </summary>
    public double UpLevel { get; set; } = 25;
    /// <summary>
    /// Upper tolerance (in μm)
    /// </summary>
    public double Max_Tol { get; set; } = 76;
    /// <summary>
    /// Lower tolerance (in μm)
    /// </summary>
    public double Min_Tol { get; set; } = 76;
}

///<summary>
/// Mod_tool: Drill tool attribute model
///</summary>
public class Mod_tool
{
    public int num { get; set; }
    public string type { get; set; } // Hole type: via/plate(nplate)
    public string shape { get; set; } // Hole shape: round/slot
    public double finish_size { get; set; } // Finished hole size (in μm)
    public double drill_size { get; set; } // Drill bit size (in μm)
    public double max_tol { get; set; } // Upper tolerance (in μm)
    public double min_tol { get; set; } // Lower tolerance (in μm)
    public double slot_len { get; set; } // Slot length (in μm)
    public string bit { get; set; } // Drill bit size (in mm, formatted string)
}
				
			

6. Why does board thickness affect drill compensation?

I did not understand this at first either. The main reason is the high thickness-to-diameter ratio (board thickness divided by hole diameter). A high ratio makes the copper at the hole center thinner and the copper at the hole edge thicker. To compute the thickness-to-diameter ratio you need the board thickness value. So board thickness enters the drill compensation rules. For high thickness-to-diameter holes, the compensation is larger.

دیدگاه‌ خود را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

پیمایش به بالا