SD1531 OLED BMP Question

Post here about your Arduino projects, get help - for Adafruit customers!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
sblue004
 
Posts: 5
Joined: Thu Sep 22, 2016 2:59 pm

SD1531 OLED BMP Question

Post by sblue004 »

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

User avatar
sblue004
 
Posts: 5
Joined: Thu Sep 22, 2016 2:59 pm

Re: SD1531 OLED BMP Question

Post by sblue004 »

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.

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: SD1531 OLED BMP Question

Post by adafruit_support_mike »

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.

User avatar
sblue004
 
Posts: 5
Joined: Thu Sep 22, 2016 2:59 pm

Re: SD1531 OLED BMP Question

Post by sblue004 »

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

User avatar
sblue004
 
Posts: 5
Joined: Thu Sep 22, 2016 2:59 pm

Re: SD1531 OLED BMP Question

Post by sblue004 »

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

User avatar
adafruit_support_mike
 
Posts: 67446
Joined: Thu Feb 11, 2010 2:51 pm

Re: SD1531 OLED BMP Question

Post by adafruit_support_mike »

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.

User avatar
sblue004
 
Posts: 5
Joined: Thu Sep 22, 2016 2:59 pm

Re: SD1531 OLED BMP Question

Post by sblue004 »

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:

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;
}
////////////////////////////////
 

Thank you for all your help!

Sean

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino”