Busan IT/로봇제어2015. 11. 6. 13:36

==================================Outline====================================

LED 제어 디바이스 드라이버

----------------------------------------------------------------------------

LED 제어 디바이스 드라이버

 

p/558 [smart.c] : 드라이버 소스

p/565 [smart.h] : 헤더 파일

p/566 [led_app.c] : 애플리케이션 소스

 

코드를 간소화 시키기 위해 LED 1개만 이용하고 이에 맞게 코드를 수정하여 작성해보자.

 

핀을 BCM23번을 사용한다.

 

 

 

사용자로부터 명령을 입력받아 LED를 제어할 수 있도록 코드를 작성하자.

 









/*** 소스 ***/


[smart.c]

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/delay.h>

#include <asm/mach/map.h>
#include <asm/io.h>
#include <asm/uaccess.h>

#include "smart.h"

#define SMART_MAJOR   501
#define NAME      "SMART_DRV"

#define GPIO_BASE_PA   0x3F200000
#define GPIO_GPFSEL1   (0x04)
#define GPIO_GPFSEL2   (0x08)
#define GPIO_GPSET0   (0x1C)
#define GPIO_GPCLR0   (0x28)
#define GPIO_GPLEV0   (0x34)

#define GPIO_FSEL23_OUT  (1<<9)

#define GPIO_23      (1<<23)

static void __iomem *gpio_base_va;
volatile unsigned *gpfsel1;
volatile unsigned *gpfsel2;
volatile unsigned *gpset0;
volatile unsigned *gpclr0;
volatile unsigned *gplev0;

unsigned int old_reg;

static void all_led_onoff(void)
{
  *gpset0 |= GPIO_23;
  
  mdelay(500);

  *gpclr0 |= GPIO_23;
}
static void led_on(void)
{
  *gpset0 |= GPIO_23;
}

static void led_off(void)
{
  *gpclr0 |= GPIO_23;
}

int led_open(struct inode *inode, struct file *filp)
{
  printk("RPi LED init=n");

  gpio_base_va = ioremap(GPIO_BASE_PA, 0x60);
  printk("gpio_base: %p\n", gpio_base_va);

  gpfsel1 = (volatile unsigned *)(gpio_base_va + GPIO_GPFSEL1);
  gpfsel2 = (volatile unsigned *)(gpio_base_va + GPIO_GPFSEL2);
  gpset0 = (volatile unsigned *)(gpio_base_va + GPIO_GPSET0);
  gpclr0 = (volatile unsigned *)(gpio_base_va + GPIO_GPCLR0);
  gplev0 = (volatile unsigned *)(gpio_base_va + GPIO_GPLEV0);

  printk("gpfsel2- addr: %p, value: %x\n", gpfsel2, *gpfsel2);
  old_reg = *gpfsel2;
  *gpfsel2 |= (GPIO_FSEL23_OUT);

  all_led_onoff();

  return 0;
}

int led_release(struct inode *inode, struct file *filp)
{
  printk("RPi LED exit\n");

  all_led_onoff();

  *gpfsel2 = old_reg;

  iounmap( (void *)gpio_base_va);

  return 0;
}

ssize_t led_read(struct file *filp, char *user, size_t size, loff_t *pos)
{
  int val;
  unsigned int led_state = 0;

  printk("RPi LED Read\n");

  val = *gplev0;

  if(val & GPIO_23)
    led_state |= 1;

  return led_state;
}

ssize_t led_write(struct file *flip, const char *user, size_t size, loff_t *pos)
{
  unsigned int led_state = 0;

  printk("RPi LED Write\n");

  get_user(led_state, (unsigned int *)user);
  printk("led valude: %d\n", led_state);

  if(led_state & 1)
    led_on();
  else
    led_off();

  return led_state;
}

long led_ioctl(struct file *flip, unsigned int cmd, unsigned long addr)
{
  int size;
  unsigned int led_state = 0;

  printk("RPi LED ioctl\n");

  if(_IOC_TYPE(cmd) != LED_IOCTL_MAGIC)
      return -EINVAL;
    
    
  if(_IOC_NR(cmd) >= LED_IOCTL_MAX)
      return -EINVAL;

  size = _IOC_SIZE(cmd);

  if(size)
  {
    if(_IOC_DIR(cmd) & _IOC_READ)
      if(access_ok(VERITY_WRITE, (void *)addr, size) < 0)
        return -ENOMEM;
    if(_IOC_DIR(cmd) & _IOC_WRITE)
      if(access_ok(VERITY_READ, (void *)addr, size) < 0)
        return -ENOMEM;
  }

  switch(cmd)
  {
    case LED_INIT:
      all_led_onoff();
      break;
    case LED_RED_ON:
      led_on();
      break;
    case LED_RED_OFF:
      led_off();
      break;
    case LED_ON_OFF:
      get_user(led_state, (unsigned int*)addr);
      printk("led_state: %d\n", led_state);

      if(led_state & 1)
        led_on();
      else
        led_off();

      break;
  }
  return 0;
}

struct file_operations led_fops = {
  .open    = led_open,
  .release  = led_release,
  .read    = led_read,
  .write    = led_write,
  .unlocked_ioctl  = led_ioctl
};

static int smart_init(void)
{
  int ret = register_chrdev(SMART_MAJOR, NAME, &led_fops);

  if(ret < 0)
  {
    printk("RPi LED Driver registration failed: %d\n", ret);
  }
  else
  {
    printk("RPi LED Driver registration success");
  }

  return ret;
}

static void smart_exit(void)
{
  unregister_chrdev(SMART_MAJOR, NAME);
  printk("RPi LED Driver unregistered\n");

  return;
}  

module_init(smart_init);
module_exit(smart_exit);

MODULE_LICENSE("GPL");



[led_app.c]


#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

#include "smart.h"

