mcufriend shield 0x4535 слабая яркость

negavoid
Offline
Зарегистрирован: 09.07.2016

Здравствуйте, прошу помощи. Приехал ко мне китайский дисплей+тач шилд, воткнул его в ардуину, склепал скетч фоторамки, работает - но картинки выводятся с очень низкой яркостью (гаммой?). Но если нажать ресет, то в течение следующей секунды бесхозный дисплей без мастера отображает эту картинку с нормальной яркостью. Есть подозрение, что такое поведение у дисплея из-за подключенной sd-карты, пока скетч побайтово читает картинку с неё, экран сильно мерцает. Подскажите плиз, что делать, куда копать?

#include <Adafruit_GFX.h>       // Core graphics library
#include <AdaLGDP4535TFTLCD.h>  // Hardware-specific library
#include <TrueRandom.h>
#include "SdFat.h"
SdFat SD;

#define LCD_RESET A4   // Can alternately just connect to Arduino's reset pin
#define LCD_CS    A3   // Chip Select goes to Analog 3
#define LCD_CD    A2   // Command/Data goes to Analog 2
#define LCD_WR    A1   // LCD Write goes to Analog 1
#define LCD_RD    A0   // LCD Read goes to Analog 0

#define SD_CS 10     // Card select for shield use

Adafruit_TFTLCD  tft( LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET );
uint8_t          spi_save;
File             root;

void setup()
{
  Serial.begin(9600);

  tft.reset();
  tft.begin( tft.readID() );
  tft.setRotation(3);

  Serial.print(F("Initializing SD card..."));
  if (!SD.begin( SD_CS )) {
    Serial.println(F("failed!"));
    return;
  }
  Serial.println(F("OK!"));
  spi_save = SPCR;
}

void loop()
{
  String bitmap = (String) TrueRandom.random( 2400 ) + ".bmp";
  tft.fillScreen(0);
  bmpDraw( string2char( bitmap ), 0, 0 );
  delay(5000);
}

char* string2char( String command ) {
  if (command.length() != 0) {
    char *p = const_cast<char*>(command.c_str());
    return p;
  }
}

// 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, int x, int 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 in buffer (R+G+B per pixel)
  uint16_t lcdbuffer[BUFFPIXEL];       // pixel out buffer (16-bit 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();
  uint8_t  lcdidx = 0;
  boolean  first = true;

  if ((x >= tft.width()) || (y >= tft.height())) return;

  Serial.println();
  Serial.print( F("Loading image '") );
  Serial.print(filename);
  Serial.println('\'');
  // Open requested file on SD card
  SPCR = spi_save;
  if ((bmpFile = SD.open(filename, O_READ)) == NULL) {
    Serial.print("File not found");
    return;
  }

  // Parse BMP header
  if (sdcard_read16(bmpFile) == 0x4D42) { // BMP signature
    Serial.print(F("File size: ")); Serial.println(sdcard_read32(bmpFile));
    (void)sdcard_read32(bmpFile); // Read & ignore creator bytes
    bmpImageoffset = sdcard_read32(bmpFile); // Start of image data
    Serial.print(F("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
    // Read DIB header
    Serial.print(F("Header size: ")); Serial.println(sdcard_read32(bmpFile));
    bmpWidth  = sdcard_read32(bmpFile);
    bmpHeight = sdcard_read32(bmpFile);
    if (sdcard_read16(bmpFile) == 1) { // # planes -- must be '1'
      bmpDepth = sdcard_read16(bmpFile); // bits per pixel
      Serial.print(F("Bit Depth: ")); Serial.println(bmpDepth);
      if ((bmpDepth == 24) && (sdcard_read32(bmpFile) == 0)) { // 0 = uncompressed

        goodBmp = true; // Supported BMP format -- proceed!
        Serial.print(F("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;

        // Set TFT address window to clipped image bounds
        SPCR = 0;
        tft.setAddrWindow(x, y, x + w - 1, y + h - 1);

        for (row = 0; row < h; row++) { // For each scanline...
          // 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;
          SPCR = spi_save;
          if (bmpFile.position() != pos) { // Need seek?
            bmpFile.seek(pos);
            buffidx = sizeof(sdbuffer); // Force buffer reload
          }

          for (col = 0; col < w; col++) { // For each column...
            // Time to read more pixel data?
            if (buffidx >= sizeof(sdbuffer)) { // Indeed
              // Push LCD buffer to the display first
              if (lcdidx > 0) {
                SPCR   = 0;
                tft.pushColors(lcdbuffer, lcdidx, first);
                lcdidx = 0;
                first  = false;
              }
              SPCR = spi_save;
              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0; // Set index to beginning
            }

            // Convert pixel from BMP to TFT format
            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];
            lcdbuffer[lcdidx++] = tft.color565(r, g, b);
          } // end pixel
        } // end scanline
        // Write any remaining data to LCD
        if (lcdidx > 0) {
          SPCR = 0;
          tft.pushColors(lcdbuffer, lcdidx, first);
        }
        Serial.print(F("Loaded in "));
        Serial.print(millis() - startTime);
        Serial.println(" ms");
      } // end goodBmp
    }
  }

  bmpFile.close();
  if (!goodBmp) Serial.println("BMP format not recognized.");
}

// sdfat.h fix
uint16_t sdcard_read16(File &f)
{
  uint16_t result;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read(); // MSB
  return result;
}

// sdfat.h fix
uint32_t sdcard_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;
}

 

p.masyukov
p.masyukov аватар
Offline
Зарегистрирован: 14.11.2015

Adafruit_GFX - помоему там есть контрастности регулировка.. по крайней мере на OLED дисплеях работает. И непонятно низкая гамма/констрастность или низкая яркость подсветки??

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

дисплей может мерцать при нехватке тока, или плохой контакт земли или vcc

negavoid
Offline
Зарегистрирован: 09.07.2016

Очень сложно сфотографировать телефоном экран, да ещё и чтобы показать яркость, но я попробовал:

"слабая яркость" - все цвета блеклые, тёмные, картинка плохо просматривается даже вблизи и с включенным светом, с расстояния в пол-метра - метр уже не разобрать, что же там нарисовано:

но после нажатия ресета - (пока сам дисплей и microsd карта неинициализирована?), картинку на дисплее видно ярко, ясно и чётко, так же, как на большом брате, цвета яркие, сочные, видно орлиным глазом метров за несколько:

На глазок этот эффект больше похож на пониженный уровень гамма-коррекции. Диоды подсветки видно с боков экрана, их яркость, вроде как, при моих манипуляциях не изменяется. Питание переключал, пробовал и от usb, и от БП на 9В/1А, и оба вместе - на ситуацию это не повлияло.

UPD: про мерцание при выводе bmp - думаю, что шилд всё же воткнут крепко - потому что оно как бы на самом деле не мерцание, а просто глазом отмечается, как быстрое дрожание эдаких бегущих полосок, видимо глаз таким образом отмечает задержки между чтением буфера с карты и отправкой его на дисплей.

Valera19701
Valera19701 аватар
Offline
Зарегистрирован: 18.10.2015

последняя версия библиотеки, попробуйте

https://github.com/prenticedavid/MCUFRIEND_kbv

negavoid
Offline
Зарегистрирован: 09.07.2016

Пробовал, белый экран, не дружит она с китайским поделием на 4535 :(

Если прервать крутящийся демо скетч от mcufriend заливкой моего, то после ресета на дисплее на миг видно нарисованные демкой прямоугольники, то есть внизу, "под белым экраном" оно всё-таки как-то работает и в память дисплея пересылает байтики правильно.

negavoid
Offline
Зарегистрирован: 09.07.2016

Мучения продолжаются, пока удалось в инициализации выставить все резисторы для гамма-коррекции в 0 Ом, стало чуть поярче, но все ещё далеко от идеала, который виден из видеопамяти после нажатия ресета.

      0x30, 0x0000,
      0x31, 0x0000,
      0x32, 0x0000,
      0x35, 0x0000,
      0x36, 0x0000,
      0x37, 0x0000,
      0x38, 0x0000,
      0x39, 0x0000,
      0x3C, 0x0000,
      0x3D, 0x0000,

 

slider
Offline
Зарегистрирован: 17.06.2014

negavoid пишет:

Мучения продолжаются, пока удалось в инициализации выставить все резисторы для гамма-коррекции в 0 Ом, стало чуть поярче, но все ещё далеко от идеала, который виден из видеопамяти после нажатия ресета.

      0x30, 0x0000,
      0x31, 0x0000,
      0x32, 0x0000,
      0x35, 0x0000,
      0x36, 0x0000,
      0x37, 0x0000,
      0x38, 0x0000,
      0x39, 0x0000,
      0x3C, 0x0000,
      0x3D, 0x0000,

 

(1) попробуйте просто закоментить регистры гаммы, пусть будут значения по умолчанию в контроллере после сброса. 

Для минимального инита вообще хватает 3-4 команды в нем , (2) попробуйте путем коментирования исключать один регистр за другим, оставить самые необходимые.

к примеру для контроллеров у которых  
setxy
LCD_Write_COM(0x2A); //column
LCD_Write_DATA(x1>>8);
LCD_Write_DATA(x1);
LCD_Write_DATA(x2>>8);
LCD_Write_DATA(x2);
LCD_Write_COM(0x2B); //page
LCD_Write_DATA(y1>>8);
LCD_Write_DATA(y1);
LCD_Write_DATA(y2>>8);
LCD_Write_DATA(y2);
LCD_Write_COM(0x2C); //write


но самый короткий инит получился:


LCD_Write_COM(0x11);// обязательно
delay(100);

 //LCD_Write_COM(0x13);

    LCD_Write_COM(0x3A);  //  Pixel Format Set
    LCD_Write_DATA(0x05);  //0x05-65k color565

	 LCD_Write_COM(0x36);  // Memory Acces Control 
	 LCD_Write_DATA(0x48);  //e8-orig ,  48-ili9327 16bit! ,

LCD_Write_COM(0x29); // обязательно

LCD_Write_COM(0x2C); // обязательно

http://arduino.ru/forum/apparatnye-voprosy/arduino-i-displei-ot-sotikov-mobilnykh-telefonov?page=1#comment-175988

Вообще похоже что инит не соответствует контроллеру, (4) попробуйте считать тип контроллера, в примерах адафруита он посылает его в сериал порт,

Есть ещё одно предположение, это изменение уровня питания диспа (5) проверте мультиметром в обоих случаях. Мож использование карты , а она же включена в дешевых шилдах напрямую, логические уровни 5в с ардуины поднимают через нее питалово 3,3в  ( т.к. microSD и дисп запитаны от одного стаба 3,3в. )  А от повышенного питалова , внутренние преобразователи на кристалле на стекле, начинают выше кочегарить разновеликие доплнительные напряжения для матрицы, из-за этого и бывает изменение яркости и контраста.  Правда подключенная подсветка напрямую к стабу немного нагружает его, но надо бы проветь, мало ли с 3,3в он поднимается до 3,6в или нежелательно ещё выше.

// при полном ините, в регистры изменяются параметры по умолчанию,  по подведенному питанию - для 3,3в надо одни значения , для 2,8в - другие, при максимально-критическом 3,6в - третьи.

 

negavoid
Offline
Зарегистрирован: 09.07.2016

slider спасибо, программные советы с утра уже успел поперебирать :( . Первым делом (4) считал примером lcd_id_readreg, оттуда получил 0х4535 и все остальные регистры по нулям, в тексте mcufriend нет поддержки этого контроллера. Нашёл даташит на LG4535, (3) инит в используемой библиотеке оказался полностью скопирован из даташита. Комментировал (1) регистры гаммы, пробовал (2) комментировать другие регистры - все безрезультатно, яркость по-прежнему остаётся слабой. Пробовал отправлять ардуину в сон после отрисовки, пробуждался обратно по таймеру - но и во сне яркость та же. Найти минимальный инит вот ещё только не пробовал. Боюсь, как бы не (5) - а при ресете microSD [отваливается/засыпает/ещё что-нибудь] и яркость на секунду становится максимальной.

diger67
Offline
Зарегистрирован: 25.07.2015
negavoid
Offline
Зарегистрирован: 09.07.2016

Выдалось ещё немного времени покопаться с этим дисплей шилдом.

Последнюю библиотеку смотрел, да тачскрин-то работает, и инит в этой библиотеке такой же. Вынул microSD, вывел битмап с компа через сериал - яркость всё та же, низкая. Если с выведенной картинкой зажать и держать ресет, тем самым отрубив ардуину - высокая. Нашел на форуме arduino.cc несколько постов, люди пишут про ту же проблему, шилды у них подобные, но на других чипах, так что, по ходу, такой уж мне достался дисплей с али  - самому рисовать примитивы ещё приемлемо, а для фоторамки слишком тёмный => видимо, расходимся, всем спасибо за внимание.