사용한 ST7735 드라이버 탑재 80x160 0.96인치 LCD

(사용한 LCD 모듈 기준)

- 디스플레이 해상도 : 80x160 (드라이버 지원 해상도는 132x162, 128x160)

- 통신 : SPI (사용 모듈의 경우 4-line serial interface 고정 (C/S(Chip Select), SCL, MOSI, MISO))

- 작동 전압(VDD) : 2.6~3.6V

- I/O 전압 (GPIO) : 1.65~VDD

- 색심도(Color Depth) : 12-bit/pixel(RGB-444, 4k), 16-bit/pixer(RGB-565, 65k), 18-bit(RGB-666, 262k)


[작동 방식]

- SPI 통신 사용, 명령어를 전송해 디스플레이를 제어하거나 RGB 데이터를 전송해 디스플레이 표현

4-line serial interface 에서 사용되는 데이터 전송 흐름

- Clock Polarity : 0 (SCL 비활성화 상태에서 LOW 유지)

- Clock Phase : 0 (SCL 첫번째 엣지에서 데이터 캡쳐, 두번째 엣지에서 출력)

- CPOL=0, CPHA=0 이므로 SCL의 Rising Edge에서 SDA 라인의 데이터가 캡쳐되고 Falling Edge에서 데이터 출력

- D/C : LOW일 때 전송되는 데이터는 명령어,

          HIGH일 때 전송되는 데이터는 명령어 레지스터에 저장될 매개변수 (명령어와 연이어 전송될 경우)

          or 디스플레이 데이터 램에 저장될 RGB 데이터 배열

- 데이터 8 비트씩, MSB부터 전송

- 전송할 데이터의 종류에 따라(명령어=0, 디스플레이 데이터/명령어 매개변수=1) D/C 라인을 Low or High로 설정한다

- C/S 라인이 LOW 상태가 된 후에 데이터 전송이 이루어져야만 한다

- 데이터 전송이 완료된 이후엔 C/S 라인을 다시 High로 설정한다

 

타이밍

- ST7735에 데이터를 쓸 때 : SCL 주기 최소 66ns (15.15Mhz 이하)

- ST7735로부터 데이터를 읽을 때  SCL 주기 최소 150ns (6.67Mhz 이하)

 

<Color Depth>

- ST7735는 디스플레이를 표현하는데 있어서 4k (RGB 4-4-4 bit), 65k (RGB 5-6-5 bit), 262k (6-6-6 bit) 총 세가지 방식의 컬러 심도를 가지고 있다

- 전송한 RGB 데이터는 ST7735 디스플레이 데이터 램(132x162x18-bit 그래픽 타입 static 램)에 저장된다

- 전원 인가 직후 기본 값은 262k (18 bit per pixel)

12 bit, 16 bit 픽셀 포맷

- 기본 컬러 심도 설정은 18 bit이므로 12, 16bit 컬러 심도를 사용하기 위해선 먼저 컬러 심도 변경에 필요한 명령어와 명령어 매개변수를 전송해 컬러 심도 설정을 변경해야한다 (3Ah(명령어(COLMOD)) + D2~D0(매개변수) 총 2byte)

- 12 bit, 16 bit 포맷 둘 다 RGB 데이터 비트가 빈틈없이 연속적으로 이어진다

- 12 bit 포맷은 RGB(4-4-4)의 형태이므로 3byte가 두 픽셀의 RGB값을 가진다

- 16 bit 포맷은 RGB(5-6-5)의 형태이므로 2byte가 한 픽셀의 RGB값을 가진다

18bit RGB 6-6-6 포맷

- 전원 인가 직후, 하드웨어 리셋시 기본적으로 설정되어 있는 컬러 심도는 18 bit RGB 6-6-6 형태

- 12 bit, 16 bit 컬러 심도와는 다르게 RGB 비트가 빈틈없이 연이어 전송되는 형태가 아니고 6bit 색상 데이터(R/G/B)+2bit로 구성된 1 byte 데이터 세 개(R+G+B)가 하나의 픽셀을 나타낸다

- 전송되는 RGB 각 1 byte의 MSB인 D7(Bit 7)부터 D2(Bit 2)까지 색상값을 입력하면 된다 (D1, D0 사용 X, 전송 O)

 

<어드레스 카운터>

어드레스 카운터 표

- 어드레스 카운터는 읽기, 쓰기를 위한 디스플레이 데이터 램의 주소를 설정한다

- 데이터는 드라이버의 램 행렬(132x162x18-bit)에 픽셀 단위로 쓰여진다

- 램의 위치는 어드레스 포인터에 의해 지정된다

- 주소 범위는 X=0~131, Y=0~161 이고 범위 밖에 주소는 허용되지 않는다

- 램에 디스플레이 데이터를 쓰기 전에 데이터가 기록될 창(window)이 정의되어야 한다

- 창은 시작 주소를 지정하는 XS, YS와 마지막 주소를 지정하는 XE, YE 커맨드 레지스터를 통해 프로그래밍 할 수 있다

- 예를 들어, 전체 디스플레이 컨텐츠가 기록된다면 윈도우는 다음 값으로 정의 할 수 있다

   XS=0, YS=0, XE=127, YE=161 (128x162)

- 수직 어드레싱 모드(MV=1), Y-주소는 각 바이트 이후에 증가하고 마지막 Y-주소(Y=YE) 이후에 Y는 YS로 랩 어라운드(어드레스 최대 번지 다음에 제로 번지가 연속함)하고, X는 다음 열을 어드레싱하기 위해 증가

- 수평 어드레싱 모드(V=0), X-주소는 각 바이트 이후에 증가하고 마지막 X-주소(X=XE) 이후에 X는 XS로 랩 어라운드하고 Y는 다음 행을 어드레싱하기 위해 증가한다

- 모든 마지막 주소(X=XE, Y=YE) 이후에 어드레스 포인터는 X=XS, Y=YS 주소로 랩 어라운드 한다

- 다양한 디스플레이 아키텍처를 다루기 위한 유연성을 위해 "CASET, RASET, MADCTL" 명령어는 X-주소, Y-주소의 반전을 허용하는 MX, MY 플래그를 정의한다

- MX, MY 그리고 MV(열<->행 교환)가 변경되면 데이터 버스트가 디스플레이 램에 다시 쓰여진다

MADCTL(Memory Data Access Control) 설정에 따른 프레임 데이터 쓰기 방향


[CUBEMX 설정]

SPI 설정
사용할 SPI가 속하는 APB의 클럭 설정

- ST7735에 데이터를 전송하기만 하므로 Trasmit Only Master 로 설정 (Master MOSI -> ST7735 SDA)

- 데이터는 8 bit씩 MSB부터 전송

- 데이터시트 상 SCL Write 주기 최소값은 66ns (15.15Mhz 이하)

- 사용하는 SPI가 속하는 APB의 클럭 속도를 설정한 뒤, SPI 프리스케일러 설정을 통해 SCL 설정

- 16Mhz 설정의 경우, 62.5ns로 최소값 보다는 낮지만 정상 작동 확인

- CPOL=Low(=0), CPHA=1 Edge(=0)

- SCL은 비활성화시 Low를 유지하고 통신 시작시 SCL 첫번째 엣지(Rising)에서 SDA 라인의 데이터가 캡쳐되고 SCL의 두번째 엣지(Falling)에서 캡쳐된 데이터가 출력된다

- 인터럽트와 DMA를 활용해 데이터 전송

- C/S (Chip Select, =SS (Slave Select), D/C (Data/Command), Reset 핀 할당 및 Output 으로 설정

(사용하지 않는 GPIO 핀들 사용)

- C/S 핀은 SPI 통신 비활성화 상태에선 High 상태를 유지하고 통신 때만 Low로 전환해 사용

- D/C 핀은 명령어를 전송할 땐 Low 상태여야하고 명령어 매개변수 or 디스플레이 데이터를 전송할 땐 High 상태여야 한다

- Reset 핀은 H/W 리셋에 사용되는 핀으로 기본적으론 High 상태를 유지하고 있어야 한다


[코드]

(Write 기능들만 구현)

<초기화>

 *기본 설정

전원 인가/하드웨어 리셋/소프트웨어 리셋 직후 디스플레이 기본 설정

- 전원 인가시 디스플레이는

  - Sleep In 상태이므로 Sleep Out 명령어를 전송해 Sleep 모드에서 빠져나온다

  - Display Off 상태이므로 Display On 명령어 전송해 디스플레이를 활성화 시킨다

- 행렬 시작 주소 (0, 0), 마지막 주소 (161, 131) 이므로 디스플레이 창은 (0~161, 0~131)이 된다

 

 *화면 반전

- 사용한 LCD의 경우, 위 사진에서 (0, 0)으로 표시한 부분이 어드레스 포인터의 시작점이다 (행,열은 사진 방향과 동일)

- 80x160 해상도에서 80에 해당하는 부분은 26~105까지의 주소를 사용한다 (반전 설정 상관없이 26~105)

- 160에 해당하는 부분은 1~160까지의 주소를 사용한다 (디스플레이 해상도가 128x160이 아닌 132x162로 추정)

(왼쪽) 기본 설정 (MY=0, MX=0, MV=0) (오른쪽) MY=0, MX=1, MV=1
Memory Data Access Control 레지스터 MV=1, MX=1, MY=0 (행열 교환, 열 주소 순서 반전)

- 행과 열의 방향은 사진과 동일하고 RGB 데이터는 열부터 순차적으로 쓰여진다

- 어드레스 포인터는 열의 마지막 부분에서 열의 시작 지점으로 돌아가고 행 주소는 1 증가한다

- 오른쪽 사진처럼 사용하기 위해 Memory Data Access Control (MADCTL) 레지스터에서 MV 비트를 1로 설정해 행과 열을 서로 바꾸고 MX 비트를 1로 설정해 열 주소 순서를 반전시켰다

 

 *RGB 출력 반전

Memory Data Access Control (MADCTL) 레지스터에서 RGB BIT의 역할
RGB 픽셀 0xFC, 0x00, 0x00 전송 / (왼쪽) MADCTL RGB BIT=0 (오른쪽) MADCTL RGB BIT=1

- 사용한 LCD 모듈의 경우, Memory Data Access Control(MADCTL) 레지스터의 RGB 비트 설정이 0임에도 불구하고 BGR 순으로 반대로 디스플레이에 데이터가 표현됨. 따라서 MADCTL 레지스터의 RGB 순서 설정 비트를 1로 변경함으로 전송한 RGB 데이터 순서대로 디스플레이 출력이 되게끔 설정.

- RGB BIT 설정으로 인해 변경된 RGB 출력 순서는 좌우, 상하 반전을 하더라도 변하지 않는다

 

*디스플레이 반전

Display Inversion On 명령어
RGB 픽셀 0xFC, 0x00, 0x00 전송, MADCTL RGB BIT=1 / (왼쪽) Inversion Off (오른쪽) Inversion On

- 사용한 LCD 모듈의 경우, Inversion Off 일 때 RGB값 0x00에서 최대 밝기, 0xFC에서 최소 밝기가 된다

- 예) R=0xFC, G=0x00, B=0x00 이라면 해당 픽셀은 Red=off / Green, Blue=최대 밝기가 된다

- Inversion On 명령어를 전송해 전송하는 R/G/B 값의 크기가 디스플레이 픽셀 밝기에 그대로 반영되게 한다

 

 *초기화 코드

//Send Command
void st7735_write_cmd(uint8_t cmd)
{
	while(HAL_SPI_GetState(&hspi1)!=HAL_SPI_STATE_READY)
	{

	}

	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, RESET);

	//Send Command
	HAL_GPIO_WritePin(SPI1_DC_GPIO_Port, SPI1_DC_Pin, RESET);
	if(HAL_SPI_Transmit_IT(&hspi1,&cmd,1)!=HAL_OK)
	{

	}
	while(HAL_SPI_GetState(&hspi1)!=HAL_SPI_STATE_READY)
	{

	}

	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, SET);
}

//Send Command, Command Parameter, Parameter Size
void st7735_write_cmd_param(uint8_t cmd, uint8_t *parameter, uint8_t param_size)
{
	while(HAL_SPI_GetState(&hspi1)!=HAL_SPI_STATE_READY)
	{

	}

	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, RESET);

	//Send Command
	HAL_GPIO_WritePin(SPI1_DC_GPIO_Port, SPI1_DC_Pin, RESET);
	if(HAL_SPI_Transmit_IT(&hspi1,&cmd,1)!=HAL_OK)
	{
		//fail
	}
	while(HAL_SPI_GetState(&hspi1)!=HAL_SPI_STATE_READY)
	{

	}

	//Send Command Parameter
	HAL_GPIO_WritePin(SPI1_DC_GPIO_Port, SPI1_DC_Pin, SET);
	if(HAL_SPI_Transmit_IT(&hspi1,parameter,param_size)!=HAL_OK)
	{
		//fail
	}
	while(HAL_SPI_GetState(&hspi1)!=HAL_SPI_STATE_READY)
	{

	}

	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, SET);
}

//Set Addresss Pointer
void st7735_set_address(uint8_t col_start, uint8_t col_end, uint8_t row_start, uint8_t row_end)
{
	uint8_t addr_pointer[4]={0};

/** Column Address Set
 * 80x160 해상도에서 80인 부분을 열로 사용한다면 열 주소는 26~105까지
 * 				  160인 부분을 열로 사용한다면 열 주소는 1~160까지
 */
	addr_pointer[1]=col_start;
	addr_pointer[3]=col_end;
	st7735_write_cmd_param(0x2A,addr_pointer,4);

/** Row Address Set
 * 80x160 해상도에서 80인 부분을 행으로 사용한다면 행 주소는 26~105까지
 * 				  160인 부분을 행으로 사용한다면 행 주소는 1~160까지
 */
	addr_pointer[1]=row_start;
	addr_pointer[3]=row_end;
	st7735_write_cmd_param(0x2B,addr_pointer,4);
}

//Initialize ST7735 Driver
void st7735_init(void)
{
	uint8_t cmd_param;

//Sleep Out
	st7735_write_cmd(0x11);
	HAL_Delay(120);

//Display On
	st7735_write_cmd(0x29);

/** MADCTL : Memory Data Access Control
 * D7 D6 D5 D4 D3  D2
 * MY MX MV ML RGB MH
 */
 	//Exchange Column, Row + Mirror Column Address Order + Mirror RGB Order
	cmd_param=0x68;
	st7735_write_cmd_param(0x36,&cmd_param,1);

/** Addresss Set
 * Column Start, Column End, Row Start, Row End
 */
	st7735_set_address(1,160,26,105);

//Display Inversion On
	st7735_write_cmd(0x21);
}

- 인터럽트를 이용해 데이터 전송

- st7735_write_cmd(), st7735_write_cmd_param() 함수를 ST7735에 명령어와 명령어+매개변수를 전송하는 기본 툴로 사용

- Sleep Out -> Display On -> Memory Data Access Control (행열 교환 및 열 방향 반전) -> Address Pointer 설정 (Window) -> Display Inversion On 순서로 ST7735 드라이버 초기화 (데이터 시트에 초기화 과정 없기에 임의 설정)

- 열과 행의 주소는 각각 2 byte의 길이를 가지는데 열과 행의 주소 둘 다 255를 넘어가지 않으므로 명령어 매개변수의 두번째, 네번째 배열에 원하는 주소를 입력해 전송

- st7735_write_cmd(), st7735_write_cmd_param() 함수는 우선적으로 SPI 사용 가능 때까지 while()문을 통해 대기

- SPI가 Ready 상태가 되면 CS(Low, SPI 통신 활성화) -> D/C (Data/Command) -> IT 통해 SPI 통신 개시 -> 통신 완료까지 while()문 사용해 대기 -> CS(High, SPI 통신 비활성화)

<폰트>

- https://github.com/ayoy/fontedit 프로그램을 이용해 폰트 헤더 파일 생성

FontEdit 프로그램 설정 (consolas 10pt 16x26)

 *문자 주소 지정 함수

void st7735_set_address_char(uint8_t col_start, uint8_t row_start)
{
	uint8_t command, addr_pointer[4]={0};

	command=0x2A;
	addr_pointer[1]=1+col_start;
	addr_pointer[3]=col_start+FONT_WIDTH;
	st7735_write_cmd_param(command,addr_pointer,4);

	command=0x2B;
	addr_pointer[1]=row_start+26;
	addr_pointer[3]=row_start+26+FONT_HEIGHT+1;
	st7735_write_cmd_param(command,addr_pointer,4);
}

- 문자 배열이 입력될 Window 주소를 전송하는 함수

- ST7735에 전송할 주소 설정 명령어 매개변수 배열 생성([0],[1]=시작 주소, [2],[3]=마지막 주소)

- 전달받은 열 시작 주소 + 폰트 너비를 열의 마지막 주소

- 전달받은 행 시작 주소 + 폰트 높이를 행의 마지막 주소로 설정

- 열 마지막 주소를 시작 주소 + 폰트 너비로 설정할 경우, 열의 마지막 주소 이후에 어드레스 포인터가 다음 행, 열의 시작 주소로 자동 이동되므로 사용하는 폰트 형태 그대로 디스플레이에 표현됨

- 열 시작 주소의 +1은 MADCTL 명령어를 통해 설정된 화면의 열이 1~160까지의 주소를 갖기 때문이고 행 시작 주소의 +26은 화면의 행이 26~105까지의 주소를 갖기 때문

- st7735_write_cmd_param() 함수를 통해 열 주소 설정 명령어+명령어 매개변수(시작,끝 주소), 행 주소 설정 명령어+명령어 매개변수(시작, 끝 주소)를 전송

 

 *Char, String 전송 함수

#include <malloc.h>
#include "fonts.h"

#define ST7735_WIDTH 160
#define ST7735_HEIGHT 80
#define FONT_WIDTH 16
#define FONT_HEIGHT 26

#define ST7735_COLOR_RED 0xFC0000
#define ST7735_COLOR_GREEN 0x00FC00
#define ST7735_COLOR_BLUE 0x0000FC
#define ST7735_COLOR_BLACK 0x000000

void st7735_write_char(uint8_t chr_ascii, uint32_t color, uint8_t col, uint8_t row)
{
	uint8_t *char_array;
	char_array=malloc(sizeof(uint8_t)*(3*(FONT_WIDTH*FONT_HEIGHT)));
	memset(char_array,0,sizeof(uint8_t)*(3*(FONT_WIDTH*FONT_HEIGHT)));
	uint8_t red,green,blue;

	red=color>>16;
	green=color>>8;
	blue=color;

	for(int j=0;j<(FONT_WIDTH*FONT_HEIGHT/8);j++)
	{
		for(int i=0;i<8;i++)
		{
			if(((consolas_10pt[(chr_ascii-32)*(FONT_WIDTH*FONT_HEIGHT/8)+j])>>(7-i))&0x01)
			{
				char_array[j*24+i*3]=red;
				char_array[j*24+i*3+1]=green;
				char_array[j*24+i*3+2]=blue;
			}
		}
	}

	st7735_set_address_char(col, row);

	//Memory Write
	st7735_write_cmd(0x2C);

	//Send RGB Pixel Data
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, RESET);
	HAL_GPIO_WritePin(SPI1_DC_GPIO_Port, SPI1_DC_Pin, SET);
	if(HAL_SPI_Transmit_DMA(&hspi1,char_array,3*(FONT_WIDTH*FONT_HEIGHT))!=HAL_OK)
	{

	}
}

- 문자 아스키 코드값, 폰트 색상, 열 시작 주소, 행 시작 주소를 전달 받아 사용

- 하나의 문자를 표현하는데 필요한 픽셀 갯수(폰트 가로*세로) *3 (RGB)만큼 malloc 함수를 사용해 메모리 할당

- memset() 함수를 사용해 할당된 메모리를 0으로 초기화

- DMA를 이용해 디스플레이 데이터를 전송하는데 지역 변수를 사용할 경우, DMA를 통한 디스플레이 데이터 전송 도중에 st7735_write_char()가 종료되면서 지역 변수가 소멸되어 쓰레기값이 전송된다

- 따라서 malloc() 함수를 통해 전송할 디스플레이 데이터만큼의 메모리를 할당하고 DMA 전송이 완료된 이후에 free() 함수를 사용해 할당된 메모리를 해제한다

- 사용한 폰트 데이터는 하나의 픽셀이 0,1의 값만을 갖고 있는 형태이므로 한 픽셀에 RGB 3바이트 데이터가 들어있는 형태로 변환해야 한다

- (전달받은 아스키 코드값 - 32) * (폰트 가로 너비 * 폰트 세로 높이 / 8) 식을 통해 폰트 배열의 시작점을 찾는다

(/8은 하나의 폰트는 폰트 가로 너비*폰트 세로 높이 만큼의 픽셀을 가지고 있으면서 1 바이트 단위로 구성된 배열을 가지고 있기 때문 (1pixel=1bit), ex)16*26 픽셀을 사용하는 폰트는 416 픽셀을 사용하고 이는 52byte 데이터로 저장된다)

- 정의된 매크로 색상은 24bit로 MSB부터 8bit씩 Red, Green, Blue 색상 데이터를 나타낸다

- 전달받은 색상을 비트 시프트를 이용해 uint8_t red, green, blue 변수에 각각 저장한 뒤 픽셀의 RGB값을 입력하는데 사용한다

- 폰트 배열을 1 byte 단위로 MSB부터 비트 시프트를 사용해 픽셀이 유효한지 확인하고 유효한 데이터(1)을 가지고 있을 경우 전달 받은 색상을 앞서 malloc() 함수를 통해 할당된 메모리에 RGB 각 1바이트씩 순차적으로 저장해 나간다

(하나의 픽셀이 RGB 3byte 데이터를 가지므로 폰트 1픽셀 데이터 -> ST7735 1픽셀 RGB 3byte 데이터)

- 1 byte에 대한 분석이 끝나면 폰트 배열 주소를 1(1byte) 증가 시킨 뒤 분석 및 RGB 변환 저장 과정 반복

- RGB 데이터 저장 완료 이후에 전달받은 col, row 값을 사용해 문자가 입력될 주소 지정

- ST7735 디스플레이 데이터 램에 데이터를 전송하기 위해 Memory Write (0x2C) 명령어를 전송 (필수)

- CS(Low), D/C(High(Data))로 설정한 뒤 DMA를 이용해 디스플레이 데이터 전송

(마지막에 CS(High) 설정 코드를 넣을 경우, DMA 전송 중에 CS핀이 High가 되어 통신이 중단된다)

 

 *문자열 전송 함수

void st7735_write_string(char *string, uint32_t font_color, uint8_t col_start, uint8_t row_start)
{
	while(*string)
	{
		st7735_write_char(*string,font_color,col_start,row_start);

		if(col_start < 160-FONT_WIDTH)
		{
			col_start+=FONT_WIDTH;
			string++;
		}
		else
		{
			break;
		}
	}
}

- 전달받은 문자열의 첫번째 문자부터 순차적으로 하나씩 st7735_write_char() 함수에 전달

- 매 전송 이후, 폰트 가로 너비만큼 열 주소를 증가

- 열의 남은 공간이 폰트의 가로 너비 보다 작을 경우 전송 중단

(필요한 경우 else 란에 row_start+폰트 높이, col_start=0 을 입력해 다음 행의 0번째 열부터 나머지 문자가 출력되게끔 설정)

 

 *stm32wbxx_it.c

stm32wbxx_it.c 위치 (CUBEMX 기준)

void DMA1_Channel1_IRQHandler(void)
{
  /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */

  /* USER CODE END DMA1_Channel1_IRQn 0 */
  HAL_DMA_IRQHandler(&hdma_spi1_tx);
  /* USER CODE BEGIN DMA1_Channel1_IRQn 1 */
  
  if(HAL_DMA_GetState(&hdma_spi1_tx)==HAL_DMA_STATE_READY)
  {
	  HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, SET);
	  free(hspi1.pTxBuffPtr);
  }
  
  /* USER CODE END DMA1_Channel1_IRQn 1 */
}

- stm32wbxx_it.c 소스 파일에 위치한 DMA 인터럽트 핸들러

- 사용한 SPI의 TX에 할당한 DMA 채널을 찾아 코드 입력

- DMA를 통한 전송이 완료되어 DMA 채널이 Ready 상태라면 CS 핀을 High (SPI 통신 비활성화)로 설정하고 전송에 사용된 디스플레이 데이터의 메모리 할당을 해제함

 

 *활용 예

void st7735_fill_screen(uint32_t color)
{
	while(HAL_SPI_GetState(&hspi1)!=HAL_SPI_STATE_READY)
	{

	}
	uint8_t *display_buffer;
	display_buffer=malloc(sizeof(uint8_t)*(3*ST7735_WIDTH*ST7735_HEIGHT));
	memset(display_buffer,0,sizeof(uint8_t)*(3*ST7735_WIDTH*ST7735_HEIGHT));

	for(int i=0; i<ST7735_WIDTH*ST7735_HEIGHT; i++)
	{
		display_buffer[i*3]=color>>16;
		display_buffer[i*3+1]=color>>8;
		display_buffer[i*3+2]=color;
	}

	st7735_set_address(1,160,26,105);

	//Memory Write
	st7735_write_cmd(0x2C);

	//Display data transfer
	HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, RESET);
	HAL_GPIO_WritePin(SPI1_DC_GPIO_Port, SPI1_DC_Pin, SET);

	if(HAL_SPI_Transmit_DMA(&hspi1,display_buffer,3*ST7735_WIDTH*ST7735_HEIGHT)!=HAL_OK)
	{

	}
}

void st7735_example(void)
{
	uint8_t st_col=0, st_row=0;

	st7735_fill_screen(ST7735_COLOR_BLACK);
	HAL_Delay(1000);
	st7735_fill_screen(ST7735_COLOR_RED);
	HAL_Delay(1000);
	st7735_fill_screen(ST7735_COLOR_GREEN);
	HAL_Delay(1000);
	st7735_fill_screen(ST7735_COLOR_BLUE);
	HAL_Delay(1000);
	st7735_fill_screen(ST7735_COLOR_BLACK);
	HAL_Delay(1000);

	st7735_write_string("Hello",ST7735_COLOR_RED,0,0);
	HAL_Delay(1000);
	st7735_write_string("Hello",ST7735_COLOR_GREEN,0,FONT_HEIGHT);
	HAL_Delay(1000);
	st7735_write_string("Hello",ST7735_COLOR_BLUE,0,FONT_HEIGHT*2);
	HAL_Delay(1000);
    
	char font_test=' ';
	for(int i=' ';i<='~';i++)
	{
	  st7735_write_char(font_test,ST7735_COLOR_RED,st_col,st_row);
	  font_test++;
	  HAL_Delay(100);
	  st_col+=FONT_WIDTH;
	  if(160<=st_col)
	  {
		  st_col=0;
		  if(st_row<52)
		  {
			  st_row+=FONT_HEIGHT;
		  }
		  else
		  {
			  st_row=0;
		  }
	  }
	}
	font_test=' ';
	for(int i=' ';i<='~';i++)
	{
	  st7735_write_char(font_test,ST7735_COLOR_GREEN,st_col,st_row);
	  font_test++;
	  HAL_Delay(100);
	  st_col+=FONT_WIDTH;
	  if(160<=st_col)
	  {
		  st_col=0;
		  if(st_row<52)
		  {
			  st_row+=FONT_HEIGHT;
		  }
		  else
		  {
			  st_row=0;
		  }
	  }
	}
	font_test=' ';
	for(int i=' ';i<='~';i++)
	{
	  st7735_write_char(font_test,ST7735_COLOR_BLUE,st_col,st_row);
	  font_test++;
	  HAL_Delay(100);
	  st_col+=FONT_WIDTH;
	  if(160<=st_col)
	  {
		  st_col=0;
		  if(st_row<52)
		  {
			  st_row+=FONT_HEIGHT;
		  }
		  else
		  {
			  st_row=0;
		  }
	  }
	}
}

- 1초 간격으로 화면 전체를 검은색 -> 빨간색 -> 초록색 -> 파란색 -> 검은색으로 채움

- (0,0)부터 "Hello" 문자열 빨간색 폰트 출력

- 1초 딜레이 이후, (0, 폰트 높이 (=26))부터 "Hello" 문자열 초록색으로 출력

- 1초 딜레이 이후, (0, 폰트 높이*2 (=52))부터 "Hello" 문자열 초록색으로 출력

- 화면의 (0, 0)부터 32번째 아스키 코드인 ' '(Space)부터 126번째 '~'까지 100ms 간격, 빨간색 폰트로 연속 출력

- 이후 초록색, 파란색 순서로 위의 과정 반복

 

 

+ Recent posts