My goal is to have an Arduino Due (96 KB RAM) write a +-1MB bitmap to an SD card.
I have an array of a several coordinates on my Arduino Due and I would like to generate the bitmap where all the coordinates have a certain color and all the other pixels/background have another color.
I do have code to write a bitmap to an SD card (see below) but the problem is that the bitmap is dynamically generated and allocated in ram and then written to the SD card. So as soon as the bitmap I do want to write to the SDcard becomes bigger than the RAM available I get an error: "xx.elf section '.bss' is not within region 'ram'.
Could anyone advice me on how to put parts of the bitmap in ram and write them to the sdcard one after another. Or would there maybe be another better approach?
#include <SPI.h>
#include <SD.h>
const int chipSelect = 10;
char name[] = "9px_0000.bmp"; // filename convention (will auto-increment)
const int w = 800; // image width in pixels
const int h = 400; // " height
const boolean debugPrint = true; // print details of process over serial?
const uint32_t imgSize = wh;
int px[wh]; // actual pixel data (grayscale - added programatically below)
File file;
const int amount_CT_samples = 20;
int Yarr[amount_CT_samples];
int Xarr[amount_CT_samples];
void setup() {
// SD setup
SerialUSB.begin(9600);
while (!SerialUSB) {
; // wait for serial port to connect. Needed for native USB port only
}
SerialUSB.print("Initializing SD card...");
if (!SD.begin(chipSelect)) {
SerialUSB.println("initialization failed!");
return;
}
SerialUSB.println("initialization done.");
// if name exists, create new filename
for (int i=0; i<10000; i++) {
name[4] = (i/1000)%10 + '0'; // thousands place
name[5] = (i/100)%10 + '0'; // hundreds
name[6] = (i/10)%10 + '0'; // tens
name[7] = i%10 + '0'; // ones
file = SD.open(name, O_CREAT | O_EXCL | O_WRITE);
if (file) {
break;
}
}
// set fileSize (used in bmp header)
int rowSize = 4 * ((3w + 3)/4); // how many bytes in the row (used to create padding)
int fileSize = 54 + hrowSize; // headers (54 bytes) + pixel data
// create image data; heavily modified version via:
// http://stackoverflow.com/a/2654860
unsigned char img = NULL; // image data
if (img) { // if there's already data in the array, clear it
free(img);
}
img = (unsigned char )malloc(3*imgSize);
for (int y=0; y<h; y++) {
for (int x=0; x<w; x++) {
int colorVal = px[y*w + x]; // classic formula for px listed in line
img[(yw + x)3+0] = (unsigned char)(colorVal); // R
img[(yw + x)3+1] = (unsigned char)(colorVal); // G
img[(yw + x)3+2] = (unsigned char)(colorVal); // B
// padding (the 4th byte) will be added later as needed...
}
}
// create padding (based on the number of pixels in a row
unsigned char bmpPad[rowSize - 3*w];
for (int i=0; i<sizeof(bmpPad); i++) { // fill with 0s
bmpPad[i] = 0;
}
// create file headers (also taken from StackOverflow example)
unsigned char bmpFileHeader[14] = { // file header (always starts with BM!)
'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0 };
unsigned char bmpInfoHeader[40] = { // info about the file (size, etc)
40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0 };
bmpFileHeader[ 2] = (unsigned char)(fileSize );
bmpFileHeader[ 3] = (unsigned char)(fileSize >> 8);
bmpFileHeader[ 4] = (unsigned char)(fileSize >> 16);
bmpFileHeader[ 5] = (unsigned char)(fileSize >> 24);
bmpInfoHeader[ 4] = (unsigned char)( w );
bmpInfoHeader[ 5] = (unsigned char)( w >> 8);
bmpInfoHeader[ 6] = (unsigned char)( w >> 16);
bmpInfoHeader[ 7] = (unsigned char)( w >> 24);
bmpInfoHeader[ 8] = (unsigned char)( h );
bmpInfoHeader[ 9] = (unsigned char)( h >> 8);
bmpInfoHeader[10] = (unsigned char)( h >> 16);
bmpInfoHeader[11] = (unsigned char)( h >> 24);
// write the file (thanks forum!)
file.write(bmpFileHeader, sizeof(bmpFileHeader)); // write file header
}
void loop() { }
UPDATE
With the following code my problem was solved. Credits to those who answered my question below!
#include <SPI.h>
#include <SD.h>
const int chipSelect = 10;
struct Pixel {
uint8_t r, g, b;
};
char name[] = "CT_0000.bmp"; // filename convention (will auto-increment)
const int w = 800; // image width in pixels
const int h = 400; // " height
const boolean debugPrint = true; // print details of process over serial?
const uint32_t imgSize = wh;
int px[wh]; // actual pixel data (grayscale - added programatically below)
File file;
const int amount_CT_samples = 50;
int Xarr[amount_CT_samples];
int Yarr[amount_CT_samples];
Pixel getPixel(int x, int y) {
const Pixel black = {0, 0, 0},
green = {0, 255, 0};
for(int i=0; i < amount_CT_samples; i++){
if(Xarr[i] == x && Yarr[i] == (h - y))return green;
}
return black;
}
void writeBitmap(File &file, int w, int h) {
size_t rowSize = 4 * ((3w + 3)/4); // padded to multiple of 4
size_t fileSize = 54 + hrowSize; // includes header
// Write image header.
uint8_t header[54] = {
// File header.
'B','M',
(uint8_t)(fileSize >> 0),
(uint8_t)(fileSize >> 8),
(uint8_t)(fileSize >> 16),
(uint8_t)(fileSize >> 24),
0,0, 0,0, 54,0,0,0,
// Image info header.
40,0,0,0,
(uint8_t)(w >> 0),
(uint8_t)(w >> 8),
(uint8_t)(w >> 16),
(uint8_t)(w >> 24),
(uint8_t)(h >> 0),
(uint8_t)(h >> 8),
(uint8_t)(h >> 16),
(uint8_t)(h >> 24),
1,0, 24,0
};
file.write(header, sizeof header);
// Write image data.
uint8_t row[rowSize];
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
Pixel pix = getPixel(x, y);
row[3*x + 0] = pix.b;
row[3*x + 1] = pix.g;
row[3*x + 2] = pix.r;
}
file.write(row, sizeof row);
}
file.close();
}
void setup() {
Serial.begin(9600);
Serial.print("Initializing SD card...");
//create dummy X and Y points
for(int i = 0; i < amount_CT_samples; i++){
Xarr[i] = i;
Yarr[i] = i;
}
if (!SD.begin(chipSelect)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
// if name exists, create new filename
for (int i=0; i<10000; i++) {
name[3] = (i/1000)%10 + '0'; // thousands place
name[4] = (i/100)%10 + '0'; // hundreds
name[5] = (i/10)%10 + '0'; // tens
name[6] = i%10 + '0'; // ones
file = SD.open(name, O_CREAT | O_EXCL | O_WRITE);
if (file) {
break;
}
}
Serial.println("start writing bitmap.");
writeBitmap(file, w, h);
Serial.println("done writing bitmap.");
}
void loop() { }