#define SMART_MAJOR   501
#define SMART_MINOR    100
#define NAME      "SMART_DRV"

#define LED_ON      1
#define LED_OFF      0

int main(void)
{
  int iFd;
  int iRtn=0;
  dev_t led_dev;
  unsigned int led_state = 0;
  char * cpBuf = "";
  unsigned char cInput;
  unsigned int uiCnt;
  int iBuf = 0;

  led_dev = makedev(SMART_MAJOR, SMART_MINOR);
  mknod(NAME, S_IFCHR|0666, led_dev);

  iFd = open(NAME, O_RDWR);
  printf("led fd: %d\n", iFd);

  sleep(1);
  printf("ioctl: LED_INIT\n");
  ioctl(iFd, LED_INIT);
  sleep(1);

  while(1)
  {
    if(iRtn == 100)
      break;
    printf("Please input command ::\n");
    printf("0: LED OFF  1: LED ON  2: LED ON/OFF  3: QUIT\n");
    read(0&cInput, sizeof(char));
    switch(cInput)
    {
      default:
        break;
      case '0':
        printf("LED OFF\n");
        ioctl(iFd, LED_RED_OFF);
        iRtn = read(iFd, &iBuf, 4);
        printf("LED state: %X, RTN: %d\n", iBuf, iRtn);
        sleep(1);
        break;

      case '1':
        printf("LED ON\n");
        ioctl(iFd, LED_RED_ON);
        iRtn = read(iFd, &iBuf, 4);
        printf("LED state: %X, RTN: %d\n", iBuf, iRtn);
        sleep(1);        
        break;

      case '2':
        printf("LED ON/OFF\n");
        for(uiCnt = 0; uiCnt < 3; ++uiCnt)
        {
          led_state = LED_ON;
          ioctl(iFd, LED_ON_OFF, &led_state);
          iRtn = read(iFd, &iBuf, 4);
          printf("LED state: %X, RTN: %d\n", iBuf, iRtn);
          sleep(1);

          led_state = LED_OFF;
          ioctl(iFd, LED_ON_OFF, &led_state);
          iRtn = read(iFd, &iBuf, 4);
          printf("LED state: %X, RTN: %d\n", iBuf, iRtn);
          sleep(1);
        }
        break;

      case '3':
        iRtn = 100;
        printf("program terminated\n");
        break;

    }
    if'\n' == getchar() );
    putchar('\n');
  }

  return 0;
}



[smart.h]

#ifndef __SMART_H__
#define __SMART_H__

#define  LED_IOCTL_MAGIC  '1'

#define LED_INIT  _IO(LED_IOCTL_MAGIC, 0)
#define LED_RED_ON  _IO(LED_IOCTL_MAGIC, 1)
#define LED_RED_OFF  _IO(LED_IOCTL_MAGIC, 2)
#define LED_ON_OFF  _IOW(LED_IOCTL_MAGIC, 7int)

#define LED_IOCTL_MAX  8

#endif // __SMART_H__



[Makefile]


obj-m = smart.o

KDIR = /usr/src/linux

PWD = $(shell pwd)

all:
  @clear
  $(MAKE) -C $(KDIR) M=$(PWD) modules
  @ls -al smart.ko

up:
  @clear
  @insmod smart.ko
  @echo ================== dmesg =================
  @dmesg | tail
  @echo ================== dmesg =================

down:
  @clear
  @rmmod smart
  @echo ================== dmesg =================
  @dmesg | tail
  @echo ================== dmesg =================

clean:
  @clear
  @rm -rf *.ko
  @rm -rf *.mod.*
  @rm -rf .*.cmd
  @rm -rf *.o
  @rm -rf modules.order
  @rm -rf Module.symvers
  @rm -rf .tmp_versions
  @ls -al
  @echo Clean :Done.

 

 

반응형
Posted by newind2000
Busan IT/로봇제어2015. 11. 4. 16:26

==================================Outline====================================

라즈베리 파이 커널 빌드와 디바이스 드라이버

----------------------------------------------------------------------------

 

라즈베리 파이 커널 빌드와 디바이스 드라이버

 

p/521

 

교재의 소스를 참고하여 디바이스 드라이버를 작성해 보겠다.

 

p/521 [simple_drv.c - part1] - 디바이스 드라이버 소스

p/528 [simple_drv.c - part2] - 디바이스 드라이버 소스

p/532 [simple_ioctl.h] - 디바이스 드라이버 명령어 정의

p/541 [Makefile] - 컴파일 실행 소스

p/542 [simple_app.c] - 디바이스 드라이버 테스트 코드

 

코딩이 완료되면 컴파일한다.

 

# make

컴파일로부터 생성된 파일들을 확인할 수 있다.

 

# ll

 

 

simple_app 애플리케이션을 컴파일을 위해 작성해놓은 ‘Makefile'을 재사용한다.

 

# make simple_app

실행 파일이 생성된 것을 확인할 수 있다.

 

모듈 명령어를 사용하여 생성한 모듈을 적재한 후 확인한다.

 

# insmod simple_app.ko

# lsmod

/proc/devices 파일을 통해서도 simple_drv정보를 확인할 수 있다.

 

 

애플리케이션을 실행시켜서 결과값을 확인해본다.





/*** 소스 ***/

[simple_drv.c]

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/poll.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>

#include "simple_ioctl.h"

#define SIMPLE_MAJOR    500
#define SIMPLE_MINOR    100

#define SIMPLE_DEV_NAME "/dev/simple"

#define SIMPLE_DEV_ADDR 0x80000000
#define SIMPLE_DEV_SIZE 0x8000

