I'm going through some of my dynamic patterns looking for things that could (or

I’m going through some of my dynamic patterns looking for things that could (or should) be rewritten. Changing a lot of my variables from simple INT to (u)int8_t (or 16 or 32) as that saves a few bytes every time (which over time adds up!) But, mainly I’m doing it both as an optimization exercise but also to write code that a) someone else would easily understand, b) is easily maintained, and c) is actually proper.

So I’m looking a the first image and it’s code. This is generated like this:

void psychedelicPower() {
static uint8_t cntr = 0;
static uint8_t hue = 0;
static int8_t increment = 1;
fill_solid(&(leds[32 + cntr]), 3, CRGB::DarkBlue);
fill_solid(&(leds[27 + cntr]), 4, CRGB::Maroon);
fill_solid(&(leds[23 + cntr]), 4, CRGB::Black);
fill_solid(&(leds[23 - cntr]), 2 * cntr, CHSV(hue++, 255, 255));
fill_solid(&(leds[19 - cntr]), 4, CRGB::Black);
fill_solid(&(leds[0]), 19 - cntr, CRGB::DarkBlue);
LEDS.show();
fill_solid(&(leds[0]), NUM_LEDS, CRGB::Black); // reset string
cntr = cntr + increment;
if (cntr > 12) increment = -increment;
if (cntr < 1) increment = -increment;
}

All I’m doing is filling the string with specific colors at specific spots and using a counter to track where that specific color needs to be. I have to believe there’s a better way to do this.

Even knowing what’s going on, every time I look at it, it takes me a bit to remember where each pixel is, where I need to start the next color, etc., etc.

The second image is a design that generates diamond shapes with an inner and outer outline (of opposite hue). That calculation is done by first deciding where along the string the center of the diamond is, then subtracting whatever amount of pixels to get to the starting point of the diamond’s edge, and fill the string n-pixels, basically fill from (center-of-diamond - n) to ((center-of-diamond - n) + 2n). The inner and outer outlines just follow along the diamond edges.

void diamonds() {
static int8_t cntr = 0;
static uint8_t hue = 0;
static int8_t increment = 1;
fill_solid(&(leds[23 + cntr]), 6, CHSV(hue + 127, 255, 255));
fill_solid(&(leds[23 - cntr]), 2 * cntr, CHSV(hue, 255, 255));
fill_solid(&(leds[17 - cntr]), 6, CHSV(hue + 127, 255, 255));
LEDS.show();
fill_solid(&(leds[0]), NUM_LEDS, CRGB::Black);
cntr += increment;
if (cntr > 12) increment = -increment;
if (cntr < 1) {
hue += 15;
increment = -increment;
}
}

So, is there a better way to do this?

You should be able to say (leds + 23 + cntr) - cleans things up a little bit, no big performance gain.

I’ll noodle on the rest - but I’m back to laying down from this migraine.

Oh I’m not looking at performance, they’re plenty fast as it is. I’m just thinking of ways to make them more readable and/or easy to understand.

inline uint8_t fillOffset(uint8_t offset, uint8_t len, CRGB & color) {
fill_solid(leds + offset, len, color);
return offset + len;
}

void psychPower() {
static uint8_t cnt = 0;
static uint8_t hue = 1;
static int8_t inc = 1:

uint8_t offset = 0;

offset = fillOffset(offset, 19 - cnt, CRGB::DarkBlue);
offset = fillOffset(offset, 4, CRGB::Black);
offset = fillOffset(offset, 2*cnt, CHSV(hue++,255,255));
offset = fillOffset(offset, 4, CRGB::Black);
offset = fillOffset(offset, 4, CRGB::Maroon);
offset = fillOffset(offset, 3, CRGB::DarkBlue);

LEDS.show();

fill_solid(leds,NUM_LEDS,CRGB::Black);

cnt += inc;
if(cnt > 12) { inc = -1; }
else if (cnt < 1) { inc = +1; }
}

(Also, I may be a new fan of textastic as a coding editor on the ipad).

But with the above, now you can change the lengths of the various color sections without having to figure out all the math/offsets for everything else :slight_smile:

You could also use fillOffset for your other pattern.

quick one, but whats the difference for the int command, and the uint8_t, should i be using it, and when to use 8, 16 and 32?

thanks!

uint8_t isn’t a command, it is a type. It means “8 bit, unsigned integer” - which means it is 1 byte in size. Likewise, uint16_t is a 16 bit unsigned integer, 2 bytes in size.

The choice doesn’t just affect how much memory is used by the variable, it also affects math operations on it, especially on the avr based arduino platforms. To add two 8 bit numbers together is a single instruction, ADD[1]. To add two sixteen bit numbers together is two instructions, ADD and ADC (add with carry), and adding two 32bit numbers together is four instructions, an add and 3 adc’s.

So, if you know that your values are always going to be in the 0-255 range, use uint8_t. If 0-65535, use uint16_t, and up to somewhere in the low four billions, then use uint32_t.

[1] to account for the possibility of overflow, gcc will often promote types behind the scenes, eg adding two 8 bit numbers together is done as a 16bit operation. This is why we have some 8bit specific math functions in lib8tion. This is also why using 16 bit numbers when you don’t need them can be extra ugly (as the get promoted to 32 bit operations)

It has to do with how large a value you’re storing. The Arduino INT stores a 16-bit value, but if all you’re doing is using 8-bit numbers, why waste the memory space? Also, (u)int8_t, (u)int16_t, (u)int32_t, and (u)int64_t are all cross platform data types (whereas Arduino INT is not.)