Tour : click picture below for previous

Back to Mike's Electric Stuff

Click picture below for next


img_5034.jpg (583324 bytes)

Ipod Nano V6 LCD hacking

See these videos for full info

 

Updated May 6 2013 - added FPGA circuitry, fixed typos.
June 29 - fixed wrong CLKP/CLKN labels in clock startup sequence

Links to MIPI documents : D-PHY (Physical low-level info) DSI specification  (Command Protocol) DCS specification   (LCD commands)

 

Connector pinout. Mating connector is Molex 503548-1220. (Connector on display is 503552-1220)

View looking at rear of mated connector

wpe71.jpg (6768 bytes)

Pin Name Direction Function
1 CLKP To display Positive clock
2 Vdd Power +3.0V (2.9 to 3.1V, abs max 4.0)  Current draw 3.5mA. Slightly content dependent.
Appears to work OK at 3.3v. Display starts washing out below 2.6v. Voltage has no obvious effect on brightness above 3.0v. I ran it up to 4.1V with no increase in current draw.
3 CLKN To display Negative clock
4 Vee Power +1.8v (1.7 to 1.9V, abs max 4.0)
1.8mA 48MHz clock, idle. 2mA updating at 15fps. Likely to be fairly clock-rate dependent.
5 GND 0V
6 SYNC From display Vertical sync.Goes low for 530uS at 60Hz. 1.8V level
7 DP To display Positive data
8 Reset To display Active low reset, 1.8v level. No internal pullup.
9 DN To display Negative data
10 LED+ Power Backlight +ve. Backlight is 4 LEDs in series. Typical Vf 14.8V at 16mA
Backlight current is specified at typ 10.5mA, max 25mA, Vf 15.5-17.0 max over this range.
Derate 25 to 5mA over 40 to 80 deg.C ambient temp.
11 GND 0V
12 LED- Backlight -ve.
Shield The four corner mechanical pads on the connector are connected to GND

This is the initialisation sequence from the datasheet.

wpe5D.jpg (9552 bytes)

I reduced the 250mS initial delay to 15mS with no obvious problems. I also tried not delaying the 3.0v supply turn-on, which also appeared to work OK.
The delay between reset and clock start sequence (see below) IS needed. I tested some shorter timings, and problems started occurring if the delay between the reset rising edge and clock start went below about 64uS.

So the mimimum intialiation would seem to be :  +3v and +1.8v on, reset low,   Wait >100uS, Reset High, Wait >100uS, Clock start sequence

I couldn't easily test any constraints on powerup to reset-high time due to FPGA configuration time. 

Clock startup sequence

At startup, the following sequence is needed to enable the clock receiver. This is the same as the sequence for the data bus.
On the ipod, the clock runs continuously - I don't know if this is necessary - it may be possible to disable the clock between commands, or even during a command between btyes - to be tested.  Non-continuous clock is an optional feature of the DSI spec. However it did work when the clock period varied from cycle to cycle when I was testing frequency range, so clock gaps between bytes. I've tested at clock rates down to 2MHz. Issues below that may have been due to my test setup.
In the ipod, the clock runs at 110MHz.
The framerate is NOT derived from this clock, but from an internal oscillator.
The absolute polarity of the LVDS clock does matter  - the sync byte will not correct for wrong clock phasing.

wpe7A.jpg (71399 bytes)

 

Data packet

A packet can contain one of more commands, Only one start byte (0xB8) is required to start the packet ( i.e. not between commands). I don't know if gaps are allowed between commands within a packet - if they are, they may need a new start byte.

The data lines must stay below 0.5V during high speed (LVDS) mode. LVDS swing is typically +/-100mV relative to a +200mV baseline.
I have found that a small positive bias was needed on the DN line on some displays - not investigated fully.

From MIPI D-PHY spec :

dphy.png (30348 bytes)

Data start - entry to high speed mode

datstart.png (18837 bytes)

 

Start byte sequence

datastart.png (22996 bytes)

 

End of data packet, exit from high-speed mode
A data line transition is needed at the end of the last byte. As the last byte will be CRC, which is ignored, a simple way to achive this would be to set the second CRC byte to 0x00 and send an extra 0xFF byte (not included in the payload byte count) to generate this transition.

datend.png (29439 bytes)

This is the hardware configuration I used to drive the display from a Lattice MACHXO2 FPGA.. The 1K pullup on DN was a last-minute fix when I found some displays didn't work - not looked in detail at the exact effect - could just have been ground shift pulling the line slightly negative without it.
Note I didn't use the clock output from the DDR IO cell, as this shares tristate control with the data line, so you can't tristate the data bus without also
tristating the clock.
The sequence to enter high speed mode on the data lines (Clock is same as data) is as follows :

LVDS tristated,DN bias and DP bias high
DP bias low
DN bias low
LVDS output enable, output low (DP=0,DN=1)

 

