Dimming LEDs with hardware PWM?

I am moving some hardware from DaisyDuino over to libdaisy (mainly due to space constraints) and I have trouble getting the RGB-LED to dimm properly. Over in Arduino-land what I would do is to call analogWrite(pin, 255) for each of the three color channels and it would work as expected.

Now I am aware there is a Led and a RgbLed implementation, but the code for the LED doesn’t look as if it is using hardware PWM?

So my questions:

  1. Is there any way to use hardware PWM on the pins that should support it (or any usable allternative to analogWrite)?

  2. If there is none, is there any example how to setup the a timer interrupt that gives predictable results with the LEDs?

As of now if I run the Led.Set(val) method, any other work that happens in the main loop leads to the LED blinking off and on or not updating as desired – seeing the implementation this is not really surprising. Any pointers to a good solution?

The LED Class is a simple Software PWM. We are still working on a hardware PWM.

Is the RGB LED you’re using something like this one?

1 Like

Yes, I use a Kingbright WP154A4SUREQBFZGW – a 4-terminal common kathode LED. For a schematic see: https://code.hfbk.net/sdiy/daisyy/daisyy-hardware/-/raw/main/images/schematic-1.jpg

I rule out hardware issues, it is on a soldered PCB that works flawlessly and very reliably with my DaisyDuino code. Here my Arduino RgbLed class from said code:

class RGBLed {
  int pin_red;
  int pin_green;
  int pin_blue;

  public:
    RGBLed(int pin_red, int pin_green, int pin_blue);
    void init();
    void off();
    void setColor(int r, int g, int b);
};

RGBLed::RGBLed(int pin_red, int pin_green, int pin_blue) {
  this->pin_red = pin_red;
  this->pin_green = pin_green;
  this->pin_blue = pin_blue;
}

void RGBLed::init() {
  pinMode(this->pin_red, OUTPUT);
  pinMode(this->pin_green, OUTPUT);
  pinMode(this->pin_blue, OUTPUT);
}

void RGBLed::off() {
  digitalWrite(this->pin_red, LOW);
  digitalWrite(this->pin_green, LOW);
  digitalWrite(this->pin_blue, LOW);
}

void RGBLed::setColor(int r, int g, int b) {
  r = min(255, max(0, r));
  g = min(255, max(0, g));
  b = min(255, max(0, b));
  analogWrite(this->pin_red, r);
  analogWrite(this->pin_green, g);
  analogWrite(this->pin_blue, b);
}

Creating the object as follows:

// RGB LED               R    G    B
RGBLed rgb_led = RGBLed(A10, A11, A9);

Of course this all boils down to the analogWrite-function from arduino.h

Looks to me like the Led class, and RgbLed, are set up to be updated at 1kz. Which is the same rate as the Audio callback with 48 buffer size.

Updated from the audio callback, the software PWM would be unaffected by whatever happens in main().

1 Like

Aha! Now I get how it is meant to be used. I will investigate whether this works for my usecase.
This is certainly info that belongs into the docu.

But I guess in the long run hardware PWM would be even better.

Update: Okay that seems to work well for my purposes as of now.

2 Likes

Hey everyone, I’d like to revive this thread with some new questions about dimming LEDs with software PWM.
@Takumi_Ogata

I’m finding that with a 1kHz update rate (48 block size and 48k sample rate), my LEDs are flickering at low brightness. If I reduce the block size to 24, they’re stable, but my audio processing can’t handle that low of a block size. I’m wondering if you can think of any ideas to get stable dim LED updating.
Here are some possible starting questions:

  1. Is it possible to make another interrupt callback function just for the LEDs, similar to the audio callback? I think it’d have to be highest priority, but that might be ok since the work is minimal.
  2. Is there a possibility of reducing the PWM bit depth? I’ve looked through the code for the LED class, and I see that it’s supposed to be 8-bit PWM, which I wouldn’t want to reduce any further. From led.h:

    However, in the implementation, it seems to be getting quantized to 16 bit resolution.
    From led.cpp:

    image
    Am I missing something there? Is the 8-bit quantization happening somewhere else? If not, maybe that could be an easy fix.

Thanks!
Aaron