#include <linux/module.h> #include <linux/fs.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/major.h> #include <linux/io.h> #include <linux/cdev.h> #include <linux/version.h> #include <linux/uaccess.h> #include <linux/delay.h> //mdelay(10) ->ms, udelay(1) ->us #include <linux/gpio.h> //커널에서 제공하는 gpio 함수 #define __BCM_2711__ /* BCM2837의 I/O Peripherals 주소*/ #if defined(__BCM_2837__) #define BCM_IO_BASE 0x3F000000 #elif defined (__BCM_2711__) #define BCM_IO_BASE 0xFE000000 #elif defined(__BCM_2835__) #define BCM_IO_BASE 0x20000000 #endif // GPIO 컨트롤러의 주소 #define GPIO_BASE (BCM_IO_BASE + 0x200000) // 0x7E2000B0 - 0x7E200000 +4 = 176 + 4 = 180 #if defined (__BCM_2837__) || defined(__BCM_2835__) #define GPIO_SIZE (180) #elif defined (__BCM_2711__) #define GPIO_SIZE (240) #endif // GPIO 설정 매크로 #define GPIO_IN(g) ( *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3)) ) //입력 #define GPIO_OUT(g) ( *(gpio+((g)/10)) |= (1<<(((g)%10)*3)) ) //출력 #define GPIO_SET(g) (*(gpio+7) = 1<<g) // high #define GPIO_CLR(g) (*(gpio+10) = 1<<g) // low #define GPIO_GET(g) (*(gpio+13) & (1<<g)) //read #define IOCTRL_LED_ON 1000 #define IOCTRL_LED_OFF 1001 #define IOCTRL_EXIT 1002 #define BUFF_SIZE 1024 #define MAJOR_NUMBER 256 #define DEVICE_NAME "gpio_led" #define GPIO_LED 18 #define RS 9 #define EN 11 #define D4 5 #define D5 6 #define D6 13 #define D7 19 static char *buffer = NULL; //커널에서 사용 버퍼 static int sz_data = 0; // data size // I/O 접근을 위한 volatile 변수 volatile unsigned *gpio; // volatile unsigned int 로 써도 됨. int는 생략가능 struct cdev gpio_cdev; //lcd prototype void lcdInit(void); void lcdComm(unsigned char cmd); void lcdChar(unsigned char data); void lcdStr(char *str); void lcdStrPos(int row, int pos, char *str); void lcdClear(void); unsigned char cmd; void lcdInit(void){ mdelay(30); //Wait for more than 30ms after VDD rises to 4.5V lcdComm(0x02); // init 4bit mode로 세팅 (전원 인가 후 기본 8비트 모드로 동작) lcdComm(0x28); // function set lcdComm(0x0F); // display on/off lcdComm(0x01); // display clear lcdComm(0x06); // entry mode set } void lcdComm(unsigned char cmd){ //상위 4비트 처리 if ((cmd & 0x10) != 0){ GPIO_SET(D4); } else{ GPIO_CLR(D4); } if ((cmd & 0x20) != 0) GPIO_SET(D5); else GPIO_CLR(D5); if ((cmd & 0x40) != 0) GPIO_SET(D6); else GPIO_CLR(D6); if ((cmd & 0x80) != 0) GPIO_SET(D7); else GPIO_CLR(D7); GPIO_CLR(RS); GPIO_SET(EN); udelay(1); GPIO_CLR(EN); //하위 4비트 처리 if ((cmd & 0x01) != 0) GPIO_SET(D4); else GPIO_CLR(D4); if ((cmd & 0x02) != 0) GPIO_SET(D5); else GPIO_CLR(D5); if ((cmd & 0x04) != 0) GPIO_SET(D6); else GPIO_CLR(D6); if ((cmd & 0x08) != 0) GPIO_SET(D7); else GPIO_CLR(D7); GPIO_SET(EN); udelay(1); GPIO_CLR(EN); udelay(1530); } void lcdChar(unsigned char data){ //상위 4비트 처리 if ((cmd & 0x10) != 0) GPIO_SET(D4); else GPIO_CLR(D4); if ((cmd & 0x20) != 0) GPIO_SET(D5); else GPIO_CLR(D5); if ((cmd & 0x40) != 0) GPIO_SET(D6); else GPIO_CLR(D6); if ((cmd & 0x80) != 0) GPIO_SET(D7); else GPIO_CLR(D7); GPIO_SET(RS); GPIO_SET(EN); udelay(1); GPIO_CLR(EN); //하위 4비트 처리 if ((cmd & 0x01) != 0) GPIO_SET(D4); else GPIO_CLR(D4); if ((cmd & 0x02) != 0) GPIO_SET(D5); else GPIO_CLR(D5); if ((cmd & 0x04) != 0) GPIO_SET(D6); else GPIO_CLR(D6); if ((cmd & 0x08) != 0) GPIO_SET(D7); else GPIO_CLR(D7); GPIO_SET(EN); udelay(1); GPIO_CLR(EN); udelay(1530); } void lcdStr(char *str){ int i; for(i=0; str[i]!=0; i++){ lcdChar(str[i]); } } void lcdStrPos(int row, int pos, char *str){ #if 0 if (row == 0 && pos<16){ lcdComm((pos & 0x0F) |0x80); } else if (row == 1 && pos<16){ lcdComm((pos & 0x0F)| 0xC0); } #else lcdComm(0x80 | (pos + row * 0x40)); #endif lcdStr(str); } void lcdClear(void){ lcdComm(0x01); } //장치파일 열기 static int my_open(struct inode *inode, struct file *filp){ printk("device driver open! \n"); try_module_get(THIS_MODULE); return 0; } //장치 파일 닫기 static int my_release(struct inode *inode, struct file *filp) { printk("<Ko> device driver release! \n"); module_put(THIS_MODULE); return 0; } //장치파일에 데이터 쓰기 static ssize_t my_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) { printk("<Ko> write to buffer! %s\n", buf); if(BUFF_SIZE < count){ sz_data = BUFF_SIZE; } sz_data = count; strncpy(buffer, buf, sz_data); printk("<Ko> buffer : %s, %d\n",buffer, sz_data); return count; } //장치 파일에서 데이터 읽어 옴. static ssize_t my_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) { printk(KERN_DEBUG "<Ko> from, buffer %s\n", buffer); // App의 read()로 보내는 buffer (사용자 값) if(!strcmp(buffer, "1")){ copy_to_user(buf, "LED ON", 7); } else if(!strcmp(buffer,"2")){ copy_to_user(buf,"LED OFF",8); } return sz_data; } static long my_ioctl(struct file *flip, unsigned int cmd, unsigned long arg){ printk(KERN_DEBUG "<Ko> cmd : %d \n" ,cmd); printk(KERN_DEBUG "IOCTRL_LED_ON : %d \n" ,IOCTRL_LED_ON); switch(cmd){ case IOCTRL_LED_ON: printk(KERN_INFO "LED ON in kernel\n"); GPIO_SET(GPIO_LED); break; case IOCTRL_LED_OFF: printk(KERN_INFO "LED OFF in kernel\n"); GPIO_CLR(GPIO_LED); break; case IOCTRL_EXIT: printk(KERN_INFO "App exit\n"); break; default: printk(KERN_INFO "unknown menu!\n"); break; } return 0; } // 파일 동작 함수 연결 static struct file_operations gpio_fops = { .owner = THIS_MODULE, .read = my_read, .write = my_write, .open = my_open, .release = my_release, .unlocked_ioctl = my_ioctl }; // cat//proc//devices -> 디바이스 드라이버 MAJOR_NUMBER 확인 // $sudo mknod /dev/gpio_led 256 0 // $sudo chmod 666 /dev/gpio_led int __init my_init(void) { dev_t devno; unsigned int count; static void* map = NULL; //I/O 접근을 위한 변수 int err; printk(KERN_INFO "Hello module!\n"); //문자 디바이스를 등록 devno = MKDEV(MAJOR_NUMBER, 0); register_chrdev_region(devno, 1, DEVICE_NAME); //문자 디바이스를 위한 구조체를 초기화 cdev_init(&gpio_cdev, &gpio_fops); gpio_cdev.owner = THIS_MODULE; count = 1; // 문자 디바이스를 추가 err = cdev_add(&gpio_cdev, devno, count); if (err < 0) { printk(KERN_ERR "ERROR : Device Add\n"); return -1; } //물리 주소를 가상 주소로 맵핑 map = ioremap(GPIO_BASE, GPIO_SIZE); if (!map) { printk(KERN_ERR "ERROR : mapping gpio memory\n"); iounmap(map); return -1; } gpio = (volatile unsigned int *)map; //LED 사용을 위한 초기화 GPIO_OUT(GPIO_LED); GPIO_OUT(RS); GPIO_OUT(EN); GPIO_OUT(D4); GPIO_OUT(D5); GPIO_OUT(D6); GPIO_OUT(D7); lcdInit(); lcdStrPos(0, 1, "delay1530"); lcdStrPos(1, 5, "2NE LINE"); return 0; } void __exit my_exit(void){ dev_t devno = MKDEV(MAJOR_NUMBER, 0); //문자 디바이스의 등록을 해제 unregister_chrdev_region(devno, 1); //문자 디바이스의 구조체를 해제 cdev_del(&gpio_cdev); if (gpio) { //매핑된 메모리를 삭제 iounmap(gpio); } printk(KERN_INFO "Bye module!\n"); } module_init(my_init); module_exit(my_exit); MODULE_AUTHOR("Ko"); MODULE_LICENSE("GPL V2");
우분투에서 make 하면 C99 어쩌구 오류남 void lcdStr(char *str){ for(int i=0; str[i]!=0; i++){ lcdChar(str[i]); } } ----------------에서 i 타입 선언을 for문 밖에 해줘야 함-------- void lcdStr(char *str){ int i; for(i=0; str[i]!=0; i++){ lcdChar(str[i]); } }
'임베디드 > KERNEL' 카테고리의 다른 글
insmod mknod chmod 명령어 (0) | 2021.01.14 |
---|---|
라즈베리파이 test_gpio4_irq (button+led) 인터럽트 (0) | 2021.01.07 |
라즈베리파이 test_gpio3_func.c 인터럽트 (0) | 2021.01.07 |
FATAL: modpost: GPL-incompatible module 에러 (0) | 2021.01.07 |
라즈베리파이 gpio _led2 (led + buzzer) (0) | 2021.01.04 |