External Serial Display not working

maldus
Posts: 83
Joined: Wed Jun 06, 2018 1:41 pm

External Serial Display not working

Postby maldus » Thu Jun 07, 2018 11:05 am

Hello everyone,
I'm trying to use this display http://www.elstore.it/wp-content/upload ... 64BKWT.pdf with an esp32. It has a NT7534 controller.

I want to connect it via SPI interface to an ESP32 DevKitC, using the esp-idf.
Initially I tried using the U8g2 library with the

Code: Select all

u8g2_Setup_nt7534_tg12864r_f
setup function; since it didn't work I moved to a direct spi communication (starting from the spi_master example). However I'm having bad luck with that as well.

The display initialization procedure should be really simple, and after that I simply flush in some lines to see if anything appears, but the screen is always unresponsive.
The screen is connected to my ESP32 (through a breakboard) in the following way:
CS -> IO22
DC(RS) -> IO21
RESET -> IO18
R/W -> GROUND
E -> GROUND
D0...D5 -> GROUND
MOSI -> IO23
CLK -> IO19
P/S -> GROUND

I have also added the necessary external capacitors. I checked all the lines with the oscilloscope and everything seems to be working properly (clean signals, correct timings,...). Assuming that my hardware configuration is correct, could someone take a look at my code and tell me if I'm doing anything wrong?

my main.c:

Code: Select all

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/spi_master.h"
#include "soc/gpio_struct.h"
#include "driver/gpio.h"
#include "esp_log.h"


//#define PIN_NUM_MISO 25
#define PIN_NUM_MOSI 23
#define PIN_NUM_CLK 19
#define PIN_NUM_CS 22

#define PIN_NUM_DC 21
#define PIN_NUM_RST 18
//#define PIN_NUM_BCKL 5

#define TAG "MainApp"

/* The commands on the serial line are taken by the NT7534 in reversed order 
    (D7 through D0) */
uint8_t reverse_byte(uint8_t x)
{
    static const uint8_t table[] = {
        0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
        0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
        0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
        0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
        0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
        0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
        0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
        0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
        0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
        0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
        0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
        0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
        0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
        0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
        0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
        0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
        0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
        0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
        0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
        0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
        0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
        0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
        0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
        0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
        0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
        0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
        0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
        0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
        0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
        0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
        0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
        0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
    };
    return table[x];
}

//Send a command to the LCD. Uses spi_device_transmit, which waits until the transfer is complete.
void lcd_cmd(spi_device_handle_t spi, const uint8_t cmd)
{
    esp_err_t ret;
    spi_transaction_t t;
    const uint8_t reversed = reverse_byte(cmd);
    memset(&t, 0, sizeof(t));           //Zero out the transaction
    t.length = 8;                       //Command is 8 bits
    t.tx_buffer = &reversed;                 //The data is the cmd itself
    t.user = (void *)0;                 //D/C needs to be set to 0
    ret = spi_device_transmit(spi, &t); //Transmit!
    assert(ret == ESP_OK);              //Should have had no issues.
}

//Send data to the LCD. Uses spi_device_transmit, which waits until the transfer is complete.
void lcd_data(spi_device_handle_t spi, const uint8_t *data, int len)
{
    esp_err_t ret;
    spi_transaction_t t;
    if (len == 0)
        return;                         //no need to send anything
    memset(&t, 0, sizeof(t));           //Zero out the transaction
    t.length = len * 8;                 //Len is in bytes, transaction length is in bits.
    t.tx_buffer = data;                 //Data
    t.user = (void *)1;                 //D/C needs to be set to 1
    ret = spi_device_transmit(spi, &t); //Transmit!
    assert(ret == ESP_OK);              //Should have had no issues.
}

//This function is called (in irq context!) just before a transmission starts. It will
//set the D/C line to the value indicated in the user field.
void lcd_spi_pre_transfer_callback(spi_transaction_t *t)
{
    int dc = (int)t->user;
    gpio_set_level(PIN_NUM_DC, dc);
}

//Initialize the display
void lcd_init(spi_device_handle_t spi)
{
    //Initialize non-SPI GPIOs
    gpio_set_direction(PIN_NUM_DC, GPIO_MODE_OUTPUT);
    gpio_set_direction(PIN_NUM_RST, GPIO_MODE_OUTPUT);

    //Reset the display
    gpio_set_level(PIN_NUM_RST, 0);
    vTaskDelay(100 / portTICK_RATE_MS);
    gpio_set_level(PIN_NUM_RST, 1);
    vTaskDelay(100 / portTICK_RATE_MS);

    lcd_cmd(spi, 0xA2); // bias
    lcd_cmd(spi, 0xA0); // ADC
    lcd_cmd(spi, 0xCF); // COM reverse
    lcd_cmd(spi, 0x24); // resistor ratio
    lcd_cmd(spi, 0x81); // electronic volume
    lcd_cmd(spi, 0x1A); // contrast
    lcd_cmd(spi, 0x2F); // power control
    lcd_cmd(spi, 0xAF); // display on
}

void app_main()
{
    esp_err_t ret;
    uint8_t data;
    spi_device_handle_t spi;
    spi_bus_config_t buscfg;
    memset(&buscfg, 0, sizeof(spi_bus_config_t));
    buscfg.miso_io_num = -1;
    buscfg.mosi_io_num = PIN_NUM_MOSI;
    buscfg.sclk_io_num = PIN_NUM_CLK;
    buscfg.quadwp_io_num = -1;
    buscfg.quadhd_io_num = -1;
    //.max_transfer_sz=PARALLEL_LINES*320*2+8;
    buscfg.flags = (SPICOMMON_BUSFLAG_SCLK | SPICOMMON_BUSFLAG_MOSI);

    spi_device_interface_config_t devcfg = {
#ifdef CONFIG_LCD_OVERCLOCK
        .clock_speed_hz = 26 * 1000 * 1000, //Clock out at 26 MHz
#else
        .clock_speed_hz = 10 * 1000, //Clock out at 10 KHz
#endif
        .mode = 0,                  //SPI mode 0
        .spics_io_num = PIN_NUM_CS, //CS pin
        .queue_size = 7,            //We want to be able to queue 7 transactions at a time
        .pre_cb=lcd_spi_pre_transfer_callback,  //Specify pre-transfer callback to handle D/C line
    };
    //Initialize the SPI bus
    ret = spi_bus_initialize(HSPI_HOST, &buscfg, 1);
    ESP_ERROR_CHECK(ret);
    ESP_LOGI(TAG, "Init spi");
    //Attach the LCD to the SPI bus
    ret = spi_bus_add_device(HSPI_HOST, &devcfg, &spi);
    ESP_ERROR_CHECK(ret);
    ESP_LOGI(TAG, "Init device");
    //Initialize the LCD
    lcd_init(spi);
    //Initialize the effect displayed
    ESP_ERROR_CHECK(ret);

    //Go do nice stuff.
    data = 0x0F;
    while(1){
        for (uint8_t i = 0; i < 8; i++)
        {
            /* start from the first column */
            lcd_cmd(spi, 0x10);
            lcd_cmd(spi, 0x00);
            /* cycle 8 pages */
            lcd_cmd(spi, (0xB0|i));

            for (int j = 0; j < 128; j++)
            {
                /* always send 0x0F - I expect some stripes on the screen */
                lcd_data(spi, &data, 1);
            }
        }
        vTaskDelay(1 / portTICK_RATE_MS);
    }
}

maldus
Posts: 83
Joined: Wed Jun 06, 2018 1:41 pm

Re: External Serial Display not working

Postby maldus » Fri Jun 08, 2018 3:30 pm

Assuming my hardware configuration was correct, the only error is that I'm reversing the command data to be sent over SPI, and there is no need for that.

That being said my hardware configuration was NOT correct. I considered the pins of the display connector in the wrong order (reversed).

Everything now works as expected.

Who is online

Users browsing this forum: No registered users and 87 guests