Thursday, October 21, 2021


I am using the TLC5928 constant current sink driver to light up my LED bar graphs.

The neat thing about this part, is that you can set a current (for all 16 outputs) using a reference resistor. The higher the resistor, the less current the chip will output. So far so good.

If you have a LED bar graph that has both GRN and RED LEDs in it, you have a problem, though. The RED is a lot brighter, and does not need nearly as much current as the GRN one. I see typically a factor 4x more current for green. However, the reference resistor sets the current for ALL channels, whether they have a red or a green LED on it.

So, how to proceed? Well, I decided to do add pulse-width-modulation for the red LEDs. I will still drive all channels with the same constant current, but the red LEDs will have their anode voltage (3.3V) interrupted at a few hundred hertz, with a specify duty-cycle. Whereas the green leds will keep seeing their uninterrupted voltage.

A GPIO pin can never deliver the current required to switch a whole bunch of red LEDs. So we introduce a little switch, called a Bipolar Junction Transistor of the PNP form.

When adding a discrete transistor to do perform this PWM job, I also need to add resistors, which makes the design more cluttered. Fortunately, you can buy pre-biased transistors that already house those resistors along with the transistor. I have evaluated 3 such pre-biased transistors for this job.

DTB114EK (R1 and R2 are 10kΩ)

DTB123TK (R1 is 2.2kΩ)

DTB113ZC (R1 is 1kΩ and R2 is 10kΩ)

Note that in my case, I have 3.3V at the emitter (pin1) and not GND.

I've found that a high R1 resistor at the base of the transistor causes the EMITTER->COLLECTOR current to be too limited when the transistor is switched on. Even when I have a continuous '0' at the base, to switch it on, the current does not get high enough to drive many LEDs. Hence, between these three, the DTB113ZC with a 1kΩ resistor at the base does the best job for my application. I find that if I have a bunch of LEDs drawing 109mA in total, and switch that current with the transistor, 90mA makes it through with the DTB113ZC, 79mA makes it through with the DTB123TK and 47mA makes it though with the DTB114EK.

Tuesday, October 19, 2021

The state of Electronic Circuit Simulation Software under Ubuntu.

Today, I was in need of electronic circuit simulation. Let's see what is available for Ubuntu.

First I tried ngspice, but that seems to be text based.

$ ngspice 
** ngspice-34 : Circuit level simulation program
** The U. C. Berkeley CAD Group
** Copyright 1985-1994, Regents of the University of California.
** Copyright 2001-2020, The ngspice team.
** Please get your ngspice manual from
** Please file your bug-reports at
** Creation Date: Sat Mar  6 03:53:35 UTC 2021
ngspice 1 ->

Ok, install the GUI for it then...

$ sudo apt install gspiceui
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Package gspiceui is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

Next up: Oregano. I managed to compose a circuit, but when I tried to simulate:

$ oregano 
Segmentation fault

Next up: xschem. Again, I managed to draw a schematic, which is done in an awkward way. When I wanted to simulate, I could find no such option in the menus. It seems it cannot?

Ok, let's move to QUCS. No hit on a package search in Ubuntu, which does not bode well. Ok, let's grab a deb from the archive.

# dpkg -i qucs_0.0.20.201022-2_amd64.deb 
Selecting previously unselected package qucs.
(Reading database ... 281811 files and directories currently installed.)
Preparing to unpack qucs_0.0.20.201022-2_amd64.deb ...
Unpacking qucs ( ...
dpkg: dependency problems prevent configuration of qucs:
 qucs depends on libqt4-qt3support (>= 4:4.5.3); however:
  Package libqt4-qt3support is not installed.
 qucs depends on libqt4-script (>= 4:4.5.3); however:
  Package libqt4-script is not installed.
 qucs depends on libqt4-svg (>= 4:4.5.3); however:
  Package libqt4-svg is not installed.
 qucs depends on libqtcore4 (>= 4:4.7.0~beta1); however:
  Package libqtcore4 is not installed.
 qucs depends on libqtgui4 (>= 4:4.8.0); however:
  Package libqtgui4 is not installed.

dpkg: error processing package qucs (--install):
 dependency problems - leaving unconfigured
Processing triggers for libc-bin (2.33-0ubuntu5) ...
Processing triggers for desktop-file-utils (0.26-1ubuntu1) ...
Processing triggers for mailcap (3.68ubuntu1) ...
Processing triggers for gnome-menus (3.36.0-1ubuntu1) ...
Processing triggers for hicolor-icon-theme (0.17-2) ...
Processing triggers for man-db (2.9.4-2) ...
Processing triggers for menu (2.1.47ubuntu4) ...
Errors were encountered while processing:
root@Workstation:/home/bram/Downloads# apt install libqt4-script libqt4-svg libqtcore4 libqtgui4
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Package libqtcore4 is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

Maybe GEDA?

# apt install geda
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Package geda is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

E: Package 'geda' has no installation candidate

Oh dear... I am about to give up now. I can see now, why CircuitLab manages to charge $399,- per year.

Friday, October 8, 2021

The SMD Hurdle

I found that programming microcontrollers and designing electronic circuits is so much more fun than modern software development for PC. I have really taken to the hobby. So much so, that I'm beginning to think a pivot is in order.

When I started mobile game development in feb 2009, I was ahead of the curve. So far ahead of the curve, that app-store money was easy to come by. No game engines, no unity available. Everything had to be custom roll-your-own code. The number of people that knew OpenGL and ObjectiveC was near zero. It was good to be at the start-point of the democratization of software development. Fast forward to today, and the market is so crowded, it is impossible to stand out.

Just as the iPhone opened up a cottage industry of app developers, I think there is a new wave that you can ride, that is not very crowded. Chinese PCB factories have made electronics design accessible to all. For $40 dollars or so, you can have your PCB printed manufactured in a small batch. And if you add a few hundred, you can even get the procurement, and placement of the components on your board, for full service fabrication of your design. Not bad!

Hence, the last few weeks, I have been designing electronic circuits using EasyEDA. It's an easy to use, free PCB design tool. I like it a lot, except for the slow cloud operations that it relies on for many of its operations. But kudos to them for providing a Linux client for it.

So far, I have ordered PCB service from both JLCPCB and PCBWay. Those are the two biggest players in the PCB market, both located in China. From JLCPCB I ordered my first design, which was Through-Hole components only, so I could do the assembly myself. From PCBWay I ordered full service PCB with assembly and component procurement included. That was quite a bit more expensive. And that order has not been completed yet, as it still waits for component delivery. The JLCPCB order did arrive already, and is shown below.

I'll go into the actual product that I am designing, at a later time. But currently, the design is getting more and more complex. The second version had SMD components, so I had pcbway do that for me.

Revision 3 had even more and even smaller components, in a QFN-24 (0.5mm spacing) package even! And to make matters worse: at both sides of the PCB. This is because my design is densily integrated and has space constraints, so I needed both sides of the board. As I was preparing my order for assembly at JLCPCB, the site told me that two-sided SMD assembly was not supported. I had to pick one side, which they would do for me. Ugh.

So, I need to reexamine my options. Would SMD mounting be something I could attempt myself? I've always backed away from it, as being too much of a hurdle.

But some makers with SMD DIY videos have convinced me that it must be possible. So I decided to have a go at it, myself! Surface mounting tiny little components on a PCB.

For this, I will be ordering a set of new tools:

  • A re-work station, which is just a temperature controlled heat-gun.
  • Solder paste (a mix of metal, solder, flux.)
  • Scraper.
  • Tweezers.
  • Big-ass magnifying glass.

In addition of all this, I must make sure that I order my PCBs with a stencil plate. This stencil will help me apply the paste to where it is needed.

In a good fortune of events, the manufacturer of the leading soldering paste is from Canada. Nice! No import duties, and fast shipping.

Anyways, wish me luck!

Oh no! That is too small!

Tuesday, September 21, 2021

LED Bars

Two LED bar graphs. You would think they would be much alike, but no.

On the left: LTA-1000Y (2017 Thailand.) On the right: FJB10Y.

The polarity is reversed. The LTA has anode on the side of the first pin. The FBJ has the cathode on the side of the first pin.

The obvious difference: face colour grey vs face colour black.

Light colour is similar, but brightness is much different. I need to use 470 ohm resistor with the LTA, and a 2K ohm resister with the FJB.

I did some extra research on another convention, for multi-coloured bars. Is 'red' on top or on the bottom of the bar?:

  • AVAGO HDSP-4832 has R/R/R/Y/Y/Y/Y/G/G/G with pin 1 as RED anode.
  • KingBright DC7G3HWA has G/G/G/G/G/G/G/R/R/R with pin 1 as GRN anode.
  • Fairchild MV5A164 (obsolete) has R/R/R/Y/Y/Y/Y/G/G/G with pin 1 as RED anode.
  • Fairchild MV5C164 (obsolete) has G/G/G/G/G/G/Y/Y/Y/R with pin 1 as GRN anode.
  • KYX B10BBGYR has B/G/G/G/G/Y/Y/Y/R/R with pin 1 as BLU anode.
  • MT1025CTF has G/G/G/G/G/Y/Y/Y/R/R with pin 1 as GRN anode. Pin 1 (unmarked) at side that has print.
  • SunLED XGMDKVGX10D has 10+10 bi-colour LEDs to interpolate between GRN to YLW to RED. To use them, 2k Ohm on R and 470 Ohm on G works well. Unfortunately, it is a common-cathode setup, which makes it useless for standard LED drivers.

Monday, September 20, 2021


Last year, I did a project with the Arduini Micro kit. This is an ATmega32U4 microcontroller.

With it, I built a USB input device, with knobs, to tune my noise fields for Ring Miner.

In that project, I was simultaneously writing USB HID data, reading turn knobs, and writing OLED displays. In order to avoid stalls I had to modify the standard lib so I could skip writing USB data if there was no space available in the buffer, which is what happens when the PC is not reading the USB HID device.

I have recently picked up the Arduino again. This time to see if I can steer LED bar graphs with it. I noticed that out of the box, Ubuntu's arduino IDE will not run. You need to patch a library before it will run.

I have been learning on how to drive LEDs with a constant current shift register. I think I will end up using the TLC5917IN chip. Unfortunately, it is only 8 bit, I would have preferred 10 bits, but it was available in-stock, and affordable.

The simplicity of micro controllers is refreshing, in this age of super complexity. Close to the metal, and straightforward.

When coding for micro controllers, use static PROGMEM const qualifier for your data that you want to reside in ROM, instead of RAM.

Sunday, July 4, 2021

Catching a fall (procedurally.)

I have been doing a lot of procedural animation, lately. Making a humanoid walk, and swing a torch at spiders.

I also needed a proper way to catch a fall, with the legs. Because I already had the Inverse Kinematics sorted, I just needed to shift the pelvis down, and up, after a fall.

To do this convincingly, I need to drop down hard at the start, then ease at the nadir, and ease again on the way back to the zenith. For this, piecewise functions come to the rescue. I ended up using this:

Monday, June 21, 2021

Field Of View

Computer monitors come in different aspect ratios. From the old school 4:3 to the ridiculous 32:9.

In my 3D games, I have to choose a Field-Of-View for the camera. Wide angle, or narrow angle views? To do this, the convention is to set a fixed vertical field of view, and then adopt the horizontal field of view that falls out of it, based on the image aspect ratio. I use this for all my 3D games: set the vertical F.o.V.

Fixing the Vertical Field of View, means that users on 4:3 monitors see less of the world, and users on ultra wide screen see more of the world. This could pose an unfair advantage.

An additional problem is that ultra wide aspect ratios lead to ultra wide angle views, which lead to a lot of distorted shapes in the corners of the screen.

But fixing the Horizontal Field of View instead, would mean that users on wide-screen would see less of the world (at top and bottom parts of screen.) This made me wonder... what if I were to fix the angle for the diagonal field instead? Fixed for all users. And then let the Horizontal/Vertical angles fall out of this.

Definitely worth an experiment! So let's do some trigonometry!

Problem: given a fixed angle for the diagonal field of view... what are the corresponding Vertical and Horizontal fields of view?

Given the fixed diagonal field of view angle α, and a given image height h, and image diagonal d, we need merely two equations to derive the vertical field of view angle β.

And with that angle β we can set up our projection matrix the usual way.

When we do all this, we go from extremist views (with fixed vertical FoV) like these: more moderate views (with fixed diagonal FoV) like the ones below. Note that the view angles change less than in the case above, between aspect ratios. The narrow aspect ratio does not show that much less on left/right, and for what it loses on the sides, it wins a little on top/bottom. I think this approach is a keeper!

For completeness, the code, which is trivial:
float vertical_fov_from_diagonal_fov( float a, float w, float h )
        const float d = sqrtf(w*w + h*h);
        const float m = d / ( 2 * tanf( a / 2 ) );

        const float b = 2 * atanf( h / (2*m) );
        return b;