Sniffa


Dani's Blog

Getting a TFT35-SPI v2.1 working with a CM5

By dani - 2026/02/17 03:47:26

In the process of building my second printer, I opted for some of the following electronics:

  • BigTreeTech Manta M8P v2.0
  • BigTreeTech CB2 Raspberry Pi CM5
  • BigTreeTech TFT35-SPI v2.1

The Manta M8P v2.0 is a printer controller board. In the PC world, it's somewhat analagous to a motherboard. Like a motherboard, you can plug in all of your hardware to it such as your motors, fans, heaterbed, etc. Like a modern motherboard, it has it's own microcontroller to handle a lot of this hardware for us. It also acts as a daughter board for the Raspberry Pi compute module family of SOC's. BigTreeTech make their own version of a compute module called the CB1 and CB2 which are designed to easily integrate with the Manta family of boards.

The BTT TFT35-SPI v2.1 is a 3.5inch touch screen display. It's used on a 3d printer to provide useful information regarding ongoing prints and provide some useful functionality. When used with a CB2, the TFT35-SPI seamlessy integrated into the printer. All I needed to do was enable an overlay on the CB2 which the BTT devs created for it. My problems began because my CB2 decided to just die on me... Then when I had the bright idea of, "Well, may as well try a CM5 this time." I didn't realise the pain I had just signed up for.

Documentation Woes

After receiving my shiny new CM5, I did the regular hardware installation for it. This included mounting a heatsink on it, plugging it into the manta board and then screwing the board down via the heatsink. So far, so good. Now the next step was to install an OS onto it.

The OS installation was challenging to say the least. The BTT documentation for the Manta is all tailored for the CM4. The CM4 related documentation while a little out of date, did lead me down the correct path. I needed to switch a couple DIP switches on the Manta. It then told me to plug a USB C cable from the CM5 side of the Manta into my computer while the printer was turned on (supplying external power to power the board). This is where I hit my first roadblock because my PC didn't see any new device plugged in.

I searched around online to see if other people ran into this issue and sure enough, there was a Github issue regarding this from a couple years ago. It turns out that just above the USB C port. It controls how the connection from the board acts. If I have the switch set in one position (the default from the factory), it communicates with the Manta via UART. If I switch it, it puts the USB-OTG mode. Once I flipped that switch, powered on the printer and connected it to my PC, my PC was suddenly able to see the CM5's microcontroller.

There however was a problem yet again... It was constantly connecting and disconnecting. This time, I couldn't find anything regarding this behaviour online. I went to an AI and asked it what it thought could be the problem. One of the suggestions was that the CM5 is picky regarding the speeds of USB. Instantly, I knew what the solution to this was. I have a Raspberry Pi 5 sitting on my desk. I then plugged the printer into that and sure enough, it instantly was recognised and didn't cause the CM5 to boot-loop.

From here, I just needed to build rpiboot and run the commands as per the github page. This loaded firmware on the CM5 which turned the built-in EMMC into a regular old flash device. From here, I simply used the dd command to flash MainsailOS over to the CM5. Because I was doing this on a Pi 5, I was able to chroot in, set up as user + password, configure networking and ssh. Then it was finally time to unmount the CM5 partitions from the Pi 5 and try to boot the CM5 normally.

I turned on the printer without it connected to my Pi 5 and I was finally relieved to have a Linux OS running on the printer. It would all be easy sailing from here, right? Right?

CM5 & Klipper Configuration

The version of MainsailOS I installed is a fork of Raspberry Pi OS, which itself is a Raspberry Pi optimised version of Debian. This image is based on the previous version of Debian Bookworm. I have updated pretty much all of my Raspberry Pi's running RPi-OS to the more current Debian Trixie. By God would this CM5 be upgraded to Trixie. The Trixie update went wonderfully without any real issues of note... well except one.

The Klipper and related installation files are all pretty much Python-based. Because upgrading to Trixie updated the version of Python, suddenly all of the Klipper VENV's no longer worked. This was easy enough to fix though. I simply installed kiauh. Kiauh allows you to install Klipper and it's ecosystem in a relatively painless manner. Just follow the github instructions and re-install everything that was already within the users directory.

I then configured Klipper in a pretty standard manner. I defined motors, fans and everything else. Once Klipper wasn't telling me I had errors, my attention then went to getting the white screen on the front of the printer to show me the UI of KlipperScreen.

TFT35-SPI Configuration

So lets discuss what the TFT35-SPI v2.1 is. The screen displays images using the SPI protocol. The digitizer (touch part of the screen) uses I2C to communicate with the CM5. The SPI chip of the screen uses an ILI9488 and the I2C chip is a NS2009. These details are important because I needed to know which Linux kernel modules to use to communicate with these chips.

