IR-controlled 4x4x6 LED Tower/Clock on ESP32

by mymcpr0j in Circuits > LEDs

946 Views, 3 Favorites, 0 Comments

IR-controlled 4x4x6 LED Tower/Clock on ESP32

1.jpg
4x4x6 LED Cube/Tower

There are many great tutorials on how to create LED cubes, but I didn’t find one that described exactly the kind of device I wanted to create (maybe I didn’t search hard enough?). So I decided to design the device myself, using information from other tutorials of course.

Here are my main considerations that determined the features of the project:

  • I wanted to use ESP32 to control the device and write a program in C for it.
  • I wanted to use about 100 LEDs.
  • I wanted the device to be as compact as possible, and I had a 15x9 cm PCB board. So I decided to place the device on this board.
  • I wanted to use an external power supply for the LEDs and supply about 20 mA (in normal on state) to each LED.
  • I wanted to control the device with an IR remote control.
  • I wanted to be able to control the brightness of the LEDs.
  • I wanted to be able to show some effects on the device.
  • I wanted the device to act as a clock and some sort of text display.

So I built an LED cube that eventually became a tower. This is my first project of this scale. Now I understand that some things could have been done differently. This is especially true for the power supply and the use of optocouplers (more on that later). But in any case, the device works the way I want it to and I want to share with everyone what I learned while working on this project.

Supplies

2.jpg
46.jpg

The device:

  • 96x matte LEDs.
  • 16x PC817C Optocouplers in DIP-4 package.
  • 16x 220 Ohm resistors 0.25 watt.
  • 16x 270 Ohm resistors 0.25 watt.
  • 6x 1 kOhm resistors 0.25 watt.
  • 6x BC337-25 Transistors.
  • 1x 5.5mm x 2.1mm 3 Pin PCB Mounting Female DC Power Jack Socket Connector.
  • 1x V38238 IR Receiver
  • 1x IR Remote (compatible with the IR Receiver)
  • 1x 1000 uF Electrolytic Capacitor
  • 2x 15-pins Female Pin Header Connector.
  • 1x 150x90 mm Double Sided PCB Board.
  • 4x PCB Spacers and Nuts
  • 1x ESP32 WROOM Development Board.
  • 2x 74HC595 8-Bit Shift Registers in DIP-16 package.
  • 24AWG solid wires (I took them from an Ethernet cable).
  • Thick (19-14 AWG) wires
  • 1x DC9V power adapter (at least 1A).

The LED soldering equipment:

  • 1x 50x70 mm Double Sided PCB Board.
  • 8x 3-pins Male Pin Header Connectors.

Tools and supplies:

  • Soldering Iron.
  • Sn 63 Pb 37 Solder Wire.
  • Rosin Soldering Flux.
  • Metal Alligator Clips.
  • Precise Side-cutting Pliers.
  • Flat Nosed Pliers.
  • Utility Knife.
  • Wooden Board.
  • Silicone Soldering Mat.
  • Multimeter.
  • Oscilloscope (optional).
  • USB tester (optional).
  • Multi-Function Tester (like LCR-TC1).
  • Breadboard (for testing).
  • A power source for breadboard.
  • Flexible Wires M/M.
  • Third Hand Soldering Tool.
  • Tweezers For Electronics.
  • Permanent Marker.

Software:

  • Arduino IDE.
  • EasyEDA editor.
  • Microsoft Excel.

Warning! 9V-powered ESP32 May Burn Your Laptop!

3.jpg

We use a 9V power source in this project. If we connect the VIN pin of the ESP32 board to a power source, we will have the same voltage on the USB power lines (see photo). If nothing is connected to the USB, this is fine, but if we connect something to the USB, we will have problems. The standard USB voltage is 5V. This means that you can burn something like a laptop if you supply the ESP32 with more than 5V via an external power source and at the same time try to connect the device to the laptop via USB to upload a firmware. So be very careful and don't forget to disconnect the external power source before using the ESP32 USB connection.

