Hello all,
I've got the ssd1351 1.5" screen up and running and I like it a lot. However I need it to display some images faster than it currently is. I'm trying to sort this out in the bitmap demo, but cant seem to get the image up there any faster.
Any help would be greatly appreciated!
Thanks.
Sean
SD1531 OLED BMP Question
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
- sblue004
- Posts: 5
- Joined: Thu Sep 22, 2016 2:59 pm
Re: SD1531 OLED BMP Question
Should mention that I'm running the screen from an arduino pro mini.
I read about storing the image in the arduino ram, which I don't think is an option with the mini.
The project is a mode selection screen. User presses a button, the screen changes to appropriate icon to represent the mode the controller is in.
I read about storing the image in the arduino ram, which I don't think is an option with the mini.
The project is a mode selection screen. User presses a button, the screen changes to appropriate icon to represent the mode the controller is in.
- adafruit_support_mike
- Posts: 67446
- Joined: Thu Feb 11, 2010 2:51 pm
Re: SD1531 OLED BMP Question
You're right that the microcontroller doesn't have enough memory to hold a full screen buffer, and that puts limits on how fast you can move data around.
With those physical limits, increasing the display speed is a matter of reducing the number of pixels you actually draw as much as possible.
With those physical limits, increasing the display speed is a matter of reducing the number of pixels you actually draw as much as possible.
- sblue004
- Posts: 5
- Joined: Thu Sep 22, 2016 2:59 pm
Re: SD1531 OLED BMP Question
That's kinda what I figured. I was just hoping that there was some magic coding that a novice like me wouldn't know. I'm consistently surprised that the creativity and cleverness of the maker community.
Thanks anyway!
-Sean
Thanks anyway!
-Sean
- sblue004
- Posts: 5
- Joined: Thu Sep 22, 2016 2:59 pm
Re: SD1531 OLED BMP Question
Hello again,
I'm hoping you might help with another little hiccup in the screen game. I have a string packet being out put over bluetooth that contains button states and such. At the same time, the bluetooth is listening for a command from the central processor, this command is a case state that tells the arduino to print one of a few small bitmaps that are stored on the sd card. The problem is that when the arduino receives the command and begins to draw the bmp, the packet stops sending. Currently this will activate an E-Stop in the system, which is something we very much don't want.
So, is there a way to both send the packet, and draw the bmp at the same time? The delay is only about 750ms, but its long enough to cause some major issues.
Any help is very much appreciated.
Thanks!
Sean
I'm hoping you might help with another little hiccup in the screen game. I have a string packet being out put over bluetooth that contains button states and such. At the same time, the bluetooth is listening for a command from the central processor, this command is a case state that tells the arduino to print one of a few small bitmaps that are stored on the sd card. The problem is that when the arduino receives the command and begins to draw the bmp, the packet stops sending. Currently this will activate an E-Stop in the system, which is something we very much don't want.
So, is there a way to both send the packet, and draw the bmp at the same time? The delay is only about 750ms, but its long enough to cause some major issues.
Any help is very much appreciated.
Thanks!
Sean
- adafruit_support_mike
- Posts: 67446
- Joined: Thu Feb 11, 2010 2:51 pm
Re: SD1531 OLED BMP Question
Without seeing the exact code I don't know if you'd be able to unroll and interleave the two operations or not.
An easier solution might be to make sure you've gotten the packet before writing the image to the display, or adding a flag that tells the system not to time out if it's in the middle of a drawing routine.
An easier solution might be to make sure you've gotten the packet before writing the image to the display, or adding a flag that tells the system not to time out if it's in the middle of a drawing routine.
- sblue004
- Posts: 5
- Joined: Thu Sep 22, 2016 2:59 pm
Re: SD1531 OLED BMP Question
Thanks for the reply!
The problem is that the arduino must continue outputting the "packet" at all times. If the computer, which is reading the packet, sends a case "1" (for example), the arduino will draw "Height Mode" and must continue to send the packet whilst doing so. As of now, it pauses sending the packet while it runs the draw function.
Is there a way to stop this pause?
Maybe storing the bmp array in the program?
A larger flash controller?
Here is the code I'm using:
Thank you for all your help!
Sean
The problem is that the arduino must continue outputting the "packet" at all times. If the computer, which is reading the packet, sends a case "1" (for example), the arduino will draw "Height Mode" and must continue to send the packet whilst doing so. As of now, it pauses sending the packet while it runs the draw function.
Is there a way to stop this pause?
Maybe storing the bmp array in the program?
A larger flash controller?
Here is the code I'm using:
Code: Select all
#include <SoftwareSerial.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1351.h>
#include <SD.h>
#include <SPI.h>
///////////////////OLED Things////////////////////////
#define sclk 13
#define mosi 11
#define dc A1
#define cs 9
#define rst A0
#define miso 12
#define SD_CS 10
// 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
Adafruit_SSD1351 tft = Adafruit_SSD1351(cs, dc, rst);
File bmpFile;
int bmpWidth, bmpHeight;
uint8_t bmpDepth, bmpImageoffset;
/////////////////////////Controller Name//////////////////////////////////
char controllername[5] = {'0','0','0','3'} ; // To be changed with every controller.
///////////////////////////Serial Declaration//////////////////////////////
int bluetoothTx = 2; // TX-O pin of bluetooth mate
int bluetoothRx = 3; // RX-I pin of bluetooth mate
SoftwareSerial bluetooth(bluetoothTx, bluetoothRx);
///////////////////Inputs//////////////////////////
const int VERT = A4; // analog SHOULD BE A4
const int HORIZ = A3; // analog
//const int Deadman = 4;
int Deadman = A2;
const int Estop = 5;
const int Zaxis = 6;
const int Sync = 7;
//const int AccelX = A2;
//const int AccelY = A3;
const int AccelZ = A6;
//////////////////Global Variables/////////////////
int battVolts; // made global for wider avaliblity throughout a sketch if needed, example a low voltage alarm, etc
int DeadmanState = 0;
int SyncState =0 ;
int ZaxisState = 0;
int EstopState = 0;
int upperlimit = 1; //Counter for Toggle bit
int lowerlimit = 0; //Counter for Toggle bit
int count; // for the Toggle bit
int bluetoothcounter = 0; //This increases when nothing is sent to the contoller and resets when a command is recieved. Used to test connection.
///////////////////////////////////////////////////////////////////////////////////////
void setup()
{
Serial.begin(19200);
bluetooth.begin(19200);
pinMode(Sync, INPUT);
pinMode(Deadman, INPUT);
pinMode(Zaxis, INPUT);
pinMode(Estop, INPUT);
pinMode(cs, OUTPUT);
digitalWrite(cs, HIGH);
tft.begin();
tft.fillScreen(BLACK);
delay(500);
if (!SD.begin(SD_CS)){ // Check SD Card
tft.setCursor(30, 60);
tft.setTextColor(RED);
tft.setTextSize(1.85);
Serial.println("SD Failed");
return;
}
Serial.println("SD OK!");
}
void loop(){
if (count < upperlimit) {
(count ++);}
else if (count > lowerlimit) {(count --);}
char BANNED = bluetooth.read();
char LEDState = 0;
LEDState = BANNED;
Serial.println(BANNED);
switch (LEDState){// Actions to be done when message recieved from Beckoff
case '0':
tft.fillScreen(BLUE);
break;
case '1':
tft.fillScreen(BLACK);
bmpDraw("height.bmp", 30, 0);
tft.setCursor(30, 60);
tft.setTextColor(BLUE);
tft.setTextSize(1.85);
tft.println("Height Mode");
break;
case '2':
tft.fillScreen(BLACK);
bmpDraw("home.bmp", 30, 0);
tft.setCursor(43, 60);
tft.setTextColor(BLUE);
tft.setTextSize(1);
tft.println("Homing");
break;
case '3':
tft.fillScreen(BLACK);
bmpDraw("dumb.bmp", 20, 0);
break;
case '4':
tft.fillScreen(BLACK);
bmpDraw("path.bmp", 30, 0);
tft.setCursor(30, 60);
tft.setTextColor(BLUE);
tft.setTextSize(1.85);
tft.println("Path Mode");
break;
case '5':
tft.fillScreen(BLACK);
bmpDraw("reset.bmp", 30, 0);
tft.setCursor(30, 60);
tft.setTextColor(RED);
tft.setTextSize(1.85);
tft.println("Reset");
break;
case '6':
tft.fillScreen(BLACK);
bmpDraw("shortcut.bmp", 30, 0);
tft.setCursor(30, 60);
tft.setTextColor(BLUE);
tft.setTextSize(1.85);
tft.println("Shortcut Mode");
break;
case '7':
tft.fillScreen(BLACK);
bmpDraw("storage.bmp", 30, 0);
tft.setCursor(30, 60);
tft.setTextColor(BLUE);
tft.setTextSize(1.85);
tft.println("Storage Mode");
break;
case '8':
break;
case '9':
break;
default:
bluetoothcounter ++;
if (bluetoothcounter >10){
}
}
if(Serial.available()) // If stuff was typed in the serial monitor
{
// Send any characters the Serial monitor prints to the bluetooth
bluetooth.print((char)Serial.read());
}
//////////////////////Joy Stick Read/////////////////////////////
String vertical, horizontal ; // read all values from the joystick
vertical = (analogRead(VERT)+10000); // will be 0-1023
horizontal = (analogRead(HORIZ)+10000); // will be 0-1023
///////////////////// Button State Read////////////////////////
char DeadmanState; //= digitalRead(Deadman);
char ZaxisState; //= digitalRead(Zaxis);
char EstopState; //= digitalRead(Estop);
char CountState;
if(digitalRead(Deadman) == 1){
DeadmanState = 'N';
}else if(digitalRead(Deadman) == 0){
DeadmanState = 'F';
}
if(digitalRead(Zaxis) == 1){
ZaxisState = 'N';
}else if(digitalRead(Zaxis) == 0){
ZaxisState = 'F';
}
if(digitalRead(Estop) == 1){
EstopState = 'N';
}else if(digitalRead(Estop) == 0){
EstopState = 'F';
}
if(count == 1){
CountState = 'N';
}else if(count == 0){
CountState = 'F';
}
/* int dms = digitalRead(Deadman);
int zs = digitalRead(Zaxis);
int ess = digitalRead(Estop);
*/
/////////////Toggle Bit///////////////////////////
///////////////////////////////////////PrintValues/////////////////////
String packet = String("V"+vertical+"v"+"H"+horizontal+"h"+"Z"+ZaxisState+"z"+"D"+DeadmanState+"d"+"E"+EstopState+"e"+"C"+CountState+"c"+"J"+controllername+"j");
bluetooth.println(packet);
///////////////Battery indicator.//////////////////////////////////////////////
battVolts=getBandgap(); //Determins what actual Vcc is, (X 100), based on known bandgap voltage
}
/////////////////////Battery Checking Function//////////////////////////////
int getBandgap(void) // Returns actual value of Vcc (x 100)
{
// For 168/328 boards
const long InternalReferenceVoltage = 1056L; // Adjust this value to your boards specific internal BG voltage x1000
// REFS1 REFS0 --> 0 1, AVcc internal ref. -Selects AVcc external reference
// MUX3 MUX2 MUX1 MUX0 --> 1110 1.1V (VBG) -Selects channel 14, bandgap voltage, to measure
ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
delay(50); // Let mux settle a little to get a more stable A/D conversion
// Start a conversion
ADCSRA |= _BV( ADSC );
// Wait for it to complete
while( ( (ADCSRA & (1<<ADSC)) != 0 ) );
// Scale the value
int results = (((InternalReferenceVoltage * 1024L) / ADC) + 5L) / 10L; // calculates for straight line value
return results;
}
///////////////////////////BitMap Drawing Fucntion///////////////////////
// This function opens a Windows Bitmap (BMP) file and
// displays it at the given coordinates. It's sped up
// by reading many pixels worth of data at a time
// (rather than pixel by pixel). Increasing the buffer
// size takes more of the Arduino's precious RAM but
// makes loading a little faster. 20 pixels seems a
// good balance.
#define BUFFPIXEL 20
void bmpDraw(char *filename, uint8_t x, uint8_t y) {
File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8_t bmpDepth; // Bit depth (currently must be 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 buffer (R+G+B per pixel)
uint8_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;
uint8_t r, g, b;
uint32_t pos = 0, startTime = millis();
if((x >= tft.width()) || (y >= tft.height())) return;
Serial.println();
Serial.print("Loading image '");
Serial.print(filename);
Serial.println('\'');
// Open requested file on SD card
if ((bmpFile = SD.open(filename)) == NULL) {
Serial.print("File not found");
return;
}
// 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;
}
// Crop area to be loaded
w = bmpWidth;
h = bmpHeight;
if((x+w-1) >= tft.width()) w = tft.width() - x;
if((y+h-1) >= tft.height()) h = tft.height() - y;
for (row=0; row<h; row++) { // For each scanline...
tft.goTo(x, y+row);
// Seek to start of scan line. It might seem labor-
// intensive to be doing this on every line, but this
// method covers a lot of gritty details like cropping
// and scanline padding. Also, the seek only takes
// place if the file position actually needs to change
// (avoids a lot of cluster math in SD library).
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
}
// optimize by setting pins now
for (col=0; col<w; col++) { // For each pixel...
// Time to read more pixel data?
if (buffidx >= sizeof(sdbuffer)) { // Indeed
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
}
// Convert pixel from BMP to TFT format, push to display
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
tft.drawPixel(x+col, y+row, tft.Color565(r,g,b));
// optimized!
//tft.pushColor(tft.Color565(r,g,b));
} // end pixel
} // end scanline
Serial.print("Loaded in ");
Serial.print(millis() - startTime);
Serial.println(" ms");
} // end goodBmp
}
}
bmpFile.close();
if(!goodBmp) Serial.println("BMP format not recognized.");
}
// 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;
}
////////////////////////////////
Sean
Please be positive and constructive with your questions and comments.