본문 바로가기
임베디드/KERNEL

라즈베리파이 gpio _led2 (led + buzzer)

by sj0020 2021. 1. 4.

1 누르면 LED 켜지고 부저 한번 울림 (led off 에서 on 상태로 될때만)
2 누르면 LED 꺼지고 부저 두번 울림 (led on 에서 off 상태로 될때만)
3 누르면 프로그램 종료되고 부저 세번 울림 (led는 무조건 off됨)

 

 

#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

#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)
#define GPIO_CLR(g)     (*(gpio+10) = 1<<g)
#define GPIO_GET(g)     (*(gpio+13) & (1<<g))

#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 GPIO_BUZZER       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;


int  i,j, state = 0;

void buzzer1(void){
	printk(KERN_INFO "buzzer1 ON\n");
	GPIO_SET(GPIO_BUZZER);
	mdelay(100);
	GPIO_CLR(GPIO_BUZZER);
}

void buzzer2(void){
	printk(KERN_INFO "buzzer2 ON\n");
	for (i=0; i < 2; i++){
		GPIO_SET(GPIO_BUZZER);
		mdelay(100);
		GPIO_CLR(GPIO_BUZZER);
		mdelay(100);
	}
}

void buzzer3(void){
	printk(KERN_INFO "buzzer3 ON\n");
	for (j=0; j<3; j++){ 
		GPIO_SET(GPIO_BUZZER);
		mdelay(100);
		GPIO_CLR(GPIO_BUZZER);
		mdelay(100);
	}
	
}

//장치파일 열기
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("<Ko> GPIO_GET(GPIO_LED): %d \n",GPIO_GET(GPIO_LED));
   printk(KERN_DEBUG "IOCTRL_LED_ON : %d \n" ,IOCTRL_LED_ON);
   

   switch(cmd){
   case IOCTRL_LED_ON:
	  if(state == 0 | state == 2){	  
		printk(KERN_INFO "LED ON in kernel\n");	  
		GPIO_SET(GPIO_LED);
		buzzer1();	 
		state = 1;
	  }
	  break;
   
   case IOCTRL_LED_OFF:
	 if(state == 1){
      printk(KERN_INFO "LED OFF in kernel\n");
      GPIO_CLR(GPIO_LED);
	  buzzer2();	
	  state = 2;
	 }
      break;
   
   case IOCTRL_EXIT:
      printk(KERN_INFO "App exit\n");
	  GPIO_CLR(GPIO_LED);
	  buzzer3();
	  state = 0;
      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_IN(GPIO_LED);
    GPIO_OUT(GPIO_LED);
	
	//부저 사용을 위한 초기화
	GPIO_OUT(GPIO_BUZZER);
    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("Rack");

 

 

#include <unistd.h>
//#include <fcntl.h>
#include <stdio.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <string.h>
#include <stdlib.h>


typedef enum {
	IOCTRL_LED_ON = 1000,
	IOCTRL_LED_OFF,
	PROGRAM_EXIT
} ioctrlCmd_t;

int main(int argc, char **argv) {
   int dev = 0;
   //char buff[1024] = { 0,};
   int menu = 0;
   dev = open("/dev/gpio_led", O_RDWR); //open은 한번만 열면 됨
   while(1){
	   printf("--------------------\nKERNEL Module Control 1.0\n--------------------\n");
	   printf("1. LED ON\n2. LED OFF\n3. EXIT\n");
	   printf("-------------------\n");
	   printf("menu : ");
	   scanf("%d", &menu);
	   switch(menu +999){
			case IOCTRL_LED_ON:
				ioctl(dev, IOCTRL_LED_ON);
				break;
			case IOCTRL_LED_OFF:
				ioctl(dev, IOCTRL_LED_OFF);
				break;
			case PROGRAM_EXIT:
				printf("Exit BYE\n");
				ioctl(dev, PROGRAM_EXIT);
				close(dev);
				exit(0);
	   }
   }
   
   return 0;
}

이해 안되는 코드

if (GPIO_GET(GPIO_LED) == 0x40000 ){ 
   //부저 울림 
   printk(KERN_INFO "buzzer ON\n"); 
   GPIO_SET(GPIO_BUZZER); 
   } 
    
   if (GPIO_GET(GPIO_LED) ==0){ 
   //부저 꺼짐 
   printk(KERN_INFO "buzzer OFF\n"); 
   GPIO_CLR(GPIO_BUZZER); 
   } 

 

232144 = 2의 18승 값
sudo rmmod [ko파일이름]