Once I burned something USB-related into one of my ESP32 boards. I was doing some experiments and after assembling the components on a breadboard, I connected the ESP32's USB cable to the USB port of a battery-powered breadboard power supply module. When I run experiments, I always connect the ESP32 to a cheap USB power source before connecting it to the laptop. If I've done something bad wrong, at least I won't burn up the laptop. When it turned out that I didn't cause a short circuit, I disconnected the battery of the power supply module and continued assembling the components. I forgot to unplug the USB cable from the power supply USB connector. I then powered the ESP32 from an external 9V power source. It worked, but I noticed that the LED on the module lit up. It was unusual, but I didn't pay much attention to it. When I connected the ESP32 to the laptop to update the firmware, I noticed that the board was successfully powered from the laptop (the LEDs on the board looked as expected), but the software couldn't see the board. I tried everything I could think of to make the ESP32 visible again, but nothing worked. Now I use this poor ESP32 to test boards before installing normal ESP32s.

ESP32 uses 3.3V, so if you use a different voltage in your project (and/or to power the ESP32), then you should be extremely careful. This voltage should only be applied to VIN. If this voltage gets to any other leg, then the board will most likely burn out. I burned one of my ESP32s this way.

Please remember these rules:

  • Don not connect externally-powered ESP32 to another devices via USB.
  • Do not apply more than 3.3V to the ESP32 pins (except the VIN pin).

I try to follow these rules, but people make mistakes. To further protect my devices, I have made the following choices:

  • I have decided to always power my ESP32 projects with 5V voltage through the VIN pin. If I really need something more than 5V in the ESP32-powered device and I need to use the same voltage source for the ESP32, then I will definitely give the ESP32 this 5V via an internal voltage regulator. With this approach, the USB port should be protected even when USB and an external power adapter are connected at the same time.
  • I have decided to use a USB hub with an external power supply to connect the ESP32 to the laptop. Maybe this will protect the laptop in case I do something really bad.

So, here we go.

How It Works

4.jpg
5.jpg
6.jpg
7.jpg
8.jpg
9.jpg
10.jpg

The LED tower consists of 6 layers and 16 columns. All LEDs cathodes (the negative pins) in a layer are connected to each other. All LEDs anodes (the positive pins) in a column are also connected to each other.

At any given time, only one of the layers is powered. We switch back and forth between the layers very quickly, creating an afterglow effect. It can look as if the LEDs in each layer are switched on.

Before we switch on the layer, we have to decide which LEDs in the layer should light up and switch them on before we supply the layer with power.

We control the layers with NPN transistors that work in switching mode. When we "turn on" the transistor connected to the corresponding ESP32 pins, we do not just turn it on. We send a PWM signal to it as long as it is switched on. This enables us to change the brightness of the LEDs.

We control the individual LEDs with shift registers through optocouplers. We need optocouplers because I decided to supply about 20 mA to each LED, which is impossible when using registers alone.

The layers are numbered from 1 to 6. The lowest layer is numbered 1, the highest layer is numbered 6.

The columns are numbered from 1 to 16. If you look at the front of the device (the ESP32 and most other things are on the back), column 1 is the furthest column to the right (at the front side), column 16 is the furthest column to the left (at the back side).

Let us look at an example.

How do you turn on these LEDs?

  • Layer 1, Column 1
  • Layer 2, Column 3
  • Layer 3, Column 5
  • Layer 4, Column 7
  • Layer 5, Column 9
  • Layer 6, Column 11

This is how it works:

  1. Write a 1 to the pin of the shift register connected to column 1 and write a 0 to another pin.
  2. Switch off all transistors and switch on the transistor connected to layer 1.
  3. Wait for some time.
  4. Repeat the process for each layer.

We can turn on any LED in any layer, so our example can be extended to something like "Layer 1, Columns 1, 4, 5, 6, 9 ....".

Schematics

CUBE-PCB-10x15-FIN.jpg
Schematic_LedCube4x4x6OptoFin_2024-04-16.png

I use EasyEDA to draw electrical circuit diagrams (you may find EasyEDA and MS Excel files in my GitHub repository). We will go into the details of the diagram from this step later. In addition to the electrical schematic, I created a component and main wiring diagram in Microsoft Excel (I think any editor like this will work). With so many components and connections in a circuit, it is very important to plan their placement in advance.

These drawings will be used for soldering and programming the device.

As you can see in the photo showing the bottom of the board (Step 2), some connections are not marked on the diagram. These are the connections between shift registers and optocouplers.

Checking the Viability of the Idea

17.jpg

During the design process of the device, I assembled the model on a breadboard. This model was used to measure various parameters and select the components. I think this type of models is very important. They allow you to test different ideas before you start soldering.

Power Source, Calculations and Measurements

11.jpg
12.jpg
13.jpg
14.jpg
15.jpg
16.jpg
18.jpg
19.jpg
20.jpg

The first idea

At first I tried to develop the device using the power source of the ESP32 board. This is only suitable for devices with relatively low power consumption. My ESP32 board has an AMS1117 33 D309 voltage regulator. According to the specification, it supports a maximum input voltage of 15V and a current of 1A.

I decided to give each LED about 20mA. I use 74HC595 shift registers that support a maximum current of 70mA through the VCC or GND pins. I can't supply 8 LEDs with 20mA directly from each register, so I decided to use some kind of "switch" in the form of a transistor or an optocoupler. Any additional component will introduce a certain voltage drop. Considering that the ESP32 supplies about 3.3V, these voltage drops are too large compared to the supply voltage. After some experiments I found out that I need about 14 Ohm resistors for the LEDs. Since I didn't have these resistors, I decided to use an external voltage source.

Switching to 9 volts

At the moment I thought that an external 9V power source was a good idea. I've some nice 9V adapters, I've 9V batteries to power the device on the go (but it has quite a large power consumption, so it cannot last long on battery power), and the ESP32 voltage regulator supports 9V. If I learn to use an external power supply - this will allow me to create devices that draw high current.

Now I can say that 9V is suitable for projects like this, but as mentioned above, there are certain risks involved. In addition to the risks, I realize that using this voltage to power the ESP32 directly will cause the voltage regulator to get very hot. Measurements with a thermocouple showed a temperature of about 85°C, which is quite high.

The GND pins of the ESP32 are connected together

On my ESP32 board, the GND pins near the VIN and 3v3 pins are connected together. This may not be the case on your board. Check this with a multimeter. This means that the 3.3V and the 9V power supply lines will have a common ground without any additional effort, which will be useful when working with transistors.

VIN pin and USB

The VIN pin receives 5V from USB when connected to a USB power source (e.g. a USB adapter or a laptop USB port). In this case, anything that receives 9V (according to the schematic) will receive 5V. The only noticeable effect is that the LEDs light up less brightly. This is very practical when programming and debugging. It is not necessary to disconnect the USB cable and connect the power supply to see the results of the program change. However, this feature of the board raises a very important question. How much power will the device consume in this mode? Is it safe to use?

Determining the current at a voltage of 9V

Before we connect the device to the USB port, we should make some calculations.

Let us first calculate (at least approximately) the power consumption of our device. Let us consider the situation in which the device is powered by a 9V power source and in which all LEDs of one layer are switched on and have the maximum brightness. In this mode, we will not switching between the layers.

Each LED receives about 20mA (9V-2.1V- 1.5V= 5.4V, 5.4V/270 Ohm = 0.02A = 20mA, more on this later). We have 16 LEDs in one layer, so we have 320mA for the LEDs alone.

Each optocoupler gets about 8.5mA. We have 16 optocouplers, so we have 136mA for the optocouplers.

The ESP32 consumes about 70mA in the mode we are use it in (no WiFi or BT).

So, 320+136+70 = 526mA.

Measurement of the current at a voltage of 9 V in mode 1.0

Later we will talk about the modes in which the device can work. Now I would like to say that these measurements were made in mode 1.0. This is a mode in which all LEDs are turned on and rapid switching between all layers is carried out (as in all other modes, except one - mode 5.8, measurement mode).

