A PS/2 interface and PCB routing progress

Routing the MAXI000 board has been a slog. A mostly enjoyable slog, but a slog all the same.

Before actually getting to the PCB design, the first task was to associate footprints with each schematic symbol.

I always dread this task; you are presented with an intimidating list of symbols from the schematic and must pick the correct footprint for the component using some pretty basic search functions. It was a particularly big chore for the MAXI000 because it is my first proper SMT board. And due to the sheer number of different size parts that are available, choosing the right one is tricky.

With through-hole resistors, for example, there are really just two choices: the resistor can be mounted flat against the board or vertically. Whilst there are larger resistors available, for use in power supplies and other high current applications, they are infrequently used. Likewise through-hole ICs are generally DIP and a 16 pin IC has really only one footprint choice.

SMT footprints are not nearly so simple.

Firstly, there are many resistor sizes in use, from 1206 (which is what MAXI000 uses) to the relatively tiny 0403 and even smaller. This is not really a problem as it is clear what size a part is since it can be measured if documentation isn’t available.

ICs are a different matter. The 74HC245 (PDF) octal bus transceiver from Texas Instruments is available in 4 different “DIP style” SMT package types (this does not include other variant factors, like supported temperature range). This includes two width variants with 50mil spaced pins, which is the spacing the MAXI000 generally uses so as to make things manageable and consistent.

Ordering the right size parts is tricky. I have so far ordered the wrong size parts three times. Hopefully I will learn from my mistakes.

As usual this is a 4 layer board. I’m quite sure it would be possible to route the power connections on this kind of board with only two layers, but the skill level required is too great for me, at least at the moment.

After associating the correct footprint to each symbol, the next task was to lay out sections of related parts, for example the connections specific to the SC16C654 (PDF) quad UART.

The general idea when laying out closely related parts was to keep the traces on the component side of the board, with the back side used only when essential to do so. At the same time, all “DIP style” ICs are orientated left to right, with the component side favoring traces perpendicular to the rows of IC pins, ie. traces on the front side should tend to run up and down the board

One particularly interesting area of the board is the video memory IC buses and how they join to the Beta FPGA. I used manual back annotations to map the address and data buses (and control signals) to convenient pins on the FPGA, as this picture shows:

Pretty much the entire set of traces between the FPGA and the memory ICs is on the component side, which would have been impossible to achieve without remapping the FPGA connections to match up with the memory ICs leads.

Also, to save some board space, the passive parts, including decoupling capacitors and the resistors that make up the SVGA DAC, are on the back side of the board.

At this stage the “islands” of parts remained isolated. After creating these islands, and it’s what dictated the size of the board, the task of figuring out how to place the connectors. The board has a quite lot of them:

There’s also:

  • 72 pin SIMM slot
  • 40 pin IDC IDE header
  • 2 by 40 pin expansion header
  • 10 pin IDC JTAG header

Although these connectors do not have to be at the edge of the board.

I like to have the bottom edge of the board, which is nearest the keyboard, clear of external connectors so placed the SIMM slot there. The expansion connector was placed at the right edge, allowing a hypothetical daughter board to rest over most of the board. The remaining connectors were placed along the top and left edges.

After this, the mammoth job of trying to link everything together.

My initial attempt at routing the board made heavy use of KiCAD‘s push routing feature. This is a fantastic feature, but I eventually found that it was not very useful when routing parallel buses and ended up doing most of the routing with a 20mil grid. But because of the “tighter” areas, especially around the PLCC flash sockets, 6mil traces were used with some areas making use of 6mil clearances, which is the tightest clearances allpcb.com provides with its standard service.

The board needs a final check, but here’s a picture of the board, without the internal layers, as it currently stands:

I am pretty pleased with the board. There’s obviously many, many vias. I’m sure a professional PCB router would be appaled, but I’ve learned a lot through this proces. SMT boards are a different animal to through-hole boards, and not only because of the more finely pitched parts: the sides of the board are no longer equal. The technique of putting traces in difference orientations on different sides works, but only up to a point. The routing has to favor the front side, since that is where the componets are.

The obligatory 3D render:

For completeness, here’s a render of the back side of the board:

After satisfying myself that the board was basically complete I thought it would be sensible to verify that the footprints chosen matched the sizes of the parts I had ordered. I did this using the low tech approach of printing out the design on paper and placing some of the key parts on it:

One critical part is missing from this dry-run: the two EPF10K20 (PDF) FPGAs, which I have yet to order.

At the point I took the above picture the layout had one footprint problem: a resistor array, of which the board has 6 parts, was the wrong size. This was quickly solved by switching footprint in KiCAD and reworking the connections, and actually the board is better for it as the correct footprint is a good deal larger, meaning the traces aren’t so bunched together.

There’s a few differences in the schematic used to layout the board, relative to the schematic published in the previous post. As I worked on the PCB layout, I tweaked the schematic in small ways. Hopefully by the time of the next post I’ll have collated the schematics togehter, with the PCB design files, for anyone interested.

The first change is the aforementioned re-pinning of the video memory connections to the Beta FPGA.

There are some other minor tweaks to the FPGA pins, including routing the /VPA 68000 pin to Beta instead of Alpha, as it’s main use is for indicating an autovectored interrupt, and Beta is the device responsible for signalling the processor of an interrupt. Also, another connection has been made from Beta to Alpha so it can indicate that Alpha must assert /DTACK. This will be needed, for example, if an SPI access is requested but the SPI bus is busy, at that moment, with a PCM sound SPI write to the MCP4902 (PDF), which may occur asynchronously to the 68000 if Beta is writing values to it from its attached memory. There may be other unforeseen reasons why the 68000 should be stalled via accesses initiated to Beta, and to not account for this does not seem wise. This means there are now three links between Alpha and Beta FPGAs: a Chip Select to Beta, an interrupt request to Beta, and a /DTACK request to Alpha. Of course these are only the anticipated uses of those connections.

To better balance the unused FPGA pins, which are exposed at the expansion connector, the user-addressable LED and buzzer are now attached to Alpha instead of Beta. Three pins on each FPGA are then available to a potential expansion daughter board.

I have removed the write protect jumper for the two 512K x 8 flashes, SST39SF040 (PDF), since they are not needed due to inadvertent writes being essentially impossible due to the way that write requests are setup in the flash.

The board includes a few test points for attaching the logic analyzer. These might be useful for the bring up to diagnose any errors etc. The expansion connector is usually sufficient for this purpose but a way to view more “burred” signals could be useful, especially around the SIMM slot.

Because of wanting to free up some pins on the Beta FPGA, the 4 bit RGB DAC has been degraded to a 3 bit one. This will limit the number of available colours to 512 instead of 4096 as I’d hoped. For the same reason the SPI PCM DACs no longer have dedicated pins on Beta. This is slightly irritating but in practice it shouldn’t really matter as the three remaining SPI ICs; the real-time clock and the two analogue joystick ADCs, should not need to be accessed any more then once per video frame. It does mean implementing some kind of arbitration mechanism for the SPI bus though, as well as the aforementioned possibility that the 68000 will need to be held via /DTACK, as sound playback will be contended with the MPUs own SPI requests.

The reason for wanting to free up some pins on Beta is to add a PS/2 port to the system.

And the reason for wanting a PS/2 port is that it would be fantastic to add a mouse port to the system. It will allow someone else building their own MAXI000 board to operate the computer without building the Amiga 600 keyboard or, perhaps, building their own translator board to convert some other keyboard to the asynchronous serial protocol used by my Amiga 600 keyboard control board.

PS/2 ports use a synchronous (clocked) serial protocol that operates on units of bytes. Unlike SPI the protocol it is bi-directional on a common data wire, so it is a little like I2C except without any addressing, which would be redundant anyway since there is only one host and one device. Two wires and two pins are used: clock and data. The device (a mouse or a keyboard) drives the clock signal for both directions.

For keyboards, key events obviously originate at the keyboard end. Communications from the host end is used to do various things including:

  • Reset the keyboard
  • Turn LEDs (Caps Lock, Num Lock and Scroll Lock) on and off
  • Set key repeat rates

Without communication from the host, the keyboard will still generate scancodes after powering on. As an aside, it was interesting to see that key up events use an escape prefix (0xf0) instead of setting the top bit, like mine and other keyboards. Obviously there must be keyboards around with more the 128 keys.

Mice are similar, but the message formatting is more involved. A 3 byte sequence is used to send the state of the buttons and X and Y offsets. And just getting the mouse to start sending movement information requires sending a command byte. Therefore my PS/2 implementation must include communication from the host to the device.

Whilst there are ready to integrate ICs that implement a PS/2 host controller, including the VT82C42 (PDF), after reading about the protocol I thought it looked like an interesting challenge to implement my own controller. One of the things which makes an it interesting challenge is that the protocol uses one wire for two way communications, something I have not attempted before.

The hardware for the prototype setup is extremely simple:

This is the same FPGA dev-board add-on board I used when bringing up my SVGA implementation; the little board includes a 3 bit RGB DAC with attached DB15 connector, along with a 6 pin mini-DIN as used by PS/2. With the multimeter I found out that the clock and data pins both have 2.2K pull-ups, which are needed because the communication channel is bi-directional. The clock and data pins were attached to free pins on the MINI000 EPM7128S (PDF) CPLD. I managed to squeeze in two logic analyzer probes for producing traces of the clock and data signals as well.

The best description of the PS/2 protocol I found is probably this one. The most useful part of this description is perhaps a diagram showing how host to device communications operate:

Whilst I did find some existing VHDL implementations, they were generally too complex and did too much. I did use one for ideas though, and borrowed the technique of sampling an external clock by shifting it into a shift register clocked by the system clock.

Before even writing a line of VHDL I I attached a USB keyboard to my logic analyser and benchtop power supply. Older keyboards (and mice), support the PS/2 wire protocol via a simple adapter – the purple device in the above picture. The data and clock pins were directly attached to the logic analyzer to capture some waveforms. This also confirmed that this particular USB keyboard supported the PS/2 protocol.

Here’s a capture obtained after typing a simple message:

I was surprised to see that this software had analysers for PS/2 ports. It even decodes the scancode into a key cap, though I think it assumes a US keyboard is always used! Interestingly the data rate, set by the keyboard, is quite low: only 12KHz.

The next job was to figure out how to read the 8 bit quantities into a register in the CPLD, which would be presented to the MPU.

First up, the mechanism to detect falling edges on the PS/2 clock pin. This is used for both transmission and reception of PS/2 data bytes. The entity (interface) is completely trivial:

entity ps2edgefinder is
  port ( MPU_CLOCK : in STD_LOGIC;
         EDGE_FOUND : out STD_LOGIC; -- '1' when a falling edge is found
         CLOCK : in STD_LOGIC);       -- The input clock to look at
end entity;

The implementation is pretty simple as well:

architecture behavioral of ps2edgefinder is
  signal EDGE_FINDER : STD_LOGIC_VECTOR (3 downto 0) := x"0";

  process (MPU_CLOCK)
    if (MPU_CLOCK'Event and MPU_CLOCK = '1') then
      -- Shift the incoming clock signal in
      EDGE_FINDER <= EDGE_FINDER (2 downto 0) & CLOCK;
      -- Check for a match against a falling edge
       if (EDGE_FINDER = "1100") then
         EDGE_FOUND <= '1';
        EDGE_FOUND <= '0';
      end if;
    end if;
  end process;
end architecture;

PS/2 clock samples are taken on each rising edge of the MPU clock and fed into the right hand end of a 4 bit shift register, which shifts left. If the shift register contains “1100” then a falling edge has been found.

Next, the interface for the receive section:

entity ps2rxshifter is
  port (  MPU_CLOCK : in STD_LOGIC;
          EDGE_FOUND : in STD_LOGIC;                      -- Has a clock edge been found?
          RX_SCANCODE : out STD_LOGIC_VECTOR (7 downto 0);-- What have we shifted in
          SCANCODE_READY_SET : out STD_LOGIC;             -- A new scancode is available
          PARITY_ERROR : out STD_LOGIC;                   -- A parity error occured
          CLOCK : in STD_LOGIC;                           -- PS2 clock pin
          DATA : in STD_LOGIC);                           -- PS2 data pin
end entity;

This is pretty straight-forward.  EDGE_FOUND is determined using the above. SCANCODE_READY_SET is an enable signal for another signal which is set by the act of receiving a byte (scancode) on the PS/2 port, and cleared when the MPU reads the scancode data register and obtains the actual scancode.

PS/2 has a simple parity check (the protocol uses odd parity) and the PARITY_ERROR output is used to indicate a parity error, indicating that the host end should disregard this byte.

CLOCK and DATA are the signals from the PS/2 port itself.

architecture behavioral of ps2rxshifter is
  signal BYTE_BUFFER : STD_LOGIC_VECTOR (7 downto 0) := x"00";-- Currently shifting byte
  signal BYTE_COUNTER : integer  range 0 to 7;                -- Byte shifting counter (0..7)
  signal PARITY_CHECK : STD_LOGIC := '0';                     -- Accumulated parity
  -- Used to rsset the shifter if no new bit by the time it overflows 
  signal SCANCODE_RX_COUNTER : STD_LOGIC_VECTOR (11 downto 0) := (others => '0');
  type T_STATE is (RX_START, RX_BYTE, RX_ODD_PARITY, RX_STOP);-- State stuff
  signal STATE : T_STATE := RX_START;

Next, the local signals.

SCANCODE_RX_COUNTER is possibly the most interesting element. It is incremented by the MPU_CLOCK signal and if it ever reaches it’s maximum value, the state machine is reset to the RX_START state. It is cleared at the start of each received bit, so this counter is used as a “timeout” to keep the system in-sync with the transmitting side. This is a 12 bit counter, so at 16 MHz the keyboard (or mouse) has approximately 256uS to generate each clock pulse. Looking at the logic analyser capture above, you can see that the period of that particular keyboard’s clock pulse is 81.6uS, ie. less then the 256uS cut-off.

  process (MPU_CLOCK)
    if (MPU_CLOCK'Event and MPU_CLOCK = '1') then
      SCANCODE_READY_SET <= '0';

      -- If we have had no clock edges for 2^12 MPU clocks, reset the state
      if (SCANCODE_RX_COUNTER = x"fff") then
        STATE <= RX_START;
      end if;

      -- Assuming we are not in the start state, move the "timeout" counter along
      if (STATE /= RX_START) then
      end if;

      if (EDGE_FOUND = '1') then
        SCANCODE_RX_COUNTER <= (others => '0');

        case STATE is			
          when RX_START =>
            BYTE_COUNTER <= 0;
            BYTE_BUFFER <= x"00";
            PARITY_CHECK <= '0';
            STATE <= RX_BYTE;

          when RX_BYTE =>
            -- Update the parity state with the latest PS/2 bit
            -- Store it in the output buffer
            -- See if we just stored the last bit?
            if (BYTE_COUNTER = 7) then
              STATE <= RX_ODD_PARITY;
            end if;
            BYTE_COUNTER <= BYTE_COUNTER + 1;
          when RX_ODD_PARITY =>
            -- Check for an even number of ones: good!
            if (PARITY_CHECK = not DATA) then
              -- No error
              PARITY_ERROR <= '0';
              PARITY_ERROR <= '1';
            end if;
            STATE <= RX_STOP;

          when RX_STOP =>
            -- Copy byte/scancode out and mark that we have a scancode
            SCANCODE_READY_SET <= '1';
            STATE <= RX_START;
        end case;
      end if;
    end if;
  end process;
end architecture;

Finally the “meat” of the receive action.

On each MPU clock, we assume that no complete scancode (byte) has been received. We then check for SCANCODE_RX_COUNTER overflow, and if it has happened then we reset the state and will later discard anything so far received. If we are not in the initial state (RX_START) then we increment this counter.

The rest of the logic deals with each PS/2 clock’s falling edge. Each edge is the reception of a bit:

  1. Start bit
  2. 8 data bits
  3. Parity bit
  4. Stop bit

The parity bit is possibly the most interesting aspect. The parity bit is calculated by accumulating XOR operations through the received data bit and what has been so far calculated. Since the XOR binary operation flips the output when the two inputs differ, this can be used for parity calculation, essentially counting the number of bits that are set, but keeping only the lowest bit of the sum.

Once a stop bit has been received, the received scancode (byte) is copied to the output and SCANCODE_READY_SET is set to 1, which is used to signal the processor, via a second addressable register, that a scancode is available for reading.

Needless to say, PS/2 transmission is a little more complicated. First up, the interface:

entity ps2txshifter is
  port ( MPU_CLOCK : in STD_LOGIC;
         nRESET : in STD_LOGIC;             -- Global reset
         EDGE_FOUND : in STD_LOGIC;         -- PS/2 falling clock edge?
         TX_COMMAND_BYTE : in STD_LOGIC_VECTOR (7 downto 0);
         -- What we are shifting out
         TX_COMMAND_TRIGGER : in STD_LOGIC; -- Go signal
         TX_CLOCK_DRIVEN : out STD_LOGIC;   -- Drive the clock pin?
         TX_DATA_DRIVEN : out STD_LOGIC;    -- Drive the data pin?
         CLOCK : out STD_LOGIC;             -- PS/2 clock OUT
         DATA : out STD_LOGIC);             -- PS2 data pin OUT
end entity;

Unlike the transmission side, here the main nRESET signal is used to clear the state. Actually this kind of tidy up is missing at various places in the code, but it happens to be needed here.

TX_CLOCK_DRIVEN and TX_COMMAND_DRIVEN are used by the “outside world” to determine whether, at this point in time, the two pins are to be driven to a value or used as inputs. This is needed as the host drives the PS/2 clock pin low briefly to indicate to the remote end that it wants to send a byte. Through the EDGE_FOUND signal, the transmission of PS/2 data from host end both reads and drives the clock pin.

architecture behavioral of ps2txshifter is
  signal MPU_CLOCK_COUNTER : STD_LOGIC_VECTOR (9 downto 0) := (others => '0');
  signal BYTE_COUNTER : integer range 0 to 7 := 0;-- Byte shifting counter (0..7)
  signal PARITY_CHECK : STD_LOGIC := '0';         -- Accumulated parity
  signal REQUEST_TO_SEND1 : STD_LOGIC := '0';     -- Sending clock pulse?
  signal REQUEST_TO_SEND2 : STD_LOGIC := '0';     -- Sending data pulse?
  signal TX_BUSY : STD_LOGIC := '0';              -- Transmittion is busy
  signal STATE : T_STATE := TX_BYTE;

Since the initial request to send a byte uses an unclocked (by the PS/2 device) pulse, a counter, clocked by the MPU clock is used to time its duration. This is the MPU_CLOCK_COUNTER signal, and it is used twice, once for a low PS/2 clock pulse, and once for a low data pulse, which acts as a start bit, as can be seen in the timing diagram above. REQUEST_TO_SEND1 and 2 are used to control this action, with a simple state machine, moved through its states via the EDGE_FOUND input, used to handle the rest of the processing.


  process (MPU_CLOCK, nRESET)
    if (nRESET = '0') then
      TX_CLOCK_DRIVEN <= '0';
      TX_DATA_DRIVEN <= '0';
    elsif (MPU_CLOCK'Event and MPU_CLOCK = '1') then
      if (TX_COMMAND_TRIGGER = '1') then
        -- Pull clock low to tell the device we want to tx
        MPU_CLOCK_COUNTER <= (others => '0');
        PARIT Y_CHECK <= '0';
        REQUEST_TO_SEND1 <= '1';
        TX_CLOCK_DRIVEN <= '1';
        CLOCK <= '0';
      end if;

      -- Send a "reqest to send" pulse on data
      if (REQUEST_TO_SEND1 = '1') then
        if (MPU_CLOCK_COUNTER = "1111111111") then
          REQUEST_TO_SEND1 <= '0';
          TX_DATA_DRIVEN <= '1';
          DATA <= '0';
          MPU_CLOCK_COUNTER <= (others => '0');
          REQUEST_TO_SEND2 <= '1';
        end if;
      end if;

      -- Send start bit, but at this point the device is not driving the clock
       if (REQUEST_TO_SEND2 = '1') then
         if (MPU_CLOCK_COUNTER = "1111111111") then
           REQUEST_TO_SEND2 <= '0';
           TX_CLOCK_DRIVEN <= '0';
           TX_BUSY <= '1';
           BYTE_COUNTER <= 0;
           STATE <= TX_BYTE;
         end if;
       end if;

       if (TX_BUSY = '1' and EDGE_FOUND = '1') then
         case STATE is
           when TX_BYTE =>
             -- Calculate the parity and send the bit
             if (BYTE_COUNTER = 7) then
               STATE <= TX_ODD_PARITY;
             end if;
             BYTE_COUNTER <= BYTE_COUNTER + 1;

           when TX_ODD_PARITY =>
             DATA <= not PARITY_CHECK;
             STATE <= TX_STOP;

           when TX_STOP =>
             DATA <= '1';
             STATE <= TX_END;

           when TX_END =>
              TX_BUSY <= '0';
              TX_DATA_DRIVEN <= '0';

        end case; 
      end if;
    end if;
  end process;
end architecture;

I’m pretty sure this logic could be simplfied. It’s especially frustrating having to time the REQUEST_TO_SEND2 block, instead of moving into a TX_START state clocked by the remote device. However, it seems that at this point the device has not yet determined that it needs to send clock pulses.

After sending the “request to send” sequence, a state machine is entered which is responsible for shifting out the data bytes, parity, and stop bit, as clocked by the EDGE_FOUND signal.

Once again the XOR function is used to build up the parity bit, this time to append it to the data sent.

Another reason to look at simplifiying this code is to save resources in the CPLD/FPGA. The complete implementation (including the MPU register read and write actions) needs around 80 macrocells in the EPM7128S (PDF) CPLD present on the MINI000 board, which is more then half of the total available. In fact the current design entirly fills the CPLD, and I had to remove the logic for the onboard buzzer. I have yet to try building the implemenation into the barely-started design for the Beta FPGA; hopefully the Flex 10K (PDF) FPGA cells are more efficent then the MAX7000 CPLD cells.

One other task was to tie the PS/2 signals together at the CPLDs pins:

USER (0) <= PS2_TX_CLOCK when (PS2_TX_CLOCK_DRIVEN = '1') else 'Z';
USER (1) <= PS2_TX_DATA when (PS2_TX_DATA_DRIVEN = '1') else 'Z';

Thus USER (0 and 1) is put into tri-state (and used for reading) when the _DRIVEN signals are low, otherwise the requisit signal is put on as an output.

The summary of all this is the PS/2 controller works rather well. I am able to read scancodes using the monitor program, polling for a new scancode on the SCANCODE_READY status bit. I am also able to send commands to a keyboard, and mouse and read from both. Here is a capture of the 68000 being used to turn on the keyboard LEDs, using a PS/2 controller implemented inside MINI000’s CPLD:

From the left:

  1. The host (CPLD) is pulling the clock low.
  2. The host then pulls the data pin low, completeing the “request to send” sequence
  3. The host pushes out data bits, under control of the clock signal originating at the keyboard
  4. After 8 bits are sent, the calculated parity bit is sent
  5. The stop bit is then sent (marked by the analyser’s decoder with a red dot)
  6. The keyboard stops sending clock pulses
  7. The keyboard then sends an acknowledgement byte (0xfa)
  8. The same sequence occurs for the second transmitted byte

In the example above the host is sending 0xed followed by 0x07 to turn on all 3 LEDs.

The implementation is not entirly complete. One thing missing, but it’s easy to add, is exposure to the TX_BUSY bit within the published status register. The 68000 code which sends two bytes, used to send the LED sequence above, is timed with a delay loop instead of polling on a “byte sending” status bit.

The MAXI000 board will include two PS/2 interfaces, making use of four pins on the Beta FPGA, but on a single port. A fairly common configuration on contemporary laptops was to include only one PS/2 port with a splitter cable. If no splitter is used, the laptop would assume that a keyboard was used. With a splitter cable, both a keyboard and mouse could be connected. Of course this is just a software convention as the PS/2 protocol itself is agnostic to the type of device on a particular port.

Thus my plan for my MAXI000 computer will be to attach my trusty Amiga 600 keyboard to the RJ10 port which is hooked up to the 16C654 (PDF) Quad UART, with a PS/2 mouse attached to the PS/2 port. But if anyone else wants to build the board they may instead choose to use a PS/2 keyboard and PS/2 mouse.

I now have two outstanding jobs:

  • Check, check and check some more the MAXI000 schematic and PCB design
    • Then I need to order the board! I have yet to decide on a supplier. I may stick with allpcb.com, or I may look at jlcpcb.com, which I’ve heard good things about and may be slightly cheaper.
  • I also have to order the outstanding parts (including those FPGAs) from utsource.net.

I’ve been pretty organised with this board; I have a nice project box containing most of the parts I need all ready to go. But on the subject of parts storage, one problem I do currently have is storing SMT parts, as the familular methods – parts drawers, anti-static foam, etc – do not really work. Some research will be required…


2 thoughts on “A PS/2 interface and PCB routing progress

  1. Niklas

    It’s really cool to follow your progress. Looks like it’s going to be a great system.

    For storing small SMD ICs, I have some small ones that are kept between sheets of ESD foam in small boxes or drawers. This is also how I’ve been sent QFPs and similar when I’ve bought small quantities from Mouser and the like. It seems to work if they’re light enough. PLCCs I just keep in plastic drawers or small boxes, but I don’t know if it’s ideal for ESD.

    1. aslak Post author

      Thanks for the comments! Sorry it took a while to get your comment up; I don’t get many!

      I think little boxes is definitely the way to go. Thingiverse has some designs for boxes that can be clicked together, or of course there is ebay.

      For passives and LEDs etc it seems taking them off the tape and putting them loose in little boxes is the way to go? And then making sure they don’t ever get mixed up!

      I really have to come up with something soon, as currently all my SMT parts are still in the anti-static shipping bags, and finding things is a bit of a pain.


Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.