Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FastLED/FastLED.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkriegsman@gmail.com <kriegsman@gmail.com@4ad4ec5c-605d-bd5c-5796-512c9b60011b>2013-05-25 18:45:26 +0400
committerkriegsman@gmail.com <kriegsman@gmail.com@4ad4ec5c-605d-bd5c-5796-512c9b60011b>2013-05-25 18:45:26 +0400
commit34074fbc46ff68a871dab0f4485b2bfb9b6c20e7 (patch)
tree2a9d4757313db0df7d1c3f44bdfd2d4bf87ffc7c
parentf364ba365ec7dfa23e7a798a72c20bdc9d0988eb (diff)
MEK: RENAMED THINGS; your code will need name changes. Renamed hsv2rgb methods. Added fixed point types, 16-bit CRGB and CHSV types, 16-bit hsv2rgb, scale16( uint16_t, fract16), fixed-to-float and float-to-fixed convenience functions, CRGB::nMaximizeBrightness method of dubious ultimate value. Cleaned up some AVR assembly functions.
-rw-r--r--hsv2rgb.cpp117
-rw-r--r--hsv2rgb.h49
-rw-r--r--lib8tion.h275
-rw-r--r--pixeltypes.h50
4 files changed, 410 insertions, 81 deletions
diff --git a/hsv2rgb.cpp b/hsv2rgb.cpp
index 8592310d..a6d367af 100644
--- a/hsv2rgb.cpp
+++ b/hsv2rgb.cpp
@@ -4,6 +4,24 @@
#include "hsv2rgb.h"
+
+void hsv2rgb_C (const struct CHSV & hsv, struct CRGB & rgb);
+void hsv2rgb_avr(const struct CHSV & hsv, struct CRGB & rgb);
+
+#if defined(__AVR__)
+void hsv2rgb(const struct CHSV & hsv, struct CRGB & rgb)
+{
+ hsv2rgb_avr( hsv, rgb);
+}
+#else
+void hsv2rgb(const struct CHSV & hsv, struct CRGB & rgb)
+{
+ hsv2rgb_C( hsv, rgb);
+}
+#endif
+
+
+
#define APPLY_DIMMING(X) (X)
#define HSV_SECTION_6 (0x20)
#define HSV_SECTION_3 (0x40)
@@ -193,6 +211,91 @@ void hsv2rgb_avr(const struct CHSV & hsv, struct CRGB & rgb)
#endif
+void hsv2rgb_spectrum( const CHSV& hsv, CRGB& rgb)
+{
+ CHSV hsv2(hsv);
+ hsv2.hue = scale8( hsv2.hue, 192);
+ hsv2rgb(hsv2, rgb);
+}
+
+
+// 16-bit version for when higher precision is needed,
+// e.g., for longer slower gradients where you don't want
+// banding to show.
+// This higher precision costs more CPU cycles.
+
+#define APPLY_DIMMING_16(X) (X)
+#define HSV_SECTION_16 (32 * 256)
+
+// hue 0..191
+void hsv2rgb16 (const CHSV16& hsv16, CRGB16& rgb16)
+{
+ // Apply dimming curves
+ uint16_t value = APPLY_DIMMING_16( hsv16.val);
+ uint16_t saturation = hsv16.sat;
+
+ // The brightness floor is minimum number that all of
+ // R, G, and B will be set to.
+ uint16_t invsat = APPLY_DIMMING_16( 65536 - saturation);
+ uint16_t brightness_floor = ((uint32_t)value * (uint32_t)invsat) / (uint32_t)65536;
+
+ // The color amplitude is the maximum amount of R, G, and B
+ // that will be added on top of the brightness_floor to
+ // create the specific hue desired.
+ uint16_t color_amplitude = value - brightness_floor;
+
+ // Figure out which section of the hue wheel we're in,
+ // and how far offset we are withing that section
+ uint16_t section = hsv16.hue / HSV_SECTION_16; // 0..5
+ uint16_t offset = hsv16.hue % HSV_SECTION_16; // 0..8191
+
+ uint16_t rampup = offset; // 0..8191
+ uint16_t rampdown = (HSV_SECTION_16 - 1) - offset; // 8191..0
+
+ if(section & 0x01) {
+ // odd sections
+ rampup += (32 * 256); // 8192 .. 16383
+ } else {
+ // even sections
+ rampdown += (32 * 256); // 8192 .. 16383
+ }
+
+
+ // scale up to 255 range
+ rampup *= 4; // 0..65535
+ rampdown *= 4; // 0..65535
+
+ // compute color-amplitude-scaled-down versions of rampup and rampdown
+ uint16_t rampup_amp_adj = ((uint32_t)rampup * (uint32_t)color_amplitude) / (uint32_t)65536; // 0 .. 65535
+ uint16_t rampdown_amp_adj = ((uint32_t)rampdown * (uint32_t)color_amplitude) / (uint32_t)65536; // 0 .. 65535
+
+ // add brightness_floor offset to everything
+ uint16_t rampup_adj_with_floor = rampup_amp_adj + brightness_floor;
+ uint16_t rampdown_adj_with_floor = rampdown_amp_adj + brightness_floor;
+
+
+ section /= 2;
+
+ if( section ) {
+ if( section == 1) {
+ // original sections 2 and 3
+ rgb16.r = brightness_floor;
+ rgb16.g = rampdown_adj_with_floor;
+ rgb16.b = rampup_adj_with_floor;
+ } else {
+ // original sections 4 and 5
+ rgb16.r = rampup_adj_with_floor;
+ rgb16.g = brightness_floor;
+ rgb16.b = rampdown_adj_with_floor;
+ }
+ } else {
+ // original sections 0 and 1
+ rgb16.r = rampdown_adj_with_floor;
+ rgb16.g = rampup_adj_with_floor;
+ rgb16.b = brightness_floor;
+ }
+}
+
@@ -211,7 +314,7 @@ void hsv2rgb_avr(const struct CHSV & hsv, struct CRGB & rgb)
// Assume no.
#define GREEN2 0
-void rainbow2rgb( const CHSV& hsv, CRGB& rgb)
+void hsv2rgb_rainbow( const CHSV& hsv, CRGB& rgb)
{
uint8_t hue = hsv.hue;
uint8_t sat = hsv.sat;
@@ -371,9 +474,15 @@ void hsv2rgb(const struct CHSV * phsv, struct CRGB * prgb, int numLeds) {
}
}
-void rainbow2rgb(const struct CHSV * phsv, struct CRGB * prgb, int numLeds) {
- for(int i = 0; i < numLeds; i++) {
- rainbow2rgb(phsv[i], prgb[i]);
+void hsv2rgb_rainbow( const struct CHSV* phsv, struct CRGB * prgb, int numLeds) {
+ for(int i = 0; i < numLeds; i++) {
+ hsv2rgb_rainbow(phsv[i], prgb[i]);
+ }
+}
+
+void hsv2rgb_spectrum( const struct CHSV* phsv, struct CRGB * prgb, int numLeds) {
+ for(int i = 0; i < numLeds; i++) {
+ hsv2rgb_spectrum(phsv[i], prgb[i]);
}
}
diff --git a/hsv2rgb.h b/hsv2rgb.h
index 5b503e7c..05670f59 100644
--- a/hsv2rgb.h
+++ b/hsv2rgb.h
@@ -4,34 +4,47 @@
#include "pixeltypes.h"
-// hsv2rgb - convert hue, saturation, and value to RGB.
-//
-// NOTE: Hue is 0-191 only!
-// Saturation & value are 0-255 each.
+// hsv2rgb_rainbow - convert a hue, saturation, and value to RGB
+// using a visually balanced rainbow (vs a straight
+// mathematical spectrum).
+// This 'rainbow' yields better yellow and orange
+// than a straight 'spectrum'.
//
+// NOTE: here hue is 0-255, not just 0-191
-#if defined(__AVR__)
-#define hsv2rgb hsv2rgb_avr
-#else
-#define hsv2rgb hsv2rgb_C
-#endif
+void hsv2rgb_rainbow( const struct CHSV& hsv, struct CRGB& rgb);
+void hsv2rgb_rainbow( const struct CHSV* phsv, struct CRGB * prgb, int numLeds);
+#define HUE_MAX_RAINBOW 255
-#define HSV_HUE_MAX 191
-void hsv2rgb_C (const struct CHSV & hsv, struct CRGB & rgb);
-void hsv2rgb_avr(const struct CHSV & hsv, struct CRGB & rgb);
+// hsv2rgb_spectrum - convert a hue, saturation, and value to RGB
+// using a mathematically straight spectrum (vs
+// a visually balanced rainbow).
+// This 'spectrum' will have more green & blue
+// than a 'rainbow', and less yellow and orange.
+//
+// NOTE: here hue is 0-255, not just 0-191
+
+void hsv2rgb_spectrum( const struct CHSV& hsv, struct CRGB& rgb);
+void hsv2rgb_spectrum( const struct CHSV* phsv, struct CRGB * prgb, int numLeds);
+#define HUE_MAX_SPECTRUM 255
-// rainbow2rgb - convert a hue, saturation, and value to RGB
-// but use a visually balanced rainbow instead of
-// a mathematically balanced spectrum.
+// hsv2rgb - convert hue, saturation, and value to RGB.
+// This 'spectrum' conversion will be more green & blue
+// than a real 'rainbow', and the hue is specified just
+// in the range 0-191. Together, these result in a
+// slightly faster conversion speed, at the expense of
+// color balance.
//
-// NOTE: here hue is 0-255, not just 0-191!
+// NOTE: Hue is 0-191 only!
+// Saturation & value are 0-255 each.
//
-#define RAINBOW_HUE_MAX 255
+void hsv2rgb(const struct CHSV& hsv, struct CRGB & rgb);
+void hsv2rgb(const struct CHSV* phsv, struct CRGB * prgb, int numLeds);
+#define HUE_MAX 191
-void rainbow2rgb( const CHSV& hsv, CRGB& rgb);
void hsv2rgb(const struct CHSV * phsv, struct CRGB * rgb, int numLeds);
void rainbow2rgb(const struct CHSV * phsv, struct CRGB * rgb, int numLeds);
diff --git a/lib8tion.h b/lib8tion.h
index 5000e6fe..cae50392 100644
--- a/lib8tion.h
+++ b/lib8tion.h
@@ -101,13 +101,13 @@
- Linear interpolation between two values, with the
fraction between them expressed as an 8- or 16-bit
- fixed point fraction (Q8 or Q16).
- lerp8by8( fromU8, toU8, fracQ8 )
- lerp16by8( fromU16, toU16, fracQ8 )
- lerp15by8( fromS16, toS16, fracQ8 )
- == from + (( to - from ) * fracQ8) / 256)
- lerp16by16( fromU16, toU16, fracQ16 )
- == from + (( to - from ) * fracQ16) / 65536)
+ fixed point fraction (fract8 or fract16).
+ lerp8by8( fromU8, toU8, fract8 )
+ lerp16by8( fromU16, toU16, fract8 )
+ lerp15by8( fromS16, toS16, fract8 )
+ == from + (( to - from ) * fract8) / 256)
+ lerp16by16( fromU16, toU16, fract16 )
+ == from + (( to - from ) * fract16) / 65536)
- Optimized memmove, memcpy, and memset, that are
faster than standard avr-libc 1.8.
@@ -149,6 +149,7 @@ Lib8tion is pronounced like 'libation': lie-BAY-shun
#define QSUB8_C 1
#define SCALE8_C 1
#define SCALE16BY8_C 1
+#define SCALE16_C 1
#define ABS8_C 1
#define MUL8_C 1
#define QMUL8_C 1
@@ -180,11 +181,13 @@ Lib8tion is pronounced like 'libation': lie-BAY-shun
#if !defined(LIB8_ATTINY)
#define SCALE8_C 0
#define SCALE16BY8_C 0
+#define SCALE16_C 0
#define MUL8_C 0
#define QMUL8_C 0
#define EASE8_C 0
#define SCALE8_AVRASM 1
#define SCALE16BY8_AVRASM 1
+#define SCALE16_AVRASM 1
#define MUL8_AVRASM 1
#define QMUL8_AVRASM 1
#define EASE8_AVRASM 1
@@ -193,11 +196,13 @@ Lib8tion is pronounced like 'libation': lie-BAY-shun
// On ATtiny, we just use C implementations
#define SCALE8_C 1
#define SCALE16BY8_C 1
+#define SCALE16_C 0
#define MUL8_C 1
#define QMUL8_C 1
#define EASE8_C 1
#define SCALE8_AVRASM 0
#define SCALE16BY8_AVRASM 0
+#define SCALE16_AVRASM 0
#define MUL8_AVRASM 0
#define QMUL8_AVRASM 0
#define EASE8_AVRASM 0
@@ -212,6 +217,7 @@ Lib8tion is pronounced like 'libation': lie-BAY-shun
#define QSUB8_C 1
#define SCALE8_C 1
#define SCALE16BY8_C 1
+#define SCALE16_C 1
#define ABS8_C 1
#define MUL8_C 1
#define ADD8_C 1
@@ -223,21 +229,71 @@ Lib8tion is pronounced like 'libation': lie-BAY-shun
///////////////////////////////////////////////////////////////////////
//
-// typdefs for fast fixed-point fractional types.
+// typdefs for fixed-point fractional types.
//
-// Q7 should be interpreted as signed 128ths.
-// Q8 should be interpreted as unsigned 256ths.
-// Q15 should be interpreted as signed 32768ths.
-// Q16 should be interpreted as unsigned 65536ths.
+// sfract7 should be interpreted as signed 128ths.
+// fract8 should be interpreted as unsigned 256ths.
+// sfract15 should be interpreted as signed 32768ths.
+// fract16 should be interpreted as unsigned 65536ths.
//
-// Example: if a Q8 has the is "128", that should be interpreted
-// as 128 256ths, or one-half.
+// Example: if a fract8 has the value "64", that should be interpreted
+// as 64/256ths, or one-quarter.
//
+//
+// fract8 range is 0 to 0.99609375
+// in steps of 0.00390625
+//
+// sfract7 range is -0.9921875 to 0.9921875
+// in steps of 0.0078125
+//
+// fract16 range is 0 to 0.99998474121
+// in steps of 0.00001525878
+//
+// sfract15 range is -0.99996948242 to 0.99996948242
+// in steps of 0.00003051757
+//
+
+typedef uint8_t fract8; // ANSI: unsigned short _Fract
+typedef int8_t sfract7; // ANSI: signed short _Fract
+typedef uint16_t fract16; // ANSI: unsigned _Fract
+typedef int16_t sfract15; // ANSI: signed _Fract
+
+
+// accumXY types should be interpreted as X bits of integer,
+// and Y bits of fraction.
+// E.g., accum88 has 8 bits of int, 8 bits of fraction
+
+typedef uint16_t accum88; // ANSI: unsigned short _Accum
+typedef int16_t saccum78; // ANSI: signed short _Accum
+typedef uint32_t accum1616;// ANSI: signed _Accum
+typedef int32_t saccum1516;//ANSI: signed _Accum
+typedef uint16_t accum124; // no direct ANSI counterpart
+typedef int32_t saccum114;// no direct ANSI counterpart
+
+
+// typedef for IEEE754 "binary32" float type internals
+
+typedef union {
+ uint32_t i;
+ float f;
+ struct {
+ uint32_t mantissa: 23;
+ uint32_t exponent: 8;
+ uint32_t signbit: 1;
+ };
+ struct {
+ uint32_t mant7 : 7;
+ uint32_t mant16: 16;
+ uint32_t exp_ : 8;
+ uint32_t sb_ : 1;
+ };
+ struct {
+ uint32_t mant_lo8 : 8;
+ uint32_t mant_hi16_exp_lo1 : 16;
+ uint32_t sb_exphi7 : 8;
+ };
+} IEEE754binary32_t;
-typedef int8_t Q7;
-typedef uint8_t Q8;
-typedef int16_t Q15;
-typedef uint16_t Q16;
///////////////////////////////////////////////////////////////////////
@@ -370,18 +426,18 @@ LIB8STATIC uint8_t sub8( uint8_t i, uint8_t j)
// the numerator of a fraction whose denominator is 256
// In other words, it computes i * (scale / 256)
// 4 clocks AVR, 2 clocks ARM
-LIB8STATIC uint8_t scale8( uint8_t i, uint8_t scale)
+LIB8STATIC uint8_t scale8( uint8_t i, fract8 scale)
{
#if SCALE8_C == 1
return ((int)i * (int)(scale) ) >> 8;
#elif SCALE8_AVRASM == 1
asm volatile(
/* Multiply 8-bit i * 8-bit scale, giving 16-bit r1,r0 */
- "mul %0, %1 \n\t"
+ "mul %0, %1 \n\t"
/* Move the high 8-bits of the product (r1) back to i */
- "mov %0, r1 \n\t"
+ "mov %0, r1 \n\t"
/* Restore r1 to "0"; it's expected to always be that */
- "eor r1, r1 \n\t"
+ "clr __zero_reg__ \n\t"
: "+a" (i) /* writes to i */
: "a" (scale) /* uses scale */
@@ -400,7 +456,7 @@ LIB8STATIC uint8_t scale8( uint8_t i, uint8_t scale)
// inputs are non-zero, the output is guaranteed to be non-zero.
// This makes for better 'video'/LED dimming, at the cost of
// several additional cycles.
-LIB8STATIC uint8_t scale8_video( uint8_t i, uint8_t scale)
+LIB8STATIC uint8_t scale8_video( uint8_t i, fract8 scale)
{
#if SCALE8_C == 1
uint8_t nonzeroscale = (scale != 0) ? 1 : 0;
@@ -410,12 +466,12 @@ LIB8STATIC uint8_t scale8_video( uint8_t i, uint8_t scale)
uint8_t nonzeroscale = (scale != 0) ? 1 : 0;
asm volatile(
- " tst %0 \n"
- " breq L_%= \n"
- " mul %0, %1 \n"
- " mov %0, r1 \n"
- " add %0, %2 \n"
- "L_%=: eor r1, r1 \n"
+ " tst %0 \n"
+ " breq L_%= \n"
+ " mul %0, %1 \n"
+ " mov %0, r1 \n"
+ " add %0, %2 \n"
+ "L_%=: clr __zero_reg__ \n"
: "+a" (i)
: "a" (scale), "a" (nonzeroscale)
@@ -432,7 +488,7 @@ LIB8STATIC uint8_t scale8_video( uint8_t i, uint8_t scale)
// This version of scale8 does not clean up the R1 register on AVR
// If you are doing several 'scale8's in a row, use this, and
// then explicitly call cleanup_R1.
-LIB8STATIC uint8_t scale8_LEAVING_R1_DIRTY( uint8_t i, uint8_t scale)
+LIB8STATIC uint8_t scale8_LEAVING_R1_DIRTY( uint8_t i, fract8 scale)
{
#if SCALE8_C == 1
return ((int)i * (int)(scale) ) >> 8;
@@ -443,7 +499,7 @@ LIB8STATIC uint8_t scale8_LEAVING_R1_DIRTY( uint8_t i, uint8_t scale)
/* Move the high 8-bits of the product (r1) back to i */
"mov %0, r1 \n\t"
/* R1 IS LEFT DIRTY HERE; YOU MUST ZERO IT OUT YOURSELF */
- /* "eor r1, r1 \n\t" */
+ /* "clr __zero_reg__ \n\t" */
: "+a" (i) /* writes to i */
: "a" (scale) /* uses scale */
@@ -458,7 +514,7 @@ LIB8STATIC uint8_t scale8_LEAVING_R1_DIRTY( uint8_t i, uint8_t scale)
// THIS FUNCTION ALWAYS MODIFIES ITS ARGUMENT DIRECTLY IN PLACE
-LIB8STATIC void nscale8_LEAVING_R1_DIRTY( uint8_t& i, uint8_t scale)
+LIB8STATIC void nscale8_LEAVING_R1_DIRTY( uint8_t& i, fract8 scale)
{
#if SCALE8_C == 1
i = ((int)i * (int)(scale) ) >> 8;
@@ -469,7 +525,7 @@ LIB8STATIC void nscale8_LEAVING_R1_DIRTY( uint8_t& i, uint8_t scale)
/* Move the high 8-bits of the product (r1) back to i */
"mov %0, r1 \n\t"
/* R1 IS LEFT DIRTY HERE; YOU MUST ZERO IT OUT YOURSELF */
- /* "eor r1, r1 \n\t" */
+ /* "clr __zero_reg__ \n\t" */
: "+a" (i) /* writes to i */
: "a" (scale) /* uses scale */
@@ -481,7 +537,7 @@ LIB8STATIC void nscale8_LEAVING_R1_DIRTY( uint8_t& i, uint8_t scale)
-LIB8STATIC uint8_t scale8_video_LEAVING_R1_DIRTY( uint8_t i, uint8_t scale)
+LIB8STATIC uint8_t scale8_video_LEAVING_R1_DIRTY( uint8_t i, fract8 scale)
{
#if SCALE8_C == 1
uint8_t nonzeroscale = (scale != 0) ? 1 : 0;
@@ -516,7 +572,7 @@ LIB8STATIC void cleanup_R1()
{
#if CLEANUP_R1_AVRASM == 1
// Restore r1 to "0"; it's expected to always be that
- asm volatile( "eor r1, r1\n\t" : : : "r1" );
+ asm volatile( "clr __zero_reg__ \n\t" : : : "r1" );
#endif
}
@@ -527,7 +583,7 @@ LIB8STATIC void cleanup_R1()
//
// THIS FUNCTION ALWAYS MODIFIES ITS ARGUMENTS IN PLACE
-LIB8STATIC void nscale8x3( uint8_t& r, uint8_t& g, uint8_t& b, uint8_t scale)
+LIB8STATIC void nscale8x3( uint8_t& r, uint8_t& g, uint8_t& b, fract8 scale)
{
#if SCALE8_C == 1
r = ((int)r * (int)(scale) ) >> 8;
@@ -544,7 +600,7 @@ LIB8STATIC void nscale8x3( uint8_t& r, uint8_t& g, uint8_t& b, uint8_t scale)
}
-LIB8STATIC void nscale8x3_video( uint8_t& r, uint8_t& g, uint8_t& b, uint8_t scale)
+LIB8STATIC void nscale8x3_video( uint8_t& r, uint8_t& g, uint8_t& b, fract8 scale)
{
#if SCALE8_C == 1
uint8_t nonzeroscale = (scale != 0) ? 1 : 0;
@@ -566,21 +622,21 @@ LIB8STATIC void nscale8x3_video( uint8_t& r, uint8_t& g, uint8_t& b, uint8_t sca
// is 256. In other words, it computes i * (scale / 256)
#if SCALE16BY8_C == 1
-LIB8STATIC uint16_t scale16by8( uint16_t i, uint8_t scale )
+LIB8STATIC uint16_t scale16by8( uint16_t i, fract8 scale )
{
uint16_t result;
result = (i * scale) / 256;
return result;
}
#elif SCALE16BY8_AVRASM == 1
-LIB8STATIC uint16_t scale16by8( uint16_t i, uint8_t scale )
+LIB8STATIC uint16_t scale16by8( uint16_t i, fract8 scale )
{
uint16_t result;
asm volatile(
// result.A = HighByte(i.A x j )
" mul %A[i], %[scale] \n\t"
" mov %A[result], r1 \n\t"
- " eor %B[result], %B[result] \n\t"
+ " clr %B[result] \n\t"
// result.A-B += i.B x j
" mul %B[i], %[scale] \n\t"
@@ -588,9 +644,9 @@ LIB8STATIC uint16_t scale16by8( uint16_t i, uint8_t scale )
" adc %B[result], r1 \n\t"
// cleanup r1
- " eor r1, r1 \n\t"
+ " clr __zero_reg__ \n\t"
- : [result] "+r" (result)
+ : [result] "=r" (result)
: [i] "r" (i), [scale] "r" (scale)
: "r0", "r1"
);
@@ -600,6 +656,76 @@ LIB8STATIC uint16_t scale16by8( uint16_t i, uint8_t scale )
#error "No implementation for scale16by8 available."
#endif
+// scale16: scale a 16-bit unsigned value by a 16-bit value,
+// considered as numerator of a fraction whose denominator
+// is 65536. In other words, it computes i * (scale / 65536)
+
+#if SCALE16_C == 1
+LIB8STATIC uint16_t scale16( uint16_t i, fract16 scale )
+{
+ uint16_t result;
+ result = ((uint32_t)(i) * (uint32_t)(scale)) / 65536;
+ return result;
+}
+#elif SCALE16_AVRASM == 1
+LIB8STATIC
+uint16_t scale16( uint16_t i, fract16 scale )
+{
+ uint32_t result;
+ const uint8_t zero = 0;
+ asm volatile(
+ // result.A-B = i.A x scale.A
+ " mul %A[i], %A[scale] \n\t"
+ // save results...
+ // basic idea:
+ //" mov %A[result], r0 \n\t"
+ //" mov %B[result], r1 \n\t"
+ // which can be written as...
+ " movw %A[result], r0 \n\t"
+ // We actually need to do anything with r0,
+ // as result.A is never used again here, so we
+ // could just move the high byte, but movw is
+ // one clock cycle, just like mov, so might as
+ // well, in case we want to use this code for
+ // a generic 16x16 multiply somewhere.
+
+ // result.C-D = i.B x scale.B
+ " mul %B[i], %B[scale] \n\t"
+ //" mov %C[result], r0 \n\t"
+ //" mov %D[result], r1 \n\t"
+ " movw %C[result], r0 \n\t"
+
+ // result.B-D += i.B x scale.A
+ " mul %B[i], %A[scale] \n\t"
+
+ " add %B[result], r0 \n\t"
+ " adc %C[result], r1 \n\t"
+ " adc %D[result], %[zero] \n\t"
+
+ // result.B-D += i.A x scale.B
+ " mul %A[i], %B[scale] \n\t"
+
+ " add %B[result], r0 \n\t"
+ " adc %C[result], r1 \n\t"
+ " adc %D[result], %[zero] \n\t"
+
+ // cleanup r1
+ " clr r1 \n\t"
+
+ : [result] "+r" (result)
+ : [i] "r" (i),
+ [scale] "r" (scale),
+ [zero] "r" (zero)
+ : "r0", "r1"
+ );
+ result = result >> 16;
+ return result;
+}
+#else
+#error "No implementation for scale16 available."
+#endif
+
+
// mul8: 8x8 bit multiplication, with 8 bit result
LIB8STATIC uint8_t mul8( uint8_t i, uint8_t j)
@@ -609,11 +735,11 @@ LIB8STATIC uint8_t mul8( uint8_t i, uint8_t j)
#elif MUL8_AVRASM == 1
asm volatile(
/* Multiply 8-bit i * 8-bit j, giving 16-bit r1,r0 */
- "mul %0, %1 \n\t"
+ "mul %0, %1 \n\t"
/* Extract the LOW 8-bits (r0) */
- "mov %0, r0 \n\t"
+ "mov %0, r0 \n\t"
/* Restore r1 to "0"; it's expected to always be that */
- "eor r1, r1 \n\t"
+ "clr __zero_reg__ \n\t"
: "+a" (i)
: "a" (j)
: "r0", "r1");
@@ -635,17 +761,17 @@ LIB8STATIC uint8_t qmul8( uint8_t i, uint8_t j)
#elif QMUL8_AVRASM == 1
asm volatile(
/* Multiply 8-bit i * 8-bit j, giving 16-bit r1,r0 */
- " mul %0, %1 \n\t"
+ " mul %0, %1 \n\t"
/* If high byte of result is zero, all is well. */
- " cpi r1, 0 \n\t"
- " breq L_%= \n\t"
+ " cpi r1, 0 \n\t"
+ " breq L_%= \n\t"
/* If high byte of result > 0, saturate low byte to 0xFF */
- " ldi r0, 255 \n\t"
- "L_%=: \n\t"
+ " ldi r0, 255 \n\t"
+ "L_%=: \n\t"
/* Extract the LOW 8-bits (r0) */
- " mov %0, r0 \n\t"
+ " mov %0, r0 \n\t"
/* Restore r1 to "0"; it's expected to always be that */
- " eor r1, r1 \n\t"
+ " clr __zero_reg__ \n\t"
: "+a" (i)
: "a" (j)
: "r0", "r1");
@@ -680,6 +806,35 @@ LIB8STATIC int8_t abs8( int8_t i)
#endif
}
+
+///////////////////////////////////////////////////////////////////////
+//
+// float-to-fixed and fixed-to-float conversions
+//
+// Note that anything involving a 'float' on AVR will be slower.
+
+// floatToSfract15: conversion from IEEE754 float in the range (-1,1)
+// to 16-bit fixed point. Note that the extremes of
+// one and negative one are NOT representable. The
+// representable range is basically
+//
+// sfract15ToFloat: conversion from sfract15 fixed point to
+// IEEE754 32-bit float.
+
+LIB8STATIC
+float sfract15ToFloat( sfract15 y)
+{
+ return y / 32768.0;
+}
+
+LIB8STATIC
+sfract15 floatToSfract15( float f)
+{
+ return f * 32768.0;
+}
+
+
+
///////////////////////////////////////////////////////////////////////
// Dimming and brightening functions
@@ -912,7 +1067,7 @@ void * memset8 ( void * ptr, uint8_t value, uint16_t num ) __attribute__ ((noinl
// linear interpolation between two unsigned 8-bit values,
// with 8-bit fraction
-LIB8STATIC uint8_t lerp8by8( uint8_t a, uint8_t b, Q8 frac)
+LIB8STATIC uint8_t lerp8by8( uint8_t a, uint8_t b, fract8 frac)
{
uint8_t delta = b - a;
uint8_t scaled = scale8( delta, frac);
@@ -922,7 +1077,7 @@ LIB8STATIC uint8_t lerp8by8( uint8_t a, uint8_t b, Q8 frac)
// linear interpolation between two unsigned 16-bit values,
// with 16-bit fraction
-LIB8STATIC uint16_t lerp16by16( uint16_t a, uint16_t b, Q16 frac)
+LIB8STATIC uint16_t lerp16by16( uint16_t a, uint16_t b, fract16 frac)
{
uint16_t delta = b - a;
uint32_t prod = (uint32_t)delta * (uint32_t)frac;
@@ -943,7 +1098,7 @@ LIB8STATIC uint16_t lerp16by16( uint16_t a, uint16_t b, Q16 frac)
// linear interpolation between two unsigned 16-bit values,
// with 8-bit fraction
-LIB8STATIC uint16_t lerp16by8( uint16_t a, uint16_t b, Q8 frac)
+LIB8STATIC uint16_t lerp16by8( uint16_t a, uint16_t b, fract8 frac)
{
uint16_t result;
if( b > a) {
@@ -960,7 +1115,7 @@ LIB8STATIC uint16_t lerp16by8( uint16_t a, uint16_t b, Q8 frac)
// linear interpolation between two signed 15-bit values,
// with 8-bit fraction
-LIB8STATIC int16_t lerp15by8( int16_t a, int16_t b, Q8 frac)
+LIB8STATIC int16_t lerp15by8( int16_t a, int16_t b, fract8 frac)
{
int16_t result;
if( b > a) {
@@ -983,7 +1138,7 @@ LIB8STATIC int16_t lerp15by8( int16_t a, int16_t b, Q8 frac)
// ease8InOuCubic: 8-bit cubic ease-in / ease-out function
// Takes around 18 cycles on AVR
-LIB8STATIC uint8_t ease8InOutCubic( uint8_t i)
+LIB8STATIC fract8 ease8InOutCubic( fract8 i)
{
uint8_t ii = scale8_LEAVING_R1_DIRTY( i, i);
uint8_t iii = scale8_LEAVING_R1_DIRTY( ii, i);
@@ -1012,7 +1167,7 @@ LIB8STATIC uint8_t ease8InOutCubic( uint8_t i)
// Asm version takes around 7 cycles on AVR.
#if EASE8_C == 1
-LIB8STATIC uint8_t ease8InOutApprox( uint8_t i)
+LIB8STATIC fract8 ease8InOutApprox( fract8 i)
{
if( i < 64) {
// start with slope 0.5
@@ -1033,7 +1188,7 @@ LIB8STATIC uint8_t ease8InOutApprox( uint8_t i)
}
#elif EASE8_AVRASM == 1
-LIB8STATIC uint8_t ease8InOutApprox( uint8_t i)
+LIB8STATIC uint8_t ease8InOutApprox( fract8 i)
{
// takes around 7 cycles on AVR
asm volatile (
@@ -1067,4 +1222,6 @@ LIB8STATIC uint8_t ease8InOutApprox( uint8_t i)
+
+
#endif
diff --git a/pixeltypes.h b/pixeltypes.h
index 35acd628..bee756c7 100644
--- a/pixeltypes.h
+++ b/pixeltypes.h
@@ -323,6 +323,16 @@ struct CRGB {
cleanup_R1();
return avg;
}
+
+ inline void nMaximizeBrightness( uint8_t limit = 255 ) {
+ uint8_t max = red;
+ if( green > max) max = green;
+ if( blue > max) max = blue;
+ uint16_t factor = ((uint16_t)(limit) * 256) / max;
+ red = (red * factor) / 256;
+ green = (green * factor) / 256;
+ blue = (blue * factor) / 256;
+ }
};
@@ -425,6 +435,46 @@ inline CRGB operator%( const CRGB& p1, uint8_t d)
}
+
+struct CHSV16 {
+ union {
+ struct {
+ union {
+ uint16_t hue;
+ uint16_t h; };
+ union {
+ uint16_t saturation;
+ uint16_t sat;
+ uint16_t s; };
+ union {
+ uint16_t value;
+ uint16_t val;
+ uint16_t v; };
+ };
+ uint16_t raw[3];
+ };
+};
+
+struct CRGB16 {
+ union {
+ struct {
+ union {
+ uint16_t r;
+ uint16_t red;
+ };
+ union {
+ uint16_t g;
+ uint16_t green;
+ };
+ union {
+ uint16_t b;
+ uint16_t blue;
+ };
+ };
+ uint16_t raw[3];
+ };
+};
+
#ifdef SUPPORT_ARGB
struct CARGB {