STM32 Hardware SPI Driver for ST7735 – Register Version

This is the optimized code completed right after dinner. The initial process was very tortuous; the previous driver worked, but it only implemented color filling and did not print text. Now it has been perfectly driven, and I would like to share the problems encountered and how I solved them.I started by referencing the code provided by the vendor to write the driver, but the vendor’s code is as follows:

/******************************************************************************      Function Description: Fill color in the specified area      Input Data: xsta, ysta   Starting coordinates                xend, yend   Ending coordinates                color       Color to fill      Return Value:  None******************************************************************************/void LCD_Fill(u16 xsta,u16 ysta,u16 xend,u16 yend,u16 color){           u16 i,j;  LCD_Address_Set(xsta,ysta,xend-1,yend-1);//Set display range  for(i=ysta;i<yend;i++) {          for(j=xsta;j<xend;j++) {            LCD_WR_DATA(color);        }    } }

Here we see LCD_WR_DATA

/******************************************************************************      Function Description: Write data to LCD      Input Data: dat Data to be written      Return Value:  None******************************************************************************/void LCD_WR_DATA(u16 dat){  LCD_Writ_Bus(dat>>8);  LCD_Writ_Bus(dat);}
/******************************************************************************      Function Description: LCD serial data writing function      Input Data: dat Serial data to be written      Return Value:  None******************************************************************************/void LCD_Writ_Bus(u8 dat) {    u8 i;  LCD_CS_Clr();  for(i=0;i<8;i++) {      LCD_SCLK_Clr();      if(dat&0x80) {         LCD_MOSI_Set();      } else {         LCD_MOSI_Clr();      }      LCD_SCLK_Set();      dat<<=1;  }  LCD_CS_Set();}

This is actually simulating SPI, which feels a bit tricky, so I had to find a way to implement hardware SPI myself.First, initialize the corresponding SPI interface. Below is the SPI hardware initialization for F4:

static void spi_init(SPI_TypeDef *SPI_N, uint32_t spi_speed) {  SPI_N->CR1 = 0;  SPI_N->CR2 = 0;  SPI_N->CR1 &= ~(               SPI_CR1_LSBFIRST  // 0:MSB first             | SPI_CR1_DFF       // 0:set to 8 bit              );  SPI_N->CR1 |= SPI_CR1_MSTR        // SPI is MASTER             | SPI_CR1_SSM     // Software slave management (The external NSS pin is free for other application uses)             | SPI_CR1_SSI     // Internal slave select (This bit has an effect only when the SSM bit is set. Allow use NSS pin as I/O)             | spi_speed       // Baud rate control             | SPI_CR1_CPHA    // Clock Phase('0:The first clock;1:The second clock' transition is the first data capture edge)             | SPI_CR1_CPOL    // Clock Polarity(0:CK to 0 when idle;1:CK to 1 when idle)             ;  SPI_N->CR1|= SPI_CR1_SPE;       //SPI enable}

I can confirm that this initialization is correct because I previously successfully drove the SPI FLASH.At first, the screen was always black, and I was stuck here for at least a week, causing me to study the register values one by one in an attempt to find a solution, but it still didn’t work. There were many articles online that I referenced, but I made no progress. Later, I simply referred to the Arduino driver to write the register settings, and surprisingly, a pattern appeared, but unfortunately, it was garbled.STM32 Hardware SPI Driver for ST7735 - Register VersionHowever, I saw someone online say that garbled screens at least indicate that the registers were successfully transmitted, which reassured me.I felt that dawn was just ahead.So I wondered if the SPI speed was too fast because I referenced the Arduino driver, which said that SPI should not exceed 27MHz. I tried to reduce the speed, but it didn’t work. I also tried flying wires to the ESP32 board, and it displayed normally. Suddenly, one day while writing the simulated I2C, I had a sudden idea while writing the delay function. I added a delay function in the CS/CD command function for driving the ST7735, and to my surprise, it worked! The color bar appeared successfully.STM32 Hardware SPI Driver for ST7735 - Register VersionThe photo taken by my phone is not very clear, but there is actually a noticeable color deviation because the color bar I want to display is as follows:

const int cb_tbl[8] = { RGB565(255,255,255),RGB565(255,255,0),RGB565(0,255,255),RGB565(0,255,0),RGB565(255,0,255),RGB565(255,0,0),RGB565(0,0,255),RGB565(0,0,0) };

This is clearly not matching; the reason is that data is being lost.

void lcd_s_fill(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color) {  // clipping  if((x >= ST7735_WIDTH) || (y >= ST7735_HEIGHT)) return;  if((x + w - 1) >= ST7735_WIDTH) w = ST7735_WIDTH - x;  if((y + h - 1) >= ST7735_HEIGHT) h = ST7735_HEIGHT - y;  LCD_S_CS_LOW;  chThdSleepMicroseconds(10);  lcd_s_setWindow(x, y, w, h, LCD_RAMWR);  uint8_t data[] = { color >> 8, color & 0xFF };    LCD_S_DC_DATA;  chThdSleepMicroseconds(10);  for(y = h; y > 0; y--) {    for(x = w; x > 0; x--) {      ST7735_WriteData(data, sizeof(data));    }  }  LCD_S_CS_HIGH;  chThdSleepMicroseconds(10);}

So I tried changing to 16-bit data transmission to reduce the number of loop transmissions. Even if there is interference, the number of interference occurrences is halved. However, command operations are all 8 bits, and the default SPI initialization is 8 bits.How can this be achieved? The method is to reinitialize to 16 bits when filling data, and after transmission is complete, reinitialize to 8 bits.

void lcd_s_fill(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color) {  // clipping  if((x >= ST7735_WIDTH) || (y >= ST7735_HEIGHT)) return;  if((x + w - 1) >= ST7735_WIDTH) w = ST7735_WIDTH - x;  if((y + h - 1) >= ST7735_HEIGHT) h = ST7735_HEIGHT - y;  LCD_S_CS_LOW;  chThdSleepMicroseconds(10);  lcd_s_setWindow(x, y, w, h, LCD_RAMWR);    //uint8_t data[] = { color >> 8, color & 0xFF };  spi_init_16bit();  LCD_S_CS_LOW;  chThdSleepMicroseconds(10);  LCD_S_DC_DATA;  chThdSleepMicroseconds(10);  for(y = h; y > 0; y--) {    for(x = w; x > 0; x--) {      ST7735_WriteData16(color);      //ST7735_WriteData(data, sizeof(data));    }  }  spi_init_8bit();    LCD_S_CS_HIGH;  chThdSleepMicroseconds(10);}

STM32 Hardware SPI Driver for ST7735 - Register VersionThe effect is as shown in the picture, haha, it worked!Finally, I implemented printing text on the LCD, referencing the printf method in nanovna, as shown in the picture.STM32 Hardware SPI Driver for ST7735 - Register VersionIn summary, the two key points are: the need to increase delay; and the 16-bit transmission.END

Leave a Comment