The company has a group of cooperation teams engaged in the 100w led chip industry for many years, with dedication, innovation spirit and service awareness, and has established a sound quality control and management system to ensure product quality.
In this tutorial I show you how to build a 100W RGB-LED driver board based on the LM3404 constant current buck regulator.
Alternatively you can use single color 30W LEDs per channel that have roughly the same forward voltages and exactly 0.9A forward current.
RGB-LEDs on AliExpress
Single color LEDs on AliExpress
If you want to use an RGB-LED chip with different power rating, use this online calculator to get proper component values for the driving circuit:
http://www.nomad.ee/micros/lm3404/
The BOM file also contains untested part list for 3-50W RGB-LEDs.
PCB images are rendered using tracespace view:
https://tracespace.io/view/
This is probably the best open source PCB render engine on the internet.
You can use a prepared LED heat sink too, if it has a hole pattern of 34×34 mm with M3 threading. I used this CPU heat sink because it was more accessible to me.
Drilling positions marked (pre-applied thermal paste is removed) Drilling Ø2.5 mm holes Tapping M3 threadsRGB-LED chips usually come in common anode configuration (positive pins are connected). The board handles channels separately and generates different forward voltages automatically so you have to split the anode pin with a small wire cutter to get 6 pins in total.
Solder wires to the pins and cover the joints with heat shrink tubes to avoid short circuits.
Finally when mounting the chip to the heat sink apply thermal paste between the chip and heat sink! Make sure it’s spread thinly across the whole chip surface. This way heat moves to the aluminum block more efficiently.
[code language="cpp"]
// Default PWM-frequency for Timer 1 and 2 is 490.2 Hz
// 8-bit gamma correction table for linear brightness control
const byte PROGMEM gamma8[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255
};
byte frpmPin = 2; // Fan RPM sense input
byte fpwmPin = 3; // Fan PWM control output
byte enPin = 12; // Enable LED drivers
byte redPin = 11; // Red-channel: Timer 2 "A" output
byte greenPin = 10; // Green-channel: Timer 1 "B" output
byte bluePin = 9; // Blue-channel: Timer 1 "A" output
byte temp = A0; // Heat sink temperature sensor analog input
int LEDTemp = 0; // Heat sink temperature
byte calculatedPWM = 0; // Control fan RPM with this PWM-value
volatile int fanRPM = 0; // Calculated fan RPM
void setup()
{
Serial.begin(115200);
pinMode(frpmPin, INPUT_PULLUP);
pinMode(fpwmPin, OUTPUT);
pinMode(enPin, OUTPUT);
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
pinMode(temp, INPUT);
pinMode(LED_BUILTIN, OUTPUT);
attachInterrupt(digitalPinToInterrupt(frpmPin), calculateFanRPM, RISING);
updateColor(redPin, 0, true);
updateColor(greenPin, 0, true);
updateColor(bluePin, 0, true);
digitalWrite(enPin, LOW); // enable all LM3404 drivers
digitalWrite(LED_BUILTIN, LOW); // turn off Arduino UNO's built-in LED
}
void loop()
{
//readHeatSinkTemp();
//changeFanRPM();
//reportFanRPM();
fadeAllColors(5); // wait 5 milliseconds between brightness changes
}
void updateColor(byte color, byte dutyCycle, bool gammaCorrection)
{
if (gammaCorrection)
{
analogWrite(color, pgm_read_byte(&gamma8[dutyCycle])); // use the lookup table to get corrected duty cycle value
}
else
{
analogWrite(color, dutyCycle); // use original duty cycle value
}
}
void fadeAllColors(int wait)
{
for (int i = 0; i <= 255; i++) // fade in
{
updateColor(redPin, i, true);
delay(wait);
}
for (int i = 255; i >= 0; i--) // fade out
{
updateColor(redPin, i, true);
delay(wait);
}
for (int i = 0; i <= 255; i++) // fade in
{
updateColor(greenPin, i, true);
delay(wait);
}
for (int i = 255; i >= 0; i--) // fade out
{
updateColor(greenPin, i, true);
delay(wait);
}
for (int i = 0; i <= 255; i++) // fade in
{
updateColor(bluePin, i, true);
delay(wait);
}
for (int i = 255; i >= 0; i--) // fade out
{
updateColor(bluePin, i, true);
delay(wait);
}
}
void readHeatSinkTemp(void)
{
LEDTemp = analogRead(temp);
//calculatedPWM = 0; // TODO
}
void changeFanRPM(void)
{
//analogWrite(fpwmPin, calculatedPWM);
}
void calculateFanRPM(void) // ISR
{
//fanRPM = 0; // TODO
}
void reportFanRPM(void)
{
// TODO
//Serial.print("Fan RPM: ");
//Serial.println(fanRPM);
}
[/code]
This example uses BLE (Bluetooth Low Energy) to receive commands from a smartphone app called Bluefruit (Adafruit). After connecting to the ESP32 module navigate to Controller / Color Picker, select a color and tap the Select button. The RGB-LED should change its color immediately.
To control the cooling fan RPM send a text message via UART menu starting with the letter "F" following a single character. This character’s byte value is used as a PWM value. Example: F0, F1, F2, …, FA, FB, FC, …, Fa, Fb, Fc, …, Fz. I will rewrite this method to be more easy to use.
[code language="cpp"]
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
// 8-bit gamma correction table for linear brightness control
const byte PROGMEM gamma8[] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
90, 92, 93, 95, 96, 98, 99,101,102,104,105,107,109,110,112,114,
115,117,119,120,122,124,126,127,129,131,133,135,137,138,140,142,
144,146,148,150,152,154,156,158,160,162,164,167,169,171,173,175,
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255
};
byte redChannel = 0; // red-channel number
byte redPin = 25; // red-channel output pin
byte greenChannel = 1; // green-channel number
byte greenPin = 26; // green-channel output pin
byte blueChannel = 2; // blue-channel number
byte bluePin = 27; // blue-channel output pin
int redPotValue = 0; // red potentiometer
int greenPotValue = 0; // green potentiometer
int bluePotValue = 0; // blue potentiometer
int pwmFrequency = 500; // Hz
byte pwmResolution = 8; // bit
byte fanPwmPin = 14;
byte fanPwmChannel = 3;
// TODO: add LM3404 enable pin, fan PWM pin and temperature reading pin (analog)
// Fan RPM input pin can't be connected directly because it is pulled up to +5V and the signal would damage the 3.3V ESP32 device. Additional logic level converter circuit must be used.
BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
uint8_t txValue = 0; // txValue is global, rxValue is local for now...
// See the following for generating UUIDs:
// https://www.uuidgenerator.net/
#define SERVICE_UUID "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID (fixed)
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
void updateColor(byte color, byte dutyCycle, bool gammaCorrection)
{
if (gammaCorrection)
{
ledcWrite(color, pgm_read_byte(&gamma8[dutyCycle])); // use the lookup table to get corrected duty cycle value
}
else
{
ledcWrite(color, dutyCycle); // use original duty cycle value
}
}
void fadeAllColors(int wait)
{
for (int i = 0; i <= 255; i++) // fade in
{
updateColor(redChannel, i, true);
delay(wait);
}
for (int i = 255; i >= 0; i--) // fade out
{
updateColor(redChannel, i, true);
delay(wait);
}
for (int i = 0; i <= 255; i++) // fade in
{
updateColor(greenChannel, i, true);
delay(wait);
}
for (int i = 255; i >= 0; i--) // fade out
{
updateColor(greenChannel, i, true);
delay(wait);
}
for (int i = 0; i <= 255; i++) // fade in
{
updateColor(blueChannel, i, true);
delay(wait);
}
for (int i = 255; i >= 0; i--) // fade out
{
updateColor(blueChannel, i, true);
delay(wait);
}
}
class MyServerCallbacks: public BLEServerCallbacks
{
void onConnect(BLEServer* pServer)
{
deviceConnected = true;
};
void onDisconnect(BLEServer* pServer)
{
deviceConnected = false;
}
};
class MyCallbacks: public BLECharacteristicCallbacks
{
// when something arrives to this sketch it triggers the onWrite callback!!!
void onWrite(BLECharacteristic *pCharacteristic)
{
// this is a local variable, can only be used within this function!!!
std::string rxValue = pCharacteristic->getValue();
if (rxValue.length() > 0)
{
Serial.print("RX: ");
for (int i = 0; i < rxValue.length(); i++)
{
if (rxValue[i] < 16) Serial.print("0");
Serial.print(rxValue[i], 16);
Serial.print(" ");
}
Serial.println();
if ((rxValue[0] == 0x21) && (rxValue[1] == 0x43)) // these two conditions refer to the "Color Picker" tool in the Bluefruit smartphone app
{
updateColor(redChannel, rxValue[2], true);
updateColor(greenChannel, rxValue[3], true);
updateColor(blueChannel, rxValue[4], true);
}
else if (rxValue[0] == 0x46) // "F" for cooling fan PWM
{
ledcWrite(fanPwmChannel, rxValue[1]); // duty cycle is the second byte
}
}
}
};
void setup()
{
Serial.begin(115200);
// Configure RGB-LED channels
ledcSetup(redChannel, pwmFrequency, pwmResolution);
ledcAttachPin(redPin, redChannel);
ledcWrite(redChannel, 0);
ledcSetup(greenChannel, pwmFrequency, pwmResolution);
ledcAttachPin(greenPin, greenChannel);
ledcWrite(greenChannel, 0);
ledcSetup(blueChannel, pwmFrequency, pwmResolution);
ledcAttachPin(bluePin, blueChannel);
ledcWrite(blueChannel, 0);
ledcSetup(fanPwmChannel, pwmFrequency, pwmResolution);
ledcAttachPin(fanPwmPin, fanPwmChannel);
ledcWrite(fanPwmChannel, 0);
// Configure analog reading
analogReadResolution(10); // Default of 12 is not very linear. Recommended to use 10 or 11 depending on needed resolution.
analogSetAttenuation(ADC_11db); // Default is 11db which is very noisy. Recommended to use 2.5 or 6.
// Create the BLE Device
BLEDevice::init("RGB Mood Light");
// Create the BLE Server
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
// Create the BLE Service
BLEService *pService = pServer->createService(SERVICE_UUID);
// Create a BLE Characteristic
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_TX,
BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristic->addDescriptor(new BLE2902());
BLECharacteristic *pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID_RX,
BLECharacteristic::PROPERTY_WRITE
);
pCharacteristic->setCallbacks(new MyCallbacks());
// Start the service
pService->start();
// Start advertising
pServer->getAdvertising()->start();
Serial.println("Waiting a client connection to notify...");
}
void loop()
{
if (deviceConnected)
{
// Send a byte-value back to the smartphone
//Serial.printf("*** Sent Value: %d ***\n", txValue);
//pCharacteristic->setValue(&txValue, 1);
//pCharacteristic->notify();
//txValue++;
}
else
{
fadeAllColors(5); // wait 5 milliseconds between brightness changes
// redPotValue = analogRead(32) / 4; // Convert 10-bit reading to 8-bit
// greenPotValue = analogRead(33) / 4;
// bluePotValue = analogRead(34) / 4;
// delay(50);
//
// updateColor(redChannel, redPotValue, true);
// updateColor(greenChannel, greenPotValue, true);
// updateColor(blueChannel, bluePotValue, true);
}
}
[/code]
V1.30: Original
V1.31:
V1.32:
More
Like
Loading...
For more information 100w led chip, please get in touch with us!