3
\$\begingroup\$

I have a complete board which is sent to factory. However, for pricing reasons it would be better to mirror the whole board. This means that everything that was on the top, will be on the bottom, and vice-versa.

How can I do this in Eagle? The components and wires should remain as-is. But everything goes onto the other side.

Could you recommend something to do this?

Thanks.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ How about you rename the layer names and export the gerber?. If the connections are as-is i don't understand how it is going to affect the manufacturing costs? \$\endgroup\$
    – ammar.cma
    Commented Sep 14, 2016 at 9:20
  • \$\begingroup\$ I think it is better not tricking with the layer names. After a few months or years I'd bet you won't remember which layer is renamed to what. Regarding the cost: it's because the silk screen. This mirrored one has the silk on its bottom. But none of the others have bottom silk. So in this case I need to order a layer for the bottom silk too which is avoidable by mirroring the whole board. \$\endgroup\$
    – Daniel
    Commented Sep 15, 2016 at 6:29

2 Answers 2

2
\$\begingroup\$

Go to the layout window in Eagle, activate the Group Tool, mark the whole board. The next step is to select the Mirror Tool, hold down CTRL and click once on the board. That's it.

\$\endgroup\$
4
  • \$\begingroup\$ Thanks. This means that all and everything (wires and components) that were on the tPlace will be on the bPlace afterwards? \$\endgroup\$
    – Daniel
    Commented Sep 15, 2016 at 9:53
  • \$\begingroup\$ Yes, basically the layers with t... prefix change to b... prefix and vice versa. \$\endgroup\$
    – auoa
    Commented Nov 28, 2016 at 16:17
  • \$\begingroup\$ I had to right click to mirror the group :) Thanks for the tip! \$\endgroup\$
    – joakimk
    Commented Jul 27, 2022 at 9:51
  • \$\begingroup\$ This isn't working for me. None of the components or traces move to the top side using this method. \$\endgroup\$
    – Landon
    Commented Aug 28, 2023 at 2:26
0
\$\begingroup\$

As I mentioned in my comment on the answer given by @auoa, I wasn't able to mirror the group using their instructions. I am using the latest version of Eagle which is now built in to Fusion 360. Maybe there was a bug or nuance error on my part... Nevertheless, here's the simple solution that worked for me:

I just added this ULP file to my local F360 ULP directory (find the directory by clicking "Browse..." button after typing Shift+U). Then enter "run mirror-board.ulp" in the command line.

I'll add the ULP code here incase something happens to the Github link...

#usage "Mirror board (with all Layers)<p>"
       "<author>Author: [email protected]</author>"

#require 5.0600

// THIS PROGRAM IS PROVIDED AS IS AND WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED
// Version 1.01 -- 2006-09-15 [email protected]
//                 2008-04-10 changed GROUP ... (>x y); [email protected]
//
// Version 1.02 -- 2009-12-01 unlock and lock emlements, swap layer colors and fill  [email protected]
//                            check via stack for blind or micro vias

string Version = "1.02";
int test = 0;

string cmd;
int    lVisible[];
int    useLayer[];
int    lcolor[];
int    lfill[];
string lNames[] = { " " };

string lockName[];
int    cntlock = 0;

int    maxX = INT_MIN;
int    minX = INT_MAX;
int    maxY = INT_MIN;
int    minY = INT_MAX;
int    bminx, bmaxx, bminy, bmaxy;

int uval = 1;

if (board) board(B) uval = B.grid.unit;
string unit[] = { "Micron", "mm", "Mil", "Inch" };
int    unitPrec[] = { 0, 1, 1, 3 }, RoundFactor = pow(10, unitPrec[uval]);

real u2u(int v) {
  switch (uval) {
    case GRID_UNIT_MIC  : return u2mic(v);
                          break;

    case GRID_UNIT_MM     : return u2mm(v);
                          break;

    case GRID_UNIT_MIL  : return u2mil(v);
                          break;

    case GRID_UNIT_INCH : return u2inch(v);
                          break;
  }
}


void checkmaxmin(int x1, int x2, int y1, int y2) {
  if (x1 > maxX) maxX = x1;
  if (x2 > maxX) maxX = x2;
  if (y1 > maxY) maxY = y1;
  if (y2 > maxY) maxY = y2;
  if (x1 < minX) minX = x1;
  if (x2 < minX) minX = x2;
  if (y1 < minY) minY = y1;
  if (y2 < minY) minY = y2;
  return;
}

void checkarc( int x1, int x2, int y1, int y2, int xc, int yc, real angle1, real angle2, real radius) {
  checkmaxmin( x1, x2, y1, y2 );
  if ( angle2 > angle1 + 270.0) {
    if     ( angle1 < 90  ) checkmaxmin( x1         , xc - radius, yc + radius, yc - radius );
    else if( angle1 < 180 ) checkmaxmin( xc - radius, xc + radius, y1         , yc - radius );
    else if( angle1 < 270 ) checkmaxmin( x1         , xc + radius, yc - radius, yc + radius );
    else if( angle1 < 360 ) checkmaxmin( xc + radius, xc - radius, y1         , yc + radius );
  }
  else if( angle2 > angle1 + 180.0) {
    if     ( angle1 < 90  ) checkmaxmin( x1         , xc - radius, yc + radius, y2          );
    else if( angle1 < 180 ) checkmaxmin( x1         , xc - radius, yc - radius, y2          );
    else if( angle1 < 270 ) checkmaxmin( x1         , xc + radius, yc - radius, y2          );
    else if( angle1 < 360 ) checkmaxmin( x1         , xc + radius, yc + radius, y2          );
  }
  else if( angle2 > angle1 + 90.0 ) {
    if     ( angle1 < 90  ) checkmaxmin( x1         , x2         , yc + radius, y2          );
    else if( angle1 < 180 ) checkmaxmin( x1         , xc - radius, y1         , y2          );
    else if( angle1 < 270 ) checkmaxmin( x1         , x2         , yc - radius, y2          );
    else if( angle1 < 360 ) checkmaxmin( x1         , xc + radius, y1         , y2          );
  }
  return;
}


real WireLength(int x1, int x2, int y1, int y2) {
  return sqrt( pow(u2u(x2) - u2u(x1), 2) + pow( u2u(y2) - u2u(y1), 2));
}


void lock_elements(void) {
  for (int lc = 0; lc < cntlock; lc++) {
    cmd += "LOCK " + lockName[lc] + ";\n";
  }
  return;
}

void setcolor(void) {
  string s;
  sprintf(s, "SET COLOR_LAYER  1 %d;\n", lcolor[16]);  // 2009-12-01 shwap layer color and fill
  cmd += s;
  sprintf(s, "SET FILL_LAYER   1 %d;\n", lfill[16]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 16 %d;\n", lcolor[1]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  16 %d;\n", lfill[1]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 21 %d;\n", lcolor[22]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  21 %d;\n", lfill[22]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 22 %d;\n", lcolor[21]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  22 %d;\n", lfill[21]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 23 %d;\n", lcolor[24]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  23 %d;\n", lfill[24]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 24 %d;\n", lcolor[23]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  24 %d;\n", lfill[23]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 25 %d;\n", lcolor[26]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  25 %d;\n", lfill[26]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 26 %d;\n", lcolor[25]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  26 %d;\n", lfill[25]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 27 %d;\n", lcolor[28]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  27 %d;\n", lfill[28]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 28 %d;\n", lcolor[27]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  28 %d;\n", lfill[27]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 29 %d;\n", lcolor[30]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  29 %d;\n", lfill[30]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 30 %d;\n", lcolor[29]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  30 %d;\n", lfill[29]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 31 %d;\n", lcolor[32]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  31 %d;\n", lfill[32]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 32 %d;\n", lcolor[31]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  32 %d;\n", lfill[31]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 51 %d;\n", lcolor[52]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  51 %d;\n", lfill[52]);
  cmd += s;
  sprintf(s, "SET COLOR_LAYER 52 %d;\n", lcolor[51]);
  cmd += s;
  sprintf(s, "SET FILL_LAYER  52 %d;\n", lfill[51]);
  cmd += s;
  return;
}

int checkVia(UL_VIA V) {
  if (V.start != 1 || V.end != 16) return 1;
  return 0;
}