Where things got difficult was that that the screen was connected to the CM5 was via a 9-pin FPC connector. The Manta documentation doesn't mention this FPC connector at all. Finding out what these pins connect to required me to look at the manta schematics. So lets compare the Manta FPC connector pin connections to what the screen says:

Pin Manta Function SOC Pin Screen
1 5V N/A VDD
2 GND N/A GND
3 SOC MISO GPIO9 MISO
4 SOC MOSI GPIO10 MOSI
5 SOC SCK GPIO11 SCK
6 SOC LCD-CS GPIO4 NSS
7 SOC Touch-CS GPIO17 RS
8 SOC BL GPIO27 SDA
9 SOC TP GPIO22 SCL

So this gives us a pretty good idea of what we're now looking at in terms of which pins are SPI:

SPI Pin
MISO GPIO 9
MOSI GPIO 10
SCK GPIO 11
CS GPIO 4

and I2C:

I2C Pin
SDA GPIO 27
SCL GPIO 22
CS GPIO 17

With this now understood, we can look at what Linux kernel modules already exist for the chips these pins are connected to. For the ILI9488, we can use the ILI9486 kernel module (as per the tft35-spi v2 github). The ILI9488 uses mostly the same instructions as the ILI9488 but seems to require a command sequence to boot the screen properly.

After many, many, MANY hours, I managed to get the following configuration for my /boot/firmware/config.txt:

[all] #dtoverlay=vc4-kms-v3d dtparam=spi=on dtoverlay=spi0-2cs,cs0_pin=8,cs1_pin=4 dtoverlay=fbtft,spi0-1,ili9486,dc_pin=17,speed=24000000,fps=60,bgr=1,rotate=90 dtparam=init=-1,0x11,-2,120,-1,0x3A,0x66,-1,0x29,-2,120

This uses the legacy framebuffer subsystem of the kernel instead of the modern drm system. For some reason, I needed to define the I2C pin as the CS for the SPI. Other than that, I mostly got the rest of this from online sources; including the TFT35 github.

Now for the I2C part. This uses a NS2009 chip. Looking around online, I found that the TSC2007 kernel driver would work for this particular chip because the NS2009 is apparently a clone of it. This time instead of adding stuff to the config.txt file, I needed to configure a bit more stuff to get the touch capabilities working. I created a file called tft35.dts. This is a device tree overlay.

/dts-v1/; /plugin/; / { compatible = "brcm,bcm2712"; fragment@0 { target-path = "/"; _overlay__ { i2c_gpio: i2c-gpio-bus { compatible = "i2c-gpio"; gpios = <&gpio 27 0 /* sda */ &gpio 22 0 /* scl */ >; i2c-gpio,delay-us = <5>; #address-cells = <1>; #size-cells = <0>; status = "okay"; ns2009: tsc2007@48 { compatible = "ti,tsc2007"; reg = <0x48>; /* Use a placeholder interrupt to satisfy the driver probe */ interrupt-parent = <&gpio>; interrupts = <17 2>; ti,x-plate-ohms = <660>; status = "okay"; }; }; }; }; };

Much of the info I found for this DTS can be attributed to stadie - btt_tft35spi_rpi. Stadies' work is designed to work with the CM4 but it gave me some of the information I needed to make this overlay work.

I then built the overlay, named it tft35-spi-custom.dtbo, copied it to /boot/firmware/overlays and added it my config.txt.

[all] # BTT TFT-35 v2.1 SPI Display output (ILI9488 IC) #dtoverlay=vc4-kms-v3d dtparam=spi=on dtoverlay=spi0-2cs,cs0_pin=8,cs1_pin=4 dtoverlay=fbtft,spi0-1,ili9486,dc_pin=17,speed=24000000,fps=60,bgr=1,rotate=90 dtparam=init=-1,0x11,-2,120,-1,0x3A,0x66,-1,0x29,-2,120

# BTT TFT-35 v2.1 I2c display touch functionality (NS2009 IC) dtoverlay=tft35-spi-custom

I then rebooted and made sure that /dev/fb0 was visible (showing that the SPI driver binded to a framebuffer) as well as /dev/input/event1 (same for the I2C driver). I next installed KlipperScreen using kiauh. I selected to use the X server over the Wayland server as the X server seems to actually work. Now the final glue pieces I needed were to tell X all about the display. I created /etc/X11/xorg.conf.d/99-tft35.conf:

Section "Device" Identifier "ili9488" Driver "fbdev" Option "fbdev" "/dev/fb0" EndSection

Section "InputClass" Identifier "TSC2007 Calibration" MatchProduct "TSC2007 Touchscreen" # This matrix handles a 90-degree clockwise rotation + flip Option "TransformationMatrix" "0 1 0 -1 0 1 0 0 1" EndSection

And finally, my work was complete and my screen finally worked!

All that awaits me now is regular printer calibration and some test prints :)