Speed problems with st7735

Hey! I’m trying to write a library to control the st7735 1.8" tft faster without any luck. I have the buffer saved in ram and the only thing slowing the display is the void that sends all the data to the display. I’m using the stm32f103c8t6 mainly because it should be much faster than atmega328. The SPI is working at full speed but I can’t still get it to refresh quickly enough. Any suggestions?

This is a full copy of the Adafruit’s library

PS. Oh come on I can’t put the whole code in here because “The message exceeds the maximum allowed length (9000 characters).” Pff…

PPS. and the spi divider is set to 0

uint16_t tftbuffer[1280];

void st7735::drawPixel(int16_t x, int16_t y, uint16_t color) {
  uint16_t pixpos = (x + y * 160);
  uint16_t remainder = pixpos % 16;
  uint16_t divided = (pixpos - remainder / 10) / 16;

  if (color == 1) {
    tftbuffer[divided] |= (1 << remainder);
  }
}

void st7735::display() {
	setAddrWindow(0, 0, 159, 127);
	DC_HIGH();
	CS_LOW();
	
	uint16_t remainder = 0;
	uint16_t divided = 0;
	
	for(uint32_t x=0;x<1280*16;x++){
		remainder = x % 16;
		divided = (x - remainder / 10) / 16;
		if(tftbuffer[divided] & (1 << remainder)){
			spiwrite(0xFFFF >> 8);
			spiwrite(0xFFFF);
		}else{
			spiwrite(0);
			spiwrite(0);
		}
		
	}
	CS_HIGH();
}

void st7735::setAddrWindow(uint8_t x0, uint8_t y0, uint8_t x1,
                           uint8_t y1) {

  writecommand(ST7735_CASET); // Column addr set
  writedata(0x00);
  writedata(x0 + xstart);   // XSTART
  writedata(0x00);
  writedata(x1 + xstart);   // XEND

  writecommand(ST7735_RASET); // Row addr set
  writedata(0x00);
  writedata(y0 + ystart);   // YSTART
  writedata(0x00);
  writedata(y1 + ystart);   // YEND

  writecommand(ST7735_RAMWR); // write to RAM
}

The ST7735 displays are very small. You can write to them very fast. Even with a ATmega328.

Bodmer has a faster library than Adafruit_ST7735
There are STM32 versions of the Adafruit_ST7735 library that come with the STM32 Core.

If you want to write your own, the main tricks are:

  1. Always setAddrWindow() for any shape of rectangle. Even a single line.

  2. Use hardware SPI. Optimise the SPI for an AVR to avoid gaps between SPI bytes.

  3. STM32 can write gap-less SPI. An STM32 has got DMA but it is not necessary.

  4. the Maple Core for STM32 has SPI.write(buf, n) as well as SPI.write_DMA(buf, n)

  5. regular Arduino Cores have only got SPI.transfer(buf, n) which will overwrite your data.

Good Luck.

Ask if you are stuck with the coding. Note that you can attach files instead of pasting to a CODE window. Or you can ZIP up a complete project and attach the ZIP.

David.

I wrote already the library but it is very slow. The (hardware)SPI is running full speed (at least I hope so).

Ps. the board is “bluepill”

Zip included

st7735.zip (7.17 KB)

I will look at it later.

You appear to setClockDivider() etc for every spiwrite().

It is only necessary at the start of a sequence. e.g. with SPI.beginTransaction()
You can make the display() function more efficient.

As a general rule, you draw a graphic only when eeded. You do NOT keep a mirror buffer in SRAM.
That technique is used for Monochrome displays like KS0108 or SSD1306 because it avoids Read-Modify-Write sequences. i.e. you manipulate a SRAM buffer and then copy the whole buffer in one go.

David.

I moved the
SPI.setClockDivider(SPI_CLOCK_DIVIDER_ADJUST);
and
SPI.setDataMode(SPI_MODE0);
to the initializing and it improved a bit. Still quite slow

I changed the display void. Got 20 fps but I really would like to get it up to 60. Any suggestions… :confused:

void st7735::display() {
	setAddrWindow(0, 0, 159, 127);
	DC_HIGH();
	CS_LOW();
	
	for(uint16_t x=0;x<1280;x++){
		
		for(uint8_t b=0;b<16;b++){
			if(tftbuffer[x] & (1 << b)){
			SPI.transfer(0xFF);
			SPI.transfer(0xFFFF);
		}else{
			SPI.transfer(0);
			SPI.transfer(0);
		}
		}
	}
	CS_HIGH();
}

You are using the wrong approach. You are treating the colour TFT like a monochrome OLED.
I ran your code on a Nucleo last night. You are drawing a new frame into the SRAM buffer. Then blitting the whole buffer in one go.

Yes, you can do the blitting faster. But do you really want a black and white picture on a colour display?

I suggest that you use the regular Adafruit_ST7735 library. Try all the supplied examples.
Bodmer is faster. There is probably a ST7735_PDQ library. This would be pretty damn quick too.

David.

I would just need a bigger display that could output smooth gameplay. I'm currently using a 0.96" ssd1306 oled (monochrome) and it is WAY too small. The adafruit library won't even work with my display without firstly modifying it... I really would like to get that working

I was replying on a Tablet. Then my left palm must have touched some icon on the screen. And I lost everything.

A 128x64 0.96" OLED is pretty small.
A 160x128 1.8" TFT is more practical.

You should be able to achieve 20 full colour frames per second with a Uno.
Probably 60 FPS with the STM32.
Actually, blitting 20480 B&W pixels takes the same time as 20480 colour pixels.

But seriously, you don't normally blit a full frame in one go. You draw / update graphics as required.
Even with an animation, you seldom change the full area with each frame. You only update small areas that have changed.

David.