wpe5E.jpg (93998 bytes)

Using non-differential signals

I have done a quick test to confirm that it does work with non-differential signals, i.e. holding one of the DP/DN and CLKN/CLKP lines to a fixed level. I haven't done any optimisation on component values yet.

Command protocol

Two commands are required to initialise the display - exit sleep and display on. They can be in either order. After this, sync pulses will start and the display will show random garbage unless previously sent a frame of image data.

Command. Hex. Italics are the ECC byte. First byte is DSI command, listed in DSI spec
Values in bold are DCS commands interpreted by the LCD controller, liste in the DCS spec.
15 11 00 25 Exit sleep mode. datasheet reccommends waiting >120mS after this command. I suspect this is just for display voltages to settle, to avoid visible effects
15 29 00 0F Display on.
15 3A 55 02 Set 16 bits per pixel mode
15 3A 77 1F Set 24 bits per pixel mode
15 36 80 12 RGB order (for 16bpp), display bottom to top (same as AVI)
15 36 88 2A BGR order (for 24bpp AVI), display bottom to top (as AVI)
  Other bits for command 36 :
Bit 0 : Flip vertical (seems to have no effect)
Bit 1 : Flip horizontal (seems to have no effect)
Bit 2 : Vertical line data latch order (seems to have no effect)
Bit 3 : 0: RGB,. 1: BGR
Bit 4 : Display refresh order, 1 = bottom to top
Bit 5 : rotate 90 deg (affects order of next display data, not current display)
Bit 6 : Flip column  (affects order of next display data, not current display)
Bit 7 : flip row  (affects order of next display data, not current display)

Bits 0 to 2 may affect the display refresh order, and so could be relevant for video applications to avoid tearing effects.

39 E1 01 0B ss < 1E0 bytes > 00 00 Write line of 16bpp display data (480 decimal bytes).
ss=0x2C for first line, 0x3C for subsequent lines
00 00 is dummy CRC - this is not checked

See this list for command strings with & ECC bytes to send multiple lines

39 D1 02 07 ss < 2D0 bytes > 00 00 Write line of 24bpp display data (720 decimal bytes).
ss=0x2C for first line, 0x3C for subsequent lines
   
The ipod sends the following commands prior to each frame, but they don't appear to be necessary
29 05 00 25 2A 00 00 00 EF 48 03 Set column address. First byte pair (MS first) is the start column, second pair the end column (0 to 239 here). 48 03 is the CRC
This command should be useable to write smaller windows of the display, and would be handy for font rendering by setting the window size to the font size
I couldn't get this command to work for sub-fullscreen sizes- either it is not implemented, or it checks the CRC
29 05 00 25 2b 00 00 00 EF 0C 08 Set line address, as above - also couldn't get it to work.
05 2C 00 25 Write memory start. I think this is duplicated by the 2C in the first line of the image data

The initialisation data can be merged with display data, which is useful if data is coming from a preformatted source where commands can be embedded along with teh display data, e.g. FPGA playing back from SPI flash.
So the full sequence to initialise and send a frame of 16bpp data would be :

for y = 0 to 239

<enter high speed mode>

send B8 15 29 00 0F 15 11 00 25 15 36 80 12 15 3A 55 02 39 E1 01 0B
; Start| DispOn    |Exitsleep  | Row order | 16bpp     | Write data

if y=0 then send 2C else send 3C

Send 1E0 (=480 dec) bytes of pixel data
Send 00 00 FF   ; dummy checksum plus data-end transition

<exit high speed mode>

next y

It is possible to send more than one line per command (tested with 2 lines, coudn't do more due to FPGA buffer size limit), but there is a 64K limit imposed by the 16 bit payload length field.
As multiple commands can be sent in one packet, it should be possible to send a whole frame in one packet, i.e. only entering high-speed mode at the start and exiting at the end.
It may also be possible to just stay in high speed mode all the time, which would be useful if the clock doesn't mind being stopped between bytes, as you wouldn;t need to do the enter/exit high-speed mode every time . *To be tested*

Packet formats from MIPI DSI spec

SoT is the entry to high-speed mode, plue the 0xB8 start byte. EoT is a transition after the last bit, then exit from high-speed mode.

Short packet

shortpkt.png (51851 bytes)

Long packet

The checksum (actually a CRC) is ignored by the display so does not need to be calculated.

longpkt.png (99337 bytes)

ECC calculation

ECC values are listed for the basic comamnds in the table above. For others, they can be calculated as follows

The ECC  byte comprises six parity bits calculated from various bits in the header as follows :

P7=0
P6=0
P5=D10^D11^D12^D13^D14^D15^D16^D17^D18^D19^D21^D22^D23
P4=D4^D5^D6^D7^D8^D9^D16^D17^D18^D19^D20^D22^D23
P3=D1^D2^D3^D7^D8^D9^D13^D14^D15^D19^D20^D21^D23
P2=D0^D2^D3^D5^D6^D9^D11^D12^D15^D18^D20^D21^D22
P1=D0^D1^D3^D4^D6^D8^D10^D12^D14^D17^D20^D21^D22^D23
P0=D0^D1^D2^D4^D5^D7^D10^D11^D13^D16^D20^D21^D22^D23

Here is some Visual Basic code (sorry!) to calculate the ECC.
It takes a 3 byte string of binary values for the packet header, and returns a 4 byte string including the ECC

Dim eccreg As Long

Private Function add_ecc(s As String) As String
Dim p0 As Byte
eccreg = Asc(Mid$(s, 1, 1)) Or (CLng(Asc(Mid$(s, 2, 1))) * 256) Or (CLng(Asc(Mid$(s, 3, 1))) * 65536)
p0 = 0
If ((gb(10) + gb(11) + gb(12) + gb(13) + gb(14) + gb(15) + gb(16) + gb(17) + gb(18) + gb(19) + gb(21) + gb(22) + gb(23)) And 1) = 1 Then p0 = p0 Or 32
If ((gb(4) + gb(5) + gb(6) + gb(7) + gb(8) + gb(9) + gb(16) + gb(17) + gb(18) + gb(19) + gb(20) + gb(22) + gb(23)) And 1) = 1 Then p0 = p0 Or 16
If ((gb(1) + gb(2) + gb(3) + gb(7) + gb(8) + gb(9) + gb(13) + gb(14) + gb(15) + gb(19) + gb(20) + gb(21) + gb(23)) And 1) = 1 Then p0 = p0 Or 8
If ((gb(0) + gb(2) + gb(3) + gb(5) + gb(6) + gb(9) + gb(11) + gb(12) + gb(15) + gb(18) + gb(20) + gb(21) + gb(22)) And 1) = 1 Then p0 = p0 Or 4
If ((gb(0) + gb(1) + gb(3) + gb(4) + gb(6) + gb(8) + gb(10) + gb(12) + gb(14) + gb(17) + gb(20) + gb(21) + gb(22) + gb(23)) And 1) = 1 Then p0 = p0 Or 2
If ((gb(0) + gb(1) + gb(2) + gb(4) + gb(5) + gb(7) + gb(10) + gb(11) + gb(13) + gb(16) + gb(20) + gb(21) + gb(22) + gb(23)) And 1) = 1 Then p0 = p0 Or 1
add_ecc = s + Chr$(p0)
End Function


Function gb(bit As Long)
gb = (eccreg \ (2 ^ bit)) And 1
End Function

Here is some C code

char parity (unsigned long val)
{ // calc XOR parity bit of all '1's in 24 bit value
unsigned long i,p;
p=0;for(i=0;i!=24;i++) {p^=val;val>>=1;}
return(p&1);
}

unsigned long add_ecc(unsigned long cmd)
{// add ecc byte to b29-24 of 24 bit command packet (lsbyte first)
cmd&=0x00ffffff;
if(parity(cmd & 0b111100010010110010110111)) cmd|=0x01000000;
if(parity(cmd & 0b111100100101010101011011)) cmd|=0x02000000;
if(parity(cmd & 0b011101001001101001101101)) cmd|=0x04000000;
if(parity(cmd & 0b101110001110001110001110)) cmd|=0x08000000;
if(parity(cmd & 0b110111110000001111110000)) cmd|=0x10000000;
if(parity(cmd & 0b111011111111110000000000)) cmd|=0x20000000;
return(cmd);
}


void sendlcdcmd(unsigned long l)
{
// send command, sends MSByte first for readability
// e.g. exit sleep 0x151100
l=((l&0xff)<<16) | (l&0xff00) | ((l&0xff0000)>>16); // reverse bytes to lsbyte first order
l=add_ecc(l);
sendpmp(l);sendpmp(l>>8);sendpmp(l>>16);sendpmp(l>>24);
}

Content creation

I highly reccommend Virtualdub for creating uncompressed AVIs for playback. It supports oddball output resolutions, and nonstandard formats like 1bppp mono and 16 bit RGB.
Virtualdub's 16 bit 565 format matches the input format for this LCD. 24 bit RGB matches the LCD if the BGR order bit is set to 1.
To improve the quality of images displayed as 16bpp, I have written this filter for virtualdub, which uses dithering to improve greyscaling, avoiding banding on colour gradients etc.
To format an arbitary video file :

Load file into virtualdub (accepts AVI,MPEG and bitmap sequences)

Video->filters->Add resize, set to 240x240 pixels.
Video->Colour Depth->16 bit RGB (565)
Audio -> No audio
Video->Compression->No compression
Set in and out markers if you only want a section of the file
File->Save as AVI

Parsing AVI files
Uncompressed AVIs are fairly easy to handle - after parsing the header, you get packed frames of data, with an 8 byte header between each frame. The frames are in a format suitable for sending directly to the display with no further processing.
Here is some sample code in C and VB6

Dimensions

wpe79.jpg (12014 bytes)

List of commands with ECC for different numbers of lines (16bpp mode)

Lines (bytes = lines*480+1)  : write command including ECC

01 : 39 E1 01 0B
02 : 39 C1 03 10
03 : 39 A1 05 15
04 : 39 81 07 0E
05 : 39 61 09 1F
06 : 39 41 0B 04
07 : 39 21 0D 01
08 : 39 01 0F 1A
09 : 39 E1 10 25
10 : 39 C1 12 3E
11 : 39 A1 14 3B
12 : 39 81 16 20
13 : 39 61 18 31
14 : 39 41 1A 2A
15 : 39 21 1C 2F
16 : 39 01 1E 34
17 : 39 E1 1F 2A
18 : 39 C1 21 0D
19 : 39 A1 23 3C
20 : 39 81 25 13
21 : 39 61 27 0E
22 : 39 41 29 19
23 : 39 21 2B 28
24 : 39 01 2D 07
25 : 39 E1 2E 2B
26 : 39 C1 30 23
27 : 39 A1 32 12
28 : 39 81 34 3D
29 : 39 61 36 20
30 : 39 41 38 37
31 : 39 21 3A 06
32 : 39 01 3C 29
33 : 39 E1 3D 37
34 : 39 C1 3F 2C
35 : 39 A1 41 16
36 : 39 81 43 0D
37 : 39 61 45 24
38 : 39 41 47 3F
39 : 39 21 49 02
40 : 39 01 4B 19
41 : 39 E1 4C 01
42 : 39 C1 4E 1A
43 : 39 A1 50 38
44 : 39 81 52 23
45 : 39 61 54 0A
46 : 39 41 56 11
47 : 39 21 58 2C
48 : 39 01 5A 37
49 : 39 E1 5B 29
50 : 39 C1 5D 06
51 : 39 A1 5F 37
52 : 39 81 61 10
53 : 39 61 63 0D
54 : 39 41 65 22
55 : 39 21 67 13
56 : 39 01 69 04
57 : 39 E1 6A 28
58 : 39 C1 6C 07
59 : 39 A1 6E 36
60 : 39 81 70 3E
61 : 39 61 72 23
62 : 39 41 74 0C
63 : 39 21 76 3D
64 : 39 01 78 2A
65 : 39 E1 79 34
66 : 39 C1 7B 2F
67 : 39 A1 7D 2A
68 : 39 81 7F 31
69 : 39 61 81 1C
70 : 39 41 83 07
71 : 39 21 85 02
72 : 39 01 87 19
73 : 39 E1 88 39
74 : 39 C1 8A 22
75 : 39 A1 8C 27
76 : 39 81 8E 3C
77 : 39 61 90 32
78 : 39 41 92 29
79 : 39 21 94 2C
80 : 39 01 96 37
81 : 39 E1 97 29
82 : 39 C1 99 3E
83 : 39 A1 9B 0F
84 : 39 81 9D 20
85 : 39 61 9F 3D
86 : 39 41 A1 1A
87 : 39 21 A3 2B
88 : 39 01 A5 04
89 : 39 E1 A6 28
90 : 39 C1 A8 3F
91 : 39 A1 AA 0E
92 : 39 81 AC 21
93 : 39 61 AE 3C
94 : 39 41 B0 34
95 : 39 21 B2 05
96 : 39 01 B4 2A
97 : 39 E1 B5 34
98 : 39 C1 B7 2F
99 : 39 A1 B9 12
100 : 39 81 BB 09
101 : 39 61 BD 20
102 : 39 41 BF 3B
103 : 39 21 C1 01
104 : 39 01 C3 1A
105 : 39 E1 C4 02
106 : 39 C1 C6 19
107 : 39 A1 C8 24
108 : 39 81 CA 3F
109 : 39 61 CC 16
110 : 39 41 CE 0D
111 : 39 21 D0 2F
112 : 39 01 D2 34
113 : 39 E1 D3 2A
114 : 39 C1 D5 05
115 : 39 A1 D7 34
116 : 39 81 D9 23
117 : 39 61 DB 3E
118 : 39 41 DD 11
119 : 39 21 DF 20
120 : 39 01 E1 07
121 : 39 E1 E2 2B
122 : 39 C1 E4 04
123 : 39 A1 E6 35
124 : 39 81 E8 22
125 : 39 61 EA 3F
126 : 39 41 EC 10
127 : 39 21 EE 21
128 : 39 01 F0 29




 

img_5034.jpg (583324 bytes)


Click picture above for Previous

Back to Mike's Electric Stuff

Click picture above for next