How to Interface a 1.39 Inch Round AMOLED with SPI
To interface a 1.39 inch 400x400 round amoled display with SPI, you need to understand that these panels typically come with an embedded MIPI DSI interface, not raw SPI. Most round AMOLEDs in this size, like the RM69330 or RM67162 driver-based units, require a bridge chip to convert SPI commands to MIPI DSI signals. A common approach is using the SH8501B or FT3267 as a bridge, where the microcontroller sends SPI frames to the bridge, which then drives the AMOLED panel at high speed. For example, the 1.39 inch round AMOLED with 400x400 resolution and 16.7M colors often operates at a 60Hz refresh rate, demanding a pixel clock around 9.6 MHz for MIPI DSI, but the SPI side can run at 10-20 MHz with 4-wire SPI mode. You must check the datasheet: if the panel has a dedicated SPI interface for initialization and command mode, you can directly use SPI to set registers like sleep out, display on, and gamma correction, but the actual pixel data transfer still goes through MIPI. Many engineers mistakenly think they can drive the full 400x400 resolution via SPI alone, but at 16-bit color depth, that's 400 * 400 * 2 = 320,000 bytes per frame. At 20 MHz SPI, a single frame takes 320,000 * 8 / 20,000,000 = 0.128 seconds, or about 7.8 frames per second, which is too slow for smooth video. So, the real trick is using SPI for control and a separate MIPI DSI lane for data, or using a microcontroller with built-in MIPI DSI controller like the STM32F469 or i.MX RT series.
Let's break down the hardware connections. The 1.39 inch round AMOLED typically has a 24-pin or 30-pin FPC connector. Pins include VCI (2.8V), VDDIO (1.8V), RESET, TE (tearing effect), MIPI DSI lanes (D0P, D0N, CLKP, CLKN), and SPI pins: CS, SCL, SDA, and DCX. The SPI is used for register configuration only. For example, on the RM69330 driver, you send a command like 0x11 (sleep out) via SPI with DCX low, then wait 120ms. Then 0x29 (display on) with DCX low. For gamma settings, you send 0xE0 with 15 parameter bytes. The SPI transaction must be fast: set CS low, send 8-bit command, then DCX high for data, send bytes, set CS high. Use a logic analyzer to verify timing: SCL idle high, data sampled on rising edge, CPOL=0, CPHA=0. The MIPI DSI side requires differential pairs with 100-ohm impedance, and the trace length should be under 5 cm to avoid signal degradation. Power sequencing is critical: VCI must come up first, then VDDIO, then reset low for 10ms, then high. If you skip this, the AMOLED might draw 200mA inrush current and damage the driver.
Now, let's talk about the bridge chip approach in detail. If you want to use a standard microcontroller like ESP32 or Raspberry Pi Pico, you need an external bridge like the FT3267. This chip converts SPI to MIPI DSI with up to 4 lanes. The FT3267 has its own SPI interface: you send a 16-bit command header followed by data. For example, to set the display resolution to 400x400, you send 0x2C00 (set column address) with start and end columns. The bridge then handles the MIPI packetization. The FT3267 also supports partial update mode, which is useful for round displays because you can update only a circular region to save bandwidth. The SPI clock on the bridge can go up to 40 MHz, giving you about 40 Mbps, which translates to roughly 15 frames per second for full screen updates. But if you use 4 MIPI lanes at 500 Mbps each, you get 2 Gbps, which is overkill for 400x400. So, the bottleneck is always the SPI side. A practical solution is to use a microcontroller with a high-speed SPI DMA, like the Teensy 4.0, which can do 60 MHz SPI with 32-byte FIFO. That gives 60 * 8 = 480 Mbps theoretical, but real throughput is around 400 Mbps due to overhead. Then, a full frame at 16-bit color takes 320,000 * 8 / 400,000,000 = 6.4 ms, or 156 frames per second. But the AMOLED's MIPI DSI receiver might not accept data that fast due to internal buffering. Typically, the RM69330 has a 400x400x16-bit frame buffer, so you can write to it at any speed, but the display updates at 60 Hz. So, you can send frames at 100 Hz, but the panel will only show 60 of them per second, causing tearing. Use the TE pin to synchronize: wait for the TE pulse before sending a new frame.
Let's look at a concrete example using an ESP32-S3 and the SH8501B bridge. The ESP32-S3 has two SPI controllers, each with DMA. Connect SPI2 to the SH8501B: CS to GPIO10, SCL to GPIO12, SDA to GPIO11, DCX to GPIO13. The SH8501B requires a 1.8V VDDIO, so use a level shifter if your ESP32 runs at 3.3V. The initialization sequence in C code looks like this: first, power up VCI and VDDIO, then delay 10ms. Set reset pin low for 5ms, then high. Wait 20ms. Then send SPI commands to the SH8501B: 0x11 (sleep out), delay 120ms. 0x29 (display on). Then set the MIPI DSI video mode: the SH8501B has a register to configure lane count, speed, and polarity. For a 400x400 panel, set the horizontal back porch to 10, front porch to 10, hsync pulse to 10, vertical back porch to 10, front porch to 10, vsync pulse to 10. The pixel clock for MIPI DSI is calculated as: (400 + 10 + 10 + 10) * (400 + 10 + 10 + 10) * 60 = 430 * 430 * 60 = 11,094,000 Hz, or about 11 MHz. The SH8501B can generate this internally from a 24 MHz crystal. For actual pixel data, you use the SPI to write to the SH8501B's frame buffer. The SH8501B has a 400x400x16-bit internal SRAM, so you can write partial regions. For a round display, you need to mask the corners: only update pixels where (x - 200)^2 + (y - 200)^2 <= 200^2. This reduces data by about 21.5%, so only 251,200 pixels per frame. At 16-bit, that's 502,400 bytes per frame. With 40 MHz SPI, that's 502,400 * 8 / 40,000,000 = 100.48 ms per frame, or 10 frames per second. That's acceptable for static UI, but not for video. To improve, use 8-bit color mode (RGB332) which halves the data to 251,200 bytes per frame, giving 20 fps. Or use a microcontroller with a parallel interface, like an STM32H7 with FMC, to write to the bridge at 100 MHz 16-bit parallel, achieving 60 fps.
Now, let's discuss the software side. You need a driver for the AMOLED that handles both SPI and MIPI. The typical flow: initialize the bridge chip via SPI, then set up the MIPI DSI link, then send display commands. For the RM69330, the command set includes 0x3A (interface pixel format), 0x36 (memory data access control), 0xB0 (frame rate control), and 0xC0 (power control). Each command has specific parameters. For example, 0x3A with 0x55 sets 16-bit color, 0x3A with 0x66 sets 18-bit, but the panel supports 16.7M colors only via 24-bit MIPI DSI. So, if you use SPI for pixel data, you're limited to 16-bit. The gamma correction is critical for AMOLEDs because they have nonlinear brightness. The RM69330 has 256 gamma registers, and you can load a preset from the datasheet. For a round display, you might also need to adjust the display window: use command 0x2A (column address set) and 0x2B (page address set) to define a rectangular area, but for round, you set the full 400x400 and rely on the mask in software. Some drivers support a circular window via 0x2C with a custom algorithm, but it's rare. The tearing effect (TE) pin is essential: when TE goes high, the panel is in vertical blanking, and you can safely write a new frame. Poll TE with an interrupt, and when it triggers, start the SPI DMA transfer. The DMA should be set to circular mode if you're streaming video. For static images, you can use a single shot.
Let's look at some real-world data. Table 1 shows the performance of different microcontrollers when driving this AMOLED via SPI and a bridge chip:
Table 1: Microcontroller Performance for 1.39 inch Round AMOLED via SPI Bridge
| Microcontroller | SPI Speed (MHz) | DMA | Full Frame Time (ms) | FPS (16-bit) | FPS (8-bit) |
|-----------------|-----------------|-----|----------------------|--------------|-------------|
| ESP32-S3 | 40 | Yes | 100.5 | 10 | 20 |
| Teensy 4.0 | 60 | Yes | 67 | 15 | 30 |
| STM32H743 | 80 | Yes | 50 | 20 | 40 |
| Raspberry Pi Pico | 30 | No | 213 | 4.7 | 9.4 |
| i.MX RT1062 | 100 | Yes | 40 | 25 | 50 |
Note that these times include the overhead of SPI transaction setup and bridge processing. The SH8501B has a 512-byte FIFO, so you can burst write 512 bytes at a time. The actual throughput is limited by the bridge's internal clock, which is typically 100 MHz. So, even with a fast SPI, the bridge might bottleneck at around 50 MB/s. For comparison, MIPI DSI at 4 lanes and 500 Mbps per lane gives 2 Gbps, or 250 MB/s, which is 5x faster. So, the SPI bridge is always the limiting factor. If you need high frame rates, consider using a microcontroller with native MIPI DSI output, like the STM32F469 or i.MX RT1170. These have a DSI host controller that can drive the panel directly without a bridge. The STM32F469 has a 2-lane MIPI DSI at 500 Mbps per lane, giving 1 Gbps total. For 400x400 at 16-bit and 60 Hz, you need 320,000 * 16 * 60 = 307.2 Mbps, which is well within the 1 Gbps budget. So, you can achieve 60 fps with ease. The downside is that these microcontrollers are more expensive and have a steeper learning curve. For example, the STM32F469 requires configuring the DSI PLL, the DSI host, and the DSI device, with registers like DSI_WRPCR, DSI_VCR, and DSI_LPC. The initialization takes about 200 lines of code. But once set up, it's rock solid.
Let's talk about power consumption. The 1.39 inch round AMOLED typically draws 150-200 mA at full brightness (400 nits). The SPI bridge chip adds another 20-30 mA. The microcontroller varies: ESP32-S3 at 240 MHz draws about 80 mA, STM32H7 at 480 MHz draws 150 mA. So, total system power is around 250-400 mA at 3.3V, or 0.825 to 1.32 watts. For battery-powered devices, you can reduce power by using partial updates: only update the active area, which for a watch face might be 100x100 pixels. That reduces data by 16x, so the SPI can run at lower speed, say 10 MHz, and the microcontroller can enter sleep mode between updates. The AMOLED itself can be put into sleep mode via SPI command 0x10, which drops current to 10 µA. The bridge chip also has a standby mode. So, a smartwatch can achieve 50 µA average current with a 1 Hz update rate.
Now, let's address common pitfalls. First, the FPC connector is fragile: the pitch is 0.3mm or 0.4mm, and you need a ZIF connector with proper locking. Use a breakout board if possible. Second, the MIPI DSI traces must be impedance-controlled. If you use a breadboard, the signal will degrade and cause flickering. Use a 4-layer PCB with ground plane under the MIPI traces. Third, the SPI level: the AMOLED's VDDIO is 1.8V, but many microcontrollers are 3.3V. You need a level shifter like the 74LVC245 or a dedicated SPI level shifter. Fourth, the reset sequence: some panels require a specific delay between power and reset. For the RM69330, the datasheet says VCI must be stable for 10ms before reset goes high. If you violate this, the panel might not initialize and draw 300 mA. Fifth, the tear effect pin: if you ignore it, you'll get tearing artifacts. Always use TE to synchronize frame writes. Sixth, the gamma settings: AMOLEDs have a gamma curve that varies between units. You might need to calibrate each panel individually by measuring brightness with a photodiode. But for most applications, the default gamma from the datasheet is acceptable.
Let's look at a specific initialization sequence for the RM69330 via SPI bridge. This is from a real project:
1. Power on VCI (2.8V) and VDDIO (1.8V). Wait 10ms.
2. Set reset low, wait 5ms, set reset high. Wait 20ms.
3. Send SPI command 0x11 (sleep out). Wait 120ms.
4. Send SPI command 0x3A with data 0x55 (16-bit color).
5. Send SPI command 0x36 with data 0x00 (normal orientation).
6. Send SPI command 0xB0 with data 0x00 (60 Hz frame rate).
7. Send SPI command 0xC0 with data 0x10 0x10 (power control).
8. Send gamma commands: 0xE0 with 15 bytes (positive gamma), 0xE1 with 15 bytes (negative gamma).
9. Send SPI command 0x29 (display on). Wait 20ms.
10. Now the panel is ready. For each frame, wait for TE pin high, then send pixel data via SPI to the bridge's frame buffer.
The pixel data format: for 16-bit, it's RGB565: bits 15-11 red, 10-5 green, 4-0 blue. For a round display, you need to set the pixels outside the circle to black (0x0000). The bridge chip might have a hardware circular mask feature, but it's rare. So, you do it in software. For a 400x400 image, you iterate through all pixels, check if (x-200)^2 + (y-200)^2 <= 40000, if not, set pixel to black. This adds CPU overhead. On an ESP32-S3, this takes about 5ms per frame. You can optimize by precomputing a mask table: a 400x400 bit array (20,000 bytes) that tells you which pixels are inside the circle. Then, during frame update, you read the mask and skip black pixels. This reduces the data to 78.5% of the full frame, as mentioned earlier.
Now, let's talk about the bridge chip selection. The SH8501B is common but has limited documentation. The FT3267 is better documented and has a reference driver. The FT3267 supports SPI mode 0 and 3, and has a 32-bit command format. For example, to write a pixel at (x,y), you send 0x2C0000 (write memory) followed by 2 bytes of pixel data. But this is inefficient for bulk writes. Instead, use the window set command: 0x2A0000 (column address) with start and end, then 0x2B0000 (page address) with start and end, then 0x2C0000 to write all pixels in that window. This allows DMA burst writes. The FT3267 also supports a "write continue" mode where you can send multiple pixels without repeating the command. The maximum SPI clock for FT3267 is 40 MHz, but some versions support 50 MHz. Check the datasheet.
Let's look at a timing diagram for the SPI write. The CS pin must be low for the entire transaction. The DCX pin indicates command (low) or data (high). For a command write: CS low, send 8-bit command on MOSI while SCL toggles, then CS high. For data write: CS low, DCX high, send 8-bit data, CS high. For bulk data