I've recently set-up a circuit with an Arduino Uno R3, an ArduCam Mini OV2640, and an SD Card reader. They are all bussed together through SPI.
I am able to successfully capture, acquire and save images in JPEG format with this setup to the SD Card from the camera. I have used the ArduCam library examples for my camera to branch my own set of functions.
I want to be able to save images in BMP format as well. I have attempted to look at the example code from the ArduCam library, however it does not appear to be as straightforward compared to saving JPEG images.
Here's my current function responsible for acquiring & saving the BMP image data:
void ReadBMPBurst()
{
Serial.println(F("ACK CMD Reading BMP burst... END"));
uint32_t length = Camera.read_fifo_length();
if (length >= MAX_FIFO_SIZE)
{
Serial.println(F("ACK CMD ERROR: Over size! END"));
Camera.clear_fifo_flag();
return;
}
if (length == 0)
{
Serial.println(F("ACK CMD ERROR: Size is 0! END"));
Camera.clear_fifo_flag();
return;
}
Camera.CS_LOW();
Camera.set_fifo_burst();
File outputFile;
if (PIN_SD_CS >= 0)
{
Camera.CS_HIGH();
outputFile = SD.open("IMG_" + String(FilesCreated++) + ".bmp", O_WRITE | O_CREAT | O_TRUNC);
Camera.CS_LOW();
Camera.set_fifo_burst();
if (!outputFile)
{
Serial.println(F("ACK CMD ERROR: Unable to create BMP on SD! END"));
Camera.clear_fifo_flag();
return;
}
}
if (PIN_SD_CS >= 0)
{
byte send1 = 0xFF;
byte send2 = 0xAA;
Camera.CS_HIGH();
outputFile.write(&send1, 1);
outputFile.write(&send2, 1);
Camera.CS_LOW();
Camera.set_fifo_burst();
}
else
{
Serial.write(0xFF);
Serial.write(0xAA);
}
for (int i = 0; i < BMPImageOffset; i++)
{
if (PIN_SD_CS >= 0)
{
byte send = pgm_read_byte(&BMPHeader[i]);
Camera.CS_HIGH();
outputFile.write(&send, 1);
Camera.CS_LOW();
Camera.set_fifo_burst();
}
else
{
Serial.write(pgm_read_byte(&BMPHeader[i]));
}
}
//SPI.transfer(0x00);
for (int i = 0; i < 240; i++)
{
for (int j = 0; j < 320; j++)
{
char VH = SPI.transfer(0x00);
char VL = SPI.transfer(0x00);
if (PIN_SD_CS >= 0)
{
Camera.CS_HIGH();
outputFile.write(&VL, 1);
delayMicroseconds(12);
outputFile.write(&VH, 1);
delayMicroseconds(12);
Camera.CS_LOW();
Camera.set_fifo_burst();
}
else
{
Serial.write(VL);
delayMicroseconds(12);
Serial.write(VH);
delayMicroseconds(12);
}
}
}
if (PIN_SD_CS >= 0)
{
byte send1 = 0xBB;
byte send2 = 0xCC;
Camera.CS_HIGH();
outputFile.write(&send1, 1);
outputFile.write(&send2, 1);
Camera.CS_LOW();
Camera.set_fifo_burst();
}
else
{
Serial.write(0xBB);
Serial.write(0xCC);
}
Camera.CS_HIGH();
if (PIN_SD_CS >= 0)
outputFile.close();
Serial.println(F("ACK CMD BMP burst read! END"));
return;
}
I'm running the code above assuming that PIN_SD_CS
will always be set to the appropriate SD Card Reader SPI CS pin. The global variable Camera
is the variable of type ArduCam
which includes all the class functions responsible for running the camera.
This function also uses the BMP header global variable BMPHeader
, declared as such:
#define BMPImageOffset 66
const char BMPHeader[BMPImageOffset] PROGMEM =
{
0x42, 0x4D, 0x36, 0x58, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x03, 0x00,
0x00, 0x00, 0x00, 0x58, 0x02, 0x00, 0xC4, 0x0E, 0x00, 0x00, 0xC4, 0x0E, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0x1F, 0x00,
0x00, 0x00
};
All of the code above was adapted from the official ArduCam library examples for my specific camera.
With the current setup, all BMP files saved to the SD card are corrupted and not readable by any image viewer I have. The most common error message being that the header is corrupted.
I was under the impression that a BMP image simply requires a header that describes it's size (hence why the size in this specific example is hardcoded to 320x240), however it clearly appears to be more complicated than that, as there may be some other things I'm missing in order to successfully save my BMP files.
Thanks for reading my post, any guidance is appreciated!