Hi,
I used the code provided by Svarun123 to save a bitmap from ArduCam to the SD card of a Adafruit 96x64 RGB OLED (SSD1331). This works well when writing a 16Bit bitmap to the SD card. However, I want to load the bitmap to the OLED and therefore, I need a 24Bit bimap. I tried to convert the bitmap format during writing to SD card and the captured bitmap can be identified but the color codes are incorrect.
Here is the initialization, the BMP header and the setup:
#include <Wire.h>
#include <ArduCAM.h>
#include <SPI.h>
#include "memorysaver.h"
#include <a_Adafruit_GFX.h>
#include <a_Adafruit_SSD1331.h>
#include <SD.h>
//#include <SPI.h>
#define sclk 13
#define mosi 11
#define oled_cs 5//10 - OLEDCS
#define rst 9
#define dc 8
#define SD_CS 4
// Color definitions
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
int FilesCreated;
// to draw images from the SD card, we will share the hardware SPI interface
Adafruit_SSD1331 tft = Adafruit_SSD1331(oled_cs, dc, rst);
// the file itself
File bmpFile;
// information we extract about the bitmap file
int bmpWidth, bmpHeight;
uint8_t bmpDepth, bmpImageoffset;
//This demo can only work on OV2640_MINI_2MP platform.
#if !(defined OV2640_MINI_2MP)
#error Please select the hardware platform and camera module in the ../libraries/ArduCAM/memorysaver.h file
#endif
#define BMPIMAGE160 54 //320x240
const char bmp_header_160[BMPIMAGE160] PROGMEM =
{
0x42, 0x4D, 0x36, 0x84, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
0x28, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x01, 0x00,
0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
// set pin 7 as the slave select for the digital pot:
const int CS = 7;
bool is_header = false;
int mode = 0;
uint8_t start_capture = 0;
ArduCAM myCAM( OV2640, CS );
uint8_t read_fifo_burst(ArduCAM myCAM);
void setup() {
Serial.begin(500000);//9600
pinMode(oled_cs, OUTPUT);
digitalWrite(oled_cs, HIGH);
// initialize the OLED
tft.begin();
Serial.println("init");
tft.fillScreen(BLUE);
delay(500);
Serial.print("Initializing SD card...");
if (!SD.begin(SD_CS)) {
Serial.println("failed!");
return;
}
Serial.println("SD OK!");
// put your setup code here, to run once:
uint8_t vid, pid;
uint8_t temp;
Wire.begin();
Serial.begin(500000);//921600
Serial.println(F("ACK CMD ArduCAM Start! END"));
Serial.println("ArduCAM Start!");
// set the CS as an output:
pinMode(CS, OUTPUT); //Konfiguration Pin 7
digitalWrite(CS, HIGH); //Pin 7 auf high setzen
// initialize SPI:
SPI.begin();
//Reset the CPLD
myCAM.write_reg(0x07, 0x80);
delay(100);
myCAM.write_reg(0x07, 0x00);
delay(100);
while(1){
//Check if the ArduCAM SPI bus is OK
myCAM.write_reg(ARDUCHIP_TEST1, 0x55);
temp = myCAM.read_reg(ARDUCHIP_TEST1);
if (temp != 0x55){
Serial.println(F("ACK CMD SPI interface Error! END"));
Serial.println("SPI interface Error!");
delay(1000);continue;
}else{
Serial.println(F("ACK CMD SPI interface OK. END"));break;
Serial.println("SPI interface OK.");break;
}
}
#if defined (OV2640_MINI_2MP)
while(1){
//Check if the camera module type is OV2640
myCAM.wrSensorReg8_8(0xff, 0x01);
myCAM.rdSensorReg8_8(OV2640_CHIPID_HIGH, &vid);
myCAM.rdSensorReg8_8(OV2640_CHIPID_LOW, &pid);
if ((vid != 0x26 ) && (( pid != 0x41 ) || ( pid != 0x42 ))){
Serial.println(F("ACK CMD Can't find OV2640 module! END"));
Serial.println("Can't find OV2640 module!");
delay(1000);continue;
}
else{
Serial.println(F("ACK CMD OV2640 detected. END"));break;
Serial.println("OV2640 detected.");
}
}
#endif
//Change to JPEG capture mode and initialize the OV5642 module
// myCAM.set_format(JPEG);
// myCAM.InitCAM();
myCAM.OV2640_set_JPEG_size(OV2640_160x120);
// Serial.println(F("ACK CMD switch to OV2640_160x120 END"));
Serial.println("switch to OV2640_160x120");
// myCAM.OV2640_set_Light_Mode(Auto);temp = 0xff;
// Serial.println(F("ACK CMD Set to Auto END"));
temp = 0xff;
//Format auf Bitmap
myCAM.set_format(BMP);
myCAM.InitCAM();
myCAM.wrSensorReg16_8(0x3818, 0x81);
myCAM.wrSensorReg16_8(0x3621, 0xA7);
delay(1000);
myCAM.clear_fifo_flag();
}
void loop() {
// put your main code here, to run repeatedly:
uint8_t temp = 0xff, temp_last = 0;
bool is_header = false;
myCAM.flush_fifo();
myCAM.clear_fifo_flag();
//Start capture
myCAM.start_capture();
while (!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK));
// captureTime = millis() - currTime;
delay(50);
// Serial.println(F("ACK CMD Image capture finished! END")); //TODO: Timing
// Serial.println(F("ACK CMD Starting image processing... END"));
// Serial.println("Starting image processing...");
// currTime = millis();
//ReadJPEGBurst();
ReadBMPBurst();
// processingTime = millis() - currTime;
// Serial.println(F("ACK CMD Image processing finished! END")); //TODO: Timing
// Serial.println("Image processing finished!");
myCAM.clear_fifo_flag();
delay(2000);
}
Here is the code for writing the bitmap to the SD card
void ReadBMPBurst()
{
// Serial.println(F("ACK CMD Reading BMP burst... END"));
Serial.println("Reading BMP burst... ");
uint32_t length = myCAM.read_fifo_length();
if (length >= MAX_FIFO_SIZE)
{
Serial.println(F("ACK CMD ERROR: Over size! END"));
myCAM.clear_fifo_flag();
return;
}
if (length == 0)
{
Serial.println(F("ACK CMD ERROR: Size is 0! END"));
myCAM.clear_fifo_flag();
return;
}
myCAM.CS_LOW();
myCAM.set_fifo_burst();
File outputFile;
if (SD_CS >= 0)
{
myCAM.CS_HIGH();
outputFile = SD.open("CAM_" + String(FilesCreated++) + ".bmp", O_WRITE | O_CREAT | O_TRUNC);
myCAM.CS_LOW();
myCAM.set_fifo_burst();
if (!outputFile)
{
Serial.println(F("ACK CMD ERROR: Unable to create BMP on SD! END"));
myCAM.clear_fifo_flag();
return;
}
}
Serial.println(SD_CS);
if (SD_CS >= 0)
{
byte send1 = 0xFF;
byte send2 = 0xAA;
myCAM.CS_HIGH();
// outputFile.write(&send1, 1);
// outputFile.write(&send2, 1);
myCAM.CS_LOW();
myCAM.set_fifo_burst();
}
else
{
Serial.write(0xFF);
Serial.write(0xAA);
}
/* Serial.print("BMPIMAGEOFFSET: ");Serial.println(BMPIMAGEOFFSET);
for (int i = 0; i < BMPIMAGEOFFSET; i++)
{
if (SD_CS >= 0)
{
byte send = pgm_read_byte(&bmp_header[i]);
Serial.print("bmpHeader");Serial.print(i);Serial.print(": ");Serial.println(send);
myCAM.CS_HIGH();
outputFile.write(&send, 1);
myCAM.CS_LOW();
myCAM.set_fifo_burst();
}
else
{
Serial.write(pgm_read_byte(&bmp_header[i]));
}
}*/
Serial.print("BMPIMAGE160: ");Serial.println(BMPIMAGE160);
for (int i = 0; i < BMPIMAGE160; i++)
{
if (SD_CS >= 0)
{
byte send = pgm_read_byte(&bmp_header_160[i]);
// Serial.print("bmpHeader");Serial.print(i);Serial.print(": ");Serial.println(send);
myCAM.CS_HIGH();
outputFile.write(&send, 1);
myCAM.CS_LOW();
myCAM.set_fifo_burst();
}
else
{
Serial.write(pgm_read_byte(&bmp_header_160[i]));
}
}
//SPI.transfer(0x00);
for (int i = 0; i < 320; i++)
{
for (int j = 0; j < 240; j++)
{
char VH = SPI.transfer(0x00);
char VL = SPI.transfer(0x00);
//R: 5bit, G: 6bit, B: 5bit
// byte fR = (VH >> 0x0C) & 0xFFFFF ;
// byte fG = ((VH & 0x00000FFF) << 0x0C) | ((VL >> 0x14) & 0xFFF);
// byte fB = VL & 0xFFFFF;
//R: 5bit, G: 5bit, B: 5bit
byte fR = (VH >> 0x08) & 0xFFFFF ;
byte fG = ((VH & 0x000000FF) << 0x0C) | ((VL >> 0x14) & 0xFFF);
byte fB = VL & 0xFFFFF;
if (SD_CS >= 0)
{
myCAM.CS_HIGH();
outputFile.write(&fR, 1);
delayMicroseconds(12);
outputFile.write(&fG, 1);
delayMicroseconds(12);
outputFile.write(&fB, 1);
delayMicroseconds(12);
/* outputFile.write(&VL, 1);
delayMicroseconds(12);
outputFile.write(&VH, 1);
delayMicroseconds(12);*/
myCAM.CS_LOW();
myCAM.set_fifo_burst();
}
}
}
if (SD_CS >= 0)
{
byte send1 = 0xBB;
byte send2 = 0xCC;
myCAM.CS_HIGH();
outputFile.write(&send1, 1);
outputFile.write(&send2, 1);
myCAM.CS_LOW();
myCAM.set_fifo_burst();
}
else
{
Serial.write(0xBB);
Serial.write(0xCC);
}
myCAM.CS_HIGH();
if (SD_CS >= 0)
outputFile.close();
// Serial.println(F("ACK CMD BMP burst read! END"));
Serial.println("BMP burst read!");
return;
}
This is what the monitor logged:
21:08:40.114 -> ACK CMD ArduCAM Start! END
21:08:40.114 -> ArduCAM Start!
21:08:40.314 -> ACK CMD SPI interface OK. END
21:08:40.314 -> ACK CMD OV2640 detected. END
21:08:40.354 -> switch to OV2640_160x120
21:08:41.834 -> Reading BMP burst...
21:08:41.874 -> 4
21:08:41.874 -> BMPIMAGE160: 54
21:08:56.474 -> BMP burst read!
21:08:58.594 -> Reading BMP burst...
21:08:58.634 -> 4
21:08:58.634 -> BMPIMAGE160: 54
21:09:13.234 -> BMP burst read!
21:09:15.394 -> Reading BMP burst...
21:09:15.434 -> 4
21:09:15.434 -> BMPIMAGE160: 54
21:09:29.994 -> BMP burst read!
This is what I get:
CAM.zip (113,1 KB)
The issue is probably the conversion of VH and VL to fR, fG and fB. But I can't find the reason.
Kind regards
Günter