|
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
|
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.
After the CubeMX peripheral init, main.c calls, in this order:
initTest(&hspi1) – creates the display object and starts the RA8875.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.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.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:
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.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:
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.
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.
| 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.
Core/Inc/main.h, Core/Src/main.c – CubeMX-generated code plus the application calls and the UART receive callbacks, inside USER CODE sections. main.h holds the TOUCH_CALIBRATION_ENABLE switch.Core/Inc/entryPointCPP.hpp, Core/Src/entryPointCPP.cpp – the C/C++ bridge: extern "C" functions that own the display and FRAM objects.Core/Inc/touchCalibration.hpp, Core/Src/touchCalibration.cpp – the three-point calibration.Core/Inc/touchCalibrationStorage.hpp, Core/Src/touchCalibrationStorage.cpp – keeping the calibration in the FRAM.F439_CPP_SPI_RA8875_TFT_LCD_04.ioc – the CubeMX project; .pdf / .txt – its configuration report.STM32F439ZITX_FLASH.ld, STM32F439ZITX_RAM.ld – linker scripts.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.
A calibration-mode run prints:
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).
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.
MIT, see LICENSE. The libraries carry their own licenses in their own folders (the display libraries are BSD 3-clause, from the Adafruit originals).