Skip to content
qfn_wizard.py 6.84 KiB
Newer Older
natsfr's avatar
natsfr committed
from __future__ import division
import pcbnew
natsfr's avatar
natsfr committed
import HelpfulFootprintWizardPlugin as HFPW
natsfr's avatar
natsfr committed
import FootprintWizardDrawingAids as FWDA
natsfr's avatar
natsfr committed
import PadArray as PA

natsfr's avatar
natsfr committed
import math

class ThermalViasArray(PA.PadGridArray):
    def NamingFunction(self, x, y):
        return self.firstPadNum

natsfr's avatar
natsfr committed
class QFNWizard(HFPW.HelpfulFootprintWizardPlugin):

    def GetName(self):
        return "QFN"

    def GetDescription(self):
        return "QFN Wizard"

    def GenerateParameterList(self):
        self.AddParam("Pads", "nbpads", self.uNatural, 20)
        self.AddParam("Pads", "pitch", self.uMM, 0.5)
        self.AddParam("Pads", "pad width", self.uMM, 0.25)
        self.AddParam("Pads", "pad length", self.uMM, 0.4)
        self.AddParam("Pads", "pitch", self.uMM, 0.5)
        self.AddParam("Pads", "oval", self.uBool, True)
        self.AddParam("Pads", "Width", self.uMM, 4)
        self.AddParam("Pads", "Length", self.uMM, 4)
natsfr's avatar
natsfr committed
        self.AddParam("Pads", "Fillet", self.uMM, 0.3)
natsfr's avatar
natsfr committed
        self.AddParam("TPad", "tpad", self.uBool, True)
        self.AddParam("TPad", "W", self.uMM, 2.6)
        self.AddParam("TPad", "L", self.uMM, 2.6)
        
        self.AddParam("TPaste", "tpaste", self.uBool, True)
        self.AddParam("TPaste", "box rows", self.uNatural, 4)
natsfr's avatar
natsfr committed
        self.AddParam("TPaste", "box cols", self.uNatural, 4)
        self.AddParam("TPaste", "percent", self.uNatural, 50)
natsfr's avatar
natsfr committed

natsfr's avatar
natsfr committed
        self.AddParam("TVias", "tvias", self.uBool, True)
        self.AddParam("TVias", "rows", self.uNatural, 3)
        self.AddParam("TVias", "cols", self.uNatural, 3)
natsfr's avatar
natsfr committed
        self.AddParam("TVias", "drill", self.uMM, 0.3)
        self.AddParam("TVias", "size", self.uMM, 0.6)
        self.AddParam("TVias", "pitch", self.uMM, 1)
natsfr's avatar
natsfr committed

natsfr's avatar
natsfr committed
    def CheckParameters(self):
        self.CheckParamInt("Pads", "*nbpads")
        self.CheckParamInt("Pads", "*nbpads", is_multiple_of=4)
        self.CheckParamBool("Pads", "*oval")
        self.CheckParamBool("TPad", "*tpad")
        self.CheckParamBool("TVias", "*tvias")
        self.CheckParamBool("TPaste", "*tpaste")
natsfr's avatar
natsfr committed

natsfr's avatar
natsfr committed
        self.CheckParamInt("TPaste", "*box rows", min_value=2)
        self.CheckParamInt("TPaste", "*box cols", min_value=2)
        self.CheckParamInt("TPaste", "*percent")

natsfr's avatar
natsfr committed
    def GetValue(self):
        return "QFN%d_%dx%dmm" % (self.parameters["Pads"]["*nbpads"],pcbnew.ToMM(self.parameters["Pads"]["Width"]),pcbnew.ToMM(self.parameters["Pads"]["Length"]))

    def GetReferencePrefix(self):
        return "U"

    def DrawThermalPadSolderPaste(self, x, y, rows, cols, percent):
natsfr's avatar
natsfr committed
        # Calculate the paste area given percentage
        x_total_size = x / (math.sqrt(1/(percent/100)))
        y_total_size = y / (math.sqrt(1/(percent/100)))
natsfr's avatar
natsfr committed

natsfr's avatar
natsfr committed
        x_box = x_total_size / cols
        y_box = y_total_size / cols
natsfr's avatar
natsfr committed
        x_spacer = (x - cols * x_box) / (cols - 1)
natsfr's avatar
natsfr committed
        y_spacer = (y - rows * y_box) / (rows - 1)
natsfr's avatar
natsfr committed
        x_step = x_spacer + x_box
        y_step = y_spacer + y_box

        # Use PAD as Paste only but Kicad complains
        # Is it a valid use ?
        pastepad = PA.PadMaker(self.module).SMDPad(x_box, y_box, pcbnew.PAD_RECT)
        only_paste = pcbnew.LSET(pcbnew.F_Paste)
        pastepad.SetLayerSet(only_paste)
        array = ThermalViasArray(pastepad, cols, rows, x_step, y_step)
        array.SetFirstPadInArray(self.parameters["Pads"]["*nbpads"]+1)
        array.AddPadsToModule(self.draw)
natsfr's avatar
natsfr committed
    def BuildThisFootprint(self):
        tpad = self.parameters["TPad"]
        pads = self.parameters["Pads"]