// main
if (board) {
  board(B) {
    int verror = 0;
    B.signals(S) S.vias(V) verror += checkVia(V);
    if (verror) {
      dlgMessageBox("!Do not use this ULP if used blind or micro via(s)!", "OK");
      exit(-1);
    }
    bminx = B.area.x1;
    bmaxx = B.area.x2;
    bminy = B.area.y1;
    bmaxy = B.area.y2;
    B.layers(L) {
      lNames[L.number] = L.name;
      lVisible[L.number] = L.visible;
      useLayer[L.number] = L.used;
      lcolor[L.number] = L.color;
      lfill[L.number] = L.fill;
    }
    B.wires(W) {
      if (W.layer == 20) {
        if (W.arc) {
          checkarc(W.arc.x1, W.arc.x2, W.arc.y1, W.arc.y2, W.arc.xc, W.arc.yc, W.arc.angle1, W.arc.angle2, W.arc.radius);
        }
        else {
          checkmaxmin( W.x1, W.x2, W.y1, W.y2 );
        }
      }
    }
    B.circles(C) {
      if (C.layer == 20) {
        checkmaxmin( C.x - C.radius, C.x + C.radius, C.y - C.radius, C.y + C.radius );
      }
    }
    B.elements(E) {
      E.package.wires(W) {
        if (W.layer == 20) {
          // *** Dimension in Packages ***
          if (W.arc) {
            checkarc(W.arc.x1, W.arc.x2, W.arc.y1, W.arc.y2, W.arc.xc, W.arc.yc, W.arc.angle1, W.arc.angle2, W.arc.radius);
          }
          else {
            checkmaxmin( W.x1, W.x2, W.y1, W.y2 );
          }
        }
      }
      E.package.circles(C) {
        if (C.layer == 20) {
          checkmaxmin( C.x - C.radius, C.x + C.radius, C.y - C.radius, C.y + C.radius );
        }
      }
    }
    string s;
    sprintf(s, "DISPLAY ALL;\n");
    cmd += s;
    sprintf(s, "GROUP ALL;\n");
    cmd += s;
    cmd += "LOCK (>S 0 0);\n";  // unlock all  2009-11-01

    sprintf(s, "GRID FINEST;\nMIRROR (>%.4f %.4f);\nGRID LAST;\n",
                  (u2u(maxX) + u2u(minX)) / 2, u2u(minY) );
    cmd += s;
    cmd += "DISPLAY NONE ";
    for(int l = 1; l < 256; l++) {
      if (lNames[l]) {  // Layer defined
        if (lVisible[l]) {
          if (l == 1 || l == 16 || l == 21 || l == 22 || l == 23 || l == 24 || l == 25 || l == 26 || l == 27 || l == 28 || l == 29 || l == 30 || l == 31 || l == 32 || l == 51 || l == 52 ) {
            if      (l ==  1) sprintf(s, " %d", 16);  // 2009-12-01 shwap visible layers
            else if (l == 16) sprintf(s, " %d",  1);
            else if (l == 21) sprintf(s, " %d", 22);
            else if (l == 22) sprintf(s, " %d", 21);
            else if (l == 23) sprintf(s, " %d", 24);
            else if (l == 24) sprintf(s, " %d", 23);
            else if (l == 25) sprintf(s, " %d", 26);
            else if (l == 26) sprintf(s, " %d", 25);
            else if (l == 27) sprintf(s, " %d", 28);
            else if (l == 28) sprintf(s, " %d", 27);
            else if (l == 29) sprintf(s, " %d", 30);
            else if (l == 30) sprintf(s, " %d", 29);
            else if (l == 31) sprintf(s, " %d", 32);
            else if (l == 32) sprintf(s, " %d", 31);
            else if (l == 51) sprintf(s, " %d", 52);
            else if (l == 52) sprintf(s, " %d", 51);
          }
          else sprintf(s, " %d", l);
          cmd += s;
        }
      }
    }
    cmd += ";\n";
    B.elements(E) if (E.locked) cmd += "LOCK " + E.name + ";\n";   // 2009-12-01
    setcolor();
  }
}

if (test) dlgDialog("Test") {
  dlgTextEdit(cmd);
  dlgHBoxLayout  {
    dlgPushButton("ok") dlgAccept();
    dlgPushButton("esc") { dlgReject(); exit(-1); }
  }
};
exit(cmd);
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.