The actual power consumption will differ from the calculated value because we are constantly switching the LEDs on and off and controlling their brightness by pulse width modulation. However, the calculated value can be used as a guide when selecting a power supply for the device.

I measured the actual power consumption of the 9V powered device. The UNI-T UT39E+ multimeter shows a consumption of 392 mA.

When I measured the current with a 1.1 ohm shunt resistor and an oscilloscope, the maximum current value (referenced to Ma) was 472 mV/1.1Ohm = 430 mA and the average value (referenced to V) was 362 mV/1.1 ohm = 329 mA. I think the spikes in the waveform have to do with either the capacitor installed on the power line to meet the immediate power needs of the device, or the inrush current of the LEDs.

Measuring the current at a voltage of 9V in 5.8 mode

Mode 5.8 is a measurement mode. In this mode, we switch on one of the layers (layer 1) at maximum brightness and do not perform any layer switching

The UNI-T UT39E+ indicates a consumption of 499mA.

The oscilloscope shows something very similar to a straight line. Ma parameter says 516 mV. This means we have 516 mV/1.1Ohm = 469mA.

Determining the current at a voltage of 5V

Now let us look at the situation when the device is powered through USB. In this case, we have 5V at the VIN pin.

In this case, each LED receives 5 mA (5V - 2.1V - 1.5V = 1.4V, 1.4V/270 Ohm = 0.0051 A = 5 mA). 5 mA * 16 = 80mA

The optocouplers draw the same current as above, so we have the same 136mA here.

The ESP32 consumes the same current as above - about 70mA

So, 80+136+70 = 286mA.

If you power a device via USB, you can hope to get 0.5A. From this we can conclude that it is safe to power a device via any USB connector.

Measurement of the current at a voltage of 5 V in mode 1.0

I measured the actual power consumption of the USB-powered device with the UNI-T UT658DUAL USB tester. It says that the device consumes 0.28A or 280mA.

Measuring the current at a voltage of 5V in 5.8 mode

The UNI-T UT658DUAL USB tester says that the device consumes 0.34A or 340mA in measurement mode.

Why do we need calculated values?

As you can see, the calculated values differ from the measured values. But they are close enough to the real values to be useful. This means that the calculated values allow us to assess the safety of connecting the device to an existing power source and choose the appropriate power source for the device. For example, if our calculations for 5V showed that the device requires 1.5 A, this would mean that it is not safe to power it via USB. However, the device must be connected to the USB when we write a program for it. Therefore, we need to decide what to do in such a situation.

How to protect the USB from high currents?

There are several ways to protect the USB from too much current. In particular, the microcontroller can be disconnected from the device before flashing a program to it. You can also connect the microcontroller to the power line via a diode. If the device is powered from an external power source, the microcontroller and everything else will work. If the device is only supplied with power through USB, only the microcontroller and the low-power components supplied with 3.3V will work.

In the beginning I used exactly this scheme for the power connection. A diode was installed between the VIN pin and the power line. Everything worked as it should, but later, which I will discuss below in the section on the problem with the shift registers, I removed the diode.

The capacitor

I use a 1000 uF electrolytic capacitor to stabilise the supply voltage. We are constantly switching about 0.3A on and off. The power supply may not be able to deliver this current quickly, which can lead to unstable operation of the device. For example, unnecessary flickering of the LEDs. The capacitor helps to ensure stable operation of the device.

The LEDs and LEDs Resistors

21.jpg
22.jpg
23.jpg
24.jpg
25.jpg
26.jpg
27.jpg
28.jpg
29.jpg
30.jpg
31.jpg
32.jpg
33.jpg

Soldering LEDs

We have 96 LEDs - 6 4x4 layers of LEDs.

When soldering the LEDs, I used the idea from this video.

How to bend LEDs legs before soldering (see the photos):

  • Bend 2 legs to the right.
  • Bend the anode (the longer leg) down approximately at the mark that the leg has