natsfr's avatar
natsfr committed
        tvias = self.parameters["TVias"]
natsfr's avatar
natsfr committed
        tpaste = self.parameters["TPaste"]
natsfr's avatar
natsfr committed
        if(tpad["*tpad"]):
            thermal_pad = PA.PadMaker(self.module).SMDPad(tpad["W"], tpad["L"], pcbnew.PAD_RECT)

            #SWIG bitset LSET problem, commented out waiting for a fix
            #Please remove this Layer in the footprint editor
            #no_paste_lset = pcbnew.LSET((pcbnew.F_Cu, pcbnew.F_Mask), 2)
            #no_paste_lset = pcbnew.LSET(2, pcbnew.F_Cu, pcbnew.F_Mask)
            #thermal_pad.SetLayerSet(no_paste_lset)
            print PEASY.layer_dict
            no_paste_lset = PEASY._to_LayerSet(('F.Cu', 'F.Mask'))
            thermal_pad.SetLayerSet(no_paste_lset)

            origin = pcbnew.wxPoint(0,0)
natsfr's avatar
natsfr committed
            array = PA.PadLineArray(thermal_pad, 1, 0, False)
            array.SetFirstPadInArray(pads["*nbpads"]+1)
            array.AddPadsToModule(self.draw)
natsfr's avatar
natsfr committed
            if(tvias["*tvias"]):
                via_size = tvias["size"]
                via_drill = tvias["drill"]
                via_rows = tvias["*rows"]
                via_cols = tvias["*cols"]
                via_pitch = tvias["pitch"]
                thermal_via = PA.PadMaker(self.module).THRoundPad(via_size, via_drill)
                array = ThermalViasArray(thermal_via, via_cols, via_rows, via_pitch, via_pitch)
                array.SetFirstPadInArray(pads["*nbpads"]+1)
                array.AddPadsToModule(self.draw)
natsfr's avatar
natsfr committed
                if(tpaste["*tpaste"]):
                    self.DrawThermalPadSolderPaste(tpad["W"], tpad["L"], tpaste["*box rows"], tpaste["*box cols"], tpaste["*percent"])
nats's avatar
nats committed

natsfr's avatar
natsfr committed
        nb_pads_row = pads["*nbpads"] / 4;
        line_start = pads["pitch"] * (nb_pads_row - 1) / 2

        pad_len = pads["pad length"]
natsfr's avatar
natsfr committed
        fillet = pads["Fillet"]
        pad_total = pad_len + fillet
        len_2 = pads["Length"] / 2
        wid_2 = pads["Width"] / 2

        pad_center_l = (len_2 - pad_len + (pad_len+fillet)/2)
        pad_center_w = (wid_2 - pad_len + (pad_len+fillet)/2)
natsfr's avatar
natsfr committed
        pad_shape = pcbnew.PAD_OVAL if pads["*oval"] else pcbnew.PAD_RECT
natsfr's avatar
natsfr committed
        v_pad = PA.PadMaker(self.module).SMDPad(pads["pad width"], pad_total, shape=pad_shape)
        h_pad = PA.PadMaker(self.module).SMDPad(pad_total, pads["pad width"], shape=pad_shape)
natsfr's avatar
natsfr committed
        pin1pos = pcbnew.wxPoint(-pad_center_l, 0)
natsfr's avatar
natsfr committed
        array = PA.PadLineArray(v_pad, nb_pads_row, pads["pitch"], True, pin1pos)
        array.SetFirstPadInArray(1)
        array.AddPadsToModule(self.draw)

natsfr's avatar
natsfr committed
        pin1pos = pcbnew.wxPoint(0, pad_center_w)
natsfr's avatar
natsfr committed
        array = PA.PadLineArray(h_pad, nb_pads_row, pads["pitch"], False, pin1pos)
        array.SetFirstPadInArray(int(nb_pads_row + 1))
        array.AddPadsToModule(self.draw)

natsfr's avatar
natsfr committed
        pin1pos = pcbnew.wxPoint(pad_center_l, 0)
        array = PA.PadLineArray(v_pad, nb_pads_row, -pads["pitch"], True, pin1pos)
        array.SetFirstPadInArray(int(nb_pads_row*2 + 1))
        array.AddPadsToModule(self.draw)
natsfr's avatar
natsfr committed
        pin1pos = pcbnew.wxPoint(0, -pad_center_w)
natsfr's avatar
natsfr committed
        array = PA.PadLineArray(h_pad, nb_pads_row, -pads["pitch"], False, pin1pos)
        array.SetFirstPadInArray(int(nb_pads_row*3 + 1))
        array.AddPadsToModule(self.draw)

        self.draw.BoxWithDiagonalAtCorner(0, 0, pads["Length"], pads["Width"], pcbnew.FromMM(0.3))
natsfr's avatar
natsfr committed
        text_size = pcbnew.FromMM(1.2)
        self.draw.Value(0, pads["Width"] + fillet, text_size)
        self.draw.Reference(0, -pads["Width"] - fillet, text_size)

natsfr's avatar
natsfr committed
QFNWizard().register()