Parametric M.2 mockup generator
// M.2 Mockup Generator | |
// by Nirav Patel <https://eclecti.cc> | |
// | |
// To the extent possible under law, Nirav Patel has waived all copyright | |
// and related or neighboring rights to M.2 Mockup Generator. | |
// | |
// An easy to use parametric M.2 mockup generator. | |
// See https://en.wikipedia.org/wiki/M.2 for more information about the | |
// M.2 (formerly NGFF) standard. | |
edge_width = 19.85; | |
edge_length = 4; | |
edge_r = 0.5; | |
hole_r = 1.75; | |
key_r = 0.6; | |
key_length = 3.5; | |
pcb_thick = 0.8; | |
bottom_edge_keepout = 5.2; | |
top_gnd_pad_r = 2.75; | |
bottom_gnd_pad_r = 3; | |
bottom_gnd_pad_offset = 1; | |
bevel = 0.3; | |
bevel_angle = 20; | |
$fn=50; | |
module key_cutout() { | |
union() { | |
translate([0, key_length - key_r]) circle(r = key_r); | |
translate([-key_r, -1]) square([key_r*2,key_length - key_r +1]); | |
} | |
} | |
function get_key(key_type="mm") = | |
key_table[search([key_type],key_table,1,0)[0]][1]; | |
key_table = [["", 100], ["A", 6.625], ["B", 5.625], ["C", 4.625], ["D", 3.625], ["E", 2.625], ["F", 1.625], ["G", -1.125], ["H", -2.125], ["J", -3.125], ["K", -4.125], ["L", -5.125], ["M", -6.125]]; | |
module m2_2d(width=22, length=30, key="M", key2="") { | |
// Start with a 2d version | |
difference() { | |
square([width, length]); | |
// Left cutout | |
translate([(width-edge_width)/2-width, -edge_r]) square([width, edge_length]); | |
translate([(width-edge_width)/2-width-edge_r, 0]) square([width, edge_length]); | |
translate([(width-edge_width)/2-edge_r, edge_length-edge_r]) circle(r=edge_r); | |
// Right cutout | |
translate([width-(width-edge_width)/2, -edge_r]) square([width, edge_length]); | |
translate([width-(width-edge_width)/2+edge_r, 0]) square([width, edge_length]); | |
translate([width-(width-edge_width)/2+edge_r, edge_length-edge_r]) circle(r=edge_r); | |
// Hole cutout | |
translate([width/2, length]) circle(r = hole_r); | |
// Key cutouts | |
translate([width/2 + get_key(key), 0]) | |
key_cutout(); | |
translate([width/2 + get_key(key2), 0]) | |
key_cutout(); | |
} | |
} | |
module m2_text(width=22, length=30, height="", key="", key2="") { | |
if (key2 != "") { | |
string = str(width, length, "-", height, "-", key, "-", key2); | |
linear_extrude(height = 1) | |
text(string, size = 2.5); | |
} else { | |
string = str(width, length, "-", height, "-", key); | |
linear_extrude(height = 1) | |
text(string, size = 2.5); | |
} | |
} | |
module m2(width=22, length=30, height="", key="", key2="") { | |
union() { | |
difference() { | |
linear_extrude(height = pcb_thick) | |
m2_2d(width, length, key, key2); | |
// The card edge bevel | |
translate([0, bevel, 0]) rotate([180-bevel_angle, 0, 0]) cube([width, 10, 10]); | |
translate([0, bevel, pcb_thick]) rotate([90+bevel_angle, 0, 0]) cube([width, 10, 10]); | |
} | |
difference() { | |
// The various component keepout zones and embossed text | |
if (height == "S1") { | |
difference() { | |
translate([0, edge_length, pcb_thick]) cube([width, length-edge_length, 1.2]); | |
translate([1, edge_length+1, pcb_thick+1.2-0.5]) m2_text(width, length, height, key, key2); | |
} | |
} else if (height == "S2") { | |
difference() { | |
translate([0, edge_length, pcb_thick]) cube([width, length-edge_length, 1.35]); | |
translate([1, edge_length+1, pcb_thick+1.35-0.5]) m2_text(width, length, height, key, key2); | |
} | |
} else if (height == "S3") { | |
difference() { | |
translate([0, edge_length, pcb_thick]) cube([width, length-edge_length, 1.5]); | |
translate([1, edge_length+1, pcb_thick+1.5-0.5]) m2_text(width, length, height, key, key2); | |
} | |
} else if (height == "D1") { | |
difference() { | |
translate([0, edge_length, pcb_thick]) cube([width, length-edge_length, 1.2]); | |
translate([1, edge_length+1, pcb_thick+1.2-0.5]) m2_text(width, length, height, key, key2); | |
} | |
translate([0, bottom_edge_keepout, -1.35]) cube([width, length-bottom_edge_keepout, 1.35]); | |
} else if (height == "D2") { | |
difference() { | |
translate([0, edge_length, pcb_thick]) cube([width, length-edge_length, 1.35]); | |
translate([1, edge_length+1, pcb_thick+1.35-0.5]) m2_text(width, length, height, key, key2); | |
} | |
translate([0, bottom_edge_keepout, -1.35]) cube([width, length-bottom_edge_keepout, 1.35]); | |
} else if (height == "D3") { | |
difference() { | |
translate([0, edge_length, pcb_thick]) cube([width, length-edge_length, 1.5]); | |
translate([1, edge_length+1, pcb_thick+1.5-0.5]) m2_text(width, length, height, key, key2); | |
} | |
translate([0, bottom_edge_keepout, -1.35]) cube([width, length-bottom_edge_keepout, 1.35]); | |
} else if (height == "D4") { | |
difference() { | |
translate([0, edge_length, pcb_thick]) cube([width, length-edge_length, 1.5]); | |
translate([1, edge_length+1, pcb_thick+1.5-0.5]) m2_text(width, length, height, key, key2); | |
} | |
translate([0, bottom_edge_keepout, -0.7]) cube([width, length-bottom_edge_keepout, 0.7]); | |
} else if (height == "D5") { | |
difference() { | |
translate([0, edge_length, pcb_thick]) cube([width, length-edge_length, 1.5]); | |
translate([1, edge_length+1, pcb_thick+1.5-0.5]) m2_text(width, length, height, key, key2); | |
} | |
translate([0, bottom_edge_keepout, -1.5]) cube([width, length-bottom_edge_keepout, 1.5]); | |
} else { | |
translate([1, edge_length+1, pcb_thick-0.5]) m2_text(width, length, height, key, key2); | |
} | |
// The ground pad keepouts | |
translate([width/2, length, pcb_thick]) cylinder(r = top_gnd_pad_r, h = 10); | |
translate([width/2, length-bottom_gnd_pad_offset, -10]) { | |
cylinder(r = bottom_gnd_pad_r, h = 10); | |
translate([-bottom_gnd_pad_r, 0, 0]) cube([bottom_gnd_pad_r*2, bottom_gnd_pad_offset, 10]); | |
} | |
} | |
} | |
} | |
m2(width=22, length=30, height="S3", key="A", key2="E"); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment