Bitmap with Teensy3.5

Status
Not open for further replies.

johnwatterson

Well-known member
Still working on this project. Morton Kopf helped me find his Site and Code. His code uses BUILTIN_SDCARD FOR THE ChipSelect PIN but the compiler complains - 'BUILTIN_CARD' was not declared in this scope:

In file included from C:\Users\Owner\Documents\Arduino\libraries\My_bitmapDisplay\My_bitmapDisplay.ino:2:0:

C:\Users\Owner\Documents\Arduino\libraries\libraries\FastLED/FastLED.h:14:21: note: #pragma message: FastLED version 3.002.001

# pragma message "FastLED version 3.002.001"

^

My_bitmapDisplay:25: error: 'BUILTIN_CARD' was not declared in this scope
const int chipSelect = BUILTIN_CARD;

Here is Morton code:

Code:
/*
This code uses the T3.6 onboard sd card slot, BMP stored on the card are light painted using a cheap strip of ws2811 leds using FastLed
code derived from lightpainting sketch:
https://forum.pjrc.com/threads/24535-OctoWS2811-POV-reading-BMP-from-SD-card
and this post:
——> https://forum.pjrc.com/threads/40871-Teensy-6-5-SDFat-BMP-file-read-fail
*/

#include <SPI.h>
#include <SD.h>
#include <FastLED.h>

File bmpFile;
const int chipSelect = BUILTIN_SDCARD;

// you can remove all Serial.print when you have your paint staff
// set up, this is just for debug

int bmpWidth, bmpHeight;
uint8_t bmpDepth, bmpImageoffset;
#define BUFFPIXEL 512

unsigned int Color(byte b, byte r, byte g); //placed here to avoid compiler error

// How many leds in your strip?
#define NUM_LEDS 432

#define DATA_PIN 2 //the pin that Led strip is attached to
CRGB leds[NUM_LEDS];
int paintSpeed = 15; //adjust this to vary image refresh rate

void setup(void) {
Serial.begin(9600);

FastLED.addLeds<WS2811, DATA_PIN, GRB>(leds, NUM_LEDS);

//test our led strip – you can remove this to the comment line "// if you dont get …"
for(int x=0;x<NUM_LEDS;x++){
leds[x] = CRGB::Green;}
FastLED.show();
delay(500);
for(int x=0;x<NUM_LEDS;x++){
leds[x] = CRGB::Red;}
FastLED.show();
delay(500);
for(int x=0;x<NUM_LEDS;x++){
leds[x] = CRGB::Blue;}
FastLED.show();
delay(500);
for(int x=0;x<NUM_LEDS;x++){
leds[x] = CRGB::Black;}
FastLED.show();
delay(500);
// if you dont get all leds lighting then going off, check your wiring

Serial.println("init");
delay(500);
Serial.print("Initializing SD card…");

if (!SD.begin(chipSelect)) {
Serial.println("initialization failed!");
return;
}
Serial.println("SD OK!");

}
void loop() {

bmpDraw("JEM.bmp");//example filename
bmpDraw("DWARFS.bmp");
bmpDraw("ISLA.bmp");
}

//////////////////Function to read BMP and send to Led strip a row at a time/////////////////////
void bmpDraw(char* filename){

File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8_t bmpDepth; // Bit depth (currently must report 24)
uint32_t bmpImageoffset; // Start of image data in file
uint32_t rowSize; // Not always = bmpWidth; may have padding
uint8_t sdbuffer[3*BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
uint32_t povbuffer[BUFFPIXEL]; // pixel out buffer (16-bit per pixel)//////mg/////this needs to be 24bit per pixel////////
uint32_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer
boolean goodBmp = false; // Set to true on valid header parse
boolean flip = true; // BMP is stored bottom-to-top
int w, h, row, col;
int r, g, b;
uint32_t pos = 0, startTime = millis();
uint8_t povidx = 0;
boolean first = true;

// Open requested file on SD card
bmpFile = SD.open(filename);
Serial.println(filename);
// Parse BMP header
if(read16(bmpFile) == 0x4D42) { // BMP signature
Serial.print("File size: ");
Serial.println(read32(bmpFile));
(void)read32(bmpFile); // Read & ignore creator bytes
bmpImageoffset = read32(bmpFile); // Start of image data
Serial.print("Image Offset: ");
Serial.println(bmpImageoffset, DEC);
// Read DIB header
Serial.print("Header size: ");
Serial.println(read32(bmpFile));
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if(read16(bmpFile) == 1) { // # planes — must be ‘1’
bmpDepth = read16(bmpFile); // bits per pixel
Serial.print("Bit Depth: "); Serial.println(bmpDepth);
if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed

goodBmp = true; // Supported BMP format — proceed!
Serial.print("Image size: ");
Serial.print(bmpWidth);
Serial.print(‘x’);
Serial.println(bmpHeight);

// BMP rows are padded (if needed) to 4-byte boundary
rowSize = (bmpWidth * 3 + 3) & ~3;

// If bmpHeight is negative, image is in top-down order.
// This is not canon but has been observed in the wild.
if(bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}

w = bmpWidth;
h = bmpHeight;

for (row=0; row<h; row++) {
if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight – 1 – row) * rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize;
if(bmpFile.position() != pos) { // Need seek?
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // Force buffer reload
}

for (col=0; col<w; col++) { // For each column…
// read more pixel data
if (buffidx >= sizeof(sdbuffer)) {
povidx = 0;
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
}
// set pixel
r = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
b = sdbuffer[buffidx++];
Serial.print(r);Serial.print(" ");Serial.print(g);Serial.print(" ");Serial.println(b);
//we need to output BRG 24bit colour//
povbuffer[povidx++] =(b<<16) + (g<<8) +r;
}

for(int i=0;i<NUM_LEDS;i++){
leds[i]=povbuffer[i];}
FastLED.show();
delay(paintSpeed);// change the delay time depending effect required
} // end scanline

} // end goodBmp
}
}//end of IF BMP
Serial.println();

bmpFile.close();
}

//*************Support Funcitons****************//
// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.
uint16_t read16(File& f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read(); // MSB
return result;
}
uint32_t read32(File& f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // MSB
return result;
 
Not seeing the code there - but the name used is missing "SD":

// Use these with the Teensy 3.5 & 3.6 SD card
//#define SDCARD_CS_PIN BUILTIN_SDCARD

"BUILTIN_CARD" :: Should be as in the posted code: const int chipSelect = BUILTIN_SDCARD;
 
Not seeing the code there - but the name used is missing "SD":



"BUILTIN_CARD" :: Should be as in the posted code: const int chipSelect = BUILTIN_SDCARD;



Thank you, Now the hardware initalizes, but lights only the leds on pin 2 of the teensy instead of the 8 by 432 that I expect. I did try some changes like NUM_LEDS NUM_STRIP and TOTAL_LEDS but no change. Here is the basic code:
Code:
// [code lang=”arduino” light=”true”]
/*
This code uses the T3.6 onboard sd card slot, BMP stored on the card are light painted using a cheap strip of ws2811 leds using FastLed
code derived from lightpainting sketch:
https://forum.pjrc.com/threads/24535-OctoWS2811-POV-reading-BMP-from-SD-card
and this post:
——> https://forum.pjrc.com/threads/40871-Teensy-6-5-SDFat-BMP-file-read-fail
Modified for bmpWidth Height and TOTLA_LEDS lights onlt Datapin 2
*/
#include <OctoWS2811.h>
#include <SPI.h>
#include <SD.h>
#include <FastLED.h>

File bmpFile;
const int chipSelect = BUILTIN_SDCARD;

// you can remove all Serial.print when you have your paint staff
// set up, this is just for debug

int bmpWidth = 72, bmpHeight = 48;
uint8_t bmpDepth, bmpImageoffset;
#define BUFFPIXEL 512

unsigned int Color(byte b, byte r, byte g); //placed here to avoid compiler error

// How many leds in your strip?
#define NUM_LEDS 432
#define NUM_ROWS 8
#define TOTAL_LEDS (NUM_LEDS * NUM_ROWS)
#define DATA_PIN 2 //the pin that Led strip is attached to
CRGB leds[TOTAL_LEDS];
int paintSpeed = 15; //adjust this to vary image refresh rate

void setup(void) {
Serial.begin(9600);

FastLED.addLeds<WS2811, DATA_PIN, GRB>(leds, TOTAL_LEDS);

//test our led strip – you can remove this to the comment line "// if you dont get …"
for(int x=0;x<TOTAL_LEDS;x++){
leds[x] = CRGB::Green;}
FastLED.show();
delay(500);
for(int x=0;x<TOTAL_LEDS;x++){
leds[x] = CRGB::Red;}
FastLED.show();
delay(500);
for(int x=0;x<TOTAL_LEDS;x++){
leds[x] = CRGB::Blue;}
FastLED.show();
delay(500);
for(int x=0;x<TOTAL_LEDS;x++){
leds[x] = CRGB::White;}
FastLED.show();
delay(500);
// if you dont get all leds lighting then going off, check your wiring

Serial.println("init");
delay(500);
Serial.print("Initializing SD card…");

if (!SD.begin(chipSelect)) {
Serial.println("initialization failed!");
return;
}
Serial.println("SD OK!");

}
 
only works on pin 2 as that is what is declared in the sketch. the call to the leds is using the Fastled library, and that has been initialised to use pin2 in your setup.
#define DATA_PIN 2 //the pin that Led strip is attached to
FastLED.addLeds<WS2811, DATA_PIN, GRB>(leds, TOTAL_LEDS);
and using FastLED.show(); to light the leds.

swap out the fasted.show calls to the ones used for the octopus library if that is what you want to do.
 
Thank you once again. My setup is 432 leds per-strip times 8 OctoWS2811 leds for atotal of 3456 leds. My bitmap is cols 72 times rows 48 - this should work - yes?
 
there are a couple of things to consider such as power supply, supply location for longer strips, delay in refresh rate for longer strips, potential delay in SD card read, etc, but yes, should work. You will also need to rework the led colour setting loop if you are planning to use a zigzag led array rather than straight rows. By the numbers above you will zigzag 6 rows for each strip? so somewhere you need to do some reworking / placement of the colours that are taken for a given location in the bitmap to the placement you want in the led array. There are a couple of ways to do this, either by using a maths function in the loop, or by using a reference array that holds the led numbers you want in the right order.
 
My original idea was to paint the existing bitmap picture to the display after sending some text saying this is a painting. That means I need to load your program to on the SD card with a file for drawing the text and then drawing the bitmap file. Everything would shut down and start over when you push a button.
 
It looks like your program did read the SD file and size it. It could not draw it to the leds because of the pin 2 problem. I did see the FastLED has a parallel program function but I do not know how to use it in this context.
 
Multi-platform Parallel output

If you are using a due or a digix or a teensy 3 or a teensy 3.1, FastLED now has some new parallel output controllers that will allow you to drive 8 lines of WS2812 strips in parallel. This means that instead of taking 15.3ms/frame of CPU time to write out 512 bytes of data, it would take closer to 1.9ms/frame. See examples/Multiple/ParallelOutputDemo to see how this works.

On the teensy 3 and 3.1 there's two sets of pins that we can use for parallel output, described below:

WS2811_PORTD - the OctoWS2811 pins - 2,14,7,8,6,20,21,5
WS2811_PORTC - pins 15,22,23,9,10,13,11,12,28,27,29,30 (yes, 12 pins! If you're willing to solder onto pads on the back of the teensy)
WS2811_PORTDC - pins 2,14,7,8,6,20,21,5,15,22,23,9,10,13,11,12 <-- 16 pins, no soldering onto pads on the back!
 
Multi-platform Parallel output
but why not just use OctoWS2811 library for eight output strips?

So, I guess from here it is run a test sketch to ensure that the SD card bitmap is read, run a test sketch to ensure that all eight strips of leds work, have a sketch that sorts out the zigzag arrangement, and then put it all together.

you can use the BMP from SD card sketch from the POV project to sort out the first part. I would do a read of the whole bmp file and put it into a buffer array, and then do the loop that sets all led pixels, and then do a single write to the pixels.
 
Thanks for your suggestions, OK, I will start on that path - make sure I can light the leds with Octows2811 library, then read the Bitmap from the SD card into a pixel map in memory and do a single pixel write to the leds. I think your program will create a buffered map for the BMP file and the OctoWS2811 library could be easy to use. How about the HID interface Teensy uses rather than a serial interface I need to write to each pixel. That is an on going problem for me because I do not understand the HID relationship. I do understand the serial terminal output that shows the SD card is available. How will the HID interface with the bitmap picture in memory output, because that is serial and DMA used by the teensy creates a conflict it seems. I can read up on the HID interface but my understanding of the teensy application is straight DMA starting with pin 2 and continuing for 8 strips. So I have to read the BMP file into memory of the teensy and then output to the leds in serial or HID? Is this correct? I do not need the speed of DMA for this project but want to be sure I know what I am doing, HID or serial output. I will look up HID right now. Thanks
 
OK, I have a program that writes to all the Leds in my 72 cols by 48 rows panel using 3.5 Teensy/Octows2811 and Mortonkopf's program for reading a bitmap file from the SD card on 3.5. However the BMP file does not write out to the Leds. I can make it down about half way to "goodBmp = true;" statement. Image size does print on serial monitor but no bmpWidth or bmpHeight. I do get 3 cols of 72 lines of code following Serial.print("Image size:") The bitmap file does not print to the Leds. Any ideas?
Code:
#define USE_OCTOWS2811
#include <OctoWS2811.h>
#include <FastLED.h>
#include <SPI.h>
#include <SD.h>

File bmpFile;
const int chipSelect = BUILTIN_SDCARD;

// you can remove all Serial.print when you have your paint staff
// set up, this is just for debug

int bmpWidth = 72, bmpHeight = 48;
uint8_t bmpDepth, bmpImageoffset;
#define BUFFPIXEL 512

#define NUM_LEDS_PER_STRIP 432
#define NUM_STRIPS 8

CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP];

// Pin layouts on the teensy 3:
// OctoWS2811: 2,14,7,8,6,20,21,5

unsigned int Color(byte b, byte r, byte g); //placed here to avoid compiler error
int paintSpeed = 15; //adjust this to vary image refresh rate

void setup(void) {
  Serial.begin(9600);
  
  LEDS.addLeds<OCTOWS2811>(leds, NUM_LEDS_PER_STRIP);
  LEDS.setBrightness(32);

// if you dont get all leds lighting then going off, check your wiring

Serial.println("init");
delay(500);
Serial.print("Initializing SD card…");

if (!SD.begin(chipSelect)) {
Serial.println("initialization failed!");
return;
}
Serial.println("SD OK!");
}

void loop() {
  static uint8_t hue = 0;
  for(int i = 0; i < NUM_STRIPS; i++) {
    for(int j = 0; j < NUM_LEDS_PER_STRIP; j++) {
      leds[(i*NUM_LEDS_PER_STRIP) + j] = CHSV((32*i) + hue+j,192,255);
    }
  }

  hue++;

  LEDS.show();
  LEDS.delay(10);



bmpDraw("YONION.bmp");          //("JEM.bmp");//example filename
//bmpDraw("RONION.bmp");        //("DWARFS.bmp");
                                // bmpDraw("ISLA.bmp");
}

//////////////////Function to read BMP and send to Led strip a row at a time/////////////////////
void bmpDraw(char* filename){

File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8_t bmpDepth; // Bit depth (currently must report 24)
uint32_t bmpImageoffset; // Start of image data in file
uint32_t rowSize; // Not always = bmpWidth; may have padding
uint8_t sdbuffer[3*BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
uint32_t povbuffer[BUFFPIXEL]; // pixel out buffer (16-bit per pixel)//////mg/////this needs to be 24bit per pixel////////
uint32_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer
boolean goodBmp = false; // Set to true on valid header parse
boolean flip = true; // BMP is stored bottom-to-top
int w, h, row, col;
int r, g, b;
uint32_t pos = 0, startTime = millis();
uint8_t povidx = 0;
boolean first = true;

// Open requested file on SD card
bmpFile = SD.open(filename);
Serial.println(filename);
// Parse BMP header
if(read16(bmpFile) == 0x4D42) { // BMP signature
Serial.print("File size: ");
Serial.println(read32(bmpFile));
(void)read32(bmpFile); // Read & ignore creator bytes
bmpImageoffset = read32(bmpFile); // Start of image data
Serial.print("Image Offset: ");
Serial.println(bmpImageoffset, DEC);
// Read DIB header
Serial.print("Header size: ");
Serial.println(read32(bmpFile));
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if(read16(bmpFile) == 1) { // # planes — must be ‘1’
bmpDepth = read16(bmpFile); // bits per pixel
Serial.print("Bit Depth: "); Serial.println(bmpDepth);
if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed

goodBmp = true; // Supported BMP format — proceed!
Serial.print("Image size: ");
Serial.print(bmpWidth);
Serial.print('X');                            //Serial.print(‘x’);
Serial.println(bmpHeight);

// BMP rows are padded (if needed) to 4-byte boundary
rowSize = (bmpWidth * 3 + 3) & ~3;

// If bmpHeight is negative, image is in top-down order.
// This is not canon but has been observed in the wild.
if(bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}

w = bmpWidth;
h = bmpHeight;

for (row=0; row<h; row++) {
if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
  pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;         //pos = bmpImageoffset + (bmpHeight – 1 – row) * rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize;
if(bmpFile.position() != pos) { // Need seek?
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // Force buffer reload
}

for (col=0; col<w; col++) { // For each column…
// read more pixel data
if (buffidx >= sizeof(sdbuffer)) {
povidx = 0;
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
}
// set pixel
r = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
b = sdbuffer[buffidx++];
Serial.print(r);Serial.print(" ");Serial.print(g);Serial.print(" ");Serial.println(b);
//we need to output BRG 24bit colour//
povbuffer[povidx++] =(b<<16) + (g<<8) +r;
}

 for(int i=0;i<(NUM_LEDS_PER_STRIP * NUM_STRIPS);i++){
//  for(int i=0;i<NUM_LEDS;i++){
leds[i]=povbuffer[i];}
//FastLED.show();
LEDS.show();
delay(paintSpeed);// change the delay time depending effect required
} // end scanline

} // end goodBmp
}
}//end of IF BMP
Serial.println();

bmpFile.close();
}

//*************Support Funcitons****************//
// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.
uint16_t read16(File& f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read(); // MSB
return result;
}
uint32_t read32(File& f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // MSB
return result;
}
 
If the prints stop midway it seems the processor is faulted [ on read32(bmpFile) ? ] and nothing is running ?

Code:
   // ...
bmpDepth = read16(bmpFile); // bits per pixel
Serial.print("Bit Depth: "); Serial.println(bmpDepth);
if((bmpDepth == 24) && ([B]read32(bmpFile)[/B] == 0)) { // 0 = uncompressed

goodBmp = true; // Supported BMP format — proceed!

If that is the case I posted "debug_t3" that enables {PJRC's} output on fault trapping and gives some way to get feedback keeping the MCU alive enough to show where it was last seen.
 
Great - let me ask you - since I am using SPI.h without pin definitions - will the teensy -Octows2811 combination understand? It looks like I am never getting to the buffer load. For example, I do not see the three lines: Serial.print(bmpWidth); Serial.print ("X"); or Serialprint(bmpHeight); Even though there are 72 row of 3 cols each of code?
 
Hi. the pins for the SD card are taken care of for you when you define "const int chipSelect = BUILTIN_SDCARD;" the Teensy will library will deal with this if using the onboard sd card slot. Hope that clarifies things.
 
My mistake. I am getting all the way down to the line - rowSize=(bmp*3+3) & ~3; then I am getting three cols of 72 lines on the serial monitor but no bitmap display on the LEDs. So far I have not found a debug_t3 file for the hardware. I am continuing to work on this project even though I am not communicating very much on the forum. I am trying to learn enough that the details make sense but it has been years since I did this so it does take time.
 
My mistake. I am getting all the way down to the line - rowSize=(bmp*3+3) & ~3; then I am getting three cols of 72 lines on the serial monitor but no bitmap display on the LEDs. ...

Trusting SerMon output when fault or error happens can be hard to pin down. That was why I looked to find a way to use the PJRC code that is off by default to trap faults and keep the USB output engine running as the processor seems to keep ticking over when it faults it just does an infinite loop. It does it for all Serial# ports it seems - but I haven't looked beyond USB Serial yet as it was evolving and I have to rewrite the code more cleanly to allow that to change at run time - and wire up a second Teensy to proxy that output to SerMon to see it.

The other thing with the 10 buckets allows following code execution in some fashion without copious printing until something goes wrong or the code gets to a point to check with the 'haltif' or assert, etc.
 
Thank you - you guys are away above my head. It will take me some time to go through this stuff. I am wondering if it is worth the time it takes for me to figure it out even with your expert help. Simply I am making a art project using teensy on 3456 leds panel I built. I want to read a bitmap picture from the SD card and send it to the 72X48 panel of leds via the teensy/octows2811. It looked like MortonKopf program would do just that. However I am lost in the details. Does anyone have a suggestion as to how to proceed with my goal in mind? I appreciate any thoughts or suggestions.
 
Started over and Morton's program is working. So far unable to get the teensy to light more than one string (432 leds) on pin 2.
 
@johnwatterson - stick with it. what you learn on this project you will be able to use on another and get up and running very quickly on the next project. So, to recap, can you post the sketch you are using. I think that you may still have the fasted calls rather than the octows2811 calls. we'll go through it with you.
 
Yes, you are absolutely right. Probably learn more about coding doing this trouble-shooting problem than any other one thing I could do. And for sure this will open a big vat of chocolate for the future.
This is the last code I tried - replaces FastLED with the teensy/octows2811 code. lights leds, but interferes with "Open requested file on SD card" section. I certainly appreciate any suggestions.
Code:
#define USE_OCTOWS2811,
#include <OctoWS2811.h>
#include <FastLED.h>
#include <SPI.h>
#include <SD.h>

File bmpFile;
const int chipSelect = BUILTIN_SDCARD;

// you can remove all Serial.print when you have your paint staff
// set up, this is just for debug

int bmpWidth = 72, bmpHeight = 48;
uint8_t bmpDepth, bmpImageoffset;
#define BUFFPIXEL 512

#define NUM_LEDS_PER_STRIP 432
#define NUM_STRIPS 8

CRGB leds[NUM_STRIPS * NUM_LEDS_PER_STRIP];

// Pin layouts on the teensy 3:
// OctoWS2811: 2,14,7,8,6,20,21,5

unsigned int Color(byte b, byte r, byte g); //placed here to avoid compiler error
int paintSpeed = 15; //adjust this to vary image refresh rate

void setup(void) {
 Serial.begin(9600);
  
  LEDS.addLeds<OCTOWS2811>(leds, NUM_LEDS_PER_STRIP);
  LEDS.setBrightness(32);

// if you dont get all leds lighting then going off, check your wiring

Serial.println("init");
delay(500);
Serial.print("Initializing SD card…");

if (!SD.begin(chipSelect)) {
Serial.println("initialization failed!");
return;
}
Serial.println("SD OK!");
}

void loop() {
  static uint8_t hue = 0;
  for(int i = 0; i < NUM_STRIPS; i++) {
    for(int j = 0; j < NUM_LEDS_PER_STRIP; j++) {
      leds[(i*NUM_LEDS_PER_STRIP) + j] = CHSV((32*i) + hue+j,192,255);
    }
  }

  hue++;

  LEDS.show();
  LEDS.delay(10);
//} 
//void loop(){
  bmpDraw("YONION.bmp");          //("JEM.bmp");//example filename
//bmpDraw("RONION.bmp");        //("DWARFS.bmp");
                                // bmpDraw("ISLA.bmp");
}
//////////////////Function to read BMP and send to Led strip a row at a time/////////////////////
void bmpDraw(char* filename){

File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8_t bmpDepth; // Bit depth (currently must report 24)
uint32_t bmpImageoffset; // Start of image data in file
uint32_t rowSize; // Not always = bmpWidth; may have padding
uint8_t sdbuffer[3*BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
uint32_t povbuffer[BUFFPIXEL]; // pixel out buffer (16-bit per pixel)//////mg/////this needs to be 24bit per pixel////////
uint32_t buffidx = sizeof(sdbuffer); // Current position in sdbuffer
boolean goodBmp = false; // Set to true on valid header parse
boolean flip = true; // BMP is stored bottom-to-top
int w, h, row, col;
int r, g, b;
uint32_t pos = 0, startTime = millis();
uint8_t povidx = 0;
boolean first = true;

// Open requested file on SD card
bmpFile = SD.open(filename);
Serial.println(filename);
// Parse BMP header
if(read16(bmpFile) == 0x4D42) { // BMP signature
Serial.print("File size: ");
Serial.println(read32(bmpFile));
(void)read32(bmpFile); // Read & ignore creator bytes
bmpImageoffset = read32(bmpFile); // Start of image data
Serial.print("Image Offset: ");
Serial.println(bmpImageoffset, DEC);
// Read DIB header
Serial.print("Header size: ");
Serial.println(read32(bmpFile));
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
if(read16(bmpFile) == 1) { // # planes — must be ‘1’
bmpDepth = read16(bmpFile); // bits per pixel
Serial.print("Bit Depth: "); Serial.println(bmpDepth);
if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed

goodBmp = true; // Supported BMP format — proceed!
Serial.print("Image size: ");
Serial.print(bmpWidth);
Serial.print('X');                            //Serial.print(‘x’);
Serial.println(bmpHeight);

// BMP rows are padded (if needed) to 4-byte boundary
rowSize = (bmpWidth * 3 + 3) & ~3;

// If bmpHeight is negative, image is in top-down order.
// This is not canon but has been observed in the wild.
if(bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}

w = bmpWidth;
h = bmpHeight;

for (row=0; row<h; row++) {
if(flip) // Bitmap is stored bottom-to-top order (normal BMP)
  pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;         //pos = bmpImageoffset + (bmpHeight – 1 – row) * rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize;
if(bmpFile.position() != pos) { // Need seek?
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // Force buffer reload
}

for (col=0; col<w; col++) { // For each column…
// read more pixel data
if (buffidx >= sizeof(sdbuffer)) {
povidx = 0;
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
}
// set pixel
r = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
b = sdbuffer[buffidx++];
Serial.print(r);Serial.print(" ");Serial.print(g);Serial.print(" ");Serial.println(b);
//we need to output BRG 24bit colour//
povbuffer[povidx++] =(b<<16) + (g<<8) +r;
}

 for(int i=0;i<(NUM_LEDS_PER_STRIP * NUM_STRIPS);i++){
//  for(int i=0;i<NUM_LEDS;i++){
leds[i]=povbuffer[i];}
//FastLED.show();
LEDS.show();
delay(paintSpeed);// change the delay time depending effect required
} // end scanline

} // end goodBmp
}
}//end of IF BMP
Serial.println();

bmpFile.close();
}

//*************Support Funcitons****************//
// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.
uint16_t read16(File& f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read(); // MSB
return result;
}
uint32_t read32(File& f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // MSB
return result;
}
 
hi, hopefully I will get a chance to look at this tomorrow, but looks like its going to be regarding BUFFPIXEL, or buffer size, as this sketch was only for sending out the bmp colour data to one row of leds.
 
Status
Not open for further replies.
Back
Top