Closed ivancuric closed 6 years ago
I can't math today, I have the dumb.
Any ideas how to fix the new()
output to go from 0x0
to 0xffff
?
#include <stdint.h>
#include <stdio.h>
#define BACKLIGHT_LEVELS 8
void main()
{
uint16_t i;
uint16_t orig(uint16_t level) {
if ( level == 0 ) {
return 0;
} else if (level == BACKLIGHT_LEVELS) {
return 0xFFFF;
}
return 0xFFFF >> ((BACKLIGHT_LEVELS - level) * ((BACKLIGHT_LEVELS + 1) / 2));
}
uint16_t new(uint16_t level) {
return ((level * level * 0xFFFF) - 0xFFFF) / (BACKLIGHT_LEVELS * BACKLIGHT_LEVELS - 1);
}
printf("Orig\tNew\n-------------\n");
for (i = 0; i <= BACKLIGHT_LEVELS; i++)
{
printf("%d\t", orig(i));
printf("%d\n", new(i));
}
}
Output:
Orig New
-------------
0 fbf0
0 0
0 c30
0 2081
0 3cf3
f 6185
ff 8e38
fff c30b
ffff ffff
For now I've just added a lookup table:
uint16_t exp_table[] = {
0x0,
0x3ff,
0xfff,
0x23ff,
0x3fff,
0x63ff,
0x8fff,
0xc3ff,
0xffff
};
And switched L861 to OCR1x = exp_table[level];
Works great: https://www.youtube.com/watch?v=5SQ2ObVLRU4
The formula should be: (x^2)*(map_max/(map_steps^2))
where map_max
is max value required, map_steps
is number of horizontal steps you have.
You can optimize this equation by caching/calculating (map_max/(map_steps^2))
value (since these never change)
return (level*level*0xFFFF)/(BACKLIGHT_LEVELS*BACKLIGHT_LEVELS);
which is x^2
mapped from 0 .. 8
to 0x0000 - 0xFFFF
(including edge values)
will give you following response&eqn2_color=2&eqn2_eqn=&eqn3_color=3&eqn3_eqn=&eqn4_color=4&eqn4_eqn=&eqn5_color=5&eqn5_eqn=&eqn6_color=6&eqn6_eqn=&x_min=0&x_max=8&y_min=0&y_max=65535&x_tick=1&y_tick=1000&x_label_freq=5&y_label_freq=5&do_grid=0&do_grid=1&bold_labeled_lines=0&bold_labeled_lines=1&line_width=4&image_w=850&image_h=525).
If you want the curve to be steeper, just increment exponential
eg. (level*level*level*0xFFFF)/(BACKLIGHT_LEVELS*BACKLIGHT_LEVELS*BACKLIGHT_LEVELS)
which is x^3
mapped to 0x0000 - 0xFFFF
I just saw
This function gives a quadratic output of [ 0, 5617, 14979, 28086, 44938, 65535 ], however from values > 1 < x <= BACKLIGHT_LEVELS. I need to tweak it to give that output for 0 < x <= BACKLIGHT_LEVELS
return (level * level * 0xFFFF) / (BACKLIGHT_LEVELS * BACKLIGHT_LEVELS);
This should work for you.
@wedranb
Thanks for the response! However the function gives out the final value as 0xFFC0
instead of 0xFFFF
.
@ivancuric It's because you're clipping remainder from division (65535 is not dividable by 9 without remainder). Check 3rd paragraph for correct solution (rearranged brackets)
Ah, got it. Thanks a lot.
OCR1x = (level * level * 0xFFFF) / (BACKLIGHT_LEVELS * BACKLIGHT_LEVELS);
Gives good results in the console when printing out with %#X
(0x0, 0x3FF, 0xFFF, 0x23FF, 0x3FFF, 0x63FF, 0x8FFF, 0xC3FF, 0xFFFF
), but for some reason only works on 3 values when programming the board 0, 1, BACKLIGHT_LEVELS
. Guess it has something to do with the types.
For some reason if I assign a hex value directly, eg 0xFFF
, it works, but having it as a returned value from the function does not.
@AleksandarDev any ideas?
Ever finish this?
Nope, but @BalzGuenat and @jackhumbert fixed it in https://github.com/qmk/qmk_firmware/commit/4931510ad38aadb1769c9241bfad0c3d77ad687f! https://github.com/qmk/qmk_firmware/blob/master/quantum/quantum.c#L933
Ah, glad to hear it then! Specifically, fixed by #2187 (tagging for reference)
How would one go about implementing a logarithmic brightness control on an ATmega32u4? I've fiddled on my Arduino a bit, and came up with the following using an LED and a rotary encoder:
Basically, mapping 100 steps to 255, but on a quadratic scale, so that the brightness has a perceptively linear scale. The current implementation has a way too sharp exponential curve.
I tested my implementation out and it works great, but I don't have the handy
map
function, plus the code doesn't seem well optimized.I found the code responsible for the current implementation of the backlight in
quantum.c
: https://github.com/qmk/qmk_firmware/blob/master/quantum/quantum.c#L824For instance, for 6 (+ off / 0) backlight levels (8 is max for some reason, even though the type is
uint16_t
), the resulting values are[ 0, 3, 63, 511, 8191, 65535 ]
, corresponding to the percentages of[ 0, 0, 0.10, 0.78, 12.5, 100]
.What I came up with is
instead of the current
with the fancy bitwise operations.
This function gives a quadratic output of
[ 0, 5617, 14979, 28086, 44938, 65535 ]
, however from values1 < x <= BACKLIGHT_LEVELS
. I need to tweak it to give that output for0 < x <= BACKLIGHT_LEVELS