Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d2f6932

Browse files
committed
Add support for KeDei v6.3 with MPI3501 controller (juj#40)
1 parent edcdad7 commit d2f6932

8 files changed

Lines changed: 315 additions & 25 deletions

File tree

CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,15 @@ if (DISPLAY_ROTATE_180_DEGREES)
154154
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDISPLAY_ROTATE_180_DEGREES")
155155
endif()
156156

157+
option(KEDEI_V63_MPI3501 "Target KeDei 3.5 inch SPI TFTLCD 480*320 16bit/186bit version 6.3 2018/4/9 display (MPI3501)" OFF)
158+
157159
option(USE_DMA_TRANSFERS "If enabled, fbcp-ili9341 utilizes DMA to transfer data to the display. Otherwise, Polled SPI mode is used to drive communication with the SPI display" ON)
160+
161+
# KeDei does not do DMA well, since after each 32-bit word one needs to refresh the chip select signal, preventing DMA batch operations altogether.
162+
if (KEDEI_V63_MPI3501)
163+
set(USE_DMA_TRANSFERS OFF)
164+
endif()
165+
158166
if (USE_DMA_TRANSFERS)
159167
message(STATUS "USE_DMA_TRANSFERS enabled, this improves performance. Try running CMake with -DUSE_DMA_TRANSFERS=OFF it this causes problems, or try adjusting the DMA channels to use with -DDMA_TX_CHANNEL=<num> -DDMA_RX_CHANNEL=<num>.")
160168
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_DMA_TRANSFERS=1")
@@ -194,6 +202,9 @@ elseif(WAVESHARE_ST7789VW_HAT)
194202
elseif(WAVESHARE_ST7735S_HAT)
195203
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DST7735S -DWAVESHARE_ST7735S_HAT")
196204
message(STATUS "Targeting WaveShare 128x128 1.44inch LCD Hat with ST7735S controller")
205+
elseif(KEDEI_V63_MPI3501)
206+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMPI3501 -DKEDEI_V63_MPI3501")
207+
message(STATUS "Targeting KeDei 3.5 inch SPI TFTLCD 480*320 16bit/18bit version 6.3 2018/4/9 display (MPI3501)")
197208
elseif(ILI9341)
198209
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DILI9341")
199210
message(STATUS "Targeting ILI9341")
@@ -227,6 +238,9 @@ elseif(TONTEC_MZ61581)
227238
elseif(MZ61581)
228239
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMZ61581")
229240
message(STATUS "Targeting MZ61581")
241+
elseif(MPI3501)
242+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMPI3501")
243+
message(STATUS "Targeting MPI3501")
230244
else()
231245
message(FATAL_ERROR "Please specify which display controller to use on command line to CMake!")
232246
endif()

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ The following LCD displays have been tested:
6363
- [Adafruit 1.54" 240x240 Wide Angle TFT LCD Display with MicroSD](https://www.adafruit.com/product/3787) with ST7789 controller
6464
- [WaveShare 240x240, 1.3inch IPS LCD display HAT for Raspberry Pi](https://www.waveshare.com/1.3inch-lcd-hat.htm) with ST7789VW controller
6565
- [WaveShare 128x128, 1.44inch LCD display HAT for Raspberry Pi](https://www.waveshare.com/1.44inch-lcd-hat.htm) with ST7735S controller
66+
- [KeDei 3.5 inch SPI TFTLCD 480*320 16bit/18bit version 6.3 2018/4/9](https://github.com/juj/fbcp-ili9341/issues/40) with MPI3501 controller
6667

6768
### Installation
6869

@@ -113,6 +114,7 @@ When using one of the displays that stack on top of the Pi that are already reco
113114
- `-DTONTEC_MZ61581=ON`: If you are running on the [Tontec 3.5" 320x480 LCD Display](https://www.ebay.com/p/Tontec-3-5-Inches-Touch-Screen-for-Raspberry-Pi-Display-TFT-Monitor-480x320-LCD/1649448059) display, pass this.
114115
- `-DWAVESHARE_ST7789VW_HAT=ON`: If specified, targets a [240x240, 1.3inch IPS LCD display HAT for Raspberry Pi](https://www.waveshare.com/1.3inch-lcd-hat.htm) with ST7789VW display controller.
115116
- `-DWAVESHARE_ST7735S_HAT=ON`: If specified, targets a [128x128, 1.44inch LCD display HAT for Raspberry Pi](https://www.waveshare.com/1.3inch-lcd-hat.htm) with ST7735S display controller.
117+
- `-DKEDEI_V63_MPI3501=ON`: If specified, targets a [KeDei 3.5 inch SPI TFTLCD 480*320 16bit/18bit version 6.3 2018/4/9](https://github.com/juj/fbcp-ili9341/issues/40) display with MPI3501 display controller.
116118

117119
###### If you wired the display to the Pi yourself
118120

@@ -127,6 +129,7 @@ If you connected wires directly on the Pi instead of using a Hat from the above
127129
- `-DST7735S=ON`: If you have a ST7735S display, use this.
128130
- `-DILI9486=ON`: If you have a ILI9486 display, pass this directive.
129131
- `-DILI9486L=ON`: If you have a ILI9486L display, pass this directive. Note that ILI9486 and ILI9486L are quite different, mutually incompatible controller chips, so be careful here identifying which one you have. (or just try both, should not break if you misidentified)
132+
- `-DMPI3501=ON`: If specified, targets a display with MPI3501 display controller.
130133

131134
And additionally, pass the following to customize the GPIO pin assignments you used:
132135

@@ -518,6 +521,7 @@ Second is the consideration about display speed. Below is a performance chart of
518521
| [Adafruit 240x240 Wide Angle TFT](https://www.adafruit.com/product/3787) | 1.54" | 240x240 | ST7789 | ? | 340MHz/4=85.00MHz | 92.23 fps |
519522
| [WaveShare 240x240 Display HAT](https://www.waveshare.com/1.3inch-lcd-hat.htm) | 1.3" | 240x240 | ST7789VW | 62.5MHz | 338MHz/4=84.50MHz | 91.69 fps |
520523
| [WaveShare 128x128 Display HAT](https://www.waveshare.com/1.44inch-lcd-hat.htm) | 1.44" | 128x128 | ST7735S | 15.15MHz | (untested) | (untested) |
524+
| [KeDei v6.3](https://github.com/juj/fbcp-ili9341/issues/40) | 3.5" | 320x480 | MPI3501 | ? | 400MHz/12=33.333MHz | 4.8fps ** |
521525
522526
In this list, *Rated SPI Bus Speed* is the maximum clock speed that the display controller is rated to run at. The *Obtained Bus Speed* column lists the fastest SPI bus speed that was achieved in practice, and the `core_freq` BCM Core speed and SPI Clock Divider `CDIV` setting that was used to achieve that rate. Note how most display controllers can generally be driven much faster than what they are officially rated at in their spec sheets.
523527
@@ -529,6 +533,8 @@ The ILI9486L controller based maithoga display runs a bit faster than ILI9486 Wa
529533
530534
If manufacturing variances turn out not to be high between copies, and you'd like to have a bigger 320x480 display instead of a 240x320 one, then it is recommended to avoid ILI9486, they indeed are slow.
531535
536+
The KeDei v6.3 display with MPI3501 controller takes the crown of being horrible, in all aspects imaginable. It is able to run at 33.33 MHz, but due to technical design limitations of the display (see [#40](https://github.com/juj/fbcp-ili9341/issues/40#issuecomment-441480557)), effective bus speed is halved, and only about 72% utilization of the remaining bus rate is achieved. DMA cannot be used, so CPU usage will be off the charts. Even though fbcp-ili9341 supports this display, level of support is expected to be poor, because the hardware design is a closed secret without open documentation publicly available from the manufacturer. Stay clear of KeDei or MPI3501 displays.
537+
532538
The Tontec MZ61581 controller based 320x480 3.5" display on the other hand can be driven insanely fast at up to 140MHz! These seem to be quite hard to come by though and they are expensive. Tontec seems to have gone out of business and for example the domain itontec.com from which the supplied instructions sheet asks to download original drivers from is no longer registered. I was able to find one from eBay for testing.
533539
534540
Search around, or ask the manufacturer of the display what the maximum SPI bus speed is for the device. This is the most important aspect to getting good frame rates, but unfortunately most web links never state the SPI speed rating, or they state it ridiculously low like in the spec sheets. Try and buy to see, or ask in some community forums from people who already have a particular display to find out what SPI bus speed it can achieve.

display.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include "ssd1351.h"
2020
#elif defined(MZ61581)
2121
#include "mz61581.h"
22+
#elif defined(MPI3501)
23+
#include "mpi3501.h"
2224
#else
2325
#error Please reconfigure CMake with your display controller directive set!
2426
#endif
@@ -110,3 +112,8 @@ void DeinitSPIDisplay(void);
110112
#if !defined(GPIO_TFT_DATA_CONTROL) && !defined(SPI_3WIRE_PROTOCOL)
111113
#error Please reconfigure CMake with -DGPIO_TFT_DATA_CONTROL=<int> specifying which pin your display is using for the Data/Control line!
112114
#endif
115+
116+
#if defined(SPI_3WIRE_PROTOCOL) && !defined(SPI_3WIRE_DATA_COMMAND_FRAMING_BITS)
117+
// 3-wire SPI displays use 1 bit of D/C framing (unless otherwise specified. E.g. KeDei uses 16 bit instead)
118+
#define SPI_3WIRE_DATA_COMMAND_FRAMING_BITS 1
119+
#endif

hx8357d.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ void InitHX8357D()
6060

6161
SPI_TRANSFER(0x11/*Sleep Out*/);
6262
usleep(120 * 1000);
63-
SPI_TRANSFER(/*Display ON*/0x29);
63+
SPI_TRANSFER(0x29/*Display ON*/);
6464

6565
#if defined(GPIO_TFT_BACKLIGHT) && defined(BACKLIGHT_CONTROL)
6666
printf("Setting TFT backlight on at pin %d\n", GPIO_TFT_BACKLIGHT);

mpi3501.cpp

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#include "config.h"
2+
3+
#ifdef MPI3501
4+
5+
#include "spi.h"
6+
7+
#include <memory.h>
8+
#include <stdio.h>
9+
10+
void ChipSelectHigh()
11+
{
12+
WAIT_SPI_FINISHED();
13+
CLEAR_GPIO(GPIO_SPI0_CE0); // Enable Touch
14+
SET_GPIO(GPIO_SPI0_CE0); // Disable Touch
15+
__sync_synchronize();
16+
SET_GPIO(GPIO_SPI0_CE1); // Disable Display
17+
CLEAR_GPIO(GPIO_SPI0_CE1); // Enable Display
18+
__sync_synchronize();
19+
}
20+
21+
void InitKeDeiV63()
22+
{
23+
// If a Reset pin is defined, toggle it briefly high->low->high to enable the device. Some devices do not have a reset pin, in which case compile with GPIO_TFT_RESET_PIN left undefined.
24+
#if defined(GPIO_TFT_RESET_PIN) && GPIO_TFT_RESET_PIN >= 0
25+
printf("Resetting display at reset GPIO pin %d\n", GPIO_TFT_RESET_PIN);
26+
SET_GPIO_MODE(GPIO_TFT_RESET_PIN, 1);
27+
SET_GPIO(GPIO_TFT_RESET_PIN);
28+
usleep(120 * 1000);
29+
CLEAR_GPIO(GPIO_TFT_RESET_PIN);
30+
usleep(120 * 1000);
31+
SET_GPIO(GPIO_TFT_RESET_PIN);
32+
usleep(120 * 1000);
33+
#endif
34+
35+
// For sanity, start with both Chip selects high to ensure that the display will see a high->low enable transition when we start.
36+
SET_GPIO(GPIO_SPI0_CE0); // Disable Touch
37+
SET_GPIO(GPIO_SPI0_CE1); // Disable Display
38+
usleep(1000);
39+
40+
// Do the initialization with a very low SPI bus speed, so that it will succeed even if the bus speed chosen by the user is too high.
41+
spi->clk = 34;
42+
__sync_synchronize();
43+
44+
BEGIN_SPI_COMMUNICATION();
45+
{
46+
CLEAR_GPIO(GPIO_SPI0_CE0); // Enable Touch
47+
CLEAR_GPIO(GPIO_SPI0_CE1); // Enable Display
48+
49+
BEGIN_SPI_COMMUNICATION();
50+
51+
usleep(25*1000);
52+
53+
SET_GPIO(GPIO_SPI0_CE0); // Disable Touch
54+
usleep(25*1000);
55+
56+
SPI_TRANSFER(0x00000000); // This command seems to be Reset
57+
usleep(120*1000);
58+
59+
SPI_TRANSFER(0x00000100);
60+
usleep(50*1000);
61+
SPI_TRANSFER(0x00001100);
62+
usleep(60*1000);
63+
64+
SPI_TRANSFER(0xB9001100, 0x00, 0xFF, 0x00, 0x83, 0x00, 0x57);
65+
usleep(5*1000);
66+
67+
SPI_TRANSFER(0xB6001100, 0x00, 0x2C);
68+
SPI_TRANSFER(0x11001100/*Sleep Out*/);
69+
usleep(150*1000);
70+
71+
SPI_TRANSFER(0x3A001100/*Interface Pixel Format*/, 0x00, 0x55);
72+
SPI_TRANSFER(0xB0001100, 0x00, 0x68);
73+
SPI_TRANSFER(0xCC001100, 0x00, 0x09);
74+
SPI_TRANSFER(0xB3001100, 0x00, 0x43, 0x00, 0x00, 0x00, 0x06, 0x00, 0x06);
75+
SPI_TRANSFER(0xB1001100, 0x00, 0x00, 0x00, 0x15, 0x00, 0x1C, 0x00, 0x1C, 0x00, 0x83, 0x00, 0x44);
76+
SPI_TRANSFER(0xC0001100, 0x00, 0x24, 0x00, 0x24, 0x00, 0x01, 0x00, 0x3C, 0x00, 0x1E, 0x00, 0x08);
77+
SPI_TRANSFER(0xB4001100, 0x00, 0x02, 0x00, 0x40, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x2A, 0x00, 0x0D, 0x00, 0x4F);
78+
SPI_TRANSFER(0xE0001100, 0x00, 0x02, 0x00, 0x08, 0x00, 0x11, 0x00, 0x23, 0x00, 0x2C, 0x00, 0x40, 0x00, 0x4A, 0x00, 0x52, 0x00, 0x48, 0x00, 0x41, 0x00, 0x3C, 0x00, 0x33, 0x00, 0x2E, 0x00, 0x28, 0x00, 0x27, 0x00, 0x1B, 0x00, 0x02, 0x00, 0x08, 0x00, 0x11, 0x00, 0x23, 0x00, 0x2C, 0x00, 0x40, 0x00, 0x4A, 0x00, 0x52, 0x00, 0x48, 0x00, 0x41, 0x00, 0x3C, 0x00, 0x33, 0x00, 0x2E, 0x00, 0x28, 0x00, 0x27, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x01);
79+
80+
#define MADCTL_BGR_PIXEL_ORDER (1<<3)
81+
#define MADCTL_ROW_COLUMN_EXCHANGE (1<<5)
82+
#define MADCTL_COLUMN_ADDRESS_ORDER_SWAP (1<<6)
83+
#define MADCTL_ROW_ADDRESS_ORDER_SWAP (1<<7)
84+
#define MADCTL_ROTATE_180_DEGREES (MADCTL_COLUMN_ADDRESS_ORDER_SWAP | MADCTL_ROW_ADDRESS_ORDER_SWAP)
85+
86+
uint8_t madctl = 0;
87+
#ifndef DISPLAY_SWAP_BGR
88+
madctl |= MADCTL_BGR_PIXEL_ORDER;
89+
#endif
90+
#if defined(DISPLAY_FLIP_ORIENTATION_IN_HARDWARE)
91+
madctl |= MADCTL_ROW_COLUMN_EXCHANGE;
92+
#endif
93+
#ifdef DISPLAY_ROTATE_180_DEGREES
94+
madctl ^= MADCTL_ROTATE_180_DEGREES;
95+
#endif
96+
SPI_TRANSFER(0x36001100/*MADCTL: Memory Access Control*/, 0x00, madctl);
97+
98+
SPI_TRANSFER(0x29001100/*Display ON*/);
99+
100+
usleep(200*1000);
101+
102+
ClearScreen();
103+
}
104+
#ifndef USE_DMA_TRANSFERS // For DMA transfers, keep SPI CS & TA active.
105+
END_SPI_COMMUNICATION();
106+
#endif
107+
108+
// And speed up to the desired operation speed finally after init is done.
109+
usleep(10 * 1000); // Delay a bit before restoring CLK, or otherwise this has been observed to cause the display not init if done back to back after the clear operation above.
110+
spi->clk = SPI_BUS_CLOCK_DIVISOR;
111+
}
112+
113+
void TurnBacklightOff()
114+
{
115+
}
116+
117+
void TurnBacklightOn()
118+
{
119+
}
120+
121+
void TurnDisplayOff()
122+
{
123+
}
124+
125+
void TurnDisplayOn()
126+
{
127+
}
128+
129+
void DeinitSPIDisplay()
130+
{
131+
ClearScreen();
132+
TurnDisplayOff();
133+
}
134+
135+
#endif

mpi3501.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#pragma once
2+
3+
#include "config.h"
4+
5+
#ifdef MPI3501
6+
7+
// Data specific to the KeDei v6.3 display
8+
#define DISPLAY_SET_CURSOR_X 0x2A001100
9+
#define DISPLAY_SET_CURSOR_Y 0x2B001100
10+
#define DISPLAY_WRITE_PIXELS 0x2C001100
11+
12+
#define DISPLAY_NATIVE_WIDTH 320
13+
#define DISPLAY_NATIVE_HEIGHT 480
14+
15+
// On KeDei v6.3 display, each 16-bit command (of which highest 8 bits are always 0x00) is always prepended with a 16-bit command/data prefix that is either 0x0011 (command) or 0x0015 (data).
16+
#define DISPLAY_SPI_BUS_IS_16BITS_WIDE
17+
18+
// KeDei v6.3 does not behave well if one sends partial commands, but must finish each command or the command does not apply
19+
#define MUST_SEND_FULL_CURSOR_WINDOW
20+
21+
// KeDei v6.3 is a 3-wire SPI display, DC line is not used
22+
#define SPI_3WIRE_PROTOCOL
23+
24+
// KeDei frames all command/data packets with a 16 bit prefix.
25+
#define SPI_3WIRE_DATA_COMMAND_FRAMING_BITS 16
26+
27+
// On KeDei, SPI commands are 32-bit wide, instead of 8-bit or 16-bit.
28+
#define SPI_32BIT_COMMANDS
29+
30+
// SPI drive settings are different compared to most other displays: KeDei SPI hat connects display to SPI channel 1 (channel 0 is for touch controller),
31+
// and Polarity and Phase are reversed. (Chip Select line is idle when high, and bits are clocked on rising edge of the serial clock line)
32+
#define DISPLAY_SPI_DRIVE_SETTINGS (1 | BCM2835_SPI0_CS_CPOL | BCM2835_SPI0_CS_CPHA)
33+
34+
// A peculiarity of KeDei is that it needs the Touch and Display CS lines pumped for each 32-bit word that is written, or otherwise it does not process bytes on the bus. (it does send
35+
// return bytes back on the MISO line though even without this, so it does at least do something even without this, but nothing would show up on the screen if this pumping is not done)
36+
#define CHIP_SELECT_LINE_NEEDS_REFRESHING_EACH_32BITS_WRITTEN
37+
38+
// On KeDei, CS0 line is for touch, and CS1 line is for the LCD
39+
#define DISPLAY_USES_CS1
40+
41+
#ifdef USE_DMA_TRANSFERS
42+
#warning KeDei v6.3 controller does not currently support DMA, rebuild with CMake directive -DUSE_DMA_TRANSFERS=OFF.
43+
#endif
44+
45+
void InitKeDeiV63(void);
46+
#define InitSPIDisplay InitKeDeiV63
47+
48+
#endif

0 commit comments

Comments
 (0)