본문 바로가기
Embedded System

[Lecture 11] LCD

by Hangii 2022. 12. 5.

128x128 pixel LCD

- LCD 한 픽셀의 색을 표현하기 위해서는 R,G,B 각각 8bit씩으로 이루어진 총 24bit의 sequence를 사용한다.

  • 그래서 당연하게도 R,G,B 각각에 쓰이는 bit 수를 늘리면 표현할 수 있는 색상의 범위가 넓어진다. 그치만 다채로운 색상을 표현하기 위해서는 소프트웨어 상에서 bit를 늘림과 함께 디스플레이 상에서 그만큼 다양한 색이 표현가능한 하드웨어를 사용해야 한다. 그렇지 않으면 아무리 다양한 색을 출력하는 코드를 작성해도 하드웨어적으로 표현되지 않게 된다.

- 보통 LCD와 같이 복잡한 디바이스를 사용하는 경우에는 코드에 initialization, graphic library, driver 등에 대한 설정이 필요하다. 레퍼런스 메뉴얼이 주어지는 경우 이를 따라서 구현하면 된다. 다행히도 대부분의 경우 embedded board를 구매하면 레퍼런스 코드가 공개되어 있다. 이 샘플 코드를 기반으로 리팩토링해서 원하는 결과를 구현하면 된다. 

 

- Bitmap Font Internals

  • LCD에 원하는 글자를 출력하려면 원하는 pixel에 특정 색을 설정하면 된다. 내가 사용한 보드는 6x8 pixel을 사용해 하나의 글자를 나타낸다. 이때 각 픽셀의 색을 변경할지 말지에 대한 정보를 bit단위로 전달한다. 
    • 예를 들어, 'A'라는 글자를 출력하고 싶으면, 8bit 수 6개를 사용해 색칠할 픽셀을 설정할 수 있다. 
    • A를 표현하기 위해 114, 40, 162, 250, 40, 128 총 6개의 10진수가 주어졌다고 하자. 이를 8bit 2진수로 바꾸면 아래 사진과 같이 나타낼 수 있다.  ->근데 갑자기 10진수를 왜 준거지..?그냥 예시를 들기 위해서인가?
    • 6x8 pixel의 왼쪽 상단부터 8bit 값들을 차례대로 채워 나간 후 1인 픽셀만 색칠하면 A가 보인다.

 

- Color Data

  • 앞에서도 설명했듯이 하나의 pixel은 24bit를 이용하기 떄문에 총 2^24가지 색을 표현한다.
  • R, G, B값이 각각 8bit로 표현되므로 32bit unsigned integer를 사용한다면 MSB부터 첫 8bit는 비우고, 다음 8bit에는 R값을, 그 다음 8bit에는 G, 그 다음엔 B값을 채우면 된다.
  • Graphic library header에 자주 사용하는 색상들의 hexadecimal 값이 사전 정의되어있다. (16진수니까 숫자 8개로 RGB값이 표현되어있다.)
    • 검정색: R,G,B에 모두 0 (0x00000000)
    • 흰색: R,G,B에 모두 F (0x00FFFFFF)
    • 파란색: R,G에 0, B에 F (0x000000FF)

- main() Template for TI Grlib

/*Graphic Library Context*/
Graphics_Context g_sContext;
  • 그래픽 라이브러리에서는 Graphic Library Context라는 것이 사용된다. Context란 현재 graphic library의 state를 표현하는 state diagram이다. 이는 현재 수행해야할 명령을 알려주는 매체 역할을 한다.
/*Initializes display*/
Crystalfontz128x128_Init();
  • LCD driver를 초기화한다. 
/*Set default screen orientation*/
Crystalfontz128x128_SetOrientation(LCD_ORIENTATION_UP);
  • LCD에서 글씨를 쓸 방향을 설정한다. LCD_ORIENTATION_LEFT, LCD_ORIENTATION_DOWN, LCD_ORIENTATION_RIGHT도 존재한다.
/*Initializes graphic context*/
Graphics_initContext(&g_sContext, &g_sCrystalfontz128x128, &g_sCrystalfontz128x128_funcs);
  • 그래픽 라이브러리를 초기화한다.
/*background 위에 쓰일 글씨 색 설정*/
Graphics_setForegroundColor(&g_sContext, GRAPHICS_COLOR_RED);

/*background 색 설정*/
Graphics_setBackgroundColor(&g_sContext, GRAPHICS_COLOR_WHITE);

/*6x8 font size를 사용해 글자 표현*/
GrContextFontSet(&g_sContext, &g_sFontFixed6x8);

/*앞에서 설정한대로 스크린을 fill*/
Graphics_clearDisplay(&g_sContext);

/*표현하고자 하는 글자의 모든 pixel값을 계산하는 것은 매우 비효율적이므로 API사용*/
/*string: 표현하고자 하는 글자 입력*/
/*ILength: string을 표현하는 데 할당할 공간의 크기. AUTO_STRING_LENGTH의 경우 입력한 string의 크기만큼 공간을 자동 할당함.*/
/*x, y 좌표: 시작 위치 설정*/
/*Opaque: 덮어쓰기 유무 설정. OPAQUE_TEXT: 배경 글자를 지우고 씀, TRANSPARENT_TEXT: 배경 글자 그대로 두고 위에 덮어씀*/
Graphics_drawString(&g_sContext,
								(int8_t *)"Hello World!",
                                AUTO_STRING_LENGTH,
                                12,
                                24,
                                OPAQUE_TEXT);

- Driver

  • 임베디드 시스템의 input과 output은 모두 하드웨어적으로 구성되어 있다. Driver란 하드웨어를 컨트롤하기 위한 코드이다.
  • OS가 있는 경우, shared library 내의 여러 개의 application code를 통해 hardware interface를 저장해두고 이를 사용해 driver를 관리한다. 
    • 이는 protection & security 면에서 유리하다.

- File Abstraction

  • What do you do with a device?
    • read, write
    • read only
    • write only
  • Lets look at some examples
    • USB device, CD-ROM, LED Display, etc, ...
  • What do you do with a file?
    • open, close, read, write, ...
  • .File is an excellent abstraction for devices
    • 어떤 device든간에 file처럼 처리하면 관리하기 편하다.

- 현재 embedded device에서는 memory-mapped I/O를 사용하고 있다. 특정 메모리 공간에 I/O가 연결되어 있고, 그 공간에 접근해서 값을 쓰게 되면 control하고자 하는 값이 register에 써진다. 반대로 값을 읽어오려는 경우 메모리 상의 I/O device에 적힌 값을 읽어오면 된다.

  • 임베디드 시스템에서는 OS를 거치지 않고 application process에서 driver에 바로 접근함을 알 수 있다.

- Push Buttons

  • button S1: P5.1
  • button S2: P3.5
  • Programming S1 & S2 Buttons
    • Initialization Code
/*pin #3의 port #5를 input으로 사용*/
P3->DIR &= ~BIT5; 
/*pin #5의 port #1을 input으로 사용*/
P5->DIR &= ~BIT1;

/*enable pull-up or pull-down*/
P3->REN |= BIT5;
P5->REN |= BIT1;

/*enable pull-up*/
P3->OUT |= BIT5;
P5->OUT |= BIT1;
    • Button Checking Code
/*Determine if S1 or S2 button in boostxl-edumkii is pressed*/
if(!(P5->IN & BIT1))
	//BS1이 pressed되었을 경우 실행할 코드
else
	//BS1 not pressed
if(!(P3->IN & BIT5))
	//BS2 pressed
else
	//BS2 not pressed

- 예제

  • LCD의 정중앙에 '*'를 표시하고 싶다면?
    • 앞서 우리가 LCD위에 나타내는 모든 것들은 6x8 pixel단위로 표현하기로 결정했다. 그런데 LCD는 128x128 pixel로 이루어졌으므로 버튼을 눌러서 이동할 수 있는 칸의 수는 다음과 같다:
      • 세로(columns): 128(px)/6 = 21(칸)
      • 가로(rows): 128(px)/8 = 16(칸)
    • 따라서 정중앙의 좌표는 x = 21(칸)/2 = 10.5(칸), y = 16(칸)/2 =8(칸)
#include <ti/devices/msp432p4xx/inc/msp.h>
#include <ti/devices/msp432p4xx/driverlib/driverlib.h>
#include <ti/grlib/grlib.h>
#include "LcdDriver/Crystalfontz128x128_ST7735.h"
#include "LcdDriver/msp432p4111_classic.h"

/* Graphic library context */
Graphics_Context g_sContext;

/*
 * Main function
 */

#define INIT -1
#define DOWN 0
#define UP 1
#define TH 100000

void main(void)
{
    int x=10, y=8;
    int bs1state=INIT;
    int bs1count=0;

    /* Initializes display */
    Crystalfontz128x128_Init();

    /* Set default screen orientation */
    Crystalfontz128x128_SetOrientation(LCD_ORIENTATION_UP);

    /* Initializes graphics context */
    Graphics_initContext(&g_sContext, &g_sCrystalfontz128x128, &g_sCrystalfontz128x128_funcs);
    Graphics_setForegroundColor(&g_sContext, GRAPHICS_COLOR_RED);
    Graphics_setBackgroundColor(&g_sContext, GRAPHICS_COLOR_WHITE);
    GrContextFontSet(&g_sContext, &g_sFontFixed6x8);
    Graphics_clearDisplay(&g_sContext);

    /* Configuring S1 & S2 buttons in boostxl-edumkii */
    P3->DIR &= ~BIT5;
    P5->DIR &= ~BIT1;
    P3->REN |= BIT5;
    P5->REN |= BIT1;
    P3->OUT |= BIT5;
    P5->OUT |= BIT1;

    Graphics_drawString(&g_sContext, (int8_t *)"*", 1, x*6, y*7, OPAQUE_TEXT);

    while(1)
    {
        if (!(P5->IN & BIT1)) {
        /*버튼을 계속 누르고 있으면 if문의 bs1count값이 늘어난다. 그러다가 TH값인 10만에 도달하면 if문 내부를 실행하게 된다. if문 내부에서 bs1count값은 다시 0으로 리셋된다.*/
            if ((++bs1count) == TH) { 
                bs1count=0;
                Graphics_drawString(&g_sContext, (int8_t *)" ", 1, x*6, y*7, OPAQUE_TEXT);
                if (y>0) y--;
                Graphics_drawString(&g_sContext, (int8_t *)"*", 1, x*6, y*7, OPAQUE_TEXT);
            }
            bs1state=DOWN;
        }
        /*버튼을 눌렀다 뗀 경우*/
        else if (P5->IN & BIT1){
            if (bs1state==DOWN) {
                bs1count=0;
               Graphics_drawString(&g_sContext, (int8_t *)" ", 1, x*6, y*7, OPAQUE_TEXT);
               if (y>0) y--;
               Graphics_drawString(&g_sContext, (int8_t *)"*", 1, x*6, y*7, OPAQUE_TEXT);
               bs1state=UP;
            }
        }
    }
}

 

'Embedded System' 카테고리의 다른 글

[Lecture 12] Joystick  (0) 2022.12.06
[Lab 10]  (0) 2022.12.05

댓글