int main()
{
    int fd, ret, rVal = 0, wVal = 200;
    char rBuf[80= "";
    char wBuf[] = "98765432109876543210";
    char *addr;
    struct pollfd pfd[1];
    dev_t simple_dev;
    char tmp[40= "";

    simple_dev = makedev(SIMPLE_MAJOR, SIMPLE_MINOR);
    ret = mknod(SIMPLE_DEV_NAME, S_IFCHR|0666, simple_dev);

    fd = open(SIMPLE_DEV_NAME, O_RDWR);
    printf("open: %d\n", fd);

    ret = read(fd, rBuf, 15);
    rBuf[ret] = '\0';
    printf("read: %s, reg: %d\n", rBuf, ret);

    ret = write(fd, wBuf, 15);
    printf("write ret: %d\n", ret);

    ret = ioctl(fd, SIMPLE_INIT);
    printf("ioctl[SIMPLE_INIT] ret: %d\n", ret);

    ret = ioctl(fd, SIMPLE_READ, &rVal);
    printf("ioctl[SIMPLE_READ] data: %d, ret: %d\n", rVal, ret);

    ret = ioctl(fd, SIMPLE_WRITE, &wVal);
    printf("ioctl[SIMPLE_WRITE] ret: %d\n", ret);

    printf("ioctl[SIMPLE_RDWR] before-> wVal: %d\n", wVal);
    ret = ioctl(fd, SIMPLE_RDWR, &wVal);
    printf("ioctl[SIMPLE_RDWR] after -> wVal : %d, ret: %d\n", wVal, ret);
    printf("--------------before mmap\n");
    sprintf(tmp, "pmap -x %d", getpid() );
    system(tmp);
    addr = (char *)mmap(0, SIMPLE_DEV_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, SIMPLE_DEV_ADDR);
    printf("mmap addr: %p\n", addr);

     printf("--------------after mmap\n");
     system(tmp);

     munmap(addr, SIMPLE_DEV_SIZE);
     printf("--------------after munmap\n");
     system(tmp);

     pfd[0].fd = fd;
     pfd[0].events = POLLIN|POLLOUT|POLLERR;

     while(1)
     {
         ret = poll((struct pollfd *)&pfd, 13000);

         if(pfd[0].revents & POLLIN)
         {
             ret = read(fd, rBuf, 10);
         }
         else if(pfd[0].revents & POLLOUT)
         {
             ret = write(fd, wBuf, 10);
         }
         else if(pfd[0].revents & POLLERR)
         {
             printf("poll error!!\n");
         }

         if(ret == 0)
         {
             printf("poll timeout occured\n");
             break;
         }

     }

     close(fd);
     return 0;
 }

[simple_app.c]
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/mman.h>
 #include <linux/sched.h>

 #include <asm/page.h>
 #include <asm/io.h>
 #include <asm/uaccess.h>
 #include <linux/poll.h>


 #ifdef ARCH_ARM
 #include <mach/irgs.h>
 #include <mach/reg_gpio.h>
 #endif

 #include "simple_ioctl.h"

 #define DEV_MAJOR   245
 #define DEV_NAME    "Simple Driver"

 #define DEV_ADDR    0x80000000
 #define DEV_SIZE    0x8000
 #define IRQF_DISABLED 0x20

 int simple_major;

 int simple_open(struct inode *inode, struct file *filp)
 {
     int major, minor;
     major = MAJOR(inode->i_rdev);
     major = MINOR(inode->i_rdev);
     printk("Simple Driver : open\n");
     printk("--> major : %d, minor : %d\n", major, minor);
     return 0;
 }

 int simple_release(struct inode *inode, struct file *filp)
 {
     printk("Simple Driver : release\n");
     return 0;
 }

 ssize_t simple_read(struct file *filp, char *buf, size_t size, loff_t *pos)
 {
     char data[] = "12345678901234567890";

     printk("Simple Driver : read\n");

     copy_to_user(buf, data, size);

     return 0x11;
 }

 ssize_t simple_write(struct file *filp, const char *buf, size_t size, loff_t *pos)
 {
    char data[40];

    copy_from_user(data, buf, size);

    printk("Simple Driver : write\n");

    data[size] = '\0';
    printk("--> from user : %s\n", data);

    udelay(100);

    return 0x22;
}

long simple_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    int size;
    int rval = 0;
    int wval = 100;
    int ret;

    printk("Simple Driver: ioctl\n");

    if(_IOC_TYPE(cmd) != SIMPLE_IOCTL_MAGIC) return -EINVAL;
    if(_IOC_NR(cmd) >= SIMPLE_IOCTL_MAX) return -EINVAL;

    size = _IOC_SIZE(cmd);

    if(size)
    {
        if(_IOC_DIR(cmd) & _IOC_READ)
            if(access_ok(VERIFY_WRITE, (void *)arg, size) < 0)
                return -EINVAL;
        if(_IOC_DIR(cmd) & _IOC_WRITE)
            if(access_ok(VERIFY_READ, (void *)arg, size) < 0)
                return -EINVAL;
    }

    switch(cmd)
    {
        case SIMPLE_INIT:
            printk("-->SIMPLE_INIT\n");
            ret = 0x31;
            break;
        case SIMPLE_READ:
            printk("-->SIMPLE_READ\n");
            copy_to_user( (void *)arg, &wval, sizeof(int) );
            ret = 0x32;
            break;
        case SIMPLE_WRITE:
            printk("-->SIMPLE_WRITE\n");
            copy_from_user( &rval, (void *)arg, sizeof(int) );
            printk("----> from user : %d\n", rval);
            ret = 0x33;
            break;
        case SIMPLE_RDWR:
            printk("-->SIMPLE_RDWR\n");
            ret = 0x34;
             break;
     }

     return ret;
 }

 int simple_mmap(struct file *filp, struct vm_area_struct *vma)
 {
     printk("Simple Driver : mmap\n");

     remap_pfn_range(vma, vma->vm_start, DEV_ADDR >> PAGE_SHIFT, DEV_SIZE, vma->vm_page_prot);

     printk("--> start : 0x%x, end: 0x%x\n", (unsigned int)vma->vm_start, (unsigned int)vma->vm_end);
     return 0;
 }

 int readCnt = 0;
 int writeCnt = 0;
 DECLARE_WAIT_QUEUE_HEAD(readQueue);
 DECLARE_WAIT_QUEUE_HEAD(writeQueue);

 int simple_poll(struct file *filp, struct poll_table_struct *pt)
 {
     unsigned int state = 0;

     printk("Simple Driver : poll\n");

     poll_wait(filp, &readQueue, pt);
     poll_wait(filp, &writeQueue, pt);

     if(readCnt > 0)
     {
         state |= POLLIN | POLLRDNORM;
     }
     if(writeCnt > 0)
     {
         state |= POLLIN | POLLWRNORM;
     }

     return state;

 }

 irqreturn_t simple_handler(int irq, void *dev_id)
 {
     printk("Simple Interrupt handler\n");
     printk("--> irq number : %d\n", irq);
     return IRQ_HANDLED;
 }

 struct file_operations simple_fops =
 {
     .open       = simple_open,
     .release    = simple_release,
     .read       = simple_read,
     .write      = simple_write,
     .unlocked_ioctl = simple_ioctl,
     .mmap       = simple_mmap,
     .poll       = simple_poll,
 };

 int simple_drv_init(void)
 {
     simple_major = register_chrdev(DEV_MAJOR, DEV_NAME, &simple_fops);

     printk("Simple Driver : registered\n");
     printk("--> major : %d\n", simple_major);

     if(request_irq(10, simple_handler, IRQF_DISABLED, "Simple Interrupt", NULL) < 0)
         printk("--> request irq failed\n");

     return simple_major;
 }

 void simple_drv_exit(void)
 {
     unregister_chrdev(simple_major, DEV_NAME);
     printk("Simple Driver : unregistered\n");
     return;
 }

 module_init(simple_drv_init);
 module_exit(simple_drv_exit);
 MODULE_LICENSE("Dual BSD/GPL");




[simple_ioctl.h]

 #define SIMPLE_IOCTL_MAGIC  's'

 #define SIMPLE_INIT         _IO(SIMPLE_IOCTL_MAGIC, 0)
 #define SIMPLE_READ         _IOR(SIMPLE_IOCTL_MAGIC, 1int)
 #define SIMPLE_WRITE        _IOW(SIMPLE_IOCTL_MAGIC, 2int)
 #define SIMPLE_RDWR         _IOWR(SIMPLE_IOCTL_MAGIC, 3int)

 #define SIMPLE_IOCTL_MAX    4


[Makefile]
 obj-m := simple_drv.o

 ifeq ($(ARCH), xxx)
 KDIR :=/usr/src/linux
 CROSS_COMPILE :=arm-none-linux-gnueabi-
 CCFLAGS := -static
 else
 KDIR :=/lib/modules/$(shell uname -r)/build
 endif

 TARGET := simple_app
 PWD := $(shell pwd)
 CC := ${CROSS_COMPILE}gcc
 LD := ${CROSS_COMPILE}ld
 AR := ${CROSS_COMPILE}ar

 all:
     $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
 $(TARGET): simple_app.c
     $(CC) $(CCFLAGS) -o $@ $^

 clean:
     $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean
     rm -f $(TARGET)



 

 

 

 

반응형
Posted by newind2000
Busan IT/로봇제어2015. 11. 3. 17:44

==================================Outline====================================

저수준 C프로그래밍

- sysfs를 이용한 GPIO 제어

- 라즈베리 파이 커널 빌드와 디바이스 드라이버

- 커널 빌드

- 모듈 프로그래밍

디바이스 드라이버 프로그래밍

- 'file_operations' 구조체의 명령어

----------------------------------------------------------------------------

저수준 C프로그래밍


sysfs를 이용한 GPIO 제어

 

p/474

 

sys파일 시스템은 하드웨어에 대한 정보를 체계적으로 제공한다. Raspbian 커널에 GPIO포트를 제어하기 위한 드라이버가 포함되어 있고 sys 파일 시스템을 통해 사용자에게 GPIO포트 설정 및 제어를 수행할 수 있는 기능이 포함되어 있다.

 

 

export파일을 제어하고자 하는 GPIO 포트 번호를 써주면 해당 핀의 파일명이 심볼릭 링크 파일로 생성된다.

 

 

이 링크를 제어하여 led를 제어할 수 있다.

 






 

라즈베리 파이 커널 빌드와 디바이스 드라이버

 

p/478

 

리눅스 커널은 리눅스 커뮤니티에서 제공한다. 사용자 편의에 위해 다양한 기능을 추가하여 공개하는 것을 배포판이라고 한다. Debian은 잘 알려진 배포판이다.

 

//GPL(General Purpose License)

 

리눅스는 GPL을 기반으로 하는 오픈소스 커널이기 때문에 이것을 사용하는 모든 프로램은 소스 코드를 공개해야 할 의무가 있다.

 

안드로이드는 리눅스 기반이지만 gcc컴파일러와 헤더파일을 사용하지 않기 때문에 소스 코드를 공개할 필요가 없다.

 

간단한 C파일을 작성하여 컴파일해보자. 컴파일이 완료되면 해당 파일의 정보를 살펴본다.

 

 

ELF32 format, ARM 아키텍쳐 사용

 

//커널 소스 다운로드 이전에 했음으로 넘어간다.

 

커널 빌드

p/493 

 

ATmega32는 리눅스 기반에서도 작동한다.

'ia64' 인텔의 CPU를 말한다.

 

RaspberryPi2의 아키텍쳐는 'mach-bcm2709'를 사용한다.

 

초보자들을 위해 기본적인 설정이 ‘config' 파일로 제공된다. 초보자의 경우는 기본적인 ‘config’파일을 사용한다.

 



 

커널 빌드 시 교재 p/4931 - 4단계까지만 수행하고 나머지 과정은 파일을 복사하여 진행하는 것이 빠르다.

 

‘menu-config ’시 수정된 내용이 있으면 저장 메시지를 띄워준다.

 

‘WinSCP’는 파일 전송을 위해 사용되는 프로그램이다. 필요할 경우 설치하여 사용한다.

 

커널 빌드는 지난 시간에 수행했음으로 따로 할 필요는 없다.

 

모듈 프로그래밍

 

p/507

 

리눅스의 경우 주변 장치는 운영체제에 의해 관리된다. 운영체제는 커널 모드와 사용자 모드로 구분해 주소 공간을 분리하고 시스템 자원을 관리한다. 이 때 장치에 대한 관리 권한은 커널 모드에만 제공된다. 시스템 콜 기반으로 커널을 관리하는 경우는 커널 소스를 직접 수정해야 하고, 컴파일과 리셋의 과정을 수행해야 한다. 모듈을 사용한다면 커널 빌드 없이 장치를 사용할 수 있다. 다만 모듈을 사용할 경우 커널 버전이 모듈 커널의 버전과 일치해야 하며 root 계정으로만 작업 가능하다.

 

교재 p/508 ~ p/509의 소스를 실행하여 간단한 모듈 동작 과정과 사용법을 알아보자.


/*** 소스 ***/

[Makefile]

 obj-m := simple_mod.o

     KDIR := /usr/src/linux
 PWD := $(shell pwd)
     FILE := simple_mod

 all:
     @echo
         $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
         dmesg | tail -5

 clean:
     @echo
         $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean
         dmesg | tail -5

 up:
     @echo
         insmod $(FILE).ko
         dmesg | tail -5
         lsmod

 down:
     @echo
         rmmod $(FILE)
         dmesg | tail -5
         lsmod


[simple_mod.c]


#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>

int simple_mod_init(void)
{
        printk("simple module loaded\n");
        return 0;
}

int simple_mod_exit(void)
{
        printk("simple module unloaded\n");
        return 0;
}

module_init(simple_mod_init);
module_exit(simple_mod_exit);
MODULE_LICENSE("GPL");

 

셸 명령어에 따른 모듈이 내부에 적재될 때 메모리 위치를 살펴보자.

4GB의 메모리라고 했을 때 커널은 상위 1GB영역에 위치한다. 이러한 커널은 다시 세 영역으로 나뉜다. 하위 16MB영역은 직접 액세스 영역, 16 ~ 896MB 영역은 Norname Zone, 896MB에서 나머지 영역은 High Memory Zone으로 구분된다.

 

shell 명령어 창에서 ‘/pro/kallsysm'명령어를 입력하면 커널 심볼 테이블을 볼 수 있다.

 

//페이지를 나누어서 출력시키기 위한 명령어 'more' -> '/pro/kallsysm | m



디바이스 드라이버 프로그래밍

 

p/517

디바이스 드라이버를 사용하기 위해서는 ‘file_operation’구조체에 정의 되어 있는 open, close, read, write 함수 등을 사용해야 한다.

file_operation 구조체는 linux/fs.h에 포함되어 있으며 함수 포인터들을 멤버로 가지고 있다.

 

프로그램이 직접적으로 하드웨어를 제어하는 것은 kernel에 의해 금지된다. 프로그램은 커널을 통해 하드웨어를 제어해야한다. 커널은 모든 장치를 파일화하여 관리한다. 하드웨어 대한 정보를 ‘/dev’ 폴더에 저장해 놓는다.

 

사용자는 임의적으로 하드웨어 장치를 생성할 수 있는 명령어는 'mknod'이다.

존재하는 장치의 구동을 위한 명령어는 'insmod'이다. 'insmod'는 장치를 초기화하기 위해 'Init' 함수를 사용한다. 또한 ‘file_oeration'구조체의 함수를 사용하여 장치를 제어하게 된다.

응용 프로그램 개발자는 파일이름만 알면 장치를 제어할 수 있다. 때문에 상세한 장치구조에 대해서는 굳이 알 필요가 없다.

 

'file_operations' 구조체의 명령어

 

open: 디바이스 드라이버가 실제로 사용되기 위해 호출되는 함수. ‘open'함수는 장치 열기에 성공했을 시, 파일 디스크립터가 아닌 ’0'을 반환한다.

 

release: 'close'함수와 같은 기능을 한다. 즉 연결되어 있는 파일 장치를 닫는 역할을 한다.

 

read: 디바이스에 대한 입력을 위해 사용되는 함수이다.

 

write: 디바이스의 출력을 위해 사용되는 함수이다.

 

ioctl: read/write 이 외의 다양한 연산을 제공한다. read/write 기능 또한 'ioctl'에서 구현 가능하다.

 

mmap: 메모리 매핑을 위한 함수로써 물리적 주소를 가상 공간으로 변환해 준다.

 

poll: 인터럽트의 처리와 연관되어 사용되는 함수이다.

'read' 함수의 4번째 인자는 읽어 들일 데이터의 시작점이다.

 

p/521 예제 코드 분석

 

예제는 내일 쳐본다.















  

 

 

 

반응형
Posted by newind2000
Busan IT/로봇제어2015. 11. 2. 15:50

==================================Outline====================================

저수준 프로그래밍

- GPIO를 제어하는 레지스터

- GPIO를 활용한 LED 제어

----------------------------------------------------------------------------

 

저수준 C 프로그래밍

 

p/459

 

ATmega 시리즈에서는 PORTx로 각 핀을 제어하면 값을 넣을 때마다 모든 값이 갱신된다. ARM 시리즈에서는 SET레지스터와 CLEAR레지스터가 따로 있어서 값이 갱신되는 것을 방지한다. 또한 해당 비트를 갱신해주지 않는 한 해당 핀의 값은 유지된다.

라즈베리파이의 하드웨어를 제어하려면 하드웨어에 대한 정보가 있어야 한다. 라즈베리파이는 브로드컴의 BCM2835 칩셋을 사용하고 있다. 데이터시트는 URL을 통해 내려 받을 수 있다.

(http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf)

AP(Application Process)CPU제조에서 도면을 구입하여 제작한 CPU제품을 말한다.

 

GPIO를 제어하는 레지스터

 

GPFSELn(GPIO Alternate function select register, n: 0 ~ 5): 핀의 기능 설정

GPSETn(GPIO Pin Output Set Register): /출력 모드 시, high설정

GPCLRn(GPIO Output Clear Register): /출력 모드 시, low설정

GPLEVn(GPIO Pin Level Registers, n: 0 ~ 1): /출력 모드 시, 해당 핀의 값 확인

GPEDSn(GPIO Event Detect Status Register): /출력 모드 시, 특정 핀의 상태 변화를 감지

GPRENn(GPIO Pin Rising Edge Detect Enable): /출력 모드 시, 상승 에지 감지

GPFENn(GPIO Pin Falling Edge Detect Enable): /출력 모드 시, 하강 에지 감지

GPPUD(GPIO Pull-up/down Registers): /출력 모드 시, 풀업 풀다운 기능 설정

 

실제 메모리의 주소로는 접근할 수 없고 가상 주소를 사용해야 한다.

 

'c'는 캐릭터 디바이스


GPIO를 활용한 LED 제어

p/472 

 

운영체제에서는 메모리 사용의 효율성을 위해서 가상 메모리를 사용하게 되고 메모리 보호를 위해서 물리적 메모리의 직접적인 접근을 허용하지 않는다. 때문에 메모리에 접근하려면 가상 메모리의 주소를 알아야 한다. 물리 메모리의 주소를 입력하면 가상화 메모리 주소로 변환시켜주는 함수 'mmap'을 사용해야 한다.



RaspberryPi2의 물리메모리 주소는 ‘3F’로 시작한다.


 

교재의 예제를 코딩해보자.



 

/*** 소스 ***/

 #include <stdio.h>
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/mman.h>

 int main()
 {
     int mem_fd;
     int i;
     unsigned int *GPIO_BASE;
     unsigned int *GPIO_GPFSEL1;
     unsigned int *GPIO_GPSET0;
     unsigned int *GPIO_GPCRL0;

     mem_fd = open("/dev/mem", O_RDWR|O_SYNC);

     GPIO_BASE = (unsigned int *)mmap(00x60, PROT_READ|PROT_WRITE, MAP_SHARED, mem_fd, 0x3F200000);

     GPIO_GPFSEL1 = (unsigned int *)(GPIO_BASE + 0x04/4);
     GPIO_GPSET0 = (unsigned int *)(GPIO_BASE + 0x1c/4);
     GPIO_GPCRL0 = (unsigned int *)(GPIO_BASE + 0x28/4);

     *GPIO_GPFSEL1 &= 0xFF1FFFFF;
     usleep(2000);
     *GPIO_GPFSEL1 |= (0x1 << 21);
     usleep(2000);

     for(i=0; i < 5; ++i)
     {
         *GPIO_GPSET0 |= (0x1 << 17);
         printf("GPIO17 LED on\n");
         sleep(1);
         *GPIO_GPCRL0 |= (0x1 << 17);
         printf("GPIO17 LED off\n");
         sleep(1);
     }

     close(mem_fd);
     munmap(GPIO_BASE, 0x60);

     return 0;
 }

 


반응형
Posted by newind2000
Busan IT/로봇제어2015. 10. 30. 16:25

==================================Outline====================================

BCM 라이브러리

PWM LED Dimming

----------------------------------------------------------------------------

 

p/441

 

BCM 라이브러리

 

주소를 가상화 시키는 이유는 메모리를 효율적으로 사용하기 위해서이다.

‘[그림 16-18] BCM 2835의 버스 주소와 물리 주소의 대응관계에서 MMU가 버스의 주소를 가상화시키는 것을 알 수 있다.

 

핀의 기능이 한 가지 이상인 경우는 핀에 여러 가지 신호가 물려 있고 사용자의 조작에 따라 스위치가 동작하여 원하는 기능을 사용할 수 있다.

 

//‘SPI’는 시리얼로 분류된다.

 

 

우선 BCM라이브러리를 다운로드 받는다. Pi2bcm2836이 가능한 파일을 설치한다.

 

 

기존의 라이브러리 제공 사이트에서 제공하는 최신버전인 1.39버전부터는 bcm2836을 지원한다.

 

아래 링크를 통해서 설치 할 수 있다.

 

http://www.airspayce.com/mikem/bcm2835/bcm2835-1.39.tar.gz

 

ssh를 통해서 터미널로 접근 및 설치 해보도록 한다.

 

설치 절차는 다음과 같다.

 

1. wget을 사용하여 라이브러리 다운로드

 

wget http://www.airspayce.com/mikem/bcm2835/bcm2835-1.39.tar.gz


2. 다운받은 파일 압축해제

 

tar xvzf bcm-2835-1.39.tar.gz

3. 압축 해제한 폴더로 이동 후 설정을 적용한다.

 

cd bcm2835-1.39/

./configure

4. 설정이 올바르게 적용 되었는지 확인한다.

make check

 

 

5. 설치한다.

make install

 

 

라즈베리파이2의 경우는 라이브러리를 사용하기 위해 디바이스 트리를 활성화시켜야 한다.





다음 'reboot'명령어를 사용하여 재부팅한다.

 

PWM LED Dimming

 

교재 p/449에 있는 [PWM제어 예제]를 사용하여 PWM 코딩을 한다.

/*** 소스 ***/

[PWM_test.c]


 #include <bcm2835.h>
 #include <stdio.h>

 #define PIN 18
 #define PWM_CHANNEL 0
 #define RANGE       1024

 int main(int argc, char **argv)
 {
     int direction = 1;
     int data = 1;
     if ( 0 == bcm2835_init() )
         return 1;

     bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_OUTP);
     bcm2835_gpio_write(PIN, LOW);
     bcm2835_delay(1000);

     bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_ALT5);

     bcm2835_pwm_set_clock(BCM2835_PWM_CLOCK_DIVIDER_2);

     bcm2835_pwm_set_mode(PWM_CHANNEL, 11);

     bcm2835_pwm_set_range(0, RANGE);

     while(1)
     {
         if(data == 1)
             direction = 1;
         else if(data == RANGE-1)
             direction = -1;

         data += direction;

         bcm2835_pwm_set_data(PWM_CHANNEL, data);
         bcm2835_delay(20);
     }
     bcm2835_close();
     return 0;
 }



