본문 바로가기

임베디드(embedded)/모듈 디바이스 드라이버

PC1602A (text lcd) 디바이스 드라이버 (device driver)

#include <linux/module.h>

#include <linux/kernel.h>

#include <linux/types.h>

#include <asm/io.h>

#include <linux/delay.h>

 

#define GPIO_BASE      0xE0200000 // GPIO의 기본 물리주소

#define DB_CONF        (0xC00/4) // DB로 사용할 핀을 설정하기위한 레지스터 주소

#define DB_DAT         (0xC04/4) // DB로 사용할 핀에 데이터를 넣기위한 레지스터 주소

#define CTRL_CONF      (0xC20/4) // LCD 제어를 위한 핀을 설정하기위한 레지스터 주소

#define CTRL_DAT       (0xC24/4) // LCD 제어를 위한 핀에 데이터를 넣기위한 레지스터 주소

 

#define RS     0 // RS로 사용할 핀의 인덱스

#define RW     1 // RW로사용할 핀의 인덱스

#define EN     3 // EN으로 사용할 핀의 인덱스

 

#define DB4    0 // LCD DB4핀에 연결될 핀의 인덱스

#define DB5    1 // LCD DB5핀에 연결될 핀의 인덱스

#define DB6    2 // LCD DB6핀에 연결될 핀의 인덱스

#define DB7    3 // LCD DB7핀에 연결될 핀의 인덱스

 

#define MD     20 // LCD 제어시 필요한 delay

 

static volatile u32 *gpio_base = 0x0;

 

static void gpio_data( int, int, int); // 레지스터에 데이터를 넘겨주는 함수

static void gpio_config( int, int, int); // 레지스터 출력설정을 위한 함수

void textlcd_set( int); // LCD 모듈에 명령어를 전달하기위한 함수

void textlcd_init( void); // LCD 모듈 초기화를 위한 함수

void textlcd_write( char); // LCD 모듈에 문자를 넘겨주는 함수

void output_message( char *); // 사용자로부터 출력할문자열을 넘겨받는 함수

void gpio_init( void); // 각 핀들의 초기설정을 위한 함수


/*

모듈이 커널에 적재될 때 수행되는 함수로 초기화 작업을 한다.


- 메모리 매핑과 기본적인 핀설정, lcd 초기화, 메시지출력 함수를 호출한다.

*/

int module_start( void)

{

        printk( "TEXT LCD device driver on!\n");

 

        gpio_base = (u32 *)ioremap( GPIO_BASE, PAGE_SIZE);

 

        gpio_init();

 

        textlcd_init();

 

        output_message("I CAN DO\nEVERYTHING!");

 

        return 0;

}

/*

모듈이 커널에서 제거될 때 수행되는 함수로 마무리 작업을 한다.

- 메모리 매핑 해제를 한다.

*/

void module_end( void)

{

        if( gpio_base)

        {

               printk("upmapping address!\n");

               iounmap( (void*)gpio_base);

        }

 

        printk("TEXT LCD devier driver off!\n");

}


/*

사용할 핀들의 초기설정(output)을 해주는 함수이다.


- 모든 핀들을 output으로 설정한다.

*/

void gpio_init( void)

{

        gpio_config( CTRL_CONF, RS, 1);

        gpio_config( CTRL_CONF, RW, 1);

        gpio_config( CTRL_CONF, EN, 1);

 

        gpio_config( DB_CONF, DB4, 1);

        gpio_config( DB_CONF, DB5, 1);

        gpio_config( DB_CONF, DB6, 1);

        gpio_config( DB_CONF, DB7, 1);

}


/*

입력받은 메시지를 LCD에 출력하는 함수이다.


- 한 글자씩 LCD로 전송해서 출력이 되게한다.

*/

void output_message( char *msg)

{

        int c = 0;

        int flag = 0;

 

        textlcd_set( 0x80);

 

        for( c = 0 ; c < strlen(msg) ; c ++)

        {

               if( (msg[c] == '\n' || c == 16) && flag == 0)

               {

                       textlcd_set( 0xC0);

 

                       flag = 1;

                      

                       if( msg[c] == '\n')

                              continue;

               }

 

               textlcd_write( msg[c]);

        }

}

 

