avr dual rgb matrix driver
by:IPON LED
2020-05-19
A friend of mine has a great idea for a great project.
He wants to make a pair of servo rigs that mimic the movement of his hand with jumping motion.
Some laser will be placed at the top of the servo system so that he can produce some kind of laserlight show.
From the laser to the LEDs, I convinced him that we finally decided to use the RGB LED matrix.
He initially tried to drive a single LED matrix using rainbowdragon, but it didn\'t work very well.
I propose to design and build a custom drive board that can drive not only a matrix but also a single ATmega328p-
The chips used on the rainbowdragon board are the same.
Take a look at this structure, here I teach you how to build the entire parent project!
So, pick up your soldering iron and order some parts.
This is to do some real embedded system design.
As always, we need to collect some materials before we go deep into the project.
A lot has happened here, so be sure to check the parts carefully!
Components and components that use multiplexing LEDs can be tricky, but we are using RGB LEDs, so imagine each RGB as three separate LEDs.
For the 8x8 matrix, that is, 192 Total LEDs on a single matrix.
Although there are only 32 connection pins, the color and brightness of each LED can still be controlled separately.
View this chart from the data table of the RGB matrix I am using.
You should see that each \"row\" has a common anode.
Again, each column (
LED of each color)
Share a cathode.
To drive only a single LED, we will drive its shared anode HI and cathode LO.
In order to control the color of each LED, we have to do some low-level multiplexing.
There are eight rows of anode, so only open each row (powered)
The time is 1/8.
The trick is to switch too fast between which lines so that the human eye cannot detect it.
In this way, the pin driving the LED cathode can only control one line of LED at a time.
When the active row switches, a new value for the cathode line must be loaded.
Just by looking at the Matrix I get, it is impossible to know what the pin is.
Also don\'t know if the pin number wraps the matrix in the same way as the pin number on the IC.
The only way to really understand is to apply voltage to a few pins until you see the pattern.
Using the schematic in the previous step, we can try to light up a single LED.
If a positive voltage is applied on pin 17 and a negative voltage is applied on pin 1, the blue LED in the first column of the first row should be turned on.
Do not apply direct battery voltage to the pin.
Online current limiting resistor is always used.
The 10k resistor and 9v battery are working properly.
If the PIN numbers are similar to the IC, pin 1 and pin 17 will be in the opposite corner, and if not, they will cross each other directly.
Once you think you have found this blue LED, try to test your findings by turning on a few other random LEDs.
Be sure to mark pin 1 as soon as you have written down the pin number!
I prefer to insert a matrix on two vertical breadboards for development;
However, this means that my row is actually a column.
So I call the \"row\" of the data table \"column \".
\"I also started counting from 0 instead of 1, which is at low-level control.
With a basic understanding of how to reuse LEDs, we can build a circuit to drive them.
The single ATmega328p will be used with an external month 16mhz crystal.
The chip will quickly switch control between eight co-yang poles (
Remember, these are the \"rows\" on the data table \").
Since the current of all LEDs in a single row is too large to power through the MCU pin, I am using HI-
Side MOSFET pair for power supply of LED current.
Keep in mind that the current source is located on the front of the Assembly.
There is a current sink on the negative side.
You can think this way (
At least in general circuit design direction)
: The Source pushes the current when the sink pulls the current.
Initially, I drove the transistor directly from the MCU, but I added an external 8 displacement bit register to do this in order to release the IO line for future capability expansion.
Current sink is handled by several constant current sinks of 8 channels.
6 chips are required for 2 matrices
Each column of R, G, and B LEDs has one.
You should also note that I have included an I2C connection.
This will be used for external control of LED color and/or flash pattern.
Also, the ISP lines are not shown in the schematic, but it is a good idea to include them in the circuit so you can program the chip!
Finally, there is a line called \"servo control\" and the only value that may change is the external resistance on the TLC5916 current receiver.
These resistors set the current for the LEDs and I will discuss how to set these values in the next few steps.
I also included this track as a Cadsoft Eagle file.
The servo control line is not required for this project.
On each LED current receiver there is an external LED connection R-EXT.
This resistor sets the LED current;
However, it won\'t share this current so we don\'t need to worry about the rated power.
According to the data sheet (
I attached it for your viewing pleasure)
The equation for determining the LED current is as follows :(1. 25V / R-Ext)
* 15 gain can actually be adjusted by a special control line sequence, but it is easiest to find the resistance using the default gain and step size.
Now, there is a scientific basis for the correct white balanced LEDs;
However, I was able to do this quickly by simply testing and observing.
If you don\'t know, a single color created by an rgb led is formed by combining different levels of red, green, and blue.
If all three lights are on, you should be able to see pure white light.
Here is the basic combination, each LED is fully turned on or off.
If the current of all three LEDs is the same, the color looks wrong.
This is the result of different intensity produced by LEDs of different colors at different currents.
Next, we will determine the resistance value of each LED current receiver.
Blue LEDs are the strongest in my matrix.
Red seems stronger than green;
However, I need more red instead of green in order to keep the balance.
With this in mind, the Blue current is limited the most, followed by green, and the red LEDs are the hardest to drive.
For my matrix, I determined the following values: the driver can absorb a higher level of current, the led has a higher rating, especially on the 1/8, but for me, this is very bright.
We need a lot of clock cycles to drive so many LEDs
This means we need to change the default of the control clock source.
The fuse that comes with the ATmega328p is set to run on the internal 8MHz Oscillator.
The clock then drops to 1 MHz in the inner part.
I decided to use an external 16MHz crystal.
This is the same timing as many of the original Arduino boards use, and also makes the numbers involved in timing control uniform.
It should be noted that programming the fuse is very simple, but this is also the easiest way to program the chip.
You can easily disable programming together, or set the clock source to some odd frequency.
Be sure to check your byte values carefully before programming!
Load the terminal console and issue the following command:> avrdudeIf this is an unknown command then you need to install some software-
That is, through
The GCC compiler and the AVRDUDE programming tool.
They are bundled together in WinAVR or Atmel Studio, but can also be installed separately on any operating system.
Using the amazing fuse calculator provided here, we can see that if using an external 16MHz crystal with no clock divided by the 8 option, we should change the low fuse to 0xE7.
This is the basic command to change the low fuse:> avrdude-p -c -P -
U lfuse: w: mIf you are using the programmer I recommend and if not, the following command will work and you will need to replace some values with values that match your settings. > avrdude -p atmega328p -c usbtiny -P usb -
U lfuse: w: 0x7 7: mIf is successful and a success message should be seen.
You can verify the fuse bit at any time using the following command:> avrdude-p atmega328p -c usbtiny -P usb -
The library provided by VThe defines the following functions in pubnub/pubnub. h.
Complete source code is provided in this GitHub repository.
Before I dive into the code, let\'s take a moment to review what\'s going on.
Once initialized, the main loop is only responsible for the LED chase sequence.
All actual controls are handled in the interrupt service program.
To do this, use 8-bit timer/counter 0.
Conceptually, the timer is used to indicate when the led is turned on or when the led is turned off.
Which LEDs should be turned on or off are determined by a pair of multi-dimensional arrays: Next, we will discuss how Timer 0 actually creates colors.
Led array is 2x8x3 bytes-
One byte per color line (R, G, & B)
In each column, in each array.
Each bit in this byte represents an LED in the row.
The color array is 2x8 bytes-
Represents one byte of the desired color for each LED.
In order to have enough time to control the two matrices, the resolution of 4 is being used.
This seems small compared to the 255 resolution used in computer colors, but remember 4x4x4 = 64 unique colors.
It\'s possible to add some resolution, but 64 unique colors seem a lot to me.
Actually, many of these colors are very similar, so I reduced it to 44 in the module/macro/color_8 bit. h header file.
The file also contains an array of individual R, G, and B levels required to create each available color.
Next, we will discuss how Timer 0 actually creates colors.
Complete source code is provided in this GitHub repository.
As mentioned earlier, an 8-bit timer is used to control all LED colors.
Each launch that compares the match signals a timed event.
The resolution of 4 means the actual values of 0, 1, 2 and 3.
A variable is used to calculate what ISR trigger time it is currently, and a switch-
Case statements are used to do something different at different times.
Nothing happens when the count is equal to the maximum resolution, because if all LEDs have been turned on, then they should remain turned on, and if they have been turned off, they should remain turned off.
At 0, it\'s time to switch the control to the next column in the 8 column.
All the led is then set to open but not actually.
The code then continues to handle the default for all other times.
In the last case, loop over each rgb led in the active column of the two matrices.
If the current counter is equal to the turn-off time of the R, G, or B LEDs of the desired color, the LED is set to turn off.
Finally, the data is transferred to a constant current drive to actually turn the LEDs on or off.
This shift is a bit-
The bang version of the actual SPI protocol, each LED driver chip has a separate data line, so it can be loaded at once.
Next, let\'s talk about the default operation of the driver.
Complete source code is provided in this GitHub repository.
As I said before, this matrix driver is actually part of a larger project.
Therefore, the circuit is set to act as a TWI (I2C)bus slave.
The current code will run the default chase sequence (
A smiling face)
, Waiting for further instructions on the TWI bus.
For larger items, each bit in the byte sends a data byte that represents the number of matrices to be enabled.
After receiving the data, the loop _ quads sequence will be enabled.
This is just looping through all possible colors defined in Module/macro/color_8bit.
H, showing the color of any matrix quadrant enabled.
If the data is not received after such a long time (
About 10 seconds)
The matrix is restored to the default chase sequence (
A smiling face).
The work of TWI is done by the TWI Interrrupt service program.
Although the ISR only needs one byte of data, it will be very easy to modify this code to handle more data bytes.
Doing so will allow external control over all aspects of the matrix drive, including setting up a single LED color, chase sequence, or even inactive display!
I highly recommend that you build the circuit on the breadboard and play with the firmware before making anything more permanent, but soldering the circuit is the ultimate goal.
You may find that some different component configurations are more effective for your purposes, and it is always easier to switch parts on a breadboard than to design something from a PCB.
I chose to weld everything to a pair of perf boards.
Ideally, the whole circuit is placed on a piece of board, but I would like to have the parts nicely laid out as the project may be shown somewhere.
You can also design a custom PCB, but there is no need here.
That is to do it!
As I said, these matrices are part of a larger project, so the drive is set to be controlled by other circuit components.
Please let me know if you have any questions and make sure to check my main project description sheet!
He wants to make a pair of servo rigs that mimic the movement of his hand with jumping motion.
Some laser will be placed at the top of the servo system so that he can produce some kind of laserlight show.
From the laser to the LEDs, I convinced him that we finally decided to use the RGB LED matrix.
He initially tried to drive a single LED matrix using rainbowdragon, but it didn\'t work very well.
I propose to design and build a custom drive board that can drive not only a matrix but also a single ATmega328p-
The chips used on the rainbowdragon board are the same.
Take a look at this structure, here I teach you how to build the entire parent project!
So, pick up your soldering iron and order some parts.
This is to do some real embedded system design.
As always, we need to collect some materials before we go deep into the project.
A lot has happened here, so be sure to check the parts carefully!
Components and components that use multiplexing LEDs can be tricky, but we are using RGB LEDs, so imagine each RGB as three separate LEDs.
For the 8x8 matrix, that is, 192 Total LEDs on a single matrix.
Although there are only 32 connection pins, the color and brightness of each LED can still be controlled separately.
View this chart from the data table of the RGB matrix I am using.
You should see that each \"row\" has a common anode.
Again, each column (
LED of each color)
Share a cathode.
To drive only a single LED, we will drive its shared anode HI and cathode LO.
In order to control the color of each LED, we have to do some low-level multiplexing.
There are eight rows of anode, so only open each row (powered)
The time is 1/8.
The trick is to switch too fast between which lines so that the human eye cannot detect it.
In this way, the pin driving the LED cathode can only control one line of LED at a time.
When the active row switches, a new value for the cathode line must be loaded.
Just by looking at the Matrix I get, it is impossible to know what the pin is.
Also don\'t know if the pin number wraps the matrix in the same way as the pin number on the IC.
The only way to really understand is to apply voltage to a few pins until you see the pattern.
Using the schematic in the previous step, we can try to light up a single LED.
If a positive voltage is applied on pin 17 and a negative voltage is applied on pin 1, the blue LED in the first column of the first row should be turned on.
Do not apply direct battery voltage to the pin.
Online current limiting resistor is always used.
The 10k resistor and 9v battery are working properly.
If the PIN numbers are similar to the IC, pin 1 and pin 17 will be in the opposite corner, and if not, they will cross each other directly.
Once you think you have found this blue LED, try to test your findings by turning on a few other random LEDs.
Be sure to mark pin 1 as soon as you have written down the pin number!
I prefer to insert a matrix on two vertical breadboards for development;
However, this means that my row is actually a column.
So I call the \"row\" of the data table \"column \".
\"I also started counting from 0 instead of 1, which is at low-level control.
With a basic understanding of how to reuse LEDs, we can build a circuit to drive them.
The single ATmega328p will be used with an external month 16mhz crystal.
The chip will quickly switch control between eight co-yang poles (
Remember, these are the \"rows\" on the data table \").
Since the current of all LEDs in a single row is too large to power through the MCU pin, I am using HI-
Side MOSFET pair for power supply of LED current.
Keep in mind that the current source is located on the front of the Assembly.
There is a current sink on the negative side.
You can think this way (
At least in general circuit design direction)
: The Source pushes the current when the sink pulls the current.
Initially, I drove the transistor directly from the MCU, but I added an external 8 displacement bit register to do this in order to release the IO line for future capability expansion.
Current sink is handled by several constant current sinks of 8 channels.
6 chips are required for 2 matrices
Each column of R, G, and B LEDs has one.
You should also note that I have included an I2C connection.
This will be used for external control of LED color and/or flash pattern.
Also, the ISP lines are not shown in the schematic, but it is a good idea to include them in the circuit so you can program the chip!
Finally, there is a line called \"servo control\" and the only value that may change is the external resistance on the TLC5916 current receiver.
These resistors set the current for the LEDs and I will discuss how to set these values in the next few steps.
I also included this track as a Cadsoft Eagle file.
The servo control line is not required for this project.
On each LED current receiver there is an external LED connection R-EXT.
This resistor sets the LED current;
However, it won\'t share this current so we don\'t need to worry about the rated power.
According to the data sheet (
I attached it for your viewing pleasure)
The equation for determining the LED current is as follows :(1. 25V / R-Ext)
* 15 gain can actually be adjusted by a special control line sequence, but it is easiest to find the resistance using the default gain and step size.
Now, there is a scientific basis for the correct white balanced LEDs;
However, I was able to do this quickly by simply testing and observing.
If you don\'t know, a single color created by an rgb led is formed by combining different levels of red, green, and blue.
If all three lights are on, you should be able to see pure white light.
Here is the basic combination, each LED is fully turned on or off.
If the current of all three LEDs is the same, the color looks wrong.
This is the result of different intensity produced by LEDs of different colors at different currents.
Next, we will determine the resistance value of each LED current receiver.
Blue LEDs are the strongest in my matrix.
Red seems stronger than green;
However, I need more red instead of green in order to keep the balance.
With this in mind, the Blue current is limited the most, followed by green, and the red LEDs are the hardest to drive.
For my matrix, I determined the following values: the driver can absorb a higher level of current, the led has a higher rating, especially on the 1/8, but for me, this is very bright.
We need a lot of clock cycles to drive so many LEDs
This means we need to change the default of the control clock source.
The fuse that comes with the ATmega328p is set to run on the internal 8MHz Oscillator.
The clock then drops to 1 MHz in the inner part.
I decided to use an external 16MHz crystal.
This is the same timing as many of the original Arduino boards use, and also makes the numbers involved in timing control uniform.
It should be noted that programming the fuse is very simple, but this is also the easiest way to program the chip.
You can easily disable programming together, or set the clock source to some odd frequency.
Be sure to check your byte values carefully before programming!
Load the terminal console and issue the following command:> avrdudeIf this is an unknown command then you need to install some software-
That is, through
The GCC compiler and the AVRDUDE programming tool.
They are bundled together in WinAVR or Atmel Studio, but can also be installed separately on any operating system.
Using the amazing fuse calculator provided here, we can see that if using an external 16MHz crystal with no clock divided by the 8 option, we should change the low fuse to 0xE7.
This is the basic command to change the low fuse:> avrdude-p -c -P -
U lfuse: w: mIf you are using the programmer I recommend and if not, the following command will work and you will need to replace some values with values that match your settings. > avrdude -p atmega328p -c usbtiny -P usb -
U lfuse: w: 0x7 7: mIf is successful and a success message should be seen.
You can verify the fuse bit at any time using the following command:> avrdude-p atmega328p -c usbtiny -P usb -
The library provided by VThe defines the following functions in pubnub/pubnub. h.
Complete source code is provided in this GitHub repository.
Before I dive into the code, let\'s take a moment to review what\'s going on.
Once initialized, the main loop is only responsible for the LED chase sequence.
All actual controls are handled in the interrupt service program.
To do this, use 8-bit timer/counter 0.
Conceptually, the timer is used to indicate when the led is turned on or when the led is turned off.
Which LEDs should be turned on or off are determined by a pair of multi-dimensional arrays: Next, we will discuss how Timer 0 actually creates colors.
Led array is 2x8x3 bytes-
One byte per color line (R, G, & B)
In each column, in each array.
Each bit in this byte represents an LED in the row.
The color array is 2x8 bytes-
Represents one byte of the desired color for each LED.
In order to have enough time to control the two matrices, the resolution of 4 is being used.
This seems small compared to the 255 resolution used in computer colors, but remember 4x4x4 = 64 unique colors.
It\'s possible to add some resolution, but 64 unique colors seem a lot to me.
Actually, many of these colors are very similar, so I reduced it to 44 in the module/macro/color_8 bit. h header file.
The file also contains an array of individual R, G, and B levels required to create each available color.
Next, we will discuss how Timer 0 actually creates colors.
Complete source code is provided in this GitHub repository.
As mentioned earlier, an 8-bit timer is used to control all LED colors.
Each launch that compares the match signals a timed event.
The resolution of 4 means the actual values of 0, 1, 2 and 3.
A variable is used to calculate what ISR trigger time it is currently, and a switch-
Case statements are used to do something different at different times.
Nothing happens when the count is equal to the maximum resolution, because if all LEDs have been turned on, then they should remain turned on, and if they have been turned off, they should remain turned off.
At 0, it\'s time to switch the control to the next column in the 8 column.
All the led is then set to open but not actually.
The code then continues to handle the default for all other times.
In the last case, loop over each rgb led in the active column of the two matrices.
If the current counter is equal to the turn-off time of the R, G, or B LEDs of the desired color, the LED is set to turn off.
Finally, the data is transferred to a constant current drive to actually turn the LEDs on or off.
This shift is a bit-
The bang version of the actual SPI protocol, each LED driver chip has a separate data line, so it can be loaded at once.
Next, let\'s talk about the default operation of the driver.
Complete source code is provided in this GitHub repository.
As I said before, this matrix driver is actually part of a larger project.
Therefore, the circuit is set to act as a TWI (I2C)bus slave.
The current code will run the default chase sequence (
A smiling face)
, Waiting for further instructions on the TWI bus.
For larger items, each bit in the byte sends a data byte that represents the number of matrices to be enabled.
After receiving the data, the loop _ quads sequence will be enabled.
This is just looping through all possible colors defined in Module/macro/color_8bit.
H, showing the color of any matrix quadrant enabled.
If the data is not received after such a long time (
About 10 seconds)
The matrix is restored to the default chase sequence (
A smiling face).
The work of TWI is done by the TWI Interrrupt service program.
Although the ISR only needs one byte of data, it will be very easy to modify this code to handle more data bytes.
Doing so will allow external control over all aspects of the matrix drive, including setting up a single LED color, chase sequence, or even inactive display!
I highly recommend that you build the circuit on the breadboard and play with the firmware before making anything more permanent, but soldering the circuit is the ultimate goal.
You may find that some different component configurations are more effective for your purposes, and it is always easier to switch parts on a breadboard than to design something from a PCB.
I chose to weld everything to a pair of perf boards.
Ideally, the whole circuit is placed on a piece of board, but I would like to have the parts nicely laid out as the project may be shown somewhere.
You can also design a custom PCB, but there is no need here.
That is to do it!
As I said, these matrices are part of a larger project, so the drive is set to be controlled by other circuit components.
Please let me know if you have any questions and make sure to check my main project description sheet!
Custom message