F439_CPP_SPI_RA8875_TFT_LCD_04 1.0
STM32F439 SPI RA8875 7-inch TFT display with FRAM-backed touch calibration, built on the STM32_GFX, STM32_RA8875 and STM32_MB85RS64V libraries
Loading...
Searching...
No Matches
F439 CPP SPI RA8875 TFT LCD 04

A bare-metal (no RTOS) C++ firmware for a NUCLEO-F439ZI that drives Adafruit's RA8875 driver board and 7-inch 800x480 TFT display over SPI1, reads the display's resistive touch panel, and stores the touch calibration in an MB85RS64V SPI FRAM so it survives a reset. It is part 4 of the RA8875 series: part 3 introduced the two display libraries, this part adds the FRAM and the touch calibration.

Status: hardware-validated on a breadboard (NUCLEO-F439ZI + Adafruit RA8875 driver board + 7-inch display + MB85RS64V FRAM breakout): the FRAM identifies and keeps its data across resets, the three-point calibration runs with the space bar and Esc keys, the result is stored in the FRAM and read back at the next boot.

How it works

After the CubeMX peripheral init, main.c calls, in this order:

  1. initTest(&hspi1) – creates the display object and starts the RA8875.
  2. initFRAM(&hspi1) – creates the FRAM driver object and checks the chip ID. The FRAM shares SPI1 with the display, so it is started after the display.
  3. testFRAM() – prints the 16 bytes at FRAM address 0 that the previous run left there, writes a new pattern with a boot counter, reads it back and compares.
  4. initTouchCalibration() – reads the stored touch calibration and prints it, or prints why none can be used.

Then one of two things happens, chosen in main.h:

  • Calibration mode (TOUCH_CALIBRATION_ENABLE defined). The program ignores whatever the FRAM holds and runs the interactive calibration (below), stores the result in the FRAM, runs a 15-second touch-to-draw demo, prints Calibration Complete and stops.
  • Normal mode (macro commented out). None of the calibration code is built, and the program runs the graphics and text demos from part 3 forever.

The calibration

Three red circles are shown one at a time. Hold the pen on each one until a green ring appears (about 0.3 seconds); shorter taps are ignored and the readings taken during the hold are averaged. After the first and the second circle the terminal on USART1 asks for a key:

  • Space bar – show the next circle.
  • Esc – throw that touch away and show the same circle again.

The next circle never appears by itself, so a second tap cannot be taken as the next point. The key is received by interrupt, so the USART1 global interrupt must be enabled in CubeMX.

How the calibration is stored

The RA8875 library writes the matrix: 29 bytes at FRAM address 0x0100. This project adds a 12-byte header at 0x0120 (the marker CAL1, a format version, the length and a CRC-32 of the matrix). The matrix is written first and the header last, so a power cut in between never leaves data that looks valid, and the data is read back and compared after every write.

Hardware

Signal NUCLEO-F439ZI Notes
SCK (display and FRAM) PA5 SPI1_SCK, shared
MISO (display and FRAM) PA6 SPI1_MISO, shared
MOSI (display and FRAM) PA7 SPI1_MOSI, shared
RA8875 CS PB6 GPIO output, label RA8875_CS, initial level high, pull-up
RA8875 Rst PC7 GPIO output, label LCD_RESET
MB85RS64V CS PB10 GPIO output, label MB85RS64_CS, initial level high, pull-up
MB85RS64V VCC +5V The chip takes 3.0 to 5.5 V. See the note below the table about its input levels
MB85RS64V GND GND
MB85RS64V HOLD VCC (+5V) Active low: a low level pauses the chip, so it will not answer
MB85RS64V WP VCC (+5V) Active low: only protects the status register; keep high so it stays writable
Debug console PA9 (TX) / PA10 (RX) USART1, 19200 baud, external USB-to-serial adapter

The FRAM is powered from +5V here. Its high input level is 0.8 x VDD, which is 4.0 V at 5 V, while the STM32 drives its outputs to 3.3 V, so SCK, MOSI and CS are below the datasheet's input level. It works on this breadboard, but powering the chip from 3.3 V instead puts those signals inside the specification.

The RA8875 board's Wait, Int, LITE and 3Vo pins are not connected.

Do not connect 3Vo. It is an output: the 3.3 V that the board's own regulator produces. It is not a power input, so never wire it to VCC, to the NUCLEO's 3.3 V pin or to any other supply rail. The board is powered from Vin (+5V, see part 3).

The display's touch panel is wired through the display board.

Files

The three libraries are separate GitHub repositories, not part of this project's source zip: STM32_GFX, STM32_RA8875 and STM32_MB85RS64V. Download each one (or clone this project with git clone --recurse-submodules), place the three folders in the project root next to Core/, and add all three to the C and C++ include paths in Project > Properties > C/C++ Build > Settings, for Debug and Release. The tutorial walks through each step.

Debug output

A calibration-mode run prints:

Starting Initialization Process
RA8875 Found
MB85RS64V Found, ID: 04 7F 03 02
FRAM at 0x0000 before this boot: 63 A5 5A FF 00 4D 43 54 46 52 41 4D 01 02 03 04
FRAM read back: 64 A5 5A FF 00 4D 43 54 46 52 41 4D 01 02 03 04
FRAM write/read-back OK, boot count 100
Reading the stored touch calibration from the FRAM
Touch calibration, attempt 1 of 3
point 1: display 80,48 raw 132,206
Press the space bar to show the next target, or Esc to redo this one
point 2: display 400,432 raw 513,886
Press the space bar to show the next target, or Esc to redo this one
point 3: display 720,240 raw 888,538
Touch calibration stored in the FRAM
Touch the screen: red dots follow your finger for 15 seconds
Calibration Complete

In normal mode, each boot prints Touch calibration read from the FRAM: followed by the six matrix values and the divider. If the FRAM holds nothing usable it prints the reason, for example Stored calibration: none (no marker in the FRAM).

Documentation

Doxygen documentation for the project and the three libraries is a separate download in the tutorial; open docs/html/index.html after unzipping it. The Doxygen configuration lives in the git repository only. To build it yourself, run doxygen Doxyfile from the repository folder.

License

MIT, see LICENSE. The libraries carry their own licenses in their own folders (the display libraries are BSD 3-clause, from the Adafruit originals).