목표
gpio 디바이스 드라이버를 이용해 어플리케이션 레벨에서 장치파일을 통해 LED를 키고 끈다.
디바이스 드라이버 모듈
라즈베리파이 4B의 핀맵은 위와 같으며 나는 단순히 LED를 이용해 GPIO를 제어할 것이므로, 14번 GND와 16번 GPIO23을 이용해 제어해볼 것이다. 그리고 18번 핀을 이용해 INPUT으로 해당값을 읽어보기도 해보자.
16번 : GPIO 23 OUTPUT
18번 : GPIO 24 INPUT
그리고 GPIO 번호를 확인해야되는데
sudo cat /sys/kernel/debug/gpio
해당 명령어를 통해 핀에 해당되는 번호를 확인할 수 있다. 원래 이전엔 핀번호나 해당 번호나 똑같았는데 라즈베리파이 상위버전으로 가면서 확인해야된다더라... 이것때메 많이 헤멨었다.
체크하면
GPIO 23 : 535
GPIO 24 : 536
이전에서 포스트에서 변화된건 read, write 함수를 fops 필드를 추가해서 장치 파일에 read, write로 접근해보고자 하는거다.
전체 코드는 좀 길어서 링크로 첨부하겠다.
https://github.com/IH02/driver_study/blob/main/day3/led_module.c
put_user 함수가 좀 집중할 필요가 있는데, 커널 모드에서 사용자 공간(user space)으로 데이터를 복사할 때 사용하는 함수이다. 여러가지로 유용할거 같고, 나는 led값을 장치파일을 읽음으로써 어플리케이션에서 읽어볼 생각이다.
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/gpio.h>
...
static ssize_t driver_read(struct file *File, char *user_buffer, size_t count, loff_t *offs) {
unsigned int led_data;
int not_copied;
if (*offs > 0) {
// 이미 읽힌 데이터에 대해서는 EOF를 반환
return 0;
}
led_data = gpio_get_value(536);
not_copied = put_user(led_data, user_buffer);
if (not_copied) {
return -EFAULT; // 오류 발생 시 오류 코드 반환
}
*offs += sizeof(led_data); // 오프셋 업데이트
printk("GPIO_driver Read: Value of LED: %d\n", led_data);
return sizeof(led_data);
}
static ssize_t driver_write(struct file *File, const char *user_buffer, size_t count, loff_t *offs) {
int to_copy, not_copied, delta;
char value;
/* Get amount of data to copy */
to_copy = min(count, sizeof(value));
/* Copy data from User Area */
not_copied = copy_from_user(&value, user_buffer, to_copy);
printk("Write - value : %d\n",value);
switch(value) {
case '0' :
gpio_set_value(535, 0);
break;
case '1' :
gpio_set_value(535, 1);
break;
default :
printk("Invalid Input!\n");
break;
}
/* Calculate data */
delta = to_copy - not_copied;
printk("GPIO_Driver Write Function \n");
return delta;
}
static struct file_operations fops = {
.owner = THIS_MODULE,
.open = driver_open,
.release = driver_close,
.read = driver_read,
.write = driver_write
};
#define MAJOR_NUM 100
gpio.h 헤더파일을 이용해 gpio_get_value, gpio_set_value 함수를 사용해 gpio 신호를 읽고, 쓸수 있도록 하였다.
그리고 init에서 gpio_request 와 gpio_direction_output, gpio_direction_input함수를 통해 출력인지 입력인지 설정하였다.
이후 make 하여 모듈 빌드..
insmod로 모듈 설치...
다바이스 파일 만들기
찾아보니 그냥 디바이스 드라이버 모듈을 설치할때 자동으로 장치 파일이 만들어지게 설정하는 방법도 있더라...
그방법을 사용하면 디바이스 파일을 만들 필요가 없다.
출력 확인
장치 파일에 쓰기작업으로 led on, 읽기작업으로 1이 출력된것을 볼 수 있음.
어플리케이션으로 확인
int main(void){
intint main(void){
int dev, data,rdata;
dev = open("/dev/led_file", O_RDWR);
read(dev,&rdata,4);
printf("led data = %x\n", rdata);
return 0;
}
간단한 어플리케이션을 설계했다.
장치파일을 열고, 읽는 작업을 하는 어플리케이션이다.
'리눅스 > 디바이스 드라이버' 카테고리의 다른 글
[디바이스 드라이버] 4. 장치파일과 디바이스 드라이버 연결하기 (2) | 2024.09.02 |
---|---|
[디바이스 드라이버] 3. 디바이스 드라이버, 장치 파일의 종류 (1) | 2024.09.02 |
[디바이스 드라이버] 2. 모듈 프로그래밍 (1) | 2024.09.01 |
[디바이스 드라이버] 1. 디바이스 드라이버란? (0) | 2024.09.01 |