Advertisement
natsfr

Kicad cuistom QFN generator

Apr 6th, 2022
1,602
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 9.72 KB | None | 0 0
  1. #  This program is free software; you can redistribute it and/or modify
  2. #  it under the terms of the GNU General Public License as published by
  3. #  the Free Software Foundation; either version 2 of the License, or
  4. #  (at your option) any later version.
  5. #
  6. #  This program is distributed in the hope that it will be useful,
  7. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9. #  GNU General Public License for more details.
  10. #
  11. #  You should have received a copy of the GNU General Public License
  12. #  along with this program; if not, write to the Free Software
  13. #  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  14. #  MA 02110-1301, USA.
  15. #
  16.  
  17. from __future__ import division
  18. import pcbnew
  19.  
  20. import pcbnew
  21. import FootprintWizardBase
  22. import PadArray as PA
  23.  
  24. class QFNWizard(FootprintWizardBase.FootprintWizard):
  25.  
  26.     def GetName(self):
  27.         return "QFNNats"
  28.  
  29.     def GetDescription(self):
  30.         return "Nats Quad Flat No-lead (QFN) footprint wizard"
  31.  
  32.     def GenerateParameterList(self):
  33.         self.AddParam("Pads", "nrow", self.uInteger, 10)
  34.         self.AddParam("Pads", "ncol", self.uInteger, 5)
  35.         self.AddParam("Pads", "pitch", self.uMM, 0.5, designator='e')
  36.         self.AddParam("Pads", "width", self.uMM, 0.25, designator='X1')
  37.         self.AddParam("Pads", "length", self.uMM, 1.5, designator='Y1')
  38.         self.AddParam("Pads", "fillet", self.uMM, 0.3)
  39.         self.AddParam("Pads", "oval", self.uBool, True)
  40.  
  41.         self.AddParam("EPad", "epad", self.uBool, True)
  42.         self.AddParam("EPad", "width", self.uMM, 10, designator="E2")
  43.         self.AddParam("EPad", "length", self.uMM, 10, designator="D2")
  44.         self.AddParam("EPad", "thermal vias", self.uBool, False)
  45.         self.AddParam("EPad", "ignore drill autosize", self.uBool, False)
  46.         self.AddParam("EPad", "thermal vias drill", self.uMM, 1, min_value=0.1)
  47.         self.AddParam("EPad", "x divisions", self.uInteger, 2, min_value=1)
  48.         self.AddParam("EPad", "y divisions", self.uInteger, 2, min_value=1)
  49.         self.AddParam("EPad", "paste margin", self.uMM, 0.1)
  50.  
  51.         self.AddParam("Package", "width", self.uMM, 14, designator='E')
  52.         self.AddParam("Package", "height", self.uMM, 14, designator='D')
  53.         self.AddParam("Package", "margin", self.uMM, 0.25, minValue=0.2)
  54.         self.AddParam("Package", "mark1", self.uBool, False)
  55.         self.AddParam("Package", "radmark1", self.uMM, 0.5)
  56.  
  57.     @property
  58.     def pads(self):
  59.         return self.parameters['Pads']
  60.  
  61.     @property
  62.     def epad(self):
  63.         return self.parameters['EPad']
  64.  
  65.     @property
  66.     def package(self):
  67.         return self.parameters['Package']
  68.  
  69.     def CheckParameters(self):
  70.         pass
  71.  
  72.     def GetValue(self):
  73.  
  74.         return "QFN-{r}x{c}_{ep}{x:g}x{y:g}_Pitch{p:g}mm".format(
  75.                 r = self.pads['nrow'],
  76.                 c = self.pads['ncol'],
  77.                 ep = "EP_" if self.epad['epad'] else '',
  78.                 x = pcbnew.ToMM(self.package['width']),
  79.                 y = pcbnew.ToMM(self.package['height']),
  80.                 p = pcbnew.ToMM(self.pads['pitch'])
  81.                 )
  82.  
  83.     def BuildThisFootprint(self):
  84.  
  85.         pad_pitch = self.pads["pitch"]
  86.         pad_length = self.pads["length"]
  87.         # Fillet allows to define how much of the pad is outside of the package
  88.         pad_fillet = self.pads["fillet"]
  89.         pad_width = self.pads["width"]
  90.  
  91.         v_pitch = self.package["height"]
  92.         h_pitch = self.package["width"]
  93.  
  94.         pads_per_row = int(self.pads["nrow"])
  95.         pads_per_col = int(self.pads["ncol"])
  96.  
  97.         row_len = (pads_per_row - 1) * pad_pitch
  98.         col_len = (pads_per_col - 1) * pad_pitch
  99.  
  100.         pad_shape = pcbnew.PAD_SHAPE_OVAL if self.pads["oval"] else pcbnew.PAD_SHAPE_RECT
  101.  
  102.         h_pad = PA.PadMaker(self.module).SMDPad( pad_length + pad_fillet, pad_width,
  103.                                                  shape=pad_shape, rot_degree=90.0)
  104.         v_pad = PA.PadMaker(self.module).SMDPad( pad_length + pad_fillet, pad_width, shape=pad_shape)
  105.  
  106.         h_pitch = h_pitch / 2 - pad_length + (pad_length+pad_fillet)/2
  107.         v_pitch = v_pitch / 2 - pad_length + (pad_length+pad_fillet)/2
  108.  
  109.         #left row
  110.         pin1Pos = pcbnew.wxPoint(-h_pitch, 0)
  111.         array = PA.PadLineArray(h_pad, pads_per_col, pad_pitch, True, pin1Pos)
  112.         array.SetFirstPadInArray(1)
  113.         array.AddPadsToModule(self.draw)
  114.  
  115.         #bottom row
  116.         pin1Pos = pcbnew.wxPoint(0, v_pitch)
  117.         array = PA.PadLineArray(v_pad, pads_per_row, pad_pitch, False, pin1Pos)
  118.         array.SetFirstPadInArray(pads_per_col + 1)
  119.         array.AddPadsToModule(self.draw)
  120.  
  121.         #right row
  122.         pin1Pos = pcbnew.wxPoint(h_pitch, 0)
  123.         array = PA.PadLineArray(h_pad, pads_per_col, -pad_pitch, True,
  124.                                 pin1Pos)
  125.         array.SetFirstPadInArray(pads_per_col+pads_per_row + 1)
  126.         array.AddPadsToModule(self.draw)
  127.  
  128.         #top row
  129.         pin1Pos = pcbnew.wxPoint(0, -v_pitch)
  130.         array = PA.PadLineArray(v_pad, pads_per_row, -pad_pitch, False,
  131.                                 pin1Pos)
  132.         array.SetFirstPadInArray(2*pads_per_col+pads_per_row + 1)
  133.         array.AddPadsToModule(self.draw)
  134.  
  135.         lim_x = self.package["width"] / 2
  136.         lim_y = self.package["height"] / 2
  137.         inner = (row_len / 2) + pad_pitch
  138.  
  139.         # epad
  140.         epad_width   = self.epad["width"]
  141.         epad_length  = self.epad["length"]
  142.  
  143.         epad_ny = self.epad["x divisions"]
  144.         epad_nx = self.epad["y divisions"]
  145.  
  146.         epad_via_drill = self.epad["thermal vias drill"]
  147.  
  148.         # Create a central exposed pad?
  149.         if self.epad['epad'] == True:
  150.            
  151.             epad_num = pads_per_row * 2 + pads_per_col * 2 + 1
  152.  
  153.             epad_w = epad_length / epad_nx
  154.             epad_l = epad_width / epad_ny
  155.  
  156.             # Create the epad
  157.             epad = PA.PadMaker(self.module).SMDPad( epad_w, epad_l, shape=pcbnew.PAD_SHAPE_RECT )
  158.             epad.SetLocalSolderPasteMargin( -1 * self.epad['paste margin'] )
  159.             # set pad layers
  160.             layers = pcbnew.LSET(pcbnew.F_Mask)
  161.             layers.AddLayer(pcbnew.F_Cu)
  162.             layers.AddLayer(pcbnew.F_Paste)
  163.             epad.SetName(epad_num)
  164.  
  165.             array = PA.EPADGridArray( epad, epad_ny, epad_nx, epad_l, epad_w, pcbnew.wxPoint(0,0) )
  166.             array.SetFirstPadInArray(epad_num)
  167.             array.AddPadsToModule(self.draw)
  168.  
  169.             if self.epad['thermal vias']:
  170.  
  171.                 # create the thermal via
  172.                 via_diam = min(epad_w, epad_l) / 2
  173.                 via_drill = min(via_diam / 2, epad_via_drill)
  174.                 if(self.epad["ignore drill autosize"]):
  175.                     via_drill = epad_via_drill
  176.                 via = PA.PadMaker(self.module).THRoundPad(via_diam, via_drill)
  177.                 layers = pcbnew.LSET.AllCuMask()
  178.                 layers.AddLayer(pcbnew.B_Mask)
  179.                 layers.AddLayer(pcbnew.F_Mask)
  180.                 via.SetLayerSet(layers)
  181.  
  182.                 via_array = PA.EPADGridArray(via, epad_ny, epad_nx, epad_l, epad_w, pcbnew.wxPoint(0,0) )
  183.                 via_array.SetFirstPadInArray(epad_num)
  184.                 via_array.AddPadsToModule(self.draw)
  185.  
  186.         # Draw the package outline on the F.Fab layer
  187.         bevel = min( pcbnew.FromMM(1.0), self.package['width']/2, self.package['height']/2 )
  188.  
  189.         self.draw.SetLayer(pcbnew.F_Fab)
  190.  
  191.         w = self.package['width']
  192.         h = self.package['height']
  193.  
  194.         self.draw.BoxWithDiagonalAtCorner(0, 0, w, h, bevel)
  195.  
  196.         # Silkscreen
  197.         self.draw.SetLayer(pcbnew.F_SilkS)
  198.  
  199.         offset = self.draw.GetLineThickness()
  200.         cliph = row_len / 2 + self.pads['pitch']
  201.         clipv = col_len / 2 + self.pads['pitch']
  202.  
  203.         self.draw.Polyline( [ [ cliph, -h/2-offset], [ w/2+offset,-h/2-offset], [ w/2+offset, -clipv] ] ) # top right
  204.         self.draw.Polyline( [ [ cliph,  h/2+offset], [ w/2+offset, h/2+offset], [ w/2+offset,  clipv] ] ) # bottom right
  205.         self.draw.Polyline( [ [-cliph,  h/2+offset], [-w/2-offset, h/2+offset], [-w/2-offset,  clipv] ] ) # bottom left
  206.  
  207.         # Add pin-1 indication as per IPC-7351C
  208.         self.draw.Line(-cliph, -h/2-offset, -w/2-pad_length/2, -h/2-offset)
  209.  
  210.         # Add round marking for pin-1
  211.         if(self.package["mark1"] == True):
  212.             cmargin = self.package["margin"]
  213.             centerx = lim_x + cmargin + self.package["radmark1"] + offset*2 + pad_fillet
  214.             centery = lim_y + cmargin - offset - self.package["radmark1"]
  215.             self.draw.Circle(-centerx, -centery, self.package["radmark1"])
  216.  
  217.         # Courtyard
  218.         cmargin = self.package["margin"]
  219.         self.draw.SetLayer(pcbnew.F_CrtYd)
  220.  
  221.         sizex = (lim_x + cmargin) * 2 + pad_length + pad_fillet*2
  222.         sizey = (lim_y + cmargin) * 2 + pad_length + pad_fillet*2
  223.  
  224.         # round size to nearest 0.1mm, rectangle will thus land on a 0.05mm grid
  225.         sizex = pcbnew.PutOnGridMM(sizex, 0.1)
  226.         sizey = pcbnew.PutOnGridMM(sizey, 0.1)
  227.         # set courtyard line thickness to the one defined in KLC
  228.         thick = self.draw.GetLineThickness()
  229.         self.draw.SetLineThickness(pcbnew.FromMM(0.05))
  230.         self.draw.Box(0, 0, sizex, sizey)
  231.         # restore line thickness to previous value
  232.         self.draw.SetLineThickness(pcbnew.FromMM(thick))
  233.  
  234.         #reference and value
  235.         text_size = self.GetTextSize()  # IPC nominal
  236.         text_offset = v_pitch / 2 + text_size + pad_length / 2
  237.  
  238.         self.draw.Value(0, text_offset, text_size)
  239.         self.draw.Reference(0, -text_offset, text_size)
  240.  
  241.         # set SMD attribute
  242.         self.module.SetAttributes(pcbnew.PAD_ATTRIB_SMD)
  243.  
  244. QFNWizard().register()
  245.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement