Call us 24/7+1 (571) 339-9155
FREE DELIVERY on all orders over $20

Extracting Transparency from Flattened Images

Ever had a semi-transparent graphic — a glass effect, a soft shadow, a wisp of smoke — that got flattened onto a solid background? The transparency data is gone. Or is it?

With a surprisingly elegant trick, you can perfectly recover the original transparency by comparing the same image on two different backgrounds. Here’s how.


Quick Start: How to Do It

The whole process is two steps:

1 Prepare two versions of your image. Upload your image to Google Gemini Pro and ask:

Convert this image to a pure solid white #FFFFFF background and keep everything else exactly unchanged

Save the result as white.png. Then, using the white image you just created, ask:

Change the white background to a solid pure black #000000. Keep everything else exactly unchanged

Save the result as black.png.

(It’s important to create black from the white version rather than generating both independently — this ensures the foreground stays perfectly aligned between the two images.)

2 Run the extraction tool. Build the executable (instructions below) and run:

.\extract-alpha.exe white.png black.png output.png

That’s it. output.png is your image with the background removed and full transparency recovered — including semi-transparent edges, shadows, and glass effects that normal background removal tools destroy.


How It Works

The Problem

Let’s say you have a layer in Photoshop, After Effects, or a game engine with semi-transparent pixels. At some point it gets composited onto a solid background and exported as a flat image — a JPEG, a screenshot, a video frame. The alpha channel is gone.

You can’t just threshold or magic-wand your way back, because semi-transparent pixels have blended with the background. A 50% transparent white pixel on a black background looks like medium gray. On a white background, it just looks white. The information about what was foreground and what was transparency has been mixed together.

But here’s the key insight: it mixed differently depending on the background color. And that difference is exactly what we need.

The Trick: Render It Twice

Take your image and render it on two backgrounds:

  • Once on pure white (255, 255, 255)
  • Once on pure black (0, 0, 0)

Now compare each pixel across the two images. The way a pixel changes between the two backgrounds tells you everything about its transparency.

The Math

Think about what happens to a single pixel at different transparency levels.

A fully opaque pixel looks identical on both backgrounds. The background can’t show through, so the color doesn’t change. The distance between the two versions is zero.

A fully transparent pixel takes on the background color completely. On white it appears as (255, 255, 255). On black it appears as (0, 0, 0). The distance between the two versions is the maximum possible — the Euclidean distance between white and black in RGB space:

max_distance = √(255² + 255² + 255²) ≈ 441.67

A semi-transparent pixel falls somewhere in between. The more transparent it is, the more it shifts between backgrounds, and the greater the distance.

This gives us a clean linear relationship:

alpha = 1 − (pixel_distance / max_distance)

That’s it. One subtraction and one division per pixel.

Recovering the Original Color

Knowing the alpha isn’t enough — we also need to figure out what color the pixel actually was before it got blended. This is where the black background version comes in handy.

The standard compositing equation for a pixel over a background is:

visible_color = (foreground_color × alpha) + (background_color × (1 − alpha))

When the background is black (0, 0, 0), the second term vanishes:

visible_color = foreground_color × alpha

So recovering the true foreground color is just:

foreground_color = visible_color_on_black / alpha

We divide each channel by alpha to “un-premultiply” the color — brightening up those semi-transparent pixels that got darkened by the blending process.

A Concrete Example

Imagine a 50% transparent bright red pixel — rgba(255, 0, 0, 0.5):

Red Green Blue
On white background 255 128 128
On black background 128 0 0

The distance between these two: √((255−128)² + (128−0)² + (128−0)²) ≈ 220.8

alpha = 1 − (220.8 / 441.67) ≈ 0.5  

Then recover the color from the black version:

R = 128 / 0.5 = 256 → clamped to 255   
G = 0 / 0.5 = 0                         
B = 0 / 0.5 = 0                         

We get back rgba(255, 0, 0, 0.5) — the exact original pixel.

Edge Cases

Near-zero alpha: When alpha is very close to zero, dividing by it amplifies noise. The implementation uses a threshold (alpha > 0.01) and outputs fully transparent black for anything below that.

Clamping: Rounding errors can push values slightly outside the 0–255 range, so everything gets clamped.

Image alignment: The two input images must be exactly the same dimensions and perfectly aligned, pixel for pixel. If you’re capturing screenshots, make sure nothing shifts between the two renders.


Build the Tool

Prerequisites

.NET SDK (8.0 or later)

Setup

# Create the project and add the image library
dotnet new console -n extract-alpha
cd extract-alpha
dotnet add package System.Drawing.Common

Program.cs

Replace the contents of Program.cs with:

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;

[SupportedOSPlatform("windows")]
class Program
{
    static void Main(string[] args)
    {
        if (args.Length < 3)
        {
            Console.Error.WriteLine("Usage: extract-alpha.exe <image-on-white> <image-on-black> <output.png>");
            Environment.Exit(1);
        }

        try
        {
            ExtractAlphaTwoPass(args[0], args[1], args[2]);
            Console.WriteLine($"Done! Saved to {args[2]}");
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"Error: {ex.Message}");
            Environment.Exit(1);
        }
    }

    static void ExtractAlphaTwoPass(string imgOnWhitePath, string imgOnBlackPath, string outputPath)
    {
        using var imgWhite = new Bitmap(imgOnWhitePath);
        using var imgBlack = new Bitmap(imgOnBlackPath);

        int width = imgWhite.Width;
        int height = imgWhite.Height;

        if (width != imgBlack.Width || height != imgBlack.Height)
            throw new Exception("Dimension mismatch: Images must be identical size");

        using var output = new Bitmap(width, height, PixelFormat.Format32bppArgb);

        // Lock bits for fast pixel access
        var rect = new Rectangle(0, 0, width, height);
        var bdWhite = imgWhite.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
        var bdBlack = imgBlack.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
        var bdOutput = output.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

        int byteCount = width * height * 4;
        byte[] pxWhite = new byte[byteCount];
        byte[] pxBlack = new byte[byteCount];
        byte[] pxOutput = new byte[byteCount];

        Marshal.Copy(bdWhite.Scan0, pxWhite, 0, byteCount);
        Marshal.Copy(bdBlack.Scan0, pxBlack, 0, byteCount);

        // Distance between White and Black: √(255² + 255² + 255²) ≈ 441.67
        double bgDist = Math.Sqrt(3.0 * 255 * 255);

        for (int i = 0; i < width * height; i++)
        {
            int offset = i * 4;

            // Format32bppArgb stores pixels in BGRA order in memory
            byte bW = pxWhite[offset];
            byte gW = pxWhite[offset + 1];
            byte rW = pxWhite[offset + 2];

            byte bB = pxBlack[offset];
            byte gB = pxBlack[offset + 1];
            byte rB = pxBlack[offset + 2];

            // Calculate distance between the two observed pixels
            double pixelDist = Math.Sqrt(
                Math.Pow(rW - rB, 2) +
                Math.Pow(gW - gB, 2) +
                Math.Pow(bW - bB, 2)
            );

            // If 100% opaque: same on both → pixelDist = 0 → alpha = 1
            // If 100% transparent: max difference → pixelDist = bgDist → alpha = 0
            double alpha = 1.0 - (pixelDist / bgDist);
            alpha = Math.Clamp(alpha, 0.0, 1.0);

            // Color Recovery: divide by alpha to un-premultiply
            double rOut = 0, gOut = 0, bOut = 0;

            if (alpha > 0.01)
            {
                rOut = rB / alpha;
                gOut = gB / alpha;
                bOut = bB / alpha;
            }

            // Write in BGRA order
            pxOutput[offset]     = (byte)Math.Min(255, Math.Round(bOut));
            pxOutput[offset + 1] = (byte)Math.Min(255, Math.Round(gOut));
            pxOutput[offset + 2] = (byte)Math.Min(255, Math.Round(rOut));
            pxOutput[offset + 3] = (byte)Math.Min(255, Math.Round(alpha * 255));
        }

        Marshal.Copy(pxOutput, 0, bdOutput.Scan0, byteCount);

        imgWhite.UnlockBits(bdWhite);
        imgBlack.UnlockBits(bdBlack);
        output.UnlockBits(bdOutput);

        output.Save(outputPath, ImageFormat.Png);
    }
}

Build and Run

# Publish as a single self-contained .exe
dotnet publish -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true

The executable will be in bin\Release\net8.0\win-x64\publish\.

.\extract-alpha.exe white.png black.png output.png

A note on System.Drawing

System.Drawing.Common is Windows-only, but since we’re publishing as a Windows exe, that’s fine. The [SupportedOSPlatform("windows")] attribute suppresses the platform warnings. Also note that System.Drawing stores pixels in BGRA order (blue first) in memory, which is why the byte offsets in the code read blue before red.


When Would You Use This?

This technique is useful any time you need to recover transparency from a composited source:

  • Game development — extracting UI elements or particles from engine screenshots
  • Video compositing — pulling a semi-transparent overlay from rendered frames
  • Web scraping — recovering icons or graphics that were served over a solid background
  • Legacy asset recovery — reconstructing layered artwork from flattened exports

The only requirement is that you can render the same content on both a white and black background with identical positioning. If you can do that, this technique will recover the alpha channel perfectly — no manual masking, no edge artifacts, no guesswork.

Assembling Duo Bluetooth DIY Kit

The unit comes with all the parts you need except the case and solder. you will need to 3D print the STL file, assemble the parts, and solder the components.  The Firmware is already loaded so you do not need to load any firmware.  

Step 1

Insert the power connector cable to the PC board (Red to the BAT+ hole) and solder it from the bottom side. Also solder on the white male battery socket on the PC board as shown. 

Step 2

Place the daughter micro controller board on the PC board and make sure its level.  there will be a small gap as shown on the left picture.  The solder it as shown starting with the inner pins on both sides with soldering iron coming from the outside.  Be careful as you don’t want to touch any of the components on the micro controller board with your iron.

Step 3 & 4

 Solder on the black 4 pin female connector. This is for the screen you will place on later.  

Solder on the two 9-pin right angle connectors as shown.

Step 5

Place the the 5 switches and make sure hey are straight and then solder them on.  Place on the colored caps and if you place to use the case, trim the edges of the blue and red caps as shows so they don’t get in the way when we close the case later on. 

Step 6

Place the screen on and connect the battery.

Turn it on with the small on/off toggle switch on the side. 

You are done, unless you want to put the unit in a 3D printed case…

Steps 7 and 8 below are optional.

Step 7 

Download the STL file and 3d print the top and bottom.   You can get the STL file from here

Take the metal protectors off the 9 pin connectors and the board and battery are positioned like show below in the bottom half of the case.

Step 8

Add the top of the case from one side as shown and then the other end and snap together. 

Thats it!  

Assembling Duo Plus DIY Kit

The unit comes with all the parts you need except the case and solder. you will need to 3D print the SDL file, assemble the parts, and solder the components.  The Firmware is already loaded so you do not need to load any firmware.  

Step 1

Insert the Pro Micro controller daughter board into the main board and solder all the pins.

Step 2

After you solder the pins, cut the pins so they don’t stick out.  Add the rest of components and solder them all.

Step 3

Place the colors caps on the switches as shown.  Note the Red cap on the daughter pro micro is a stand for the screen.

Step 4

Download the STL file and 3d print the top and bottom.   You can get the STL file from here

Add the top of the case first as shown on the picture below.

Step 5

Add the bottom of the case from one side as shown and then the other end and stap together. 

Thats it!  Connect the cord and plug into you USB port and enjoy.

Create RGB Rainbow Gradient with Programming Code

Here is some code that will help you create all the RGB values needed for generating a RGB Rainbow gradient. The code steps through 6 sets of transitions from one color to another in 256 steps each .

  • Red to Yellow
  • Yellow to Green
  • Green to Cyan
  • Cyan to Blue
  • Blue to Magenta
  • Magenta back to Red

With 6 transitions, each in 256 steps provides 1536 total colors and here is the result from the code below:

See it in action here:  https://codepen.io/alijani/pen/zYVmzqR


html file:

<canvas id="myCanvas" width="1536" height="200"></canvas>

Js File:

const canvas = document.getElementById("myCanvas");
const ctx = canvas.getContext("2d");

var x;
for (x=0; x<1536; x++) {          // 6*256
  ctx.fillStyle =  rainbow(x);
  ctx.fillRect(x, 0, x, 200);  
}


// Accepts values 0 through 1535 and returns the one of 1536 colors in rainbow.
function rainbow(x) {   
    let r = Math.trunc(x / 256);    // 0-5     
    let c = x % 256; 
   
    if (r==0) {
      value = rgb(255,c,0);        // red to yellow transition
    } else if (r==1) {
      value = rgb(255-c,255,0);    // yellow to green transition
    } else if (r==2) {
      value = rgb(0,255,c);        // green to cyan transition
    } else if (r==3) {
      value = rgb(0,255-c,255);    // cyan to blue transition
    } else if (r==4) {
      value = rgb(c,0,255);        // blue to magenta transition
    } else if (r==5) {
      value = rgb(255,0,255-c);    // Magenta to ren transision
    }
    return value;     
}

// simple function to convert rgb decimal values to #RRGGBB hex color string used in html
function rgb(r,g,b) {
  return "#"+(r).toString(16).padStart(2,'0')+(g).toString(16).padStart(2,'0')+(b).toString(16).padStart(2,'0');
}

How to Interface with Atari Driving Controller – Arduino Programming

The Atari driving controller uses a 16 position encoder that sends pulses to to pin 1 and pin 2 of the game port. These pulses can be deciphered or decoded to understand if the player is spinning the controller in the left or right direction.

Here is how the spinners encoder works. If you look at the photo below, imagine point A is connected to Pin 1 and Point B is connector to Pin 2. As you spin the encoder the will make contact with the C blocks which are connected to common ground. So at the position shown, pin 1 (A) and Pin 2 (B) are not touching ground (C). but is you spin right, Pin 1 (A) will touch ground first but if you spin left, Pin 2 (B) will Touch ground first.

So if you are in the middle where A and B are not touching ground. you go from BA being 00 to 01, and if you spin a bit more you get to where the black pen is where the value becomes 11. Then if you keep going, you go to 10 and then back to 00.

Now if you spin left, you go from being 00 to 10, then 11, then 01.

All the programmer has to do is read the state of pin 1 and pin 2 continuously and compare it to its previous values to determine the direction the play turned. Here is a table that tells you if the player turned right or left based on the current and prior readings of pins 1 and 2.

With only 2 pins there are 4 possible combinations of values that Pin 1 and 2 can produce, like a 2 bit binary number.

Pin 2Pin 12 bit
Value
000
011
102
113
Previous
Value
Current
Value
Direction
01Right
13Right
20Right
32Right
02Left
10Left
23Left
31Left

Now we have all the logic we need to develop the pseudocode
  1. Get state of pins 1 and 2
  2. For current value, combine the pin values like binary bits and convert to decimal
  3. compare the current value to old value
  4. if the value has changed from perivious value,
    • Use table above to determine if you will move left or right
    • update the previous value to current value
  5. go back to step 1.

So all we need to do is connect pin 1 and 2 to pulled up IO ports of a micro controller. For the fire button, use pin 6 and connect it to a pulled up IO port. When the player presses fire button, pin 6 will go low. When the player spins, you can figure out easily if they spined right or left now!

Here is some sample code assuming you have used GPIO ports 1 for Pin 1, 2 for pin 2 and 3 for pin 6 (fire):

bool A;
bool B;
bool F;
int P=0;

void setup() {
    pinMode(1, INPUT_PULLUP);  
    pinMode(2, INPUT_PULLUP);  
    pinMode(3, INPUT_PULLUP);  
}

void loop() {
    A = !digitalRead(1);
    B = !digitalRead(2);
    F = !digitalRead(3);

    int V = A+B*2; 
    if (V != P) {
       if ((P==0 && V==1) || (P==1 && V==3) || (P==2 && V==0) || (P==3 && V==2)) {
           // Moved right code goes here
       } else if ((P==0 && V==2) || (P==1 && V==0) || (P==2 && V==3) || (P==3 && V==1)) {
           // Moved left code goes here
       }
       P = V;
    }
}

iCode Firmware Release 9 now available

iCode retro gaming USB adapters get a major upgrade with the release of its latest update, iCode Firmware 9, on Sunday, March 5th. This version brings a lot of new features, which should delight fans of retro video games!

On the hardware side, Firmware 9 is now compatible with the iCode USB models including the UNO, DUO, and QUAD. There are different Firmware 9 downloads specific to each hardware model and revision.

Among the most important new features, version 9 of firmware introduces a new menu navigation system to control all aspects of the device. Once configured, the device remembers all the changes and the last mode of operation, and it will return to the exact state even after a power cycle. This allows the device to be imbedded into arcade cabinets without having to have regular access to the device’s controls.

There has also been a variety of optimizations done which now deliver ultra-low latency play including use of paddles and trackballs.

Below is the list of changes for the release since the prior major release 8.

  • Plus editions now support Sega Genesis 3 button and 6 button Controllers. Also supports Start and Mode buttons. Must set settings menu “Console” to Genesis to activate. For Quad, H12 required. For some Duo Plus & Plus Pro H10 and below, special hardware mod may be needed. See iCode Community forums for details.
  • Device now remembers the mode you were in, even after a power cycle.
  • You can now see mode you are in even if display activity is turned off.
  • Device now remembers if your display was off even after a power cycle.
  • Optimized trackball and paddle mouse operation to provide much smother control. Keep display off for best experience when using mouse mode.
  • Device turns display always off when in trackball mode for optimized smooth trackball operation, unless you specifically turn on after in trackball mode.
  • Device no longer switches back to mode 1 when you access the menu system
  • When you switch target of where joystick or paddles to be reported to, system now correctly clears all gamepad values from prior target
  • Fixed buttons on paddles 3 and 4 on port 2 as they were reversed
  • Optimized auto paddle detection
  • Optimized screen display
  • Optimized Paddle auto calibration
  • Support for iCode Quad adapters
  • Full and Half duplex Paddle Modes
  • Added ColecoVision mode for Plus editions
  • New settings for paddle detection mode. OFF setting is useful for ColecoVision controllers
  • Added Keyboard on/off mode for Plus editions
  • Added compatibility with most recent update of MiSTer Atari 7800 core which changed paddle buttons. In MiSTer mode, Paddle buttons now register as button 3 which works correctly as fire button on Mister. In regular mode, paddle buttons on dual paddles connected to a single port will continue to register as button 0 and 1.
  • Fixed bug with mapping and display of buttons 8 through 32
  • Swapped default button maps for buttons 0 and 1. Red is now button 0, and Green is button 1 by default.
  • Revamped entire settings menu. You now have menus for paddles settings, main menu, and other settings.
  • Moved mister mode toggle to other settings menu
  • Removed mode 2 and common from UNO Devices
  • Improved auto-paddle detection when in MiSTer mode. Pressing yellow button.
  • Added status T indicator on display when in Mister mode
  • Fixed display not showing all inputs correctly after auto paddle updates
  • Fixed port 2 to report correct paddles order for dual paddles on the port.
  • In mouse mode, paddle buttons now correctly report to as mouse buttons.
  • When in mouse mode, paddles and trackballs now correctly only report as mouse and not gamepads
  • Added ability to set destination target as left / right or hat switch for Joystick and paddles data
  • Moved default paddles data to be reported as right hand stick instead of left to avoid conflict with joystick stick data which defaults to left hand.
  • Added developer menu that allows paddle data views. paddle sensor control, and more.
  • Added factory reset to developer menu

RetroArch and Stella configuration for iCode Duo Adapters

Configuring RetroArch Stella 2014 core or Stella desktop emulators to work properly with Atari Paddles can be quite confusing. This guide will help you quickly configure both emulators iCode Duo retro adapters. I recommend Desktop Stella as it will be more responsive and easier to configure.

Stella (Desktop) Configuration

Coming Soon.

RetroArch Configuration

RetroArch has multiple cores that can emulate the Atari 2600. If you want to play paddle games, only the Stella 2014 core will work for you because its the only core that supports absolute positioning that is needed for paddle games. This feature was added to Stella 2014 core starting with version 3.9.3. Here is how you can load the right core and make sure you have the correct version:

  1. From the main menu, select Load Core option.
  2. Select “Atari -2600 (Stella 2104)”. If this is not present, you can use the “Download a Core” option to get it.
  3. Once the core is loaded, you will see it loaded in the bottom left corner of the screen with the version shown. If your version is lower than 3.9.3 you will have to use the Online Updater option from the main menu to download the current version.