The distance between the columns is 9 PCB holes. So I made a gear like in the video which helped me a lot.

Before soldering the LEDs, I decided to make their legs longer to protect them from overheating. My LEDs don't have very long legs, and the soldering point would be very close to the LED. Now I think this is unnecessary as LEDs tolerate heat well and soldering takes very little time.

Finally, I've 4 types of LEDs:

  • Two legs are extended - 60 LEDs.
  • Extended cathode (for the bottom layer) - 12 LEDs.
  • Extended anode and bent cathode (for the upper layers on the back of the tower) - 20 LEDs.
  • Normal anode and bent cathode (for the bottom layer at the back of the tower) - 4 LEDs.

It's recommended to check all LEDs before and after soldering, as it's not so easy to replace a defective LED in an assembled tower.

And it's recommended to solder things like LEDs and IR receivers with some kind of heat sink, e.g. metal alligator clips. In some cases it's essential to use a heat sink, for example when soldering thick wires to connect the layers of the tower in our project. Otherwise, you may accidentally desolder the nearest LED solder joint.

As a result, we obtain 4 LED panels, the dimensions of which are 4x6. In their rear part there are LEDs with bent cathodes. We will solder thick wires to them, which will connect the cathodes of all LEDs of the same layer. Another wire is soldered to the front of the top layer to ensure stability.

See photos from Step 2.

Selecting the resistors for the LEDs

I decided to give each LED about 20 mA. We use a supply voltage of 9V. The forward voltage drop of the LEDs is about 2V (measured value: 2.06V). When selecting the resistor, you should also take into account that the anode of the LED is connected to the power line through an optocoupler. There is also a voltage drop on the optocoupler - about 1V in our case. The cathode of the LED is connected to the power supply through a transistor. There is also a voltage drop here. The measured value is 0.28V, and we have another small voltage drop. Let us take this voltage drop as 0.22V. We therefore have a voltage drop of 0.5V here.

Let us remember Ohm's law: R = U/I. R = 9V-2V-1V-0.5V/0.02A = 5.5V/0.02A = 275 Ohm.

Since I did not have a 275 Ohm resistor available, I decided to use the closest value. Normally, in such cases, it is advisable to use a resistor whose value exceeds the calculated value. In our case, as the LEDs are not constantly switched on, I decided that a 270 ohm resistor was perfectly acceptable.

How much current does the LED receive when a 270 Ohm resistor is used?

I = U/R = 5.5/270 = 0.0203A = 20.3mA

How much power do these resistors have to dissipate?

P = I^2*R = 0.0203^2*270 = 0.11W.

Our resistors can dissipate 0.25W, so they are suitable for our purpose.

The Shift Registers, Optocouplers and Optocouplers Resistors

34.jpg
35.jpg
36.jpg
37.jpg
38.jpg

I use PC817C 317N optocouplers.

I do not know who made the optocouplers I use. But after looking at the documentation on similar optocouplers, I found out that they are quite capable of handling a voltage of 9V and a current of 20 mA.

I connected the optocoupler as follows:

  • Pin 1 is the anode of the optocoupler LED, which is connected through a resistor to one of the outputs of the shift register. By applying a high level to this output, we switch on the optocoupler LED.
  • Pin 2 is the LED cathode of the optocoupler, which is connected to GND.
  • Pin 3 is the emitter of the phototransistor, which is connected to the LED via a resistor.
  • Pin 4 is the collector of the phototransistor, which is connected to the 9V line.

The high level of the shift register is 3.3V.

I measured the forward voltage drop at the optocoupler (pins 1 - 2) with the LCR-TC1 multifunction tester. It shows 1.18V.

The shift register must be able to switch on 8 LEDs simultaneously. The documentation states that the maximum current it can conduct through itself is 70 mA. Therefore, each shift register pin can supply a maximum of 70/8 = 8.75 mA.

I do not want to overload the shift registers and decide that the current supplied by the register pins should not exceed 8.5 mA.

Let us calculate the value of the resistor required to limit the current to this value.

R = U/I = 3.3-1.18/0.0085 = 2.12/0.0085 = 249 Ohm.

I have tried various resistors here and found that the 220 Ohm resistor is the most suitable. It supplies us with 8.35mA.

I think this is due to some additional voltage drops that I did not take into account in the calculations.

The documentation of the optocoupler states that its LED can be operated at 50mA. The measurements given in the documentation were taken at 20mA. 20mA is the current normally used when working with LEDs.

The main question now is whether the 8.35mA supplied to the optocoupler LED is sufficient for the optocoupler transistor to pass the 20mA required for the LED.

Measurements on a breadboard have shown that this is sufficient, provided that the resistor for the LED is selected correctly, taking into account the voltage drop across the phototransistor. We talked about this above. Therefore, a 220 ohm resistor was chosen for the connection of the optocoupler to the shift register.

We connect the shift registers to the ESP32 and to GND and VCC.

The Transistors

39.jpg
40.jpg
51.jpg

Why do we need transistors? I know that the pins of the ESP32 can source 40mA and sink 28mA current. We need to sink 16x20 = 320mA current (when all LEDs in a layer are on and have maximum brightness). 320 is much more than 28.

So the transistor should be able to handle about 2x320 = 640 mA. I think this or a larger safety margin is needed to not overload the transistor.

I want to control the 9V power supply via 3.3V signals from ESP32 pins. I want to use a minimum number of components. I want to connect the LED cathodes to the GND line. All this clearly indicates that I need NPN transistors, and I need to use them in switching mode.

I had several types of suitable transistors. I chose the NPN transistor BC337-25.

Here is the basic data about the transistor and about our system, which will help us to understand whether the transistor is suitable for us, and will also help us to calculate the resistance of the resistor through which the pin of the microcontroller and the base of the transistor are connected.

  • Maximum collector current: 0.8A.
  • Ic (collector current we need): 0.32A
  • Collector–emitter voltage: 45V.
  • Collector-emitter voltage we need: 9V.
  • hFE (the current gain or amplification factor) measured: 234 (min 160, max 400, measuring the parameters of different transistors of this series gives slightly different results).
  • Ucontrol (control voltage): 3.3V.
  • Ube (the voltage between the base and the emitter): 0.7V.

There are different ways to calculate resistors for transistors.

It is known that to ensure the stable operation of the transistor in the switching mode, the ratio of the collector current to the base current should not exceed the gain of the transistor.

Let's decide that we will calculate by taking the collector current to be 0.64A.

Ibase = Ic/hFE = 0.64/234 = 0.0027 A

Rbase = Ubase/Ibase = (3.3 - 0.7)/0.0027 = 2.6/0.0027 = 962 ohm.

I decided to take a 1Kohm resistor. This will give us Ibase = U/R = 2.6/1000 = 0.0026A. Let's check if the ratio of the collector current to the base current does not exceed the gain of the transistor: 0.64/0.0026 = 246. 246 is slightly larger than 234, but the specs say the transistor's min hFE is 160, and the max is 400. So, I think we are in a safe range anyway, and I think it's OK providing that the 0.64 is 2x greater safety margin than the real 0.32A.

I tested this on a breadboard. Everything worked as expected.

As a result, we have a reliable mechanism to switch the layers on and off, and we don't overload the ESP32 (every pin needs only 2.6 mA to control the transistor).

I'm using 24 AWG wires to connect layers to the transistors. Their capabilities are sufficient for our purposes.

The IR Decoder, Finding Out IR Codes, Remote Device Control

41.jpg
42.jpg
43.jpg

The IR Receiver and Remote Control

I'm using a V38238 IR receiver here. To connect it to the microcontroller, you need to use a pull-up resistor. ESP32 supports built-in pull-up resistors. I enable it in the code. I tested the device with external and built-in pull-up resistors. I couldn't find any difference.

It seems to me that IR receivers are sensitive to heat. Once I burned one of them while soldering. Use overheat protection when soldering the module. This can be a metal alligator clip.

I don't think you'll find the exact same remote as in the project. So to create it, you need to know the codes that the remote generates when you press different buttons. To do this, you can comment out a couple strings in my code to print out IR codes and use your remote codes in your project. My IR code is based on the code I found in Freenove's ESP32-C tutorial.

The device supports 6 modes and a lot of submodes. Everything is commented in the code. If necessary, the number of modes and submodes in which the device can operate can be easily expanded. This is possible thanks to the application architecture.

These buttons control the device:

  1. Power button: on/off the device.
  2. Numbers 1-5: switching between modes.
  3. "|<" and ">|" buttons: switching between submodes.
  4. "+" and "-" buttons: control LEDs brightness (in those submodes that support brightness control).
  5. Reverse arrow button: changes the symbol's orientation in text and clock mode. It makes the symbols readable from different points of view.
  6. Play button: resets current mode/submode.
  7. Menu button: switches the device to the clock setting submode in the time display mode. The first press sets the first hour digit. The second sets the second hour digit. The third sets the first minute digit. The fourth sets the second minute digit. The fifth returns to time display mode.
  8. "C" button: increase a number during clock settings. When the number reaches its maximum value, it is reset to 0.

Modes/submodes list

Here is a list of modes and submodes in which the device can operate:

0 - off mode

0.0 - all off.

1 - all on modes.

1.0 - all on.

1.1 - breathing light.

1.2 - down-top brightness decreasing.

1.3 - top-down brightness decreasing.

1.4 - edges-center brightness decreasing.

1.5 - center-edges brightness decreasing.

1.6 - opposite change in brightness of neighboring layers.

2 - random modes.

2.0 - random LEDs.

2.1 - random symbols.

3 - clock mode.

3.0 - clock.

3.1 - set/show first hours number.

3.2 - set/show second hours number.

3.3 - set/show first mins number.

3.4 - set/show second mins number.

4 - text modes.

4.0 - text.

4.1 - text.

4.2 - text.

4.3 - text.

4.4 - text.

4.5 - text.

4.6 - text.

4.7 - text.

5 - technical modes.

5.0 - show columns.

5.1 - show horizontal layers.

5.2 - show individual LEDs (voxels).

5.3 - show vertical layers.

5.4 - show vertical layers.

5.5 - show vertical layers.

5.6 - show vertical layers.

5.7 - show edges.

5.8 - measurement mode.

Soldering and Testing Components During Soldering

44.jpg
45.jpg

Before soldering, I assembled all the necessary components on a separate board. Before soldering a component, I checked its rating and functionality. To do this, I used a breadboard. I assembled a circuit on it to test optocouplers. I connected a component tester to the breadboard. With the tester, I checked resistors and transistors. When soldering, I checked the device for short circuits using a multimeter.

If the capacitor is on the board, the multimeter will beep for a while when you touch the power line and the ground line. It looks as if there is a short circuit in the device. This lasts until the capacitor is charged.

Solving the Shift Register Problem and Occam's Razor

47.jpg
49.jpg

After soldering the parts to the board, I connected the microcontroller to it. Then I did a quick check of the device. To do this, I used a simple program that I had written during the prototype assembly phase. The transistors, shift registers, optocouplers, diode and infrared receiver worked as expected. At this stage, the LED plates had not yet been soldered to the board. The leads of the resistors, which are connected to the columns of the light tower, were sticking out of the circuit board. There was therefore a risk that the 9V line could be inadvertently connected to low-voltage lines. This could damage the microcontroller. Therefore, such checks must be carried out very carefully.

After soldering in the LED plates, I carried out more complex tests. They showed that the device was not working properly. I had the feeling that the shift registers were generating incorrect signals. At the same time, the device behaved differently each time. What is the reason for this?

At first I thought the shift registers were defective and replaced them. But that didn't help. Then I decided that the microcontroller was faulty and replaced it. That didn't help either. I read somewhere that diodes can generate noise that interferes with the shift registers. I removed the diode and connected the VIN pin of the microcontroller directly to the power line. That did not help. Next, I read that you should add small ceramic capacitors to keep the shift registers stable. Bring them as close as possible to the power supply pins. I soldered the capacitor in. But that didn't help either. And then I checked the wires connecting the shift registers to the microcontroller. It turned out that one of the lines was badly soldered. This was the main reason for the unstable operation of the device. The simplest explanation for a problem is usually the most plausible. "When you hear hoofbeats think horses, not zebras."

When the connection was restored, I opened the program I used to test the device. I found an error in it. Its essence is that in one place I used the "==" sign instead of the "=" sign. As a result the light tower showed different data each time. It was supposed to show the special array's contents in a cycle. But, instead it showed the array first and then garbage from memory.

When I solved these problems, I ran into another one. It was especially noticeable when showing the light tower layers one after another. Namely, when the next layer was turned on, the previous layer also glowed, although weaker. The problem is that the ESP32 works too fast. The shift registers do not have time to switch when using standard shiftOut() function. I replaced this function with the one found here. After that, the device finally worked. Now it was possible to write a full-fledged program for it.

It is worth noting that while troubleshooting, I accidentally dropped the device and sort of crumpled it. I wasn't able to get the tower fully aligned, so you can see that the LEDs aren't positioned perfectly.

Software Overview

48.jpg
50.jpg

You can find the code in the attached files or in my GitHub repository.

I am using Arduino IDE 2.3.2.

I wrote the code in C and included detailed comments. Here I will talk about the architecture of the program and the operation of its most important parts.

The most important parts of the code connect the program and the LED tower's hardware. They are arrays int layers[LAYERS_COUNT][2] and byte columns[COLUMNS_COUNT][2]. Using these arrays, we may turn on/off layers and turn on/off LEDs.

Information about which LEDs are on/off in each layer is stored in the array byte current_animation[LAYERS_COUNT][2]. When you would like to display something, you have to fill the array using an animation function and then it will be displayed on a cube in the function void scan_layers(anim anim_func). This function accepts an anim_func function, which has the type typedef void (*anim)(). The anim_func function changes this array. It can also change the byte current_pwm[LAYERS_COUNT] array to adjust layer brightness.

In each program's cycle, we call the void decode_ir() function. If any button is pressed on the remote control, this function checks the received code. If it turns out that the code is one of the codes that it recognizes, it performs certain actions. They mainly come down to modifying the int modes[MODES_COUNT][SUBMODES_COUNT] array.

If a mode/submode is active, this means the number 1 is written to the modes array. At any moment, only one mode/submode can be active. This number determines which function from the anim animations[MODES_COUNT][SUBMODES_COUNT] array will be used to control the state of the light tower.

To modify an existing animation, you should modify the corresponding animation function. To add a new animation, you should check if we have a free slot in the modes and manual_pwm_change arrays. If the mode you wish to extend has no free submodes slots, you should increase the SUBMODES_COUNT constant. It is necessary to ensure that the number of actually existing submodes corresponds to the indicator for the desired mode from the int submodes_count_in_modes[MODES_COUNT] array. This array is used in the decode_ir() function to correctly switch between submodes. The next step is to add a pointer to the matching animation function to the animations array. This can be done in the standard void setup() function. Then you need to write a function and the new submode can be used by switching to it with the arrow buttons.

We have 2 files in the project. One of them is an .ino file which contains all the main code. The other is an .h file which contains font description and a helper function to work with it.

I widely use 0b-notation when working with byte variables. This makes the code clearer and easier to work with.

Conclusions and Future Work

4x4x6 LED Cube/Tower

I am very glad that I brought this project to completion. While working on it, I gained valuable experience that I would like to use in working on new projects. One of my next projects might be like this LED tower. But, I will probably use 5V as the supply voltage. I might also use other components (like transistor instead of optocouplers) and LEDs.

If we talk about the evolution of this project, it is possible to equip it with Bluetooth and WiFi control and create more animations.

Thank you!