After a hint from @limor about a reset pin and some experimenting, I decided to re-do this PCB, this time properly, following all the rules.
So the reset pin is now tied to the board's reset. That frees up one digital pin, which I can now use for chip select, instead of having it pulled down permanently. Because the Trinket M0 doesn't have a pull-up resistor on its reset pin, I had to add one.
The second resistor is for the LED back-light, so you can pick the right one for the brightness you desire.
Finally, I added a filter capacitor to the display's power, for good measure.
I also fixed the mounting holes and added a logo. The logo is up-side-down in relation to the text on the board, but I only noticed it now and who looks at those things anyways.
The first problem, that library supports the "green tab" ST7735 displays, but not the "red tab" ones — and of course, the one that I have, despite having a green tab, is of the "red tab" variety and needs a different initialization sequence. Fortunately the MicroPython version of that library supports it, so I made a quick pull request to also add it to the CircuitPython version. I tested it on the ESP8266, so that I can compare both MicroPython and CircuitPython, and it worked fine. Great.
Now, back to the Trinket M0, it still doesn't work. The display remains blank. What's the problem? It worked with the ESP8266. Let's take a logic analyzer and see...
Hmm, that doesn't look right. Before every byte being transmitted, there is this weird blip both on the data and the clock lines. Let's look closer.
Yeah, definitely something is not right. What could it be? Probably something specific to the Trinket M0. So I reported the bug in the CircuitPython project, and went to sleep.
The next day I had a look into the code of the display library, and the code of the BusDevice library that it uses, and had an epiphany. The BusDevice code calls spi.configure() before every transmission, to make sure it's done with the correct baud rate and mode — and that call resets the SPI peripheral and causes the blip.
Sure enough, commenting that line out makes the display work:
Adafruit just recently released a new version of their Trinket boards, this time with the Atmel SAMD21 Cortex-M0 ARM chip, and with CircuitPython loaded on it by default. Of course I had to get a couple, and managed to do it before they went out of stock.
By a complete coincidence, the package with them arrived as the same time as the package from Aliexpress with the tiny ST7735 TFT display screens. I put them one next to the other, and what do you know — a perfect fit!
So I fired up my trusty Fritzing and quickly made a breakout board for this display, with the pins matching the pins on the Trinket M0. A few clicks later I have the order placed for OSHPark.
(Yeah, I was in a hurry, so one of the mounting holes is slightly shifted. Oh well.)
Because I only had five pins to use, and I'm not entirely sure if I can use the MISO pin for other purpose while the SPI is used on this microcontroller, I had to hard-wire the LED and CS pins. By a complete coincidence, the SCL pin is free (it's the MISO pin), and the SDA pin is the same as DC — so I think I should be still able to use the I²C bus with this connected.