Reverse engineering Nokia C1 LCD pinout and interface

Nokia C1 LCD pinout is not documented and no datasheet is available online. But the display is extremely low cost and would be a great one for using in microcontroller projects! So here is what we do about it…

nokia C1 lcd pinout and protocol datasheet

 

Why hack a display?

Hacking a Nokia C1-01 LCD seems like a fun project. But is it? It is much more than a casual challenge. Note that the display on this phone is a 1.8″ 160×128 true color display that is capable of showing 262k colors! It can even play true-color videos. LCD modules that do this and can be used readily with an Arduino will typically cost you thousands of bucks (INR). On the other hand, you can hack one of these LCD displays that are used in popular phones and you can purchase these LCDs as phone spare parts for a quarter of the price of an Arduino itself!

What can you possibly use the display for? You can make a small portable oscilloscope out of it or you could make an Arduino photo frame, if you are into that sort of things.
What will I use it for? I will use it to act as user interface for my IoT development boards powered by ESP8266 (which will be live on www.iot-bits.com very soon!). By using a commonly found phone display, I can make much cheaper development boards! This LCD will effectively cut down cost by ~40%

Hardware hacking workflow

No attack succeeds without a plan of action. What approach works best with hardware reverse engineering depends on the type of application. As no security is involved here, and this is only about figuring out the protocol and connections, this is relatively a very easy task.
A good approach would be as follows:

  • Figure out the connections by physical inspection of connector
  • Figure out connections by using a multimeter
  • Guess the data interface based on pin count
  • Reverse engineer the protocol using a logic analyzer
  • Guess some commands and search for similar LCD controllers on internet
  • Try some commands and see what they do
  • Finalize results!

Physical Inspection

The electronics industry presents numerous challenges where only practical experience with electronics can actually help. One such example is with physical inspection. If you have a good knowledge of PCB design and typical routing practices in flat flex connectors (the flexible connector used on the LCD display here), then it is easy to guess many things based on physical appearance of the connector itself.

Here is the front and back view of the LCD display flat flex connector:

Nokia C1 LCD display connector pinout

The image on the left is the front view and the one on the right is the view of the connector from the back side of the display.

As you can see on the connector, the upper pin is marked pin 1 and the bottom pin is pin 12 in both images. The golden part is the solder mask and the exposed metal part can be soldered on to the phone circuit (phone PCB). Also, the vias connect both front and rear metal pads – so there are just 12 pins on this LCD that need to be figure out!

On closer physical observation:

  • Pin 1 and pin 12 are not connected to anything!
  • Pin 4 and pin 9 are most probably ground pins (why? Notice the wider traces heading into the display. From basics of PCB design, power traces are ALWAYS wider for higher current carrying capacity)
  • Pin 8 is some sort of power supply pin as well. Because it is quite thick, compared to most other traces.
  • Pin 10 and pin 11 are probably LED backlight power supply (why? Because they are equal width, wide traces. Also, they are effectively the last 2 pins of the connector. And LED backlight connections are almost always the last 2 pins. You would know this by experience of working with color LCDs).

Studying the host connections

The next immediate step is to measure the voltages on the pins when the phone is actually powered on and working!

Now that we already guessed most connections – it is time to confirm the guesses. Here is how to confirm the guesses:

  • First point of attack is finding the LED backlight connections. Because it might be pin 10 and pin 11, the two pin voltages are checked by putting the multi-meter between those two. And it stays at 3.3V only whenever the backlight is on! The reading tells the polarity of the supply as well. So backlight pins are now confirmed.
  • Pin 8 is also confirmed as power supply pin, as it always receives 3.3V from phone circuit when powered on.
  • Pin 4 and pin 9 have zero resistance between them when LCD is connected to phone. Also, 3.3V can be noted w.r.t. these pins. So these must be ground pins as guessed.
  • The remaining pins will have to be confirmed using a logic analyzer…

Guessing the data link

The data link with LCDs is usually one of these:

  • 8-bit parallel data bus + control signals
  • 16- or 18-bit parallel bus + control pins
  • Serial bus

Here, the interface is obviously serial. Out of 12 pins, we already know 2 are unconnected, 2 are ground, 2 are LED backlight and 1 3.3V supply. That leaves 5 pins only!

As there must be a clock pin and at least one data pin, there must also be a reset pin (why? Because all other common color LCDs have it!). That leaves 2 mysterious pins…

Guessing the protocol

What could the communication protocol be? How is the LCD getting the image data from the phone circuit?
Again, from experience, you can know you have only 3 possibilities:

  • I2C interface (400 kbps speed, uses SCL and SDA pins only)
  • SPI interface (over 30 mbps speed, uses SCK, MOSI, MISO, CS pins)
  • Custom interface (some special non-standard protocol)

Here, I2C is impossible – the speed is too low. The LCD cannot play videos with 400 kbps data rate!
So SPI seems highly likely, it needs 4 pins and has the type of speed expected.

Reverse engineering the protocol

Subsequent parts will cover reverse engineering of the actual communication protocol between the LCD and the phone. Observing that can reveal a lot of the commands used to put graphics on the display! It will also reveal what the remaining pins are actually used for.

Until then, happy hacking!

 

13 Responses

  1. thanks Mr Pratik Panda.i’m also surprised with this post. finally i got it…thanks
    am interesting with embedded developments using reusing parts from e-wastes

    • That is really cool! I might do more posts like this in the future. 🙂

  2. #include “driver/c_types.h”
    #include “driver/integer.h”
    #include “driver/lcd_101.h”
    #include “driver/spi.h”

    #include “math.h”

    // lcd nokia a101 or c1
    //#define PCF8833 // use for 6100
    //#define SPFD54124B // use for 6085 and 6101
    #define ST7735R // use for JD-T1800 (1.8″)

    #define SCLK 1
    #define SDATA 2
    #define CS 3
    #define RESET 4

    #define _width 160
    #define _height 128

    // *************************************************************************************
    // LCD Include File for Philips PCF8833 STN RGB- 132x132x3 Driver
    //
    // Taken from Philips data sheet Feb 14, 2003
    // *************************************************************************************
    // Philips PCF8833 LCD controller command codes
    #define NOP 0x00 // nop
    #define SWRESET 0x01 // software reset
    #define BSTROFF 0x02 // booster voltage OFF
    #define BSTRON 0x03 // booster voltage ON
    #define RDDIDIF 0x04 // read display identification
    #define RDDST 0x09 // read display status
    #define SLEEPIN 0x10 // sleep in
    #define SLEEPOUT 0x11 // sleep out
    #define PTLON 0x12 // partial display mode
    #define NORON 0x13 // display normal mode
    #define INVOFF 0x20 // inversion OFF
    #define INVON 0x21 // inversion ON
    #define DALO 0x22 // all pixel OFF
    #define DAL 0x23 // all pixel ON
    #define SETCON 0x25 // write contrast
    #define DISPOFF 0x28 // display OFF
    #define DISPON 0x29 // display ON
    #define CASET 0x2A // column address set
    #define PASET 0x2B // page address set
    #define RAMWR 0x2C // memory write
    #define RGBSET 0x2D // colour set
    #define RGBSET8 0xce
    #define PTLAR 0x30 // partial area
    #define VSCRDEF 0x33 // vertical scrolling definition
    #define TEOFF 0x34 // test mode
    #define TEON 0x35 // test mode
    #define MADCTL 0x36 // memory access control
    #define SEP 0x37 // vertical scrolling start address
    #define IDMOFF 0x38 // idle mode OFF
    #define IDMON 0x39 // idle mode ON
    #define COLMOD 0x3A // interface pixel format
    #define SETVOP 0xB0 // set Vop
    #define BRS 0xB4 // bottom row swap
    #define TRS 0xB6 // top row swap
    #define DISCTR 0xB9 // display control
    #define DOR 0xBA // data order
    #define TCDFE 0xBD // enable/disable DF temperature compensation
    #define TCVOPE 0xBF // enable/disable Vop temp comp
    #define EC 0xC0 // internal or external oscillator
    #define SETMUL 0xC2 // set multiplication factor
    #define TCVOPAB 0xC3 // set TCVOP slopes A and B
    #define TCVOPCD 0xC4 // set TCVOP slopes c and d
    #define TCDF 0xC5 // set divider frequency
    #define DF8COLOR 0xC6 // set divider frequency 8-color mode
    #define SETBS 0xC7 // set bias system
    #define RDTEMP 0xC8 // temperature read back
    #define NLI 0xC9 // n-line inversion
    #define RDID1 0xDA // read ID1
    #define RDID2 0xDB // read ID2
    #define RDID3 0xDC // read ID3
    #define DISCTL 0xca
    #define COMSCN 0xbb
    #define VOLCTR 0x81
    #define PWRCTR 0x20
    #define VOLCTR 0x81
    #define VOLUP 0xd6
    #define VOLDOWN 0xd7
    #define TMPGRD 0x82
    #define EPCTIN 0xcd
    #define EPCOUT 0xcc
    #define EPMWR 0xfc
    #define EPMRD 0xfd
    #define EPSRRD1 0x7c
    #define EPSRRD2 0x7d
    #define NOOP 0x25
    #define DATCTL 0xbc
    #define DISON 0xaf
    #define DISOFF 0xae
    #define DISNOR 0xa6
    #define DISINV 0xa7
    #define SLPIN 0x95

    ///////////////////////////////////////////////////////////////////////////////////////////

    /////////////////////////////////////////////////////////////////////////////////////////////

    #define BKLGHT_LCD_ON 1
    #define BKLGHT_LCD_OFF 2

    // Booleans
    #define NOFILL 0
    #define FILL 1

    // 12-bit color definitions
    #define WHITE 0xFFF
    #define BLACK 0x000
    #define RED 0xF00
    #define GREEN 0x0F0
    #define BLUE 0x00F
    #define CYAN 0x0FF
    #define MAGENTA 0xF0F
    #define YELLOW 0xFF0
    #define BROWN 0xB22
    #define ORANGE 0xFA0
    #define PINK 0xF6A

    // 8-bit color definitions
    #define WHITE8 0xFF
    #define BLACK8 0x00
    #define RED8 0xe0
    #define GREEN8 0x1c
    #define BLUE8 0x3
    #define CYAN8 0x1F
    #define MAGENTA8 0xF0F
    #define YELLOW8 0xfc
    #define BROWN8 0xec
    #define ORANGE8 0xF0
    #define PINK8 0xe3

    // Font sizes
    #define SMALL 0
    #define MEDIUM 1
    #define LARGE 2

    #define CMD 0
    #define DATA 1

    void Delay_ms(uint16_t ms)
    {
    uint16_t i,j;
    for( i = 0; i < ms; i++ )
    {
    for( j = 0; j < 1141; j++ );
    }
    }

    // Pass 8-bit (each) R,G,B, get back 16-bit packed color
    int Color565(char r , char g , char b)
    {
    return ((r & 0xF8) << 8) | ((g & 0xFC) <> 3);

    }

    void send(char data1, char cd) {
    int c;

    init_lcd_pin();

    cs_lcd(0);//CS=0;
    sclk_lcd(0);//SCLK=0;

    if(cd == CMD)
    data_lcd(0);
    else
    data_lcd(1);
    sclk_lcd(1);// SCLK=1;

    for (c=8;c>0;c–) {
    sclk_lcd(0);// SCLK=0;
    if ((data1&0x80)==0){
    data_lcd(0);//SDATA=0;
    }
    else {
    data_lcd(1);// SDATA=1;
    }
    sclk_lcd(1);// //SCLK=1;

    data1=data1<> 8;

    for(i = 0; i > 8 );

    }

    }

    ICACHE_FLASH_ATTR void setAddrWindow(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
    {

    send(CASET, CMD);
    send(x0, DATA);
    send(x1, DATA);
    send(PASET, CMD);
    send(y0, DATA);
    send(y1, DATA);
    send(RAMWR, CMD); // write to RAM
    }

    ICACHE_FLASH_ATTR void fillScreen(uint16_t color) {
    fillRect(0, 0, _width, _height, color);
    }

    // fill a rectangle
    ICACHE_FLASH_ATTR void fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
    uint16_t color) {
    int i;
    uint8_t l_color ,h_color;
    // rudimentary clipping (drawChar w/big text requires this)
    if((x >= _width) || (y >= _height)) return;
    if((x + w – 1) >= _width) w = _width – x;
    if((y + h – 1) >= _height) h = _height – y;

    setAddrWindow(x, y, x+w-1, y+h-1);
    color=color^0xffff;
    l_color =color & 0x00ff ;
    h_color=color >> 8;

    for(i = 0; i > 8 );

    }

    }

    // *****************************************************************************
    // InitLcd.c
    //
    // Initializes the Philips PCF8833 LCD Controller
    //
    // Inputs: none
    //
    // Author: bashniji
    // *****************************************************************************

    ICACHE_FLASH_ATTR void InitLcd(int mod)
    {

    int16 I;

    init_lcd_pin();

    Delay_ms(25);

    // LCD Hardware Reset
    rst_lcd(0);
    Delay_ms(5);
    rst_lcd (1);

    cs_lcd (1); // cs 1
    sclk_lcd (1); // cklc 1
    data_lcd (1); //SDATA 1

    send(SWRESET, CMD);//softwar reset
    //cs1();

    send(SLEEPOUT, CMD); // Sleep out (command 0x11)

    //Inversion on (command 0x20)
    send(INVON, CMD); // seems to be required for this controller
    // send(INVOFF,CMD);

    // send(NORON,CMD);
    //cs1();
    // Color Interface Pixel Format (command 0x3A)

    if(mod==12){

    // send(RGBSET8,cmd); // setup 8-bit color lookup table [RRRGGGBB]
    send(0x2d, CMD);
    //RED
    send(0,DATA);
    send(2,DATA);
    send(4,DATA);
    send(6,DATA);
    send(8,DATA);
    send(10,DATA);
    send(12,DATA);
    send(15,DATA);
    // GREEN
    send(0,DATA);
    send(2,DATA);
    send(4,DATA);
    send(6,DATA);
    send(8,DATA);
    send(10,DATA);
    send(12,DATA);
    send(15,DATA);
    //BLUE
    send(0,DATA);
    send(4,DATA);
    send(9,DATA);
    send(15,DATA);

    send(NOP,DATA); // nop

    //cs1();
    send(NOP,DATA); // nop

    //cs1();
    send(COLMOD,CMD);
    send(0x03,DATA); // 0x03 = 12 bits-per-pixel
    //cs1();

    }

    if(mod==8){
    // send(0x00,DATA);
    send(COLMOD,CMD);
    send(0x2,DATA);
    }

    if(mod==16){
    // send(0x00,DATA);

    send(COLMOD,CMD);
    send(0x05,DATA);//0x05 = 16 bits-per-pixel

    //gammaAdjustmentST7735();

    //cs1();

    }

    _C(0x2b); _D(0x00); _D(0x00); _D(0x00); _D(0xa1);
    _C(0x2a); _D(0x00); _D(0x00); _D(0x00); _D(0x83);

    //cs1();

    //cs1();
    // Memory access controler (command 0x36)
    send(MADCTL,CMD);
    send( 0x80,DATA); // 0xC0 = mirror x and y, reverse rgb 0xC8 00 08
    //cs1();
    // Write contrast (command 0x25)
    send (SETCON,CMD);
    send(0x35,DATA); // contrast 0x30
    //cs1();
    Delay_ms(20);
    // Display On (command 0x29)
    send(DISPON,CMD);
    //cs1();

    // gammaAdjustmentST7735();

    }

    ICACHE_FLASH_ATTR void LCDSetXY(int x, int y) {
    // Row address set (command 0x2B)
    send(CASET, CMD);
    send(x, DATA);
    send(x, DATA);
    // Column address set (command 0x2A)

    send(PASET, CMD);
    send(y, DATA);
    send(y, DATA);
    }

    ICACHE_FLASH_ATTR void drawPixel(int16_t x, int16_t y, uint16_t color) {

    if((x = _width) || (y = _height)) return;
    setAddrWindow(x,y,x+1,y+1);
    color=color^0xffff;
    _D((color >> 8 ) ); // high byte
    _D((color & 0x00ff ) ); // low byte

    }

    ///////////////////////////////////////////////////////////////////////////////
    ICACHE_FLASH_ATTR void glcd_pixel(int x, int y, int color)
    {

    int temp_color=0;
    LCDSetXY(x, y);
    send(RAMWR, CMD);

    color=color^0xffff;
    _D((color >> 8 ) ); // high byte
    _D((color & 0x00ff ) ); // low byte

    send(NOP,CMD);
    }

    ICACHE_FLASH_ATTR void glcd_line (int x1, int y1, int x2, int y2, int color1)
    {
    int dy, dx;
    int addx=1, addy=1;
    int P, diff;

    int i=0;

    dx = abs((x2 – x1));
    dy = abs((y2 – y1));

    if(x1 > x2)
    addx = -1;
    if(y1 > y2)
    addy = -1;

    if(dx >= dy)
    {
    dy *= 2;
    P = dy – dx;
    diff = P – dx;

    for(; i<=dx; ++i)
    {
    glcd_pixel(x1, y1, color1);

    if(P < 0)
    {
    P += dy;
    x1 += addx;
    }
    else
    {
    P += diff;
    x1 += addx;
    y1 += addy;
    }
    }
    }

    else
    {
    dx *= 2;
    P = dx – dy;
    diff = P – dy;

    for(; i<=dy; ++i)
    {
    glcd_pixel(x1, y1, color1);

    if(P < 0)
    {
    P += dx;
    y1 += addy;
    }
    else
    {
    P += diff;
    x1 += addx;
    y1 += addy;
    }
    }
    }

    }

    ICACHE_FLASH_ATTR void glcd_rect(int x1, int y1, int x2, int y2, int color,int fil)

    {
    if(fil)
    {
    #ifdef LARGE_LCD
    int16 i, xmin, xmax, ymin, ymax;
    #else
    int8 i, xmin, xmax, ymin, ymax;
    #endif

    if(x1 < x2) // Find x min and max
    {
    xmin = x1;
    xmax = x2;
    }
    else
    {
    xmin = x2;
    xmax = x1;
    }

    if(y1 < y2) // Find the y min and max
    {
    ymin = y1;
    ymax = y2;
    }
    else
    {
    ymin = y2;
    ymax = y1;
    }

    for(; xmin <= xmax; ++xmin)
    {
    for(i=ymin; i x2)
    {
    int16 temp;
    temp = c1;
    c1 = c2;
    c2 = temp;
    addx = -1;
    }
    if(y1 > y2)
    {
    int16 temp;
    temp = c1;
    c1 = c2;
    c2 = temp;
    addy = -1;
    }

    if(dx >= dy)
    {
    P = 2*dy – dx;
    diff = P – dx;

    for(i=0; i<=dx; ++i)
    {
    for(j=-half_width; j= 0 && temp+c2 <=0)
    glcd_pixel(x1, y1+j, color1);
    }
    if(P < 0)
    {
    P += 2*dy;
    x1 += addx;
    }
    else
    {
    P += diff;
    x1 += addx;
    y1 += addy;
    }
    }
    }
    else
    {
    P = 2*dx – dy;
    diff = P – dy;

    for(i=0; i<=dy; ++i)
    {
    if(P < 0)
    {
    P += 2*dx;
    y1 += addy;
    }
    else
    {
    P += diff;
    x1 += addx;
    y1 += addy;
    }
    for(j=-half_width; j= 0 && temp+c2 <=0)
    glcd_pixel(x1+j, y1, color1);
    }
    }
    }
    }

    // *************************************************************************************
    // LCDSetCircle.c
    //
    // Draws a line in the specified color at center (x0,y0) with radius
    //
    // Inputs: x0 = row address (0 .. 131)
    // y0 = column address (0 .. 131)
    // radius = radius in pixels
    // color = 12-bit color value rrrrggggbbbb
    //
    //
    // *************************************************************************************

    void glcd_circle(int x, int y, int radius, int color1 ,int fill2,int fil )
    {

    int a, b, P;

    a = 0;
    b = radius;
    P = 1 – radius;

    do
    {
    if(fil)
    {
    glcd_line(x-a, y+b, x+a, y+b, fill2);
    glcd_line(x-a, y-b, x+a, y-b, fill2);
    glcd_line(x-b, y+a, x+b, y+a, fill2);
    glcd_line(x-b, y-a, x+b, y-a, fill2);
    }
    else
    {
    glcd_pixel(a+x, b+y, color1);
    glcd_pixel(b+x, a+y, color1);
    glcd_pixel(x-a, b+y, color1);
    glcd_pixel(x-b, a+y, color1);
    glcd_pixel(b+x, y-a, color1);
    glcd_pixel(a+x, y-b, color1);
    glcd_pixel(x-a, y-b, color1);
    glcd_pixel(x-b, y-a, color1);
    }

    if(P < 0)
    P += 3 + 2 * a++;
    else
    P += 5 + 2 * (a++ – b–);
    } while(a <= b);
    }

    //////////////////////////////////////////////////////////////////////////

  3. hi pratik ,finally found the pinout of c1 lcd
    1,12 nc
    2 reset
    3 cs
    4,9 gnd
    5 sda
    6 sck
    7 vddi
    8 vdd
    10,11 led

    which protocol is used this lcd?
    i think it is i2c
    devolep a program using this lcd and arduino uno

    • Hello Ameen, the protocol used is 9-bit SPI. The controller supports many protocols! But the C1-01 display only supports 9-bit SPI.

  4. Hi Pratik. can i use c1-01 display in my arduino project?
    you have library files for c1-01 lcd

    • You can use it, I have the datasheet of the C1-01 controller. But I do not have any code library for this LCD yet!

  5. can i use nokia 700 oled display for reverse engineering,it has MIPI interface

    • You can see how it is initialized using a logic analyzer!
      It should be easy I think. Give it a shot and let me know what happens?

Leave a Reply