/*

gpio의 data register 값을 설정해주는 함수이다.

- 넘겨받은 pin의 위치와 값을 설정해준다.

- data register는 핀 당 1bit의 크기를 가진다.

*/

static void gpio_data( int gpio, int bit, int value)

{

        u32 data = 0x0;

 

        data = gpio_base[gpio];

 

        data &= ~(1 << bit);

 

        data |= (value << bit);

 

        gpio_base[gpio] = data;

}


/*

gpio의 config register 값을 설정해주는 함수이다.


- 넘겨받은 pin의 위치와 값을 설정해준다.

- config register는 핀 당 4bit의 크기를 가진다.

*/

static void gpio_config( int gpio, int bit, int value)

{

        u32 data = 0x0;

 

        data = gpio_base[gpio];

 

        data &= (~(0xF << (bit * 4)));

 

        data |= (value << (bit * 4));

 

        gpio_base[gpio] = data;

}

 

/*

text lcd에 문자를 출력하는 함수이다.

- 인자 값으로받은 한 글자의 메시지를 출력한다.

- 8bit 값의 데이터를 전송할 때는 상위 4니블을 전송하고, 하위4 니블을 전송한다.

*/

void textlcd_write( char dat)

{

        gpio_data(CTRL_DAT, RS, 1);

        gpio_data(CTRL_DAT, RW, 0);

 

        mdelay(MD);

 

        gpio_data(CTRL_DAT, EN, 1);

 

        mdelay(MD);

 

        gpio_base[DB_DAT] = (dat >> 4) & 0x0f;              

       

        gpio_data(CTRL_DAT, EN, 0);

 

        mdelay(MD);

 

        gpio_data(CTRL_DAT, EN, 1);

 

        mdelay(MD);

 

        gpio_base[DB_DAT] = dat & 0x0f;             

 

        gpio_data(CTRL_DAT, EN, 0);

}


/* 

text lcd의 초기화 작업을 하는 함수이다.


- 레퍼런스를 참조하여 초기화 작업을 수행한다.

- 4bit interface로 동작되게 설정한다.

*/

void textlcd_init( void)

{

        int c = 0;

 

        mdelay(MD);

 

        for( c = 0 ; c < 3 ; c ++)

        {

               gpio_data( CTRL_DAT, RS, 0);

               gpio_data( CTRL_DAT, RW, 0);

 

               mdelay(MD);

 

               gpio_data( CTRL_DAT, EN, 1);

 

               mdelay(MD);

 

               gpio_base[DB_DAT] = 0x3;

 

               gpio_data( CTRL_DAT, EN, 0);

 

               mdelay(MD);

 

        }

 

        mdelay(MD);

 

        gpio_data( CTRL_DAT, EN, 1);

 

        mdelay(MD);

 

        gpio_base[DB_DAT] = 0x2;

 

        gpio_data( CTRL_DAT, EN, 0);

 

        mdelay(MD);

 

        textlcd_set( 0x28);

        textlcd_set( 0x08);

        textlcd_set( 0x01);

        textlcd_set( 0x06);

        textlcd_set( 0x0F);

}

 

/*

text lcd에 명령을 전송하는 함수이다.


- 4bit의 interface 이기 때문에 8bit 명령을 넘겨 받으면 상위4 니블 전송 후,

- 하위4 니블을 마저 전송한다.

*/

void textlcd_set( int data)

{

       

        gpio_data( CTRL_DAT, RS, 0);

        gpio_data( CTRL_DAT, RW, 0);

 

        mdelay(MD);

 

        gpio_data( CTRL_DAT, EN, 1);

 

        mdelay(MD);

 

        gpio_base[DB_DAT] = (data >> 4) & 0x0f;

 

        gpio_data( CTRL_DAT, EN, 0);

 

        mdelay(MD);

 

        gpio_data( CTRL_DAT, EN, 1);

 

        mdelay(MD);

 

        gpio_base[DB_DAT] = data & 0x0f;

 

        gpio_data( CTRL_DAT, EN, 0);

 

        mdelay(MD);

}

 

module_init( module_start);

module_exit( module_end);

 

MODULE_LICENSE("GPL");