From 33527707ba626d7aae6e643288eae5da2d05372e Mon Sep 17 00:00:00 2001 From: matheusnascimentoti99 Date: Mon, 24 Feb 2020 21:42:53 -0300 Subject: [PATCH] UPDATE --- Makefile | 18 ++ Module.symvers | 0 PBL.S | 219 ++++++++++++++++ README.md | 24 +- app_test | Bin 0 -> 13696 bytes app_test.c | 248 +++++++++++++++++++ app_test.o | Bin 0 -> 5276 bytes lcd_driver.c | 630 +++++++++++++++++++++++++++++++++++++++++++++++ lcd_driver.h | 129 ++++++++++ lcd_driver.ko | Bin 0 -> 14788 bytes lcd_driver.mod.c | 64 +++++ lcd_driver.mod.o | Bin 0 -> 4000 bytes lcd_driver.o | Bin 0 -> 12776 bytes lcd_lib.c | 123 +++++++++ lcd_lib.h | 149 +++++++++++ lcd_lib.o | Bin 0 -> 2904 bytes modules.order | 1 + pbl | Bin 0 -> 8788 bytes pbl.o | Bin 0 -> 2404 bytes running_test.c | 54 ++++ 20 files changed, 1658 insertions(+), 1 deletion(-) create mode 100644 Makefile create mode 100644 Module.symvers create mode 100644 PBL.S create mode 100755 app_test create mode 100644 app_test.c create mode 100644 app_test.o create mode 100644 lcd_driver.c create mode 100644 lcd_driver.h create mode 100644 lcd_driver.ko create mode 100644 lcd_driver.mod.c create mode 100644 lcd_driver.mod.o create mode 100644 lcd_driver.o create mode 100644 lcd_lib.c create mode 100644 lcd_lib.h create mode 100644 lcd_lib.o create mode 100644 modules.order create mode 100755 pbl create mode 100644 pbl.o create mode 100644 running_test.c diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..f533ade --- /dev/null +++ b/Makefile @@ -0,0 +1,18 @@ +EXTRA_CFLAGS = -Wall +KDIR = /lib/modules/`uname -r`/build +obj-m = lcd_driver.o +all: ko app_test + +ko: + make -C $(KDIR) M=`pwd` + +app_test: app_test.o lcd_lib.o + gcc -o app_test app_test.o lcd_lib.o + +app_test.o: app_test.c + gcc -c app_test.c +lcd_lib.o: lcd_lib.c lcd_lib.h + gcc -c lcd_lib.c +clean: + make -C $(KDIR) M=`pwd` clean + rm app_test diff --git a/Module.symvers b/Module.symvers new file mode 100644 index 0000000..e69de29 diff --git a/PBL.S b/PBL.S new file mode 100644 index 0000000..b9e950e --- /dev/null +++ b/PBL.S @@ -0,0 +1,219 @@ +.data + + + filepath: .asciz "/dev/lcd_1602" + r: .ascii "r" + a: .ascii "a" + i: .ascii "i" + e: .ascii "e" + l: .ascii "l" + p: .ascii "p" + u: .ascii "u" + c: .ascii "c" + n: .ascii "n" + P: .ascii "P" + person: .ascii "¥" + bloco: .ascii "#" + excl: .ascii "!" + esp: .ascii " " + + @my struct + .align 4 + x: .word 2 + y: .word 1 + cenario: .word 0,0,1,1,0,0,0,1,1,1,0,0,1,1,1,1 + .equ count, 80000000 + +.text +.global main + +main: + LDR r11,=count + BL clear + BL gameplay + LDR R1,=i + MOV R7, #4 + MOV R0, #1 + MOV R2, #12 + SWI 0 + B end +gameplay: + BL set_position_DOWN + LDR R10, =cenario + MOV R3,#16 + B moveCen + +moveCen: + CMP R3, #0 + BEQ movingOn + LDR R6, [R10, #0] + CMP R6, #0 + BEQ adsEsp @ Se for 0 escreve espaço + B adsBlo + +adsEsp: + LDR R9,=esp + BL write + ADD R10, R10, #4 + SUB R3, R3, #1 + B moveCen + +adsBlo: + LDR R9,=bloco + BL write + ADD R10, R10, #4 + SUB R3, R3, #1 + B moveCen + +movingOn: + LDR r10,=cenario @ Move a base do vetor para o registrador r9 + MOV R3, #16 + B moving @ O objetivo dele é colocar a primeira posição do vetor para a ultima sem comprometer a ordem do array + +moving: + CMP R3, #0 + BEQ delay @ Se r2 for igual a 0 o processo vai para o delay + BL swap + ADD R10, R10, #4 @ Vai para a proxima posição do array "r9[i] = r9[i+1]" + B moving + +swap: @ Ele troca a primeira posição para a segunda posição + LDR R6, [R10, #0] + LDR R7, [R10, #4] + STR R7, [R10, #0] + STR R6, [R10, #4] + SUB R3, R3, #1 + LDR R1,=i + MOV R7, #4 + MOV R0, #1 + MOV R2, #1 + SWI 0 + BX LR + +delay: + SUB r11, r11, #1 + CMP r11, #0 + BNE delay + LDR r11,=count + B gameplay + + +end: + B end + +write: + SUB sp, sp, #8 + STR lr, [sp] + BL open + MOV R7, #54 @IOCTL + MOV R1, #4 @put flag + MOV R2,R9 @Valor deve ser atribuido antes da chamada da função + SWI 0 + BL close + LDR LR, [sp] + ADD sp, sp, #8 + BX LR + +set_position_DOWN: + SUB sp, sp, #8 + STR lr, [sp] + BL open + MOV R7, #54 @IOCTL + MOV R1, #10 + LDR R2,=x + SWI 0 + LDR LR, [sp] + ADD sp, sp, #8 + BX LR + +set_position_UP: + SUB sp, sp, #8 + STR lr, [sp] + BL open + MOV R7, #54 @IOCTL + MOV R1, #10 + LDR R2,=y + SWI 0 + LDR LR, [sp] + ADD sp, sp, #8 + BX LR + +open: + MOV R7, #5 @ função open + LDR R0, =filepath @ file pointer + MOV R1, #0 @Permissão de adm + MOV R2, #00700 @flag + SWI 0 + BX LR + +close: + + MOV R0, R9 + MOV R7, #6 + SWI 0 @Close + BX LR + +clear: + SUB sp, sp, #8 + STR LR, [sp] + BL open + MOV R7, #54 @IOCTL + MOV R1, #1 @clear flag + SWI 0 + BL close + LDR LR, [sp] + ADD sp, sp, #8 + BX LR + +home_title: + SUB sp, sp, #8 + STR LR, [sp] + LDR R9,=esp + BL write + BL write + BL write + LDR R9,=P + BL write + LDR R9,=u + BL write + LDR R9,=l + BL write + LDR R9,=e + BL write + + LDR R9,=esp + BL write + LDR R9,=p + BL write + LDR R9,=a + BL write + LDR R9,=r + BL write + LDR R9,=a + BL write + BL set_position_DOWN + LDR R9,=esp + BL write + BL write + BL write + BL write + LDR R9,=i + BL write + LDR R9,=n + BL write + LDR R9,=i + BL write + LDR R9,=c + BL write + LDR R9,=i + BL write + LDR R9,=a + BL write + LDR R9,=r + BL write + LDR R9,=excl + BL write + LDR LR, [sp] + ADD sp, sp, #8 + BX LR + diff --git a/README.md b/README.md index c690af7..819636c 100644 --- a/README.md +++ b/README.md @@ -1 +1,23 @@ -# JumpGameSBC \ No newline at end of file +# LCD16x2_Driver + +This is a kernel level Linux Device driver to control a 16x2 character LCD (with HD44780 LCD controller) with 4 bit mode. + + - Provide API for app in userspace to comminicate with LCD + - The LCD is interfaced with a micro-controller using GPIO pins. + - Driver is written on the Raspberry Pi 3 B, the kernel version 4.19.75-v7+ + +# List of APIs + +| Function | Description | +| ------ | ------ | +| __void _lcd_init_(void)__ | __Init LCD, set default configure (display + cursor + blink on)__ | +| __void _lcd_clear_display_(void)__ | __Clear display and set cursor to home position__ | +| __void _lcd_put_char_(char c)__ | __Display character at current cursor position__ | +| __void _lcd_put_string_(const char *s)__ | __Display string at current cursor position__ | +| __void _lcd_put_string_super_(const char *s)__ | __Clear display and display on 2 line if string length > 16__ | +| __void _lcd_goto_xy_(unsigned char x, unsigned char y)__ | __Set cursor to specified position__ | +| __void _lcd_scroll_left_(void)__ | __scroll text to left__ | +| __void _lcd_scroll_right_(void)__ | __scroll 2 line text to right__ | +| __void _lcd_set_display_(unsigned char display, unsigned char cursor, unsigned char blink)__ | __Set cursor to home position__ | +| __void _lcd_upload_custom_char_(unsigned char location, unsigned char *charmap)__ | __Upload data for custom char to CGRAM__ | +| __void _lcd_set_auto_scroll_(unsigned char status)__ | __Set enable or disable auto move all the text one space to the left each time a letter is added__ | diff --git a/app_test b/app_test new file mode 100755 index 0000000000000000000000000000000000000000..f80cf3ac81dfaca471bce65cfb2fff98cf8f0bd6 GIT binary patch literal 13696 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 E7qeV54*&oF literal 0 HcmV?d00001 diff --git a/app_test.c b/app_test.c new file mode 100644 index 0000000..df1edb7 --- /dev/null +++ b/app_test.c @@ -0,0 +1,248 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "lcd_lib.h" +#define BUFFER_SIZE 50 + +/**************************Define Custom Character***********************/ + +unsigned char type0[8] = { /* Arrow Up */ + 0x04, + 0x0E, + 0x15, + 0x04, + 0x04, + 0x04, + 0x04, + 0x00 +}; +unsigned char type1[8] = { /* Face */ + 0x1F, + 0x15, + 0x15, + 0x1F, + 0x11, + 0x0A, + 0x04, + 0x00 +}; +unsigned char type2[8] = { /* Heart*/ + 0x00, + 0x0A, + 0x1F, + 0x1F, + 0x0E, + 0x04, + 0x00, + 0x00 +}; + +unsigned char type3[8] = { /* Music*/ + 0x01, + 0x03, + 0x05, + 0x09, + 0x0B, + 0x0B, + 0x18, + 0x18 +}; +unsigned char type4[8] = { /* Arrow down */ + 0x04, + 0x04, + 0x04, + 0x04, + 0x15, + 0x0E, + 0x04, + 0x00 +}; +unsigned char type5[8] = { /* Smile */ + 0x00, + 0x00, + 0x0A, + 0x00, + 0x11, + 0x0E, + 0x00, + 0x00 +}; +unsigned char type6[8] = { /* Sad*/ + 0x00, + 0x00, + 0x0A, + 0x00, + 0x0E, + 0x11, + 0x00, + 0x00 +}; + +unsigned char type7[8] = { /* Bell*/ + 0x00, + 0x04, + 0x0E, + 0x0E, + 0x1F, + 0x1F, + 0x04, + 0x00 +}; +unsigned char *type[8] = {type0, type1,type2,type3,type4,type5, type6, type7}; + +/*Ham kiem tra entry point write cua vchar driver*/ +void write_data_chardev() +{ + char user_buf[BUFFER_SIZE]; + printf("\nEnter your message: "); + scanf(" %[^\n]s", user_buf); + lcd_put_string_super(user_buf); +} + +void goto_xy(void) +{ + unsigned int x, y; + printf("\nEnter position (line,column): "); + scanf(" %d %d", &x, &y); + lcd_goto_xy(x,y); + +} +void set_display(void) +{ + unsigned int display, cursor, blink; + printf("\nEnter your choice [display-cursor-blink] : "); + scanf("%d %d %d", &display, &cursor, &blink); + lcd_set_display(display,cursor,blink); +} +void upload_custom_char(void) +{ + int i; + unsigned int location; + unsigned char *map = NULL; + printf("\nEnter custom character type [0-7] ([x]: address [x], type[x]): "); + scanf(" %d", &location); + lcd_upload_custom_char(location, type[location]); +} +void put_char() +{ + unsigned char chr; + printf("\nEnter character : "); + scanf(" %c", &chr); + lcd_put_char(chr); +} +void set_autoscroll() +{ + unsigned int status; + printf("\nEnter status (1: en, 0:dis) : "); + scanf(" %d", &status); + lcd_set_auto_scroll(status); +} +void put_custom_char() +{ + unsigned int num; + printf("\nEnter location of character [0-7] : "); + scanf(" %d", &num); + lcd_put_char(num); +} +void put_string() +{ + char user_buf[BUFFER_SIZE]; + printf("\nEnter your message: "); + scanf(" %[^\n]s", user_buf); + lcd_put_string(user_buf); +} +int main() +{ + int ret = 0; + char option = 'q'; + int fd = -1; + printf("Select below options: \n"); + + printf("\tW (to write string (two line))\n"); + + printf("\tC (to clear screen LCD)\n"); + + printf("\tG (to goto XY)\n"); + + printf("\tD (to control display)\n"); + + printf("\tU (to upload custom character)\n"); + + printf("\tp (to put a character)\n"); + + printf("\to (to put custom character)\n"); + + printf("\tP (to put string (one line))\n"); + + printf("\tL (to scroll left)\n"); + + printf("\tR (to scroll right)\n"); + + printf("\tA (to enable/disable autoscroll)\n"); + + printf("\tq (to quit the application)\n"); + while(1) + { + printf("Enter your options: "); + scanf(" %c", &option); + switch (option) + { + /* Write string (two line if can) */ + case 'W': + write_data_chardev(); + break; + /* Clear Screen LCD */ + case 'C': + lcd_clear_display(); + break; + /* Write data to device file */ + case 'G': + goto_xy(); + break; + /* Set Display */ + case 'D': + set_display(); + break; + /* Upload custom character */ + case 'U': + upload_custom_char(); + break; + /* Put a character */ + case 'p': + put_char(); + break; + case 'o': + put_custom_char(); + break; + /* Put a string */ + case 'P': + put_string(); + break; + /* Scroll Left */ + case 'L': + lcd_scroll_left(); + break; + /* Scroll right */ + case 'R': + lcd_scroll_right(); + break; + /* Set enable/disable autoscroll*/ + case 'A': + set_autoscroll(); + break; + /* Quit TEST APPLICATION */ + case 'q': + if(fd > -1) + printf("Quit the application. Goodbye!!!\n"); + return 0; + default: + printf("Invalid option %c \n", option); + break; + } + } +} diff --git a/app_test.o b/app_test.o new file mode 100644 index 0000000000000000000000000000000000000000..8c1232f5985da6ceb7bd547e30f409cc5db5d7ce GIT binary patch literal 5276 zcmb`KPi$1j9mi+?*s+bF3&jd4+jvM!yKd~w5*%<`S2D#EB1}aIsBVES&$|!2%6i|j z?`^Q9O3i^vR7xdU5!DAITq%_}aNxiJMXtnwND#UsKiu8z0j1pu)$bb1`IN4t?E>2U;p2d zSAV-Sc>BOoMqOI|$I8mz2Xp(E5~;Z_(zdSVzMxHk$=myv)VV)DVwg?5NQ^eb7?wVr zdjC?J#Oaf^w%q1rKlkKer{26=(@!48F-BsQxEdixAW_^D;*Lm+6k?j#sr^g2)#9d} zJWNUa)ne~M*l8;^b5^;z`)#>3%Y#wwO?h`RZ-u%TXIL2SIhAhx-T}xcrl0Jv(ZiWzFM3Ih+*=va`|uKB(aF>IRB5e!e<)I z`)SPo+T8wSm0P^uiRbVr7Oukw!bRad;a%Y!;cek9;ezm{@P=?+cwKl+h_TIjzueG| zF7L|i#`^l;e&Xv(e>kAjm%~Y=PC%X}luAmS`g7={EqzUTkLUwdd#BVNuhQR+^}p8B z7-u776vFk|je8-#E!-@8P57#?OZZLUdf_*OYlUk-z84B}g=O;jq^wIm+ZNc?a*g9% zIUKd)eVR#W0o9*cCUI)YyE$wU8Y}!O)7aLTETE7ke*Wsqnab0&e+y8y(*i#AInx66M zH9h6}zH`bQ(&(bM9{okfabJnO>iMOhZ8SyUoAT`{e^nX_iFtU==$MtZNe+l&Gc;aE!6$Mo6?0zr{)xxR4`LTlwAML<2rM6 z`uLD`ip3go)KL126%{67@-0R=ya-_OD@5&n-~@GFXSNM#x6-F`L&&d}=}7Knui%(_ z^iEnygyWk*K5)x!AKkZr^Kcr#u80{~3HoLtn2F)V#8mDMb4b(_XKZJ*TLfrwaC} zu~+MXc3xzUcCXR?ubnvl!G=A`+^e`z=CF?$JF@o5WnFep28emcZmX3}O`?&pcA0j! z;!Kp?w~;!joqFJf-RabR+W4HVmjWG3!dk7COX0km7}hefW>~48tkNN?_j+D&V#eLF zWedlDzw(h&E*0g`=&c3aq14{pyN7hORZH7?Lrv|V z6D1YvLA7OvYHe+cwZ}T*8u?o%RQoPJ0jby0C=t`z)RINlRyc?v-H)??2O+wy;0XAKQMmu@yE3 zHs*wCiyTFNrAcpB;m=EDJlEs-@wXv+QK-KTrYxOnDDt8Gd(gFI&!L{N^c|?PEsDoy zIcVuWM12IJA&j>dWZ^U3fc5orqlFjd;WX*hCjB?i*>@bm{=aUre+r%JkE3`J<;-=PxxQnr+s$>rT;Da< z9p<{zT$MQw@s7aA z8hI+@r)NyvcZ0l~21XB0f_%8Cn*kbeIGUpWi>tJQKq3CTiZC2j)4av7>9ue;O}9ANiJ2!(hBMT+ifTw!?2y{LYg7;eJK? ztoUCMzZ)dtEs}4C`xgD4LMKyrmS$WMe#7LpaQ~wHAawFD`CW`lJI0?T;eVFgj`3-S z->mQo+u=7)!tWOOZn&?}Z&Cc7ieD0Ik$xLV#N+-(zl?C0?TE+Uee~nnO%I0q9R14T zH_P@Re4PsUyO8=-;dS8+;eznC@UC!C_(=Gb@R<*UM74Js5E}J z@Ovwr3%`ZZ@1RZ{2TBjQ6VH#tOUG}t^bhbpkONr%B-T-x#5&~p$aQy4_=)hm@Pcqw zcu_bf{7iURctv;rmd%P$_s*Q*H(JiWj)qy+1zE zk8g&;hbp`4(1ENI;FtYG9p?f@`Hu^31t*eHm|9aX^=bk48kMNJ84c}_5iwlDhv*=T z9njgIer*suDx+grnDQKk6H+Ilc$kux;yuPU;RxCokA0(f*g{R*DBiIaG+2dWvoLSg zu_c&7Kkg|}iN@vrPCqP3Q-+arkJJg;D0_r}DJOVyR-q5e5eRat8U+{nG3Tg6ex#L- uIuE}^bi{YO;xk}=DG28{x>r%)&gmmQ=;e*XkSm@U@; literal 0 HcmV?d00001 diff --git a/lcd_driver.c b/lcd_driver.c new file mode 100644 index 0000000..2d7ae31 --- /dev/null +++ b/lcd_driver.c @@ -0,0 +1,630 @@ +/* + * Filename: lcd_driver.c + * Date: 11/11/2019 + * Description: character driver for a LCD 16x02 device + * Author: VietAnh Bui + */ +#include /* Define module_init(), module_exit()*/ +#include /*contain function allocate/free device number*/ +#include /*contain function for creating device file*/ +#include /* cointain kmalloc & kfree*/ +#include /*contain function work with cdev*/ +#include /*transport data between user vs kernel*/ +#include /* contain function services ioctl */ +#include +#include +#include +#include /*linux gpio interface*/ +#include + +#include /*delay*/ +#include "lcd_driver.h" + +#define DRIVER_AUTHOR "AnhBV-DiemPV" +#define DRIVER_VERSION "1.0" +#define DRIVER_DESC "The character device driver for LCD 16x02 HD44780" +// ********* Linux driver Constants ****************************************************************** + +#define MINOR_NUM_START 0 /* minor number starts from 0 */ +#define MINOR_NUM_COUNT 1 /* the number of minor numbers required */ + +/************************Driver Structures*******************************/ + +#define CLASS_NAME "class_lcd" +#define DEVICE_NAME "lcd_1602" + +struct _lcd_driver +{ + dev_t dev_number; /*dynamically allocated device major number*/ + struct class *lcd_class; /*class structure*/ + struct device *dev; + struct cdev *lcd_cdev; /*cdev structure*/ +} lcd_driver; + +/****************************Device Specific-START************************/ + +/*************Setup GPIO**********************/ +static int lcd_pin_setup(unsigned int pin_number) +{ + int ret; + PIN_DIRECTION gpio_direction = OUTPUT_PIN; + + /* Request GPIO allocation */ + ret = gpio_request(pin_number, "GPIO Pin Request"); + if (ret != 0) + { + printk(KERN_DEBUG "ERR: Failed to request gpio %d\n", pin_number); + return ret; + } + /* Set GPIO export & disallow user space to change direction of GPIO */ + ret = gpio_export(pin_number, 0); + if (ret != 0) + { + printk(KERN_DEBUG "ERR: Failed to export gpio %d\n", pin_number); + return ret; + } + /* Set GPIO direction */ + ret = gpio_direction_output(pin_number, gpio_direction); + if (ret != 0) + { + printk(KERN_DEBUG "ERR: Failed to set direction gpio %d\n", pin_number); + return ret; + } + + /* Set init value of GPIO*/ + gpio_set_value(pin_number, 0); + + /* Return 0 if there is no error*/ + return 0; +} + +/***********Setup All GPIO*******************/ +static void lcd_pin_setup_All(void) +{ + lcd_pin_setup(LCD_RS_PIN_NUMBER); + lcd_pin_setup(LCD_EN_PIN_NUMBER); + + lcd_pin_setup(LCD_D4_PIN_NUMBER); + lcd_pin_setup(LCD_D5_PIN_NUMBER); + lcd_pin_setup(LCD_D6_PIN_NUMBER); + lcd_pin_setup(LCD_D7_PIN_NUMBER); +} + +/***********Release a GPIO********************/ +static void lcd_pin_release(unsigned int pin_number) +{ + gpio_unexport(pin_number); /* return GPIO pin */ + gpio_free(pin_number); /* unexport GPIO pin */ +} + +/***********Release All GPIO*******************/ +static void lcd_pin_release_All(void) +{ + lcd_pin_release(LCD_RS_PIN_NUMBER); + lcd_pin_release(LCD_EN_PIN_NUMBER); + + lcd_pin_release(LCD_D4_PIN_NUMBER); + lcd_pin_release(LCD_D5_PIN_NUMBER); + lcd_pin_release(LCD_D6_PIN_NUMBER); + lcd_pin_release(LCD_D7_PIN_NUMBER); +} +/********************LCD Nibble************************/ +static void lcd_nibble(char data) +{ + int db7_data = 0; + int db6_data = 0; + int db5_data = 0; + int db4_data = 0; + usleep_range(2000, 3000); /* added delay instead of busy checking */ + /*Get 4 bit Upper*/ + db7_data = ((data) & (0x01 << 7)) >> (7); + db6_data = ((data) & (0x01 << 6)) >> (6); + db5_data = ((data) & (0x01 << 5)) >> (5); + db4_data = ((data) & (0x01 << 4)) >> (4); + + /*Set value to correspond GPIO*/ + gpio_set_value(LCD_D7_PIN_NUMBER, db7_data); + gpio_set_value(LCD_D6_PIN_NUMBER, db6_data); + gpio_set_value(LCD_D5_PIN_NUMBER, db5_data); + gpio_set_value(LCD_D4_PIN_NUMBER, db4_data); +} +/***********LCD send command******************* + * Only 4 upper bit was used */ +static void lcd_send_command(char command) +{ + /*Send signal to Pin*/ + lcd_nibble(command); + /*Set to command mode*/ + gpio_set_value(LCD_RS_PIN_NUMBER, RS_COMMAND_MODE); + usleep_range(5, 10); + /* Simulate falling edge triggered clock */ + gpio_set_value(LCD_EN_PIN_NUMBER, 1); + usleep_range(5, 10); + gpio_set_value(LCD_EN_PIN_NUMBER, 0); +} +/******************LCD send data************************************/ +static void lcd_send_data(char data) +{ + /* Part 1. Upper 4 bit data (from bit 7 to bit 4)*/ + lcd_nibble(data & 0xF0); + /* Part 1. Set to data mode*/ + gpio_set_value(LCD_RS_PIN_NUMBER, RS_DATA_MODE); + usleep_range(5, 10); + + /* Part 1. Simulate falling edge triggered clock */ + gpio_set_value(LCD_EN_PIN_NUMBER, 1); + usleep_range(5, 10); + gpio_set_value(LCD_EN_PIN_NUMBER, 0); + + /* Part 2. Lower 4 bit data (from bit 3 to bit 0)*/ + lcd_nibble((data & 0x0F) << 4); + /* Part 2. Set to data mode */ + gpio_set_value(LCD_RS_PIN_NUMBER, RS_DATA_MODE); + usleep_range(5, 10); + + /* Part 2. Simulate falling edge triggered clock */ + gpio_set_value(LCD_EN_PIN_NUMBER, 1); + usleep_range(5, 10); + gpio_set_value(LCD_EN_PIN_NUMBER, 0); +} +/************************LCD init******************************/ +/* Initialize the LCD in 4 bit mode as described on the HD44780 LCD controller document.*/ +static void lcd_initialize() +{ + usleep_range(41 * 1000, 50 * 1000); /* wait for more than 40 ms once the power is on */ + + lcd_send_command(0x30); /* Instruction 0011b (Function set) */ + usleep_range(5 * 1000, 6 * 1000); /* wait for more than 4.1 ms */ + + lcd_send_command(0x30); /* Instruction 0011b (Function set) */ + usleep_range(100, 200); /* wait for more than 100 us */ + + lcd_send_command(0x30); /* Instruction 0011b (Function set) */ + usleep_range(100, 200); /* wait for more than 100 us */ + + lcd_send_command(0x20); /* Instruction 0010b (Function set)*/ /*Set interface to be 4 bits long*/ + + usleep_range(100, 200); /* wait for more than 100 us */ + + lcd_send_command(0x20); /* Instruction 0010b (Function set) */ + lcd_send_command(0x80); /* Instruction NF**b + Set N = 1, or 2-line display + Set F = 0, or 5x8 dot character font*/ + usleep_range(41 * 1000, 50 * 1000); + + /* Display off, Cursor Off, Blink Off*/ + lcd_send_command(0x00); /* Instruction 0000b */ + lcd_send_command(0x80); /* Instruction 1000b */ + usleep_range(100, 200); + + /* Display clear, return the cursor Home */ + lcd_send_command(0x00); /* Instruction 0000b */ + lcd_send_command(0x10); /* Instruction 0001b */ + usleep_range(100, 200); + + /* Entry mode set: Inc cursor to the right when writing, don't shift screen*/ + lcd_send_command(0x00); /* Instruction 0000b */ + lcd_send_command(0x60); /* Instruction 01(I/D)Sb -> 0110b + Set I/D = 1, or increment or decrement DDRAM address by 1 + Set S = 0, or no display shift */ + usleep_range(100, 200); + + /* Initialization Completed, but set up default LCD setting here */ + + /* Display On/off Control */ + lcd_send_command(0x00); /* Instruction 0000b*/ + lcd_send_command(0xF0); /* Instruction 1DCBb + Set D= 1, or Display on + Set C= 1, or Cursor on + Set B= 1, or Blinking on + */ + usleep_range(100, 200); +} +/**************Display string on LCD with line number*******************************/ +static int lcd_print(char *msg, unsigned int lineNumber) +{ + unsigned int counter = 0; + unsigned int lineNum = lineNumber; + + if (msg == NULL) + { + printk(KERN_DEBUG "ERR: Empty data for lcd_print \n"); + return -1; + } + + if ((lineNum != 1) && (lineNum != 2)) + { + printk(KERN_DEBUG "ERR: Invalid line number readjusted to 1 \n"); + lineNum = 1; + } + + lcd_setLine(LCD_FIRST_LINE); + if (lineNum == 1) + { + lcd_setLine(LCD_FIRST_LINE); + while (*(msg) != '\0') + { + if (counter >= NUM_CHAR_PER_LINE) + { + lineNum = 2; /* continue writing on the next line if the string is too long */ + counter = 0; + break; + } + lcd_send_data(*msg); + msg++; + counter++; + } + } + if (lineNum == 2) + { + lcd_setLine(LCD_SECOND_LINE); + while (*(msg) != '\0') + { + if (counter >= NUM_CHAR_PER_LINE) + { + break; + } + lcd_send_data(*msg); + msg++; + counter++; + } + } + return 0; +} +/*************************Set line to display *********************************/ +void lcd_setLine(unsigned int line) +{ + if (line == 1) + { + lcd_send_command(0x80); /* set position to LCD line 1*/ + lcd_send_command(0x00); + } + else if (line == 2) + { + lcd_send_command(0xC0); + lcd_send_command(0x00); + } + else + { + printk("ERR: Invalid line number. Select either 1 or 2 \n"); + } +} + +/*************************LCD clean display*********************************/ +static void lcd_clearDisplay(void) +{ + /*Send 0x01 command*/ + lcd_send_command(0x00); /* upper 4 bits of command - 0000b */ + lcd_send_command(0x10); /* lower 4 bits of command - 0001b */ + + printk(KERN_INFO "LCD Driver: display clear\n"); +} +/*************************LCD scroll left*********************************/ +static void lcd_scroll_left(void) +{ + unsigned char command = LCD_SHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT; + lcd_send_command(command & 0xF0); /* upper 4 bits of command */ + lcd_send_command((command & 0x0F) << 4); /* lower 4 bits of command */ + + printk(KERN_INFO "LCD Driver: display clear\n"); +} +/*************************LCD scroll right*********************************/ +static void lcd_scroll_right(void) +{ + unsigned char command = LCD_SHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT; + lcd_send_command(command & 0xF0); /* upper 4 bits of command */ + lcd_send_command((command & 0x0F) << 4); /* lower 4 bits of command */ + + printk(KERN_INFO "LCD Driver: display clear\n"); +} +/************************LCD Set cursor to position (x,y)*********************/ +static void lcd_gotoxy(axis_t *position) +{ + char command; + + if (1 == position->x) + { + command = 0x80 + position->y; + + lcd_send_command(command & 0xF0); /* upper 4 bits of command */ + lcd_send_command((command & 0x0F) << 4); /* lower 4 bits of command */ + } + else if (2 == position->x) + { + command = 0xC0 + position->y; + + lcd_send_command(command & 0xF0); /* upper 4 bits of command */ + lcd_send_command((command & 0x0F) << 4); /* lower 4 bits of command */ + } + else + { + printk("ERR: Invalid line number. Select either 1 or 2 \n"); + } +} +/**********************LCD Set ON/OFF Display/Cursor/Blink********************************/ +static void lcd_set_display(display_control_t *display_option) +{ + /* Display On/off Control */ + /* Instruction 1DCBb - COMMAND CONTROL DISPLAY 0x08*/ + /* Set D= 1, or Display on + Set C= 1, or Cursor on + Set B= 1, or Blinking on + */ + unsigned char command = 0; + command = LCD_DISPLAYCONTROL | (display_option->display ? LCD_DISPLAYON : LCD_DISPLAYOFF) | (display_option->cursor ? LCD_CURSORON : LCD_CURSOROFF) | (display_option->blink ? LCD_BLINKON : LCD_BLINKOFF); + + lcd_send_command(command & 0xF0); /* 4 Upper bit*/ + lcd_send_command((command & 0x0F) << 4); /* 4 Lower bit - contain display config */ +} +/**********************LCD Upload custom character to CGRAM********************************/ +static void lcd_create_char(custom_char_t *custom_chr) +{ + unsigned char command = 0x00, i; + command = LCD_SETCGRAMADDR | ((custom_chr->location & 0x07) << 3); /* = LCD_SETCGRAMADDR + (location*8) => 5x8 character */ + lcd_send_command(command & 0xF0); /* 4 Upper bit */ + lcd_send_command((command & 0x0F) << 4); /* 4 Lower bit */ + usleep_range(60, 100); + for (i = 0; i < 8; i++) + { + lcd_send_data(custom_chr->charmap[i]); + usleep_range(60, 100); + } + lcd_clearDisplay(); +} +static void lcd_set_autoscroll(unsigned char status) +{ + unsigned char command = 0x00; + if (ENABLE == status) + { + command = LCD_ENTRYMODESET | LCD_ENTRYSHIFTINCREMENT | LCD_ENTRYLEFT; + } + else if (DISABLE == status) + { + command = LCD_ENTRYMODESET & (~LCD_ENTRYSHIFTINCREMENT) & (~LCD_ENTRYLEFT); + } + else + { + printk(KERN_DEBUG "Invalid status to set Enable/Disable autoscroll\n"); + return; + } + lcd_send_command(command & 0xF0); /* 4 Upper bit */ + lcd_send_command((command & 0x0F) << 4); /* 4 Lower bit */ +} +/****************************Device Specific-END**************************/ + +/****************************OS Specific-START************************/ +/****Function open entry point*****/ +static int char_lcd_open(struct inode *inode, struct file *filp) +{ + printk(KERN_INFO "Open device file event\n"); + return 0; +} +/****Function release entry point*****/ +static int char_lcd_release(struct inode *inode, struct file *filp) +{ + printk(KERN_INFO "Close event\n"); + return 0; +} +/****Function read entry point*****/ + +/****Function write entry point*****/ +static ssize_t char_lcd_write(struct file *filp, const char __user *user_buf, size_t len, loff_t *off) +{ + char *kernel_buf = NULL; + if (NULL == user_buf) + { + printk(KERN_DEBUG "ERR: Empty user buffer\n"); + return -ENOMEM; + } + printk(KERN_INFO "Handle write event from %lld, %zu bytes\n", *off, len); + + kernel_buf = kzalloc(len, GFP_KERNEL); + if (copy_from_user(kernel_buf, user_buf, len)) + { + return -EFAULT; + } + kernel_buf[len] = '\0'; + /*clear display*/ + lcd_clearDisplay(); + + /*print on the first line by default*/ + lcd_print(kernel_buf, LCD_FIRST_LINE); + kfree(kernel_buf); + printk(KERN_INFO "LCD Driver: write()\n"); + return len; +} +/**************************Function ioctl entry point********************************/ +static long char_lcd_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + printk("Handle ioctl event (cmd: %u)\n", cmd); + + switch (cmd) + { + case 1: + { + lcd_clearDisplay(); + break; + } + case 10: + { + axis_t position; + if (copy_from_user(&position, (axis_t *)arg, sizeof(position))) + { + printk(KERN_DEBUG "ERR: Failed to copy from user space buffer \n"); + return -EFAULT; + } + printk(KERN_INFO "Cursor go [%d][%d]\n", position.x, position.y); + lcd_gotoxy(&position); + printk(KERN_INFO "After call lcd_gotoxy [%d][%d]\n", position.x, position.y); + break; + } + case 3: + { + display_control_t display; + if (copy_from_user(&display, (display_control_t *)arg, sizeof(display))) + { + printk(KERN_DEBUG "ERR: Failed to copy from user space buffer \n"); + return -EFAULT; + } + lcd_set_display(&display); + printk(KERN_INFO "Control display: Display [%s], Cursor [%s], Blink [%s]\n", + (display.display) ? "enable" : "disable", + (display.cursor) ? "enable" : "disable", + (display.blink) ? "enable" : "disable"); + break; + } + case 4: + { + unsigned char character; + if (copy_from_user(&character, (unsigned char *)arg, sizeof(character))) + { + printk(KERN_DEBUG "ERR: Failed to copy from user space buffer \n"); + return -EFAULT; + } + lcd_send_data(character); + printk(KERN_INFO "Put character: %c\n", character); + break; + } + case 5: + { + lcd_scroll_left(); + break; + } + case 6: + { + lcd_scroll_right(); + break; + } + case 7: + { + custom_char_t custom_chr; + if (copy_from_user(&custom_chr, (custom_char_t *)arg, sizeof(custom_chr))) + { + printk(KERN_DEBUG "ERR: Failed to copy from user space buffer \n"); + return -EFAULT; + } + lcd_create_char(&custom_chr); + break; + } + case 8: + { + lcd_initialize(); + break; + } + case 9: + { + unsigned char status; + if (copy_from_user(&status, (unsigned char *)arg, sizeof(status))) + { + printk(KERN_DEBUG "ERR: Failed to copy from user space buffer \n"); + return -EFAULT; + } + lcd_set_autoscroll(status); + printk(KERN_INFO "%s auto scroll\n", (ENABLE == status) ? "Enable" : "Disable"); + break; + } + } + return ret; +} + +/* file operation structure */ +static struct file_operations lcd_fops = +{ + .owner = THIS_MODULE, + .open = char_lcd_open, + .release = char_lcd_release, + .write = char_lcd_write, + .unlocked_ioctl = char_lcd_ioctl, +}; + +/****************************OS Specific-END**************************/ + +static int __init lcd_driver_init(void) +{ + + /* dynamically allocate device major number */ + if (alloc_chrdev_region(&lcd_driver.dev_number, MINOR_NUM_START, MINOR_NUM_COUNT, DEVICE_NAME) < 0) + { + printk(KERN_DEBUG "ERR: Failed to allocate major number \n"); + return -1; + } + + /* create a class structure */ + lcd_driver.lcd_class = class_create(THIS_MODULE, CLASS_NAME); + + if (IS_ERR(lcd_driver.lcd_class)) + { + unregister_chrdev_region(lcd_driver.dev_number, MINOR_NUM_COUNT); + printk(KERN_DEBUG "ERR: Failed to create class structure \n"); + + return PTR_ERR(lcd_driver.lcd_class); + } + + /* create a device and registers it with sysfs */ + lcd_driver.dev = device_create(lcd_driver.lcd_class, NULL, lcd_driver.dev_number, NULL, DEVICE_NAME); + + if (IS_ERR(lcd_driver.dev)) + { + class_destroy(lcd_driver.lcd_class); + unregister_chrdev_region(lcd_driver.dev_number, MINOR_NUM_COUNT); + printk(KERN_DEBUG "ERR: Failed to create device structure \n"); + + return PTR_ERR(lcd_driver.dev); + } + + /* initialize a cdev structure */ + lcd_driver.lcd_cdev = cdev_alloc(); + cdev_init(lcd_driver.lcd_cdev, &lcd_fops); + + /* add a character device to the system */ + if (cdev_add(lcd_driver.lcd_cdev, lcd_driver.dev_number, MINOR_NUM_COUNT) < 0) + { + device_destroy(lcd_driver.lcd_class, lcd_driver.dev_number); + class_destroy(lcd_driver.lcd_class); + unregister_chrdev_region(lcd_driver.dev_number, MINOR_NUM_COUNT); + printk(KERN_DEBUG "ERR: Failed to add cdev \n"); + return -1; + } + + /*setup GPIO pins*/ + lcd_pin_setup_All(); + + /* initialize LCD once */ + lcd_initialize(); + + printk(KERN_INFO "Initialize lcd driver successfull!\n"); + return 0; +} + +static void __exit lcd_driver_exit(void) +{ + /* clear LCD display */ + lcd_clearDisplay(); + + /* remove a cdev from the system */ + cdev_del(lcd_driver.lcd_cdev); + + /* remove device */ + device_destroy(lcd_driver.lcd_class, lcd_driver.dev_number); + + /* destroy class */ + class_destroy(lcd_driver.lcd_class); + + /* deallocate device number */ + unregister_chrdev_region(lcd_driver.dev_number, MINOR_NUM_COUNT); + + /* releasse GPIO pins */ + lcd_pin_release_All(); + + printk(KERN_INFO "lcd Driver Exited. \n"); + printk(KERN_INFO "Goodbye!!!\n"); +} + +module_init(lcd_driver_init); +module_exit(lcd_driver_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_VERSION(DRIVER_VERSION); diff --git a/lcd_driver.h b/lcd_driver.h new file mode 100644 index 0000000..751fb69 --- /dev/null +++ b/lcd_driver.h @@ -0,0 +1,129 @@ +/* + * Filename: lcd_driver.h + * Date: 12/11/2019 + * Description: header file for driver + * Author: VietAnh Bui + */ +#ifndef _LCD_DRIVER_H_ +#define _LCD_DRIVER_H_ + + +#define ENABLE 1 +#define DISABLE 0 +/******************LCD Command****************************/ +#define LCD_CLEARDISPLAY 0x01 +#define LCD_RETURNHOME 0x02 +#define LCD_ENTRYMODESET 0x04 +#define LCD_DISPLAYCONTROL 0x08 +#define LCD_SHIFT 0x10 +#define LCD_FUNCTIONSET 0x20 +#define LCD_SETCGRAMADDR 0x40 +#define LCD_SETDDRAMADDR 0x80 + +#define LCD_ENTRYRIGHT 0x00 +#define LCD_ENTRYLEFT 0x02 +#define LCD_ENTRYSHIFTINCREMENT 0x01 +#define LCD_ENTRYSHIFTDECREMENT 0x00 + +#define LCD_DISPLAYMOVE 0x08 +#define LCD_CURSORMOVE 0x00 +#define LCD_MOVERIGHT 0x04 +#define LCD_MOVELEFT 0x00 + +#define LCD_DISPLAYON 0x04 +#define LCD_DISPLAYOFF 0x00 +#define LCD_CURSORON 0x02 +#define LCD_CURSOROFF 0x00 +#define LCD_BLINKON 0x01 +#define LCD_BLINKOFF 0x00 +/******************LCD Pin Configuration******************/ + +#define LCD_RS_PIN_NUMBER 26 +#define LCD_EN_PIN_NUMBER 19 + +#define LCD_D4_PIN_NUMBER 13 +#define LCD_D5_PIN_NUMBER 6 +#define LCD_D6_PIN_NUMBER 5 +#define LCD_D7_PIN_NUMBER 11 + + + +/********************LCD Instruction**********************/ +#define RS_COMMAND_MODE 0 /* Select Instruction Register with RS pin*/ +#define RS_DATA_MODE 1 /* Select Data Register with RS pin*/ + +#define LCD_FIRST_LINE 1 +#define LCD_SECOND_LINE 2 +#define NUM_CHAR_PER_LINE 16 + +/**********************GPIO Support ***********************/ + +typedef enum pin_dir +{ + INPUT_PIN = 0, + OUTPUT_PIN = 1 +} PIN_DIRECTION; + +/******************Define IOCTL Command ********************/ +#define MAGICAL_NUMBER 248 +#define LCD_CLEAR _IO(MAGICAL_NUMBER, 0) +#define LCD_GOTOXY _IOW(MAGICAL_NUMBER, 1, axis_t *) +#define LCD_SET_DISPLAY _IOW(MAGICAL_NUMBER, 2, display_control_t *) +#define LCD_PUT_CHAR _IOW(MAGICAL_NUMBER, 3, unsigned char *) +#define LCD_SCROLL_LEFT _IO(MAGICAL_NUMBER, 4) +#define LCD_SCROLL_RIGHT _IO(MAGICAL_NUMBER, 5) +#define LCD_UPLOAD_CUSTOM_CHAR _IOW(MAGICAL_NUMBER, 6, custom_char_t *) +#define LCD_INIT _IO(MAGICAL_NUMBER, 7) +#define LCD_SET_AUTOSCROLL _IOW(MAGICAL_NUMBER, 8, unsigned char *) + +/**********************Data Structure***********************/ +typedef struct custom_chr +{ + unsigned char location; + unsigned char *charmap; +}custom_char_t; + +typedef struct axis +{ + unsigned char x; + unsigned char y; +}axis_t; + +typedef struct display_control +{ + unsigned char display; + unsigned char cursor; + unsigned char blink; +}display_control_t; + +/******************Function Prototype**********************/ + +static int lcd_pin_setup(unsigned int pin_number); +static void lcd_pin_setup_All( void ); +static void lcd_pin_release(unsigned int pin_number); +static void lcd_pin_release_All( void ); + +static void lcd_nibble(char data); +static void lcd_send_command(char command); +static void lcd_send_data(char data); +static void lcd_initialize(void); +static int lcd_print(char * msg, unsigned int lineNumber); +static void lcd_clearDisplay(void); +static void lcd_setLine(unsigned int line); + +/* Set cursor goto line x, column y*/ +static void lcd_gotoxy(axis_t *position); + +/* Set ON/OFF Display/Cursor/Blink*/ +static void lcd_set_display(display_control_t *display_option); +/* Scroll to left*/ +static void lcd_scroll_left(void); +/* Scroll to right*/ +static void lcd_scroll_right(void); +/* Upload custom character to CGRAM ((Character Generator RAM) */ +/* Only have 8 byte for custom character, location 0-7 */ +static void lcd_create_char(custom_char_t *custom_chr); + +/* Set auto scroll- moves all the text one space to the left each time a letter is added*/ +static void lcd_set_autoscroll(unsigned char status); +#endif /*_LCD_DRIVER_H_*/ diff --git a/lcd_driver.ko b/lcd_driver.ko new file mode 100644 index 0000000000000000000000000000000000000000..9fd08ca9724ec23f6e296a552e3f7b76c48fe1ee GIT binary patch literal 14788 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 +#include +#include +#include + +BUILD_SALT; + +MODULE_INFO(vermagic, VERMAGIC_STRING); +MODULE_INFO(name, KBUILD_MODNAME); + +__visible struct module __this_module +__attribute__((section(".gnu.linkonce.this_module"))) = { + .name = KBUILD_MODNAME, + .init = init_module, +#ifdef CONFIG_MODULE_UNLOAD + .exit = cleanup_module, +#endif + .arch = MODULE_ARCH_INIT, +}; + +#ifdef CONFIG_RETPOLINE +MODULE_INFO(retpoline, "Y"); +#endif + +static const struct modversion_info ____versions[] +__used +__attribute__((section("__versions"))) = { + { 0xad1a7def, "module_layout" }, + { 0x1d11aa3a, "cdev_del" }, + { 0x38ef651b, "device_destroy" }, + { 0x88647e86, "cdev_add" }, + { 0x7a3acc89, "cdev_init" }, + { 0xb4673642, "cdev_alloc" }, + { 0xe30a435, "class_destroy" }, + { 0x765f4408, "device_create" }, + { 0x6091b333, "unregister_chrdev_region" }, + { 0xd15f066d, "__class_create" }, + { 0xe3ec2f2b, "alloc_chrdev_region" }, + { 0x37a0cba, "kfree" }, + { 0x12da5bb2, "__kmalloc" }, + { 0xfe990052, "gpio_free" }, + { 0xee90f06e, "gpiod_unexport" }, + { 0xe31620ea, "gpiod_direction_output_raw" }, + { 0xddaa5251, "gpiod_export" }, + { 0x47229b5c, "gpio_request" }, + { 0xdb7305a1, "__stack_chk_fail" }, + { 0x5f754e5a, "memset" }, + { 0x28cc25db, "arm_copy_from_user" }, + { 0x8f678b07, "__stack_chk_guard" }, + { 0xffb0dcd9, "gpiod_set_raw_value" }, + { 0x350a004, "gpio_to_desc" }, + { 0x12a38747, "usleep_range" }, + { 0x2e5810c6, "__aeabi_unwind_cpp_pr1" }, + { 0x7c32d0f0, "printk" }, + { 0xb1ad28e0, "__gnu_mcount_nc" }, +}; + +static const char __module_depends[] +__used +__attribute__((section(".modinfo"))) = +"depends="; + + +MODULE_INFO(srcversion, "3D1A958D8FE358361AC75D2"); diff --git a/lcd_driver.mod.o b/lcd_driver.mod.o new file mode 100644 index 0000000000000000000000000000000000000000..83b35b934840806018002df4cdeb546b82c4bd97 GIT binary patch literal 4000 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 E2R|-HK>z>% literal 0 HcmV?d00001 diff --git a/lcd_lib.c b/lcd_lib.c new file mode 100644 index 0000000..bacf5ce --- /dev/null +++ b/lcd_lib.c @@ -0,0 +1,123 @@ +#include "lcd_lib.h" + +static int lcd_open_dev(void) +{ + int fd = open(DEVICE_NODE, O_RDWR); + if(fd < 0) + { + printf("Cannot open the device file \n"); + exit(1); + } + return fd; +} +static void lcd_close_dev(int fd) +{ + close(fd); +} + +void lcd_init(void) +{ + int fd = lcd_open_dev(); + ioctl(fd, 8); + lcd_close_dev(fd); +} + +void lcd_clear_display(void) +{ + int ret =0; + int fd = lcd_open_dev(); + ret = ioctl(fd, 1); + lcd_close_dev(fd); + printf("%s display in char device\n", (ret < 0)?"Couldn't clear":"Cleared"); +} + +void lcd_goto_xy(unsigned char x, unsigned char y) +{ + coordinate_t location; + location.x = x; + location.y = y; + int fd = lcd_open_dev(); + /* printf("Library: Cursor goto: %d, %d\n", location.x, location.y); */ + ioctl(fd, 10, &location); + lcd_close_dev(fd); +} + +void lcd_set_display(unsigned char display, unsigned char cursor, unsigned char blink) +{ + control_display_t control; + control.display = display; + control.cursor = cursor; + control.blink = blink; + int fd = lcd_open_dev(); + ioctl(fd, 3, &control); + lcd_close_dev(fd); +} + +void lcd_upload_custom_char(unsigned char location, unsigned char *charmap) +{ + custom_character_t custom_char; + custom_char.location = location; + custom_char.charmap = charmap; + int fd = lcd_open_dev(); + ioctl(fd, 7, &custom_char); + lcd_close_dev(fd); +} + +void lcd_scroll_left(void) +{ + int fd = lcd_open_dev(); + ioctl(fd, 5); + lcd_close_dev(fd); +} + +void lcd_scroll_right(void) +{ + int fd = lcd_open_dev(); + ioctl(fd, 6); + lcd_close_dev(fd); +} + +void lcd_put_char(unsigned char chr) +{ + int fd = lcd_open_dev(); + ioctl(fd, 4, (unsigned char *)&chr); + lcd_close_dev(fd); +} + +void lcd_put_string(unsigned char *str) +{ + unsigned char *tmp = str; + unsigned char counter = 0; + int fd = lcd_open_dev(); + while (*(tmp) != '\0') + { + if (counter >= NUM_CHAR_PER_LINE) + { + break; + } + ioctl(fd, 4, tmp); + tmp++; + counter++; + } + lcd_close_dev(fd); +} + +void lcd_put_string_super(unsigned char *str) +{ + int fd = lcd_open_dev(); + write(fd, str, strlen(str)+ 1); /* Print string to screen */ + lcd_close_dev(fd); +} + +int lcd_set_auto_scroll(unsigned char status) +{ + /* Check Check the correctness of the parameter */ + if((ENABLE != status) && (DISABLE != status)) + { + return -1; + } + int fd = lcd_open_dev(); + ioctl(fd, 9, &status); + lcd_close_dev(fd); + return 0; +} diff --git a/lcd_lib.h b/lcd_lib.h new file mode 100644 index 0000000..8b79c39 --- /dev/null +++ b/lcd_lib.h @@ -0,0 +1,149 @@ +/* + * Filename: lcd_lib.h + * Date: 14/11/2019 + * Description: header file for LCD library use LCD Driver + * Author: VietAnh Bui + */ +#ifndef _LCD_LIB_H_ +#define _LCD_LIB_H_ +#include +#include +#include +#include +#include +#include +#include + +#define DEVICE_NODE "/dev/lcd_1602" +#define NUM_CHAR_PER_LINE 16 +#define NUM_LINE 2 +#define ENABLE 1 +#define DISABLE 0 +/*********************GPIO Configure************************/ + +/**********************Data Structure***********************/ +typedef struct _custom_char +{ + unsigned char location; + unsigned char *charmap; +}custom_character_t; + +typedef struct _coordinate +{ + unsigned char x; + unsigned char y; +}coordinate_t; + +typedef struct _display_control +{ + unsigned char display; + unsigned char cursor; + unsigned char blink; +}control_display_t; + +/* Define command for IOCTL*/ +#define MAGICAL_NUM 248 +#define CLEAR_DISPLAY _IO(MAGICAL_NUM, 0) +#define GOTO_XY _IOW(MAGICAL_NUM, 1, coordinate_t *) +#define SET_DISPLAY _IOW(MAGICAL_NUM, 2, control_display_t *) +#define PUT_CHAR _IOW(MAGICAL_NUM, 3, unsigned char *) +#define SCROLL_LEFT _IO(MAGICAL_NUM, 4) +#define SCROLL_RIGHT _IO(MAGICAL_NUM, 5) +#define UPLOAD_CUSTOM_CHAR _IOW(MAGICAL_NUM, 6, custom_character_t *) +#define INIT_LCD _IO(MAGICAL_NUM, 7) +#define SET_AUTOSCROLL _IOW(MAGICAL_NUM, 8, unsigned char *) + +/**********************Function Prototype ***********************/ + +/** + * @brief Init LCD + * Set cursor position to (0, 0), set enable cursor, enable blink + * The order of the connection pins has been defined in the driver + * The feature that provides configuration of connector pins will be updated in later versions + * @param void + * @return void + */ +void lcd_init(void); +/** + * @brief Open device file of LCD + * @param void + * @return file descriptor of device file + */ +static int lcd_open_dev(void); +/** + * @brief Close device file of LCD + * @param fd file descriptor + * @return close device file + */ +static void lcd_close_dev(int fd); +/** + * @brief Clear LCD display + * Clear screen of LCD and set cursor position to (1, 0) + * @param void + * @return void + */ +void lcd_clear_display(void); +/** + * @brief Set cursor goto line x, column y (LCD 16x02) + * @param x line number. (1 <= x <= 2) + * @param y column number. (0 <= y <= 15) + * @return void + */ +void lcd_goto_xy(unsigned char x, unsigned char y); +/** + * @brief Control Display + * Set option to control display LCD + * @param display to enable/disable display LCD. (ENABLE or DISABLE) + * @param cursor to enable/disable cursor LCD. (ENABLE or DISABLE) + * @param blink to enable/disable blink LCD. (ENABLE or DISABLE) + * @return void + */ +void lcd_set_display(unsigned char display, unsigned char cursor, unsigned char blink); +/** + * @brief Upload custom character to CGRAM (Character Generator RAM) in LCD + * CGRAM in LCD can contain maximum data display for 8 character with font 5x8 + * @param location is address of custom character in CGRAM. (0-7) + * @param charmap is pointer to array contain data display for custom character. You can visit link: https://maxpromer.github.io/LCD-Character-Creator/ + * @return void + */ +void lcd_upload_custom_char(unsigned char location, unsigned char *charmap); +/** + * @brief Scroll both of line to left LCD + * @param void + * @return void + */ +void lcd_scroll_left(void); +/** + * @brief Scroll both of line to right LCD + * @param void + * @return void + */ +void lcd_scroll_right(void); +/** + * @brief Put character to current cursor in LCD + * @param chr character + * @return void + */ +void lcd_put_char(unsigned char chr); +/** + * @brief Put string to screen + * If length of string over 16, do not put to line 2. + * So be careful when using this function. + * @param str pointer to string + * @return void + */ +void lcd_put_string(unsigned char *str); +/** + * @brief Put string to screen, if line not enough to display, cursor move to line 2 + * @param str pointer to string + * @return void + */ +void lcd_put_string_super(unsigned char *str); +/** + * @brief Set enable or disable auto scroll + * Moves all the text one space to the left each time a letter is added + * @param status status (enable = ENABLE, disable = DISABLE) + * @return void + */ +int lcd_set_auto_scroll(unsigned char status); +#endif /*_LCD_LIB_H_*/ diff --git a/lcd_lib.o b/lcd_lib.o new file mode 100644 index 0000000000000000000000000000000000000000..c3974c18b876f597d02e2ab66e1b2541a28c4cb5 GIT binary patch literal 2904 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 a<1qN4FGKs|TLNFUypBPcxiUki?fwIk|K_~_ literal 0 HcmV?d00001 diff --git a/pbl.o b/pbl.o new file mode 100644 index 0000000000000000000000000000000000000000..58ad913f59fb9361e294cccfd8430120f6838baf GIT binary patch literal 2404 zcma);U1%It6vzLQ*`(Q6HLai2udPOjsGImfsNzG~S`nI>;Ag=?GT9xw1CyO$XVPw< zU>`&z7>F7qh;_%BN|2z57AdlnP=ofdpbtJaS@xwqL?usBT>oe0PIsE-!2@T1=iK|h z=gvLz!M<}~;6+W-5SxZ>G&A7pws5BPnGoGbqa7pPRq988KU(RBcUI~tH>ha{YTGkG zjk5K}fGd5R>pxwoclHLgMx${Bc(ryj(1DRp>%beL>qt?T`KVIQP@4)S*R^ZO zBIkag|4d(DzCz0Q1+q#mljq3uOGsT*V3B{NwI|Kn|9KnCuYGcb%Uax3OR3NI-X-7J%~)_ z3kOIKBhyi3AiauAM}~p)FESmUFpxe*reiw;>2YLwxR)F)&Rqu5>&SF0F_8NbnI7(a zcbxJBGAH*jG9C9ZXx<|o4>Ff~9hr_t7>Fh^9gi}|s7yNYA>;UYkeuJ1@Og-*OxFf4JC3w zWimg(cqEaZWc+&~e~+<@MW$hj!LrI^{l|=F68S9S*Amxrin*Q0zhwS+BLANGTq2kL z7UZE1?b<|`>1f4yH6!Tc{&?H6P1o=XJn1-caLtnE6ftT$IR|DrXT$VdbmdV-&MX=w z%R$Z=FZ$>*kh4vrgrmlo>DtBw%wis%=?}Y(XZe;>9DZT&&6hFe95eTuMWIzZI#`5} z_YSZmvCnpJykz;Nnnd1|I^J=^h2wHf&UQTW`kJo~q2P>}!@lL)TxVECgztcSQ{*_p zZp9(Rf?`=QP|UMWqPNKwx~u3bmK9GZo>Y8S@qNV)6sHwu6lWDbQw$X66z3He6p{5N z#(ZOx^h*&7aa1zxtZ$ZmWb=k^AUo=L$nJgRP}cDMk~KQ+o1S#wf7t_6u?1*TYI)ul zc@43tmn(da(;Vzq6B}G`k+H0k^`dL1Kdkcj>-HyW6*v}K{JoNQS@f~)a2zP1)D-Kb zb4or%p^2{fO^WuG3DGAm8!mOr9FV^_vX@++>@8^J{KT=?;(g^in$%TUs6Q5w GvF<-Z()*kM literal 0 HcmV?d00001 diff --git a/running_test.c b/running_test.c new file mode 100644 index 0000000..4a5a499 --- /dev/null +++ b/running_test.c @@ -0,0 +1,54 @@ +#include +#include +#include +#include +#include "lcd_lib.h" + +char *LargeText = " Viet Nam vo dich!!! "; + +int iLineNumber = 2; /* Line number to show your string (Either 0 or 1) */ + +int iCursor = 0; + +void UpdateLCDDisplay() +{ + int iChar; + int iLenOfLargeText = strlen(LargeText); /* enght of string. */ + if (iCursor == (iLenOfLargeText - 1)) /* Reset variable for rollover effect. */ + { + iCursor = 0; + } + lcd_goto_xy(iLineNumber, 0); + + if (iCursor < iLenOfLargeText - 16) /* This loop exicuted for normal 16 characters. */ + { + for (iChar = iCursor; iChar < iCursor + 16; iChar++) + { + lcd_put_char(LargeText[iChar]); + } + } + else + { + for (iChar = iCursor; iChar < (iLenOfLargeText - 1); iChar++) /* This code takes care of printing charecters of current string. */ + { + lcd_put_char(LargeText[iChar]); + } + for (int iChar = 0; iChar <= 16 - (iLenOfLargeText - iCursor); iChar++) /* Reamining charecter will be printed by this loop. */ + { + lcd_put_char(LargeText[iChar]); + } + } + iCursor++; +} +int main() +{ + lcd_clear_display(); + lcd_goto_xy(1,0); + lcd_put_string(" DASAN VN "); + while (1) + { + UpdateLCDDisplay(); + usleep(80000); + } + return 0; +}