一、ST7735介绍
ST7735是一款spi驱动的lcd屏,通过spi发送用于操作lcd的寄存器指令和显示数据
二、ST7735操作模式
当DC引脚为低,命令模式,目的是设置芯片显示参数等
当DC引脚为高,数据模式,发送的数据应该为图像rgb数据,保存在display ram并显示
BLK是控制LCD背光(不开背光,无法显示)
三、ST7735 rgb模式
ST7735有多种数据模式,包含RGB666\RGB444\RGB565等,如下图
四、ST7735 驱动代码-RGB565模式
#include <stdint.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#define LCD_RESET _IOW('L',0x1,int)
#define LCD_DCX _IOW('L',0x2,int)
#define LCD_POWER _IOW('L',0x3,int)
#define GPIO_LOW 0x0000
#define GPIO_HIGH 0x0001
#define LCD_HEIGHT 128
#define LCD_WIDTH 160
/***************************** command ***************************/
#define ST7735_SleepOut 0x11
#define ST7735_FullColor 0xB1 //in normal mode
#define ST7735_8Colors 0xB2 //in idle mode
#define ST7735_InPartialMode 0xB3 //
#define ST7735_INVCTR 0xB4 //display inversion control
#define ST7735_PWCTR1 0xC0 //power control 1
#define ST7735_PWCTR2 0xC1 //power control 2
#define ST7735_PWCTR3 0xC2 //power control 3
#define ST7735_PWCTR4 0xC3 //power control 4
#define ST7735_PWCTR5 0xC4 //power control 5
#define ST7735_VMCTR1 0xC5 //VCOM control 1
#define ST7735_MADCTL 0x36 //Memory data access control
#define ST7735_GMCTRP1 0xE0 //Gamma '+'polarity Correction characteristics setting
#define ST7735_GMCTRN1 0xE1 //Gamma '-'polarity Correction characteristics setting
#define ST7735_COLMOD 0x3A //interface pixel format
#define ST7735_CASET 0x2A //column address set
#define ST7735_RASET 0x2B //Row Address Set
#define ST7735_RAMWR 0x2C //Memory write
#define ST7735_DISPON 0x29 //display on
static int spi_gpio_fd;
static int spi_fd;
static const char *device = "/dev/spidev32766.0";
static const char *spi_gpio_device = "/dev/spi_gpio";
static uint32_t mode=SPI_MODE_0;
static uint8_t bits = 8;
static uint32_t speed = 15000000;
static uint16_t delay=0;
static void pabort(const char *s)
{
perror(s);
abort();
}
static void transfer(int fd, uint8_t *tx, uint8_t *rx, size_t len)
{
int ret;
struct spi_ioc_transfer tr = {
.tx_buf = (unsigned long)tx,
.rx_buf = (unsigned long)rx,
.len = len,
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
if (mode & SPI_TX_QUAD)
tr.tx_nbits = 4;
else if (mode & SPI_TX_DUAL)
tr.tx_nbits = 2;
if (mode & SPI_RX_QUAD)
tr.rx_nbits = 4;
else if (mode & SPI_RX_DUAL)
tr.rx_nbits = 2;
if (!(mode & SPI_LOOP)) {
if (mode & (SPI_TX_QUAD | SPI_TX_DUAL))
tr.rx_buf = 0;
else if (mode & (SPI_RX_QUAD | SPI_RX_DUAL))
tr.tx_buf = 0;
}
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message");
}
static void transfer_command(int fd, uint8_t command,size_t len)
{
uint8_t value=command;
ioctl(spi_gpio_fd, LCD_DCX, GPIO_LOW);
transfer(fd,&value,NULL,len);
}
static void transfer_command_parameter(int fd, uint8_t parameter,size_t len)
{
uint8_t value=parameter;
ioctl(spi_gpio_fd, LCD_DCX, GPIO_HIGH);
transfer(fd,&value,NULL,len);
}
static void transfer_data(int fd, uint8_t *tx, uint8_t *rx, size_t len)
{
ioctl(spi_gpio_fd, LCD_DCX, GPIO_HIGH);
transfer(fd,tx,rx,len);
}
static void set_window_regs(uint8_t x_start, uint8_t x_end, uint8_t y_start, uint8_t y_end) //设置需要显示的窗口大小,起始位置
{
uint8_t command=0x00;
uint8_t data=0x00;
//x方向大小
transfer_command(spi_fd, ST7735_CASET, 1);
transfer_command_parameter(spi_fd, 0x00,1);
transfer_command_parameter(spi_fd, x_start,1);
transfer_command_parameter(spi_fd, 0x00,1);
transfer_command_parameter(spi_fd, x_end-1,1);
//y方向大小
transfer_command(spi_fd, ST7735_RASET, 1);
transfer_command_parameter(spi_fd, 0x00,1);
transfer_command_parameter(spi_fd, y_start,1);
transfer_command_parameter(spi_fd, 0x00,1);
transfer_command_parameter(spi_fd, y_end-1,1);
}
static void clean_window(uint8_t x_start, uint8_t x_end, uint8_t y_start, uint8_t y_end, uint16_t back_color)
{
//缓存上色
uint8_t rgb[(x_end-x_start)*(y_end-y_start)*2];
for(int i=0;i<(x_end-x_start)*(y_end-y_start)*2;i++){
if( 0 == i%2){
rgb[i]= (back_color & 0xFF00)>>8;
}else{
rgb[i]= back_color & 0x00FF;
}
}
//开窗口
set_window_regs(x_start,x_end,y_start,y_end);
//缓存写入显存
transfer_command(spi_fd, ST7735_RAMWR, 1);
for(int i=0;i<(x_end-x_start);i++){
transfer_data(spi_fd, &rgb[i*(y_end-y_start)*2], NULL, (y_end-y_start)*2);
}
}
static void spi_lcd_reset(unsigned int value)
{
ioctl(spi_gpio_fd, LCD_RESET, value); //reset芯片
}
static void spi_lcd_power(unsigned int value)
{
ioctl(spi_gpio_fd, LCD_POWER, value);
}
static void spi_init(void)
{
int ret;
//set spi_mode
ret = ioctl(spi_fd, SPI_IOC_WR_MODE32, &mode);
if (ret == -1)
pabort("can't set spi mode");
ret = ioctl(spi_fd, SPI_IOC_RD_MODE32, &mode);
if (ret == -1)
pabort("can't get spi mode");
//bits per word
ret = ioctl(spi_fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't set bits per word");
ret = ioctl(spi_fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
pabort("can't get bits per word");
//max speed hz
ret = ioctl(spi_fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't set max speed hz");
ret = ioctl(spi_fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
pabort("can't get max speed hz");
printf("spi mode: 0x%x\n", mode);
printf("bits per word: %d\n", bits);
printf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
}
static void st7735_lcd_init(void)
{
spi_lcd_reset(GPIO_LOW);
usleep(1000);
spi_lcd_reset(GPIO_HIGH);
usleep(1000);
transfer_command(spi_fd, ST7735_SleepOut, 1);
usleep(100*1000);
transfer_command(spi_fd, ST7735_FullColor, 1); //选择需要调整的参数时是什么类型的
transfer_command_parameter(spi_fd, 0x05,1); //发送芯片参数
transfer_command_parameter(spi_fd, 0x3c,1);
transfer_command_parameter(spi_fd, 0x3c,1);
transfer_command(spi_fd, ST7735_8Colors, 1);
transfer_command_parameter(spi_fd, 0x05,1);
transfer_command_parameter(spi_fd, 0x3c,1);
transfer_command_parameter(spi_fd, 0x3c,1);
transfer_command(spi_fd, ST7735_InPartialMode, 1);
transfer_command_parameter(spi_fd, 0x05,1);
transfer_command_parameter(spi_fd, 0x3c,1);
transfer_command_parameter(spi_fd, 0x3c,1);
transfer_command_parameter(spi_fd, 0x05,1);
transfer_command_parameter(spi_fd, 0x3c,1);
transfer_command_parameter(spi_fd, 0x3c,1);
transfer_command(spi_fd, ST7735_INVCTR, 1);
transfer_command_parameter(spi_fd, 0x03,1);
transfer_command(spi_fd, ST7735_PWCTR1, 1);
transfer_command_parameter(spi_fd, 0x28,1);
transfer_command_parameter(spi_fd, 0x08,1);
transfer_command_parameter(spi_fd, 0x04,1);
transfer_command(spi_fd, ST7735_PWCTR2, 1);
transfer_command_parameter(spi_fd, 0xc0,1);
transfer_command(spi_fd, ST7735_PWCTR3, 1);
transfer_command_parameter(spi_fd, 0x0d,1);
transfer_command_parameter(spi_fd, 0x00,1);
transfer_command(spi_fd, ST7735_PWCTR4, 1);
transfer_command_parameter(spi_fd, 0x8d,1);
transfer_command_parameter(spi_fd, 0x2a,1);
transfer_command(spi_fd, ST7735_PWCTR5, 1);
transfer_command_parameter(spi_fd, 0x8d,1);
transfer_command_parameter(spi_fd, 0xee,1);
transfer_command(spi_fd, ST7735_VMCTR1, 1);
transfer_command_parameter(spi_fd, 0x1a,1);
transfer_command(spi_fd, ST7735_MADCTL, 1);
transfer_command_parameter(spi_fd, 0xa0,1);
transfer_command(spi_fd, ST7735_GMCTRP1, 1);
transfer_command_parameter(spi_fd, 0x04,1);
transfer_command_parameter(spi_fd, 0x22,1);
transfer_command_parameter(spi_fd, 0x07,1);
transfer_command_parameter(spi_fd, 0x0a,1);
transfer_command_parameter(spi_fd, 0x2e,1);
transfer_command_parameter(spi_fd, 0x30,1);
transfer_command_parameter(spi_fd, 0x25,1);
transfer_command_parameter(spi_fd, 0x2a,1);
transfer_command_parameter(spi_fd, 0x28,1);
transfer_command_parameter(spi_fd, 0x26,1);
transfer_command_parameter(spi_fd, 0x2e,1);
transfer_command_parameter(spi_fd, 0x3a,1);
transfer_command_parameter(spi_fd, 0x00,1);
transfer_command_parameter(spi_fd, 0x01,1);
transfer_command_parameter(spi_fd, 0x03,1);
transfer_command_parameter(spi_fd, 0x13,1);
transfer_command(spi_fd, ST7735_GMCTRN1, 1);
transfer_command_parameter(spi_fd, 0x04,1);
transfer_command_parameter(spi_fd, 0x16,1);
transfer_command_parameter(spi_fd, 0x06,1);
transfer_command_parameter(spi_fd, 0x0d,1);
transfer_command_parameter(spi_fd, 0x2d,1);
transfer_command_parameter(spi_fd, 0x26,1);
transfer_command_parameter(spi_fd, 0x23,1);
transfer_command_parameter(spi_fd, 0x27,1);
transfer_command_parameter(spi_fd, 0x27,1);
transfer_command_parameter(spi_fd, 0x25,1);
transfer_command_parameter(spi_fd, 0x2d,1);
transfer_command_parameter(spi_fd, 0x3b,1);
transfer_command_parameter(spi_fd, 0x00,1);
transfer_command_parameter(spi_fd, 0x01,1);
transfer_command_parameter(spi_fd, 0x04,1);
transfer_command_parameter(spi_fd, 0x13,1);
transfer_command(spi_fd, ST7735_COLMOD, 1);
transfer_command_parameter(spi_fd, 0x05,1);
transfer_command(spi_fd, ST7735_DISPON, 1);
}
int main(int argc, char *argv[])
{
spi_gpio_fd = open(spi_gpio_device, O_RDWR);
if (spi_gpio_fd < 0)
pabort("can't open device");
spi_fd = open(device, O_RDWR);
if (spi_fd < 0)
pabort("can't open device");
spi_init();
st7735_lcd_init(); //LCD芯片初始化
clean_window(0, LCD_WIDTH, 0, LCD_HEIGHT, 0xF800); //设置LCD屏为一种颜色-红色,使用RGB565
spi_lcd_power(1); //LCD屏背光设置
sleep(10);
close(spi_gpio_fd);
close(spi_fd);
return 0;
}
结果展示
五、ST7735上点阵字体使用
使用点阵字体主要目的在于降低字体的储存空间,例如下图B字母,8*11大小,只看第一行像素点的信息,11111100转换为字节为0xFC(当然还可以压缩),但转换为显示数据,如RGB565,每一个像素需要用2byte,第一行就占用了16byte的空间
如果需要使用点阵字体,将对应像素点转换为对应的颜色即可,如第一行,显示数据为0x00(rgb565-黑色) 0x00 0x00 0x00 0x00 0x00 0xFF(白色) 0xFF