I’ve decided rather than making a topic here every time I have a question
on my show, I’ll just have one big topic where I post all my questions; so here it is!
On episode 31, I’ve become stumped on how the PWM signals are driving the LEDs in the
LED fade demo included with the freedom-e SDK.
In led_fade.c we see the following code:
uint16_t r=0xFF;
uint16_t g=0;
uint16_t b=0;
char c = 0;
// Set up RGB PWM
PWM1_REG(PWM_CFG) = 0;
// To balance the power consumption, make one left, one right, and one center aligned.
PWM1_REG(PWM_CFG) = (PWM_CFG_ENALWAYS) | (PWM_CFG_CMP2CENTER);
PWM1_REG(PWM_COUNT) = 0;
// Period is approximately 244 Hz
// the LEDs are intentionally left somewhat dim,
// as the full brightness can be painful to look at.
PWM1_REG(PWM_CMP0) = 0;
GPIO_REG(GPIO_IOF_SEL) |= ( (1 << GREEN_LED_OFFSET) | (1 << BLUE_LED_OFFSET) | (1 << RED_LED_OFFSET));
GPIO_REG(GPIO_IOF_EN ) |= ( (1 << GREEN_LED_OFFSET) | (1 << BLUE_LED_OFFSET) | (1 << RED_LED_OFFSET));
GPIO_REG(GPIO_OUTPUT_XOR) &= ~( (1 << GREEN_LED_OFFSET) | (1 << BLUE_LED_OFFSET));
GPIO_REG(GPIO_OUTPUT_XOR) |= (1 << RED_LED_OFFSET);
while(1){
volatile uint64_t * now = (volatile uint64_t*)(CLINT_CTRL_ADDR + CLINT_MTIME);
volatile uint64_t then = *now + 100;
while (*now < then) { }
if(r > 0 && b == 0){
r--;
g++;
}
if(g > 0 && r == 0){
g--;
b++;
}
if(b > 0 && g == 0){
r++;
b--;
}
uint32_t G = g;
uint32_t R = r;
uint32_t B = b;
PWM1_REG(PWM_CMP1) = G << 4; // PWM is low on the left, GPIO is low on the left side, LED is ON on the left.
PWM1_REG(PWM_CMP2) = (B << 1) << 4; // PWM is high on the middle, GPIO is low in the middle, LED is ON in the middle.
PWM1_REG(PWM_CMP3) = 0xFFFF - (R << 4); // PWM is low on the left, GPIO is low on the right, LED is on on the right.
From what I understand, we aren’t scaling so pwms will be the low 16-bits of the
pwm counter. We are starting our colour at r = 0xFF, so the logic is going to cycle
us between these rgb values 0xFF0000, 0x00FF00, 0x0000FF…
Looking at the led as it fades from colour to colour, that is exactly what the program
seems to be doing.
My confusion comes from the last 3 lines where we set the values of PWM_CMP1-3.
We see that we are producing a right-aligned PWM waveform for G, center aligned for B,
and left-aligned for R. By doing 0xFFFF - R, it looks like with the subtraction we
are inverting it back to behave like a right-aligned waveform? I tried graphing
out a right aligned waveform for G where G is 0xFF. I put 2^16 units on the x-axis
as the counter should reset at that point since that is when pwms would overflow
and we have PWM_CMP0 at 0. So we start by doing 0xFF << 4 which would give us
0xFF0. This would give us a signal that is off for ~6% of the PWM cycle and on
for the rest as it is right-aligned. As the value in G decreases, the time we are
pulling the line low would decrease, making the percent of the cycle we are off for
smaller until it is on 100%. Wouldn’t that mean we start with a pretty bright green light
and let it grow brighter? That is backwards from what I would logically expect, and what
we observe when we see the program run. I also don’t understand (B << 1) << 4, isn’t
that just B << 5?
Logically I would expect a left aligned waveform for R, G, and B where duty cycle
corresponds directly with the brightness of that LED, so I am totally lost regarding
how this code is working.