Now that your core is loaded, lets make sure RetroArch sees your iCode Duo device and is setup properly.

  1. Connect your paddles and turn on the iCode device. Move your paddles fully to right, then full left, then move them to center. This calabrates your paddles on the device.
  2. On RetroArch, go to the Main Menu and on the left meu navigation, select Settings and then select Input menu option in the main screen.
  3. Scroll down and select the menu option named “Port 1 Controls”
  4. Make sure your Device index is set to the iCode device First gamepad. Also Analog to digital must be set to None as shown.
  5. Press enter on B Button and system will wait for you to press the paddle 1 button. This should set the B button value to 0.
  6. Go to the Select Button menu item and press enter. When system waits, press the yellow button on the iCode device. If you have the wireless Duo , this will set the value to 3.
  7. next is Start, map it to White button.
  8. Next is Right Analog X+, Spin paddle 1 clock wise
  9. Next is Right Analog X-, Spin paddle 1 counter clock wise
  10. Next is Right Analog Y+, Spin paddle 2 clock wise
  11. Next is Right Analog Y-, Spin paddle 2 counter clock wise
  12. X button to Blue button on the iCode Device
  13. White you are still in this area, turn off the iCode device and connect the Joysticks and then turn the device back on so its in Joystick mode.
  14. Now map D-Pad Up, Down, Left, Right to each of the 4 directions
  15. Select “Save Controller Profile” near the top.

How to flash EMMC module to boot with Odroid XU4

Flashing and Booting from an EMMC module on an Odroid XU4 can be tricky. This is because you need a bootloader placed on a hidden Partition of the eMMC memory module. When you clean or flash an EMMC module with normal tools like Etcher or Rufus, you might delete the hidden partition that had the bootloader and the XU4 will simply not boot from your image even if the image you flashed is bootable.

While there are recovery images you can download that have the bootloader needed on it, most images you flash after that will still not contain the bootloader and you would be back to square 1.

The best was found to create a properly bootable EMMC is as follows:

  1. If your EMMC module does not boot, its best to first do a recovery process as described on https://wiki.odroid.com/accessory/emmc/recovery_xu4, then see if your EMMC boots to android. You might be able to skip this step 1 but its still recommended. Then go to step 2.
  2. Flash the image your want to boot from on to your EMMC module and see if it boots. if it does then you are set. if not, go to step 3.
  3. Flash the image your want to boot from on BOTH an SD card and your EMMC module.
  4. With the XU4 off and switch set to boot from SD, insert both them flashed EMMC and SD card on your XU4
  5. Turn on your XU4 and let it boot from SD
  6. SSH into the XU4 or get to a terminal window on it and login
  7. At the prompt type: ls /dev/mmc* and hit enter
  8. Your will see all the partitions on both the SD and the EMMC device. Both will start with mmc so don’t get confused by that. Almost always, your EMMC module are the mmc words that have blk0 and blkboot0 in them and your SD card will be the other one, probably the ones that have blk1 or blk2 in the name. In the Batocera environment I was testing, my SD card happens to be the one with blk2 in them. This will be important as it will get used in steps below

What we are going to do now is use the linux dd command to copy the boot partition from your SD card to the appropriate area on the EMMC. Your EMMC device we want to write to is typically mmcblk0boot0 and it will be protected. So we first have to unlock it, then use the dd command as follows:

  1. Type echo 0 > /sys/block/mmcblk0boot0/force_ro and hit enter. This will unlock and give us access to the partition.
  2. Now type dd if=/dev/mmcblk2 of=/dev/mmcblkboot0 bs=512 skip=1 seek=0 count=16381

The last step might take a few seconds or minute. Once you see no more activity, you can now lock the partition again.

  1. Type echo 1 > /sys/block/mmcblk0boot0/force_ro and hit enter.

Now shutdown your XU4 and remove the SD card and flip the switch to boot from your EMMC!

This is what worked for me. Here is a screenshot of my session after step 4 of the first part.

Tutorials and Videos on using iCode adapters for Atari Joysticks, Paddles, Trackballs, and Driving Controllers.

Atari Paddles

Atari Paddle Jitter elimination with Auto and Manual Calibration

See how you can eliminate Paddle Jitter by using the full spectrum of your paddle range on your games. Unlike all other adapters on the market, the iCode duo adapters have auto range calibration plus they give you the ability to you fine tune your device to match your specific paddle range based on the specific game you want to play.

This video walks you through all the calibration settings to help you do this quickly.

Configure Retropie on Stella 2014 Retroarch for Atari Paddles

Learn how to configure your Retropie to work perfectly with Atari Paddles to play paddle games like Breakout and Warlords, with perfect precision!

Windows Configuration for Paddles on iCode Atari USB Adapter using Stella Emulator

Learn how to connect 4 original Atari paddles to your PC running Stella Emulator. You will see all configuration steps needed for 4 Paddles. Video walks through configuration needed to play 4 player Warlords with 4 paddles on your PC.

Atari CX-80 Trackball

Configure iCode Duo plus to connect to an Atari Trackball CX-80 for games like missile command

This video shows you how to configure your iCode Duo Plus USB device to use an Atari Trackball to play Missile Command running Atari 8 bit emulation on your PC or other systems.

MiSTer FPGA configuration

MiSTer FPGA with Atari paddles and joysticks using iCode Plus Adapter

Walkthrough on how to setup your iCode Duo Plus USB Adapter to work flawlessly with MiSTer FPGA. The updated firmware even support 2 player paddles with ease. Let me know if you have any questions and check us out at www.icode.com where you get one.

Atari 5200 Controllers

Atari 5200 Controllers on Mac OS with Analog games like Super Breakout & Missile Command on Emulator

This video shows you how to configure your Mac running Atari 8 bit emulation to work with your Atari 5200 controller using the iCode Duo Plus 5200. The videos shows examples of hot to play Missile Command and Super breakout with precision control!

RetroPie

iCode Wireless Bluetooth adapter with Raspberry Pi 4 and RetroPie

Learn how to connect 2 original Atari joysticks wirelessly to your Raspberry pi 4 running Retropie. You will see all configuration steps needed.

Retropie Configuration for iCode USB Adapters

Walkthrough of how to configure iCode usb adapter with Retropie, Retroarch, Stella, and lr-Stella. Video covers Paddles and Joystick configuration.

Atari Driving Controllers

Configure Atari Driving Controllers on Stella emulator

Learn how to configure your iCode USB adapters for Atari Driving Controllers to play multiplayer games like Atari Indy 500. Video shows how to Connect multiple Atari Driving Controllers to a single USB port.

Post navigation

Analog to Digital conversion with RC circuit in microcontroller projects

How to flash EMMC module to boot with Odroid XU4

Analog to Digital conversion with RC circuit in microcontroller projects.

Analog to Digital conversion with RC circuit in microcontroller projects.

If you were to take the knob or dial off of an electronic device, you might find a potentiometer underneath it.    A potentiometer is a variable resistor, and the kind shown below changes resistance as the knob turns. This particular one has a resistance range from 0 ohms to 10,000 ohms.

RC circuit use combination of a resistor (R) and a capacitor (C) to control charge rate of a capacitor. One of the applications of RC circuits is to use a potentiometer as the resistor (R) and this allows you to control how it takes to charge the capacitor (C). The higher the resistance, the longer it takes for the capacitor to charge.

These two components together form an RC (resistor-capacitor) circuit.  When the switch is turned on, the capacitor begins to charge. The charge rate always follows the following standard RC charging curve.

The amount of time it takes for charging the capacitor to 63.2% can be calculated using the formula T = R*C in seconds. So for above T = R*C = 100k x 22uF = 2.2 Seconds to get to the 1T line.

TTL circuits on micro controllers typically have a threshold voltage of 1.6V before they recognize an input as HIGH.

So what you can do is connect a digital port to the + side of the capacitor (Vc). Set the port to INPUT mode and force it to LOW. This will discharge the capacitor and immediately the capacitor will begin to charge. Now in a tight loop, just count up from zero and read the PIN till it goas high.

pinMode(pinVC, INPUT);  

digitalWrite(A0, LOW);   // this will discharge the capacitor

Int i=0; While (! digitalread(PinVC)) { i++; }

The value of i will vary based on how you turn the knob!

To calculate how long it takes for the capacitor to get to a certain voltage you can use the following: t = -ln((Vs-Vc)/Vs)R*C

ln mean natural log or log base e, Vs is the supply voltage, and Vc is the voltage across capacitor

For example, an Atari Paddle uses a 1 Meg ohm resistor. Say we wanted to read the paddles at least 30 times per second using a 5v microcontroller board. What value of capacitor should we use? If you use a 1 Meg Ohm Pot and a 5v board with 1.6 volts being the TTL threshold voltage, a capacitor of 0.068uF, it will take 26.23ms for the pin to go high at the max pot value. – ln((5-1.6)/5)*1000000*0.000000068 = 26.23ms This means you can read it ~38 times per second (1000 / 26.23). Since NTSC frame rate is about 30 frames per second, this will allow you to read it at least once per frame! This is probably why Atari hardware uses a 0.068uF capacitor in its RC circuit

Search for products

Back to Top