|
H753_CPP_SPI_Resistive_Touch_Screen_Controller 1.0
STM32H753 SPI resistive touchscreen (Adafruit 333 overlay + 5767 TSC2046 controller) driver and tutorial
|
This documentation covers a STM32 Nucleo-H753ZI tutorial project that reads a 4-wire resistive touchscreen overlay (Adafruit #333) through a TI TSC2046 SPI touch controller breakout (Adafruit #5767), built as two independent, reusable STM32 HAL libraries rather than one combined driver.
The firmware demonstrates:
Adafruit_TSC2046 depends on Adafruit_BusIO for its actual SPI transaction code – the touch-specific logic (control-byte layout, pressure formula) lives in Adafruit_TSC2046 itself, but the low-level "assert CS, clock bytes, deassert CS" plumbing is BusIO's, not TSC2046-specific. Porting only the TSC2046 driver and leaving that shared plumbing folded inside it would mean re-deriving the same SPI-transaction code again for the next Adafruit chip this site ports (a BusIO consumer other than TSC2046 is expected eventually, since BusIO backs most of Adafruit's SPI/I2C ecosystem). STM32BusIO is deliberately factored out as its own self-contained library up front instead, so that reuse doesn't require retroactively splitting TSC2046 apart later.
Both reference libraries are larger than what this project needs: Adafruit_BusIO also covers I2C devices, a "generic device" abstraction, and three other SPI addressing conventions besides the one TSC2046 uses (ADDRBIT8_HIGH_TOREAD); Adafruit_SPIDevice also has a software/bit-banged SPI fallback path with no STM32 HAL equivalent. None of that is ported – STM32SPIDevice and STM32BusIORegister cover exactly the hardware-SPI, MSB-first, ADDRBIT8_HIGH_TOREAD subset that TSC2046 (and presumably most future SPI-only Adafruit ports) actually needs. See each class's own file header comment for the specific reference-library feature it corresponds to and what was intentionally left out.
HAL_SPI_TransmitReceive() call over one padded buffer, instead of the reference library's Arduino byte-at-a-time transfer() loop – STM32 HAL supports multi-byte buffer transfers directly, so there's no need to clock one byte at a time.buildControlByte() in TSC2046.cpp) rather than the reference library's packed bitfield union – C/C++ bitfield-to-byte packing order is implementation-defined, so explicit shifts are the portable choice even though this specific toolchain (GCC ARM) would likely have packed it the same way.The target device for this project has a static, printed graphic panel (icons, labels, buttons like "On"/"Off") with the transparent resistive overlay mounted directly on top of it – there is no active display anywhere in this design. TSC2046::getPoint() only reports a raw touch position and pressure; turning that into "the On button was pressed" additionally requires a calibration step (mapping the raw 0-4095 ADC range to the panel's physical coordinates) and a hit-test step (checking that mapped position against the known rectangle for each button/icon on that specific panel's layout). Both of those are application-level concerns built on top of this driver, not part of the driver itself. They are implemented in this project's application layer, described next.
The printed panel has four rows: LED 1, LED 2 and LED 3, each split into an OFF half and an ON half, and a full-width BEEP row. The application layer turns raw readings into actions in three steps:
The CubeMX-generated main.c is plain C, so the C++ driver is reached through the C-callable functions in entryPointCPP.hpp (for example initTSC2046() and tsc2046GetPoint()). The driver object is constructed inside initTSC2046(), after the SPI peripheral is configured, rather than as a global that would construct too early.
When TOUCH_SELFTEST_ENABLE is defined in main.h, touchSelfTestRunAll() (touchSelfTest.h) runs once at boot, before the touch loop starts, and prints a result for each of three checks: a raw SPI transfer completes, the response has the TSC2046's fixed frame shape (which catches a floating MISO line or an unpowered chip), and with the panel untouched no sample looks like a touch. It is read-only. A temperature-sensor check is deliberately left out, because the chip's on-die temperature reading is not accurate; see the note in touchSelfTest.h.