반응형
Posted by newind2000
Busan IT/로봇제어2015. 10. 28. 15:56

==================================Outline====================================

푸쉬 버튼을 이용한 LED 제어

----------------------------------------------------------------------------

 

p/275 푸쉬 버튼을 이용한 LED 제어

 


 

 

WiringPi를 설치한 후 ‘gpio readall'를 입력한다.

 

LED를 토글 시키는 코드를 만들고 상태를 표시 시켜보자.

 

//스위치가 없기 때문에 점프 선을 이용하자.

 




계속 깜빡거린다.

 

꺼진 상태에서 input pinLOW를 연결하면 토글이 되지 않고 LED가 꺼진 상태를 유지하게 된다.



 

반응형
Posted by newind2000
Busan IT/로봇제어2015. 10. 26. 16:16

==================================Outline====================================

플라스크 기반의 GPIO 포트 제어

스마트홈

----------------------------------------------------------------------------

 

플라스크 기반의 GPIO 포트 제어

교재 p/211

 

웹의 링크를 통해 GPIO를 제어 하는 코딩을 해보자.

 

[leds.py]


 from flask import Flask, render_template, request
 import RPi.GPIO as GPIO

 app = Flask(__name__)

 GPIO.setmode(GPIO.BCM)

 leds = {
 23 : {'name' : 'RED LED''state' : GPIO.LOW},
 24 : {'name' : 'GREEN LED''state' : GPIO.LOW},
 25 : {'name' : 'BLUE LED''state' : GPIO.LOW},
 }

 for led in leds:
     GPIO.setup(led, GPIO.OUT)
     GPIO.output(led, GPIO.OUT)

 def getGpioState():
     for led in leds:
         leds[led]['state']=GPIO.input(led)

     return leds

 @app.route("/")
 def main():
     gpioState = {
         'leds' : getGpioState()
     }

     return render_template('main.html', **gpioState)

 @app.route("/<led>/<act>")
 def action(led, act):
     led = int(led)
     leds = getGpioState()
     dev = leds[led]['name']
     if act == "on":
         GPIO.output(led, GPIO.HIGH)
         msg = "Turned " + dev + " on. "
     elif act == "off":
         GPIO.output(led, GPIO.LOW)
         msg = "Turned " + dev + " off. "
     elif act == "toggle":
         GPIO.output(led, not GPIO.input(led))
         msg = "Toggled " + dev + "."
     else:
         msg = "Undefined action!"

     gpioState = {
         'msg' : msg,
         'leds' : getGpioState()
     }

     return render_template('main.html', **gpioState)

 if __name__ == "__main__":
     app.run(host='192.168.0.173', port=8888, debug=True)



                                                                            

 

[main.html]

 

 <html>
 <head>
     <title>RGB LED Status</title>
 </head>

 <body>
     <h1>RGB Led Status</h1>

     {% for led in leds %}
     <p>
     {{ leds[led].name }}
     {% if leds[led].state == true %}
         is currently on (<a href="/{{led}}/off">turn off</a>)
     {% else %}
         is currently off (<a href="/{{led}}/on">turn on</a>)
     {% endif %}
     </p>
     {% endfor %}

     {% if msg %}
     <h2>{{ msg }}</h2>
     {% endif %}

 </body>
 </html>

 

 

 

 

스마트홈

교재 p/221 

 

캐리어 주파수는 통신 내용을 전송하기 위해 만들어져 있는 주파수이다. 이 때 캐리어 주파수에 내용을 싣기 위한 작업을 변조라고 하고 변조된 내용을 해석하는 것을 복조라고 한다.


LonWork 



 

LonWork는 네트워크로 가전을 제어하는데 따로 랜선과 네트워크 수신 장치를 사용하지 않고 제어하는 방법을 고안해냈다.

 

 

 

반응형
Posted by newind2000
Busan IT/로봇제어2015. 10. 23. 15:44

==================================Outline====================================

웹 프로그래밍

- GPIO를 통한 웹서비스 메시지 제어 

----------------------------------------------------------------------------

 

//PiFace는 따로 장치를 구입해서 장착해야되기 때문에 교재의 해당 부분은 넘어가도록 한다.

 

교재 p/200

 

웹 프로그래밍

 

네트워크를 사용하기 위해서는 웹 서비스를 제공하는 서버가 필요하다.

 

플라스크는 파이썬을 위한 마이크로 웹 프레임워크로 Werkzeug, Jinja2를 기반으로 하는 오픈소스 서비스이다.

 

윈도우의 경우 IIS(Internet Information Services)를 제공한다. 무료로 제공되는 서비스 중에 톰캣이 있다.

 

//Apache Tomcat - http://tomcat.apache.org/

 

HTML은 소스코드가 고정 되어 있기 때문에 유동성 있게 페이지가 변동되지 않는다. 유동성 있는 서비스를 제공하기 위해서는 ASP, JSP, PHP를 사용하여 변수 값을 바꾼 후 다시 HTML로 변환해야 한다.

 

서비스 제공자 - ASP: Microsoft

                        JSP: JAVA

                        PHP: C문법 적용

 

일반적으로 웹 서비스를 제공하기 위해서는 웹을 표현하는 htmlASP, JSP, PHP 중 택 1하여 사용하여야 한다.

 

ASPwindow운영체제를 사용해야 하지만 JSPPHP는 운영체제를 가리지 않고 사용할 수 있다.

 

GPIO를 통한 웹서비스 메시지 제어

 

GPIO제어를 통한 웹서비스 메시지를 제어하는 것을 해보자.

 

p/202~p/211을 참고한다.

 

우선 파이선PIP를 설치한다.

 

apt-get install python-pip

 

 

 

python-pip 설치 후 플라스크를 설치한다.

 

pip install flask

 

 

교재 p/203"hello_flask.py"를 작성한다.

[hello_flask.py]

 

 

 

입력을 마친 후 실행시킨다.

 

입력한 IP와 포트번호를 웹에 입력하면 자신이 설정한 메시지가 뜬다.

 

웹에서 해당 서비스를 요청한 경우 이를 라즈베리파이에서 확인할 수 있다.

 

플라스크 서버에 HTML 웹페이지를 구성하고, 웹브라우저를 통해 클라이언트가 접속했을 때 서버의 시간을 출력해 보자.

 

교재 p/205에 나와있는 "gettime.py"를 작성하고 작성한 파일과 동일한 위치에 "templates"라는 폴더를 만든다. 그런 다음 main.html 파일을 작성하여 만든 폴더에 넣는다.

 

[gettime.py]

[main.html]


 

플라스크를 기반으로 GPIO 포트 모니터링

 

플라스크를 이용하여 웹을 통해 라즈베리 파이를 제어해본다. 핀에 on/off 상태를 웹서버에서 확인할 수 있도록 만든다.

 

port 23, 24, 25를 사용하도록 한다.

 

[gpio.html]

 

[check_switch.py]




반응형
Posted by newind2000
Busan IT/로봇제어2015. 10. 20. 16:14

==================================Outline====================================

PWM을 사용한 LED dimming

스크래치

----------------------------------------------------------------------------

 

자바에서는 모든 함수는 클래스 내에 존재해야 한다. 반면에 C++는 함수가 main함수에서 수행된다.

 

java의 컴파일러는 javac이다. 'smart.java'라는 파일을 컴파일하면 'smart.class'라는 파일이 생성된다.

 

 

컴파일이 실행하는 도중에 진행되는 언어를 인터프리터 언어(Interpretor Language)라고 한다.

 

//‘wget‘ 웹에서 해당 파일을 직접 가져오는 명령어이다.

 

//직사각형 형태의 파형을 구형파라고 한다.


PWM을 사용한 LED dimming 

 

PWM을 사용한 LED dimming을 만들어 보자.

 

 

 

교재 p/114 [led_dimming.py]


 import RPi.GPIO as GPIO
 import time

 LED = 18
 GPIO.setmode(GPIO.BCM)

 GPIO.setup(LED, GPIO.OUT)

 LED = GPIO.PWM(LED, 100)

 LED.start(0)

 delay = 0.1

 try:
     while True:
         for i in range(0101):
             LED.ChangeDutyCycle(i)
             time.sleep(delay)
         for i in range(100, -1, -1):
             LED.ChangeDutyCycle(i)
             time.sleep(delay)

 except KeyboardInterrupt:
     LED.stop()
     GPIO.cleanup()

 

 

스크래치

 

p/116 스크래치

 

p/131까지 책을 보며 혼자 진행한다.

 

adobe AIR -

http://get.adobe.com/air/

 

스크래치 오프라인 에디터 - https://scratch.mit.edu/scratchr2/static/sa/Scratch-440.exe 

 

//윈도우용 스크래치를 다운 받아 수행한다.


반응형
Posted by newind2000
Busan IT/로봇제어2015. 10. 20. 09:13

==================================Outline====================================

교재 훑어보기

라즈베리파이2와 파이선을 활용한 코딩

----------------------------------------------------------------------------

 

교재 훑어보기

 

라즈베리 파이로 구현하는 사물 인터넷 프로젝트

 

Chapter 1 ~ 4

 

 

USART를 지원한다는 것은 비동기 데이터 전송 시 사용되는 헤더(header)와 테일(tail)을 만들어 준다는 뜻이다.

 

GPIO로 모든 신호를 만들어 낼 수 있다.


라즈베리파이2와 파이선을 활용한 코딩

 

라즈베리파이와 파이썬을 활용하여 코딩을 해보자.

 

1. 라즈베리파이2GPIO도면 습득

 

2. 파이선 라이브러리 설치

apt-get install python-dev

 

3. GPIO핀에 대해서 H/L pin 테스트

 

우선 파이선 패키지가 설치 되어 있는지 확인해 보자.

 

설치가 되어 있다면 파이썬 패키지를 설치해야 한다.

 

apt-get install python-dev

 

설치가 완료되면 'python'을 입력하여 프롬프트를 실행시키고 구구단을 프로그램을 만들어본다.

 

이제 LED를 활용하여 불을 켜고 끄는 프로그램을 만들어보자.



 

코드를 'led_onoff.py'로 저장한 후 ‘python led_onoff.py'로 실행시켜본다.

깜빡거리는 것을 볼 수 있다.

 


 

반응형
Posted by newind2000