Hi there,
I'm currently building a display made with neopixels.
I've gotten as far as showing an image using an array of hexValues, right now i'm trying to get the image to scroll infinitly, i've got it working, but every cycle the image shifts up a row on the display, so jumping back and forth.
Since the neopixels take a single string of values and not a 2d array it's not as simple as keeping it in one row.
I hope this is understandable, and that someone might know what to do.
this is the function that controls what is displayed, and for scrolling the image
i have rows of 44 pixels, and 8 rows
int position_blinker = 44;
int stepsize_blinker = 44/11;
void showAnimation_03(int thisFrame)
{
int excludedCounter;
excludedCounter = -2;
for(int i = 0; i < frame_pixels; i++)
{
int tempI = i+(position_blinker-23);
for(int e = 0; e < 28; e++)
{
if(i == excludes[e])
{
//skip pixel
excludedCounter += 1;
}else
{
uint64_t thisLed;
thisLed = pgm_read_dword(&(animation_matrix_03[thisFrame][tempI]));
leds[i-excludedCounter] = thisLed;
}
}
}
FastLED.show();
if(position_blinker > 0)
{
position_blinker-=stepsize_blinker;
}else{
position_blinker = 44;
}
}
Where do the magic numbers 23 and 28 come from?!?
What is in the 'excludes' array?!?
What is the value of 'frame_pixels'?!?
the 23 can be left out, that was me trying out a way to fix it, the 28 is because the display is not square, i left out some pixels, so in order to still show the image as it should, i skip some pixels.
frame_pixels has a value of 352
with 325 total leds
So not all rows are are 44 pixels long and the 'exclude' array gives the addresses of the pixels that aren't really there. The 'frame' has data for a 44x8 display but if you sent all 352 pixels then some would go off the end of the short rows and appear at the front of the next row?
I'd like to help but without seeing the rest of the sketch I don't think I will be able to figure out how to do what you want to do.
What is the exact arrangement of your LEDs? Did you leave the missing LEDs off at the beginning, end, left side, right side, randomly in the middle? Is the array wired in a zig-zag pattern, or is every row left-to-right or right-to-left?
My initial impression, given the lack of context for the function, is that tempI is going to exceed the bounds of the array that the image is stored in. Also, you can't generally straight copy an image into an LED matrix using an offset, you have to apply the offset to each row individually.
I uploaded all code to github, you can find it here:
The snippet i pasted here can be found in sequencer.h
The function is being called from a function inside inputs.h
(void inputDetector)
The "image" is found in animation_x.h which is an arrayof 44x8 pixels, since neopizels are wired in a string, one frame/image is also being done as a listand not as 2d array
Also made a map of the display, to show the numbering order, and what leds are left out(orange is left out)
const uint64_t animation_matrix_03[][352] PROGMEM = {
Why use 64-bit numbers to hold 24-bit values?
For some reason that was the only way i got it working, but i might have missed something
I would get rid of the 'excluded' pixels and for each row, have the beginning and ending pixel address for the row.
const byte RowEnds[8][2] =
{
{7, 44 - 6} .
{3, 44 - 2},
{2, 44 - 1},
{1, 44 - 0},
{0, 44 - 0},
{0, 44 - 0},
{0, 44 - 1},
{2, 44 - 3}
};
int position_blinker = 44;
const int stepsize_blinker = 4;
void showAnimation_03(int thisFrame)
{
unsigned stripOffset = 0;
for (byte row = 0; row < 8; row++)
{
for (byte col = RowEnds[row][1]; col < RowEnds[row][2]; col++)
{
unsigned imageOffset = (row * 44) + ((col + (position_blinker + 44)) % 44);
leds[stripOffset++] = pgm_read_dword(&(animation_matrix_03[thisFrame][imageOffset]));;
}
}
FastLED.show();
if (position_blinker > -22)
{
position_blinker -= stepsize_blinker;
}
else
{
position_blinker = 22;
}
}
Raymond1432:
Also made a map of the display, to show the numbering order, and what leds are left out(orange is left out)
In reference to your image, an array is numbered starting with 0, so your array of 352 pixels should be from 0 to 351.
@johnwasser that piece of code doesn't seem to work, but from what i can see i should divide the LEDs in to rows and columns, and then look up the correct number in the array?
Also about the uint64 being used when it's 24bit, while testing out that was the only way i got it working, was trying now, and uint32 works too, but there is no uint24? from what i found using 24bit might require some more code, but my main concern is, will it affect memory? as you might have noticed I need quite some memory to store all the "images" especially when an image has more frames(animation). I did switch to an arduino Due though, so i have more memory than i used to.
@david_2018 you're absolutely right, totally missed that, never noticed it as it didn't affect functionality.
Napalm1432:
@johnwasser that piece of code doesn't seem to work,
"doesn't seem to work" in what way? It copies a bunch of data from FLASH to the leds[] array. Does nothing show up? Are the lines skewed? WHAT?!? The least useful comment on a sketch is "it doesn't work".
Napalm1432:
Also about the uint64 being used when it's 24bit, while testing out that was the only way i got it working, was trying now, and uint32 works too, but there is no uint24? from what i found using 24bit might require some more code, but my main concern is, will it affect memory?
Yes. Using 8 bytes per 3-byte value (uint64_t) takes up twice as much FLASH as using 4 bytes per 3-byte value (uint32_t).
Sorry should have clarified, nothing showed up, pixels stayed on the last state they were on.
Also some other animations didn't show up as well, only when removing the byte RowEnds array did it work as it used to
Thanks, I changed it all to uint32 now, sketch size was reduced by half
There is no uint24_t, you need to define a structure of three uint8_t. Reduces the memory needed by 25%, and allows direct copy from the image to the pixel array using memcpy_P().
david_2018:
There is no uint24_t
Actually there is in AVR-GCC, it is just called __uint24. There is also __int24.
You have a rather complex situation, because of the non-rectangular display. Since parts of the image can be missing from the display, the image has to be copied over to the display each time. The missing pixels also make it more difficult to calculate the starting pixel on the display row. The arrangement of the display could add a bit of difficulty, because the display pixels are numbered right to left, while the image arrays are numbered left to right, but you have already reversed the images so that isn't a concern.
I used the suggestion of an array to store the number of missing pixels, although the implementation is a bit different.
//number of pixels missing from the right and left side of the display
//note - display is numbered from right to left
int16_t missing_pixels[8][2] = {
{7, 6}, // 0 - 43
{3, 2}, // 44 - 87
{2, 1}, // 88 - 131
{1, 0}, //132 - 175
{0, 0}, //176 - 219
{0, 0}, //220 - 263
{0, 1}, //264 - 307
{2, 3} //308 - 351
};
const byte start_of_row = 0; //convenient names for use with the missing_pixels array
const byte end_of_row = 1;
byte display_columns = 44; //number of columns in display
byte display_rows = 8; //number of rows in display
void showAnimation(const uint32_t image_matrix[][352], byte frame_number, int scroll_offset) {
int row_total_display;
int row_total_image;
int source_pixel;
for (int row = 0; row < display_rows; row++) {
//calculate the starting pixel on the current row of the display
// by adding up the number of pixels on all the previous display rows
row_total_display = 0;
for (int i = 0; i < row; i++) {
row_total_display += (display_columns - missing_pixels[i][start_of_row] - missing_pixels[i][end_of_row]);
}
//calculate the starting pixel on the current row of the image
row_total_image = display_columns * row;
for ( int column = 0; column < (44 - missing_pixels[row][start_of_row] - missing_pixels[row][end_of_row]); column++) {
//calculate the pixel position in the image file that will go at the start of the row in the display
source_pixel = row_total_image + ( //start at the first pixel of the row
(column + missing_pixels[row][start_of_row] //adjust for missing pixels at start of row on display
+ (display_columns + scroll_offset)) //add the scroll offset
% display_columns); //adjusts for when image wraps around to beginning of row
leds[row_total_display + column] = pgm_read_dword(&(image_matrix[frame_number][source_pixel]));
}
}
}
This is a generic function that you pass the image array to, so the showAnimation_03 function is a bit different. I've also changed the code for updating position_blinker, the test for -22 would throw off the animation a bit because it does not evenly divide by 4 (the step size you are using).
void showAnimation_03(int thisFrame) {
showAnimation(animation_matrix_03, thisFrame, position_blinker);
FastLED.show();
position_blinker -= stepsize_blinker;
if (position_blinker <= 0) {
position_blinker = 44;
}
}
Thank you very much, this works so much better now, I still have a few pixels at the end of the row that shift up though.
I attached a video, in the video you'll see an arrow moving, which should only move horizontal, but at the end of the row you'll see some of the pixels be shifted up.
(in this animation i'm not yet using the scroll offset, all frames of this animation are in an array)
(just noticed i used wrong account, but i am in fact Raymond1432)