본문 바로가기
RaspberryPi

[Raspberry Pi Kernel] Kernel의 시스템 콜 함수를 활용한 GPIO Button, LED 제어

by TYB 2024. 2. 16.
반응형
 

[Raspberry Pi Kernel] Kernel의 시스템 콜 함수를 활용한 GPIO LED 제어

[Ubuntu-RaspberryPi] C언어로 U-Boot gpio제어를 통한 led 동작 및 버튼 제어 구현 목표는 led 0xff 명령어를 치면 이름 이니셜을 띄워주면서 led 작동시키고 button을 누르면 8개의 버튼 중 해당 버튼에 맞게 O

program-developers-story.tistory.com

 

이전 글 먼저 하고 오세영~

 

 

우분투로 넘어와서 이전 글에서 작성한 코드들 좀만 더 함수화하겠음.

 

커널 시스템 콜 함수 코드임.

ubuntu@ubuntu8:~/pi_bsp/kernel/linux/kernel$ cp test_mysyscall.c test_mysyscall.c_v2

#include <linux/kernel.h>
#include <linux/gpio.h>
#define OFF 0
#define ON  1
#define GPIOLEDCNT 8
int gpioLed[] = {6,7,8,9,10,11,12,13};
int gpioLedInit(void);
void gpioLedSet(long val);
void gpioLedFree(void);

asmlinkage long sys_mysyscall(long val)
{
        gpioLedInit();
        gpioLedSet(val);
        gpioLedFree();
        return 1;
}


int gpioLedInit(void)
{
        int i;
        int ret = 0; //함수들의 리턴값 저장용 변수
        char gpioNameBuff[10];//애는 스택에서 선언하는거고
        for(i=0;i<GPIOLEDCNT;i++)
        {
                sprintf(gpioNameBuff,"led%d",i);
                ret = gpio_request(gpioLed[i],gpioNameBuff);
                if(ret < 0){
                        printk("Failed gpio_request() gpio%d error \n",6);
                        return ret;
                }
                ret = gpio_direction_output(gpioLed[i],OFF);
                if(ret < 0){
                        printk("Failed gpio_direction_output() gpio%d error \n",6);
                        return ret;
                }
        }

}

void gpioLedSet(long val)
{
        int i;
        for(i=0;i<GPIOLEDCNT;i++)
        {
                gpio_set_value(gpioLed[i],(val>>i) & 0x1);//입력을 0xff처럼 받아서 1비트씩 비교해서 val를 써주면 됨
        }
}

void gpioLedFree(void)
{
        int i;
        for(i=0;i<GPIOLEDCNT;i++)
        {
                gpio_free(gpioLed[i]);
        }

}

 

리눅스 디바이스 드라이버 단에선 c 코드 작성할 때 입력값 없으면 void 넣어줘야 됨. warning 나옴

 

작성 끝났으니, 빌드하고 파일 넘기고

 

라즈베리파이에서도 파일 받아서 폴더에 넣어주고 재부팅합시다

잘됬죠?


gpio 버튼을 통해 led를 제어하는 코드

 

1. kernel system call 함수 부분

#include <linux/kernel.h>
#include <linux/gpio.h>
#define OFF 0
#define ON  1
#define GPIOLEDCNT 8
#define GPIOKEYCNT 8
int gpioLed[] = {6,7,8,9,10,11,12,13};
int gpioKey[] = {16,17,18,19,20,21,22,23};
int gpioLedInit(void);
int gpioKeyInit(void);
unsigned long gpioKeyGet(void);
void gpioKeyFree(void);
void gpioLedSet(long val);
void gpioLedFree(void);

asmlinkage long sys_mysyscall(long val)
{
        int ret;
        ret=gpioLedInit();
        if(ret<0)
        {
                return ret;
        }
        gpioLedSet(val);
        gpioLedFree();

        ret=gpioKeyInit();
        if(ret<0)
                return ret;
        ret=gpioKeyGet();
        gpioKeyFree();
        return ret;
}


int gpioLedInit(void)
{
        int i;
        int ret = 0; //함수들의 리턴값 저장용 변수
        char gpioNameBuff[10];//애는 스택에서 선언하는거고
        for(i=0;i<GPIOLEDCNT;i++)
        {
                sprintf(gpioNameBuff,"led%d",i);
                ret = gpio_request(gpioLed[i],gpioNameBuff);
                if(ret < 0){
                        printk("Failed gpio_request() gpio%d error \n",6);
                        return ret;
                }
                ret = gpio_direction_output(gpioLed[i],OFF);
                if(ret < 0){
                        printk("Failed gpio_direction_output() gpio%d error \n",6);
                        return ret;
                }
        }
        return 1;
}

void gpioLedSet(long val)
{
        int i;
        for(i=0;i<GPIOLEDCNT;i++)
        {
                gpio_set_value(gpioLed[i],(val>>i) & 0x1);//입력을 0xff처럼 받아서 1비트씩 비교해서 val를 써주면 됨
        }
}

void gpioLedFree(void)
{
        int i;
        for(i=0;i<GPIOLEDCNT;i++)
        {
                gpio_free(gpioLed[i]);
        }

}

int gpioKeyInit(void)
{
        int i;
        int ret = 0; //함수들의 리턴값 저장용 변수
        char gpioNameBuff[10];//애는 스택에서 선언하는거고
        for(i=0;i<GPIOKEYCNT;i++)
        {
                sprintf(gpioNameBuff,"key%d",i);
                ret = gpio_request(gpioKey[i],gpioNameBuff);
                if(ret < 0){
                        printk("Failed gpio_request() gpio%d error \n",6);
                        return ret;
                }
                ret = gpio_direction_input(gpioKey[i]);
                if(ret < 0){
                        printk("Failed gpio_direction_output() gpio%d error \n",6);
                        return ret;
                }
        }
        return 1;

}

unsigned long gpioKeyGet(void)
{
        unsigned long key_value=0x00;
        int i;
        for(i=0;i<GPIOKEYCNT;i++)
        {
                key_value = (key_value) | gpio_get_value(gpioKey[i])<<i;
        }
        return key_value;
}

void gpioKeyFree(void)
{
        int i;
        for(i=0;i<GPIOKEYCNT;i++)
        {
                gpio_free(gpioKey[i]);
        }
}

 

빌드해서 파이에 zImage 넘겨주고

라즈베리파이 재부팅~

 

 

2. application 부분

pi@pi08:~/systemcall_test$ vi syscall_app_v2_ledkey.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <asm-generic/unistd.h>
#pragma GCC diagnostic ignored "-Wunused-result"
int main(int argc, char *argv[])
{
        unsigned int val=0, key_data,key_data_old=0;
        int i;
        if(argc < 2)
        {
                printf("USAGE : %s ledVal[0x00~0xff]\n",argv[0]);
                return 1;
        }
        val = strtoul(argv[1],NULL,16);
        if(val<0 || 0xff<val)
        {
                printf("Usage : %s ledValue(0x00~0xff)\n",argv[0]);
                return 2;
        }
        do {
                usleep(100000);  //100MSec
                key_data = syscall(__NR_mysyscall,val);
                if(key_data != key_data_old)
                {
                        key_data_old = key_data;
                        if(key_data)
                        {
                                val = key_data;
                                puts("0:1:2:3:4:5:6:7");
                                for(i=0;i<8;i++)
                                {
                                        if(key_data & (0x01 << i))
                                                putchar('O');
                                        else
                                                putchar('X');
                                        if(i != 7 )
                                                putchar(':');
                                        else
                                                putchar('\n');
                                }
                                putchar('\n');
                        }
                        if(key_data == 0x80)
                                break;
                }
        }while(1);
        printf("mysyscall return value = %#04x\n",key_data);
        return 0;
}

 

컴파일하고 실행~

 

 

 

 

 

 


vi 명령어

cw해서 커서 뒤에 있는 한 단어 삭제 하고 문자들을 넣어줄수 있는데

 

:%s 모든 문자열 중에 

/gpioLedCnt 이 문자를

/GPIOLEDCNT 이 문자로 바꾸겠다.

:%s /gpioLedCnt/GPIOLEDCNT

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

반응형