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. 5. 22:51

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

비트맵 구조체

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

비트맵 구조체

크기가 가로 400픽셀, 세로 400픽셀인 비트맵 파일을 임의로 생성하여 비트맵파일에 대해서 알아보기로 하자.

 

 


각 픽셀이 RGB로 표현되기 때문에 이 비트맵 파일의 용량은 (400 * 400) * 3이고, 54byte는 헤더파일이다헤더 파일은 실제내용을 간추린 정보를 제공하는데 이것을 오버 헤더라고 한다.


 

비트맵 파일은 픽셀 단위로 데이터를 저장한다. 1byte(8bits)에는 한가지 색에 대한 정보를 가지고 있다.  1픽셀은 3byte로 구성되는데,  각 바이트는 빨(Red), 녹(Green), 파(Blue)로 이루어져 있다.

 

**빛의 3원색:  빨강, 녹색, 파랑 

**색의 3원색:  자주, 노랑, 청록

 

 

** 빛은 섞을수록 밝아지고 색은 섞을수록 어두워진다.

위에서 만든 비트맵 파일을 헥사뷰를 사용하여 출력해본다. 54byte가 'FF'가 아닌 값으로 표시되고 있음을 알 수 있다. 

 

54Byte는 비트맵 파일의 헤더부분이며 비트맵 파일에 대한 정보를 담고 있다. 비트맵 파일의 구조체를 살펴보도록 하자. 


 

/* BITMAPFILEHEADER 구조체 */

typedef struct tagBITMAPFILEHEADER{ //bmfh

WORD bfType; // 파일의 형태, 0x42, 0x4d (BM) 이어야함

WORD bfSize; // 비트맵 파일의 크기 (Byte단위)

WORD bfReserved1; // 예약. 0으로 설정

WORD bfReserved2; // 예약2. 0으로설정

DWORD bfOffBits; // 실제 비트맵데이터까지의 오프셋값

// 실제로는 bfOffBits = BITMAPFILEHEADER크기 + BITMAPINFOHEADER크기 + RGBQUAD 구조체배열의크기 이다.

} BITMAPFILEHEADER;

 

/* BITMAPINFOHEADER 구조체 */

typedef struct tagBITMAPINFOHEADER{ //bmfh

DWORD biSize; // 이 구조체의 크기. 구조체 버전확인할수 있다.

LONG biWidth; // 비트맵의 가로 픽셀수

LONG biHeight; // 비트맵의 세로 픽셀수

WORD biPlanes; // 플레인의 갯수 반드시 1이어야함

WORD biBitCount; // 한 픽셀이 구성되는 비트의수

DWORD biCompression; // 압축방법. BI_RGB일땐 비압축 BI_RLE8, BI_RLE4인경우 run length encode방법으로 압축

DWORD biSizeImage; // 이미지의 크기. 압축이 안되어있을때는 0

LONG biXPelsPerMeter; // 가로 해상도

LONG biYPelsPerMeter; // 세로 해상도

DWORD biClrUsed; // 색상테이블을 사용하였을때 실제 사용되는 색상수

DWORD biClrImportant; // 비트맵을 출력하는데 필수 색상수

} BITMAPINFOHEADER;

 

비트맵 파일 구조체를 참고하여 구조체 멤버들을 출력해보자. 

 

400 * 400 크기의 BMP파일의 경우 한 픽셀당 3byte를 차지하고 그 값을 red, greeb, blue의 정도는 8bit(256) 나누어 표시할 수 있다. 파일의 총 크기는 480054byte이고 54byte는 헤더파일임으로 파일의 시작점에서 54byte 떨어진 지점부터의 데이터를 조작함으로써 BMP파일을 변형시킬 수 있다.

BMP파일을 조작하여 여러 가지 색깔로 변형시켜보자.

**BMP이미지를 수정하여 원본에 덮어 쓰도록 하자.

각 색에 대한 출력 정보는 0 ~ FF로 표현된다. '0'이 가장 낮은 단계이며 'FF'가 가장 높은 단계이다. 가로 픽셀이 400, 세로 픽셀이 400인 비트맵 구조체에서 가로 한 줄의 용량은 400 * 3이다. 좌측 상단에서 우측 하단까지 'for문'을 사용하여 데이터의 값을 입력할 값을 설정해주면 된다.

각 픽셀의 첫 번째 바이트는 blue, 두 번째 바이트는 green, 세 번째 바이트는 red이다. 비트맵 파일의 정보를 수정하여 색이 어떻게 바뀌는지 출력해보자.







소스 코드는 아래와 같다.

/*** 소스 ***/ 

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


int main(int iNum, char * cpArr[])
{
  int iRtn;
  int iFd;
  BITMAPFILEHEADER stBFHead;
  BITMAPINFOHEADER stBIHead;
  char cBuf[16*16];
  unsigned char * ucpBuf;
  
  unsigned int uiCntX;
  unsigned int uiCntY;

  

  iFd = open(cpArr[1], O_RDWR|O_BINARY);  
  if(iFd == 0)
  {
    printf("파일을 열 수 없습니다.\n");
    return -1;
  }

  iRtn = read(iFd, &stBFHead, sizeof(BITMAPFILEHEADER));
  if(iRtn == 0)
  {
    printf("파일을 읽을 수 없습니다.\n");
    close(iFd);            
    return -1;
  }
  if0x4D42 != (stBFHead.bfType) )
  {
    printf("BMP파일이 아닙니다.\n");
    close(iFd);            
    return -1;
  }
  iRtn = lseek(iFd, sizeof(BITMAPFILEHEADER), SEEK_SET);
  if(iRtn != sizeof(BITMAPFILEHEADER) )
  {
    printf("읽어들일 부분이 잘못 지정되었습니다.\n");
    close(iFd);            
    return -1;
  }
  iRtn = read(iFd, &stBIHead, sizeof(BITMAPINFOHEADER));
  if(iRtn == 0)
  {
    printf("INFO헤더가 존재하지 않습니다.\n");
    close(iFd);            
    return -1;
  }

  ucpBuf = (void *)malloc(stBIHead.biSizeImage);
  if(0 == ucpBuf)
  {
    printf("사용 가능한 메모리가 부족합니다.\n");
    close(iFd);
    return -1;
  }
  lseek(iFd, sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER), SEEK_SET);
  iRtn = read(iFd, ucpBuf, stBIHead.biSizeImage);
  

  if(iRtn == 0)
  {
    printf("데이터를 읽을 수 없습니다.\n");
    close(iFd);        
    free(ucpBuf);
    return -1;
  }
  for(uiCntY=0; uiCntY < stBIHead.biHeight; ++uiCntY)
  {
    for(uiCntX=0; uiCntX < stBIHead.biWidth; ++uiCntX)
    {
      ucpBuf[uiCntY * (stBIHead.biWidth * 3) + (uiCntX * 3) + 0= 0//blue  
      ucpBuf[uiCntY * (stBIHead.biWidth * 3) + (uiCntX * 3) + 1= 0//green
      ucpBuf[uiCntY * (stBIHead.biWidth * 3) + (uiCntX * 3) + 2= 0xFF; //red            
    }
  }
  lseek(iFd, 54, SEEK_SET);
  iRtn = write(iFd, ucpBuf, stBIHead.biSizeImage);
  if(iRtn == 0)
  {
    printf("데이터 쓰기에 실패 했습니다.\n");
    close(iFd);        
    free(ucpBuf);
    return -1;
  }

  lseek(iFd, 54, SEEK_SET);
  iRtn = read(iFd, cBuf, 16*16);  

  
  
  
  close(iFd);
  free(ucpBuf);
  
  return 0;

} 

 

 

 

 

반응형
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/Assembly2015. 11. 3. 17:36

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

Bit Manipulation

Shift and Rotate Instructions

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

  

p/259

 

Converting a 2' Complement Integer to an ASCII string

 

아는 것임으로 패스

 

 

p/267

 

Bit Manipulation

 

다 아는 것임으로 넘어간다....

 

클럭 사이클이 메모리가 개입하면 눈에 띄게 커지는 것을 알 수 있다.

 

‘test'명령어는 결과 값이 accumulator 레지스터에 들어가는 것과는 제외하는 ’and' 연산과 동일하다. 'test'는 명령어는 특정 비트의 값을 확인하거나 추출하기 위해서 사용된다.

 

test dx, 2000h ; check bit 13

 

Shift and Rotate Instructions

 

p/278

h(로직): 쉬프트를 사용하면 빈 자리는 무조건 ‘0’으로 채워진다.

a(연산): 음수/양수를 판별하여 음수일 경우 빈자리를 ‘1’, 양수일 경우 ‘0’으로 채워준다.

 

예제를 통해 확인해 보자.



쉬프트 연산의 사이클은 곱셈과 나눗셈에 비해 낮기 때문에 2의 제곱의 곱셈과 나눗셈에서는 쉬프트 연산을 사용하는 효율적이다.

 


 

operand3개인 쉬프트연산도 사용할 수 있다.

//해당 명령어가 존재한다는 것만 알고 있자.

 



 

 

반응형
Posted by newind2000
Busan IT/Assembly2015. 11. 3. 12:53

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

String Instruction

- stos

- lods

Character Translation

- xlat

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

교재 p/249

 

stos

 

같은 문자를 반복하여 저장한다.

 

lods

 

‘esi’에 있는 문자열을 'eax'에 저장한다.

 

 

Character Translation

 

교재 p/254

 

xlat

 

'EBX' 문자열이 시작하는 주소를 가리키고 ‘AL’에서 배열의 값을 가지고 있는 상황에서 'AL'에 해당 값이 들어가게 된다.

 

 

[Figure 7.13 Translation program]



 

 /*** 소스 ***/


.386
.MODEL FLAT
ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD
INCLUDE io.h
cr  equ   0dh
Lf  equ   0ah

.STACK 4096

.DATA
string     BYTE   'This is a #!$& STRING'0
strLength  EQU  $ - string - 1
label1     BYTE   "Original string  ->"0
label2     BYTE   cr, Lf, "Translated string"0
crLf     BYTE   cr, Lf, 0
table     BYTE   48 DUP (' '), '0123456789'7 DUP (' ')
    BYTE   'abcdefghijklmnopqrstuvwxyz'6 DUP (' ')
    BYTE  'abcdefghijklmnopqrstuvwxyz'133 DUP (' ')

.CODE
_start:    output   label1
    output   string
    output   crlf
    mov   ecx, strLength
    lea  ebx, table
    lea  esi, string
    lea  edi, string

forIndex:  lodsb
    xlat
    stosb
    loop  forIndex
    
    output label2
    output string
    output crlf

    INVOKE ExitProcess, 0
PUBLIC _start

 

 

 

 

 

 

 

 

 

 

반응형
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/ARM Controller2015. 11. 2. 12:06

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

PWM를 사용한 LED 불 밝기 조절

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

 

PWM를 사용한 LED 불 밝기 조절

 

PA0번 핀의 기능을 확인해보자.

 

[PA0]

 

 

PA0PWM의 출력으로 사용 설정을 해준다

 

1. PA/AFIO/TIM2 clock 공급: RCC->APB2ENR, APB1ENR

2. PA 설정: PA0 출력 설정. AFIO를 사용한다. 내부적인 특수 기능을 사용하기 때문에 AFIO를 사용해야 한다.

 

출력 설정 시 open drainpush pull을 사용할 수 있다. push/pull은 입출력시 high/low값이 확실하게 구분된다. open drain값은 high출력이 없고 low만 존재한다. open drain은 그라운드 연결을 스위치로 제어하면서 제어하는 방식을 뜻한다.

 

3. TIM2 설정: TIM2_ARR은 카운팅 시 꼭지점이다. TIM2_CCR은 카운터의 비교 값이 들어있는 레지스터이다. 카운터의 값이 CCR과 일치할 경우 인터럽트가 발생한다.

 

 

특정 키를 입력 받았을 때 불 밝기가 조절 되도록 코딩을 해보자.





/*** 소스 ***/

#include <stm32f10x.h>
volatile unsigned int Timer2_Counter=0;
 
void init_port(void)
{    
    GPIO_InitTypeDef PORTA;
    GPIO_InitTypeDef PORTC;
 
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);
     
    PORTA.GPIO_Pin = GPIO_Pin_0;
    PORTA.GPIO_Mode = GPIO_Mode_AF_PP;
    PORTA.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_Init(GPIOA, &PORTA);
     
    PORTC.GPIO_Pin = GPIO_Pin_12;
    PORTC.GPIO_Mode = GPIO_Mode_Out_PP;
    PORTC.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_Init(GPIOC, &PORTC);
}
 
void TIM2_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET)
    {
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // Clear the interrupt flag
        Timer2_Counter++;
        GPIOC->BRR = GPIO_Pin_12;  // PB0 OFF
    }
 
    if(TIM_GetITStatus(TIM2,TIM_IT_CC1) != RESET)
    {
        TIM_ClearITPendingBit(TIM2,TIM_IT_CC1);
        GPIOC->BSRR = GPIO_Pin_12;  // PB0 ON
    }
}
 
void init_Timer2()
{
    NVIC_InitTypeDef NVIC_InitStructure;
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef OutputChannel;    
     
    /* TIM2 Clock Enable */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
     
    /* Enable TIM2 Global Interrupt */
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
     
    /* TIM2 Initialize */   
    TIM_TimeBaseStructure.TIM_Period=100-1// 100kHz
    TIM_TimeBaseStructure.TIM_Prescaler=24-1;
    TIM_TimeBaseStructure.TIM_ClockDivision=0;
    TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
     
    /* TIM2 PWM Initialize */
    OutputChannel.TIM_OCMode = TIM_OCMode_PWM1;
    OutputChannel.TIM_OutputState=TIM_OutputState_Enable;
    OutputChannel.TIM_OutputNState=TIM_OutputNState_Enable;
    OutputChannel.TIM_Pulse=50-1// 50% duty ratio
    OutputChannel.TIM_OCPolarity=TIM_OCPolarity_Low;
    OutputChannel.TIM_OCNPolarity=TIM_OCNPolarity_High;
    OutputChannel.TIM_OCIdleState=TIM_OCIdleState_Set;
    OutputChannel.TIM_OCNIdleState=TIM_OCIdleState_Reset;
    TIM_OC1Init(TIM2,&OutputChannel);
     
    /* TIM2 Enale */
    TIM_Cmd(TIM2,ENABLE);
    TIM_ITConfig(TIM2,TIM_IT_Update | TIM_IT_CC1 ,ENABLE); // interrupt enable
}
 
void make_pwm(u16 val)
{
    TIM_OCInitTypeDef OutputChannel;
     
    OutputChannel.TIM_OCMode = TIM_OCMode_PWM1;
    OutputChannel.TIM_OutputState=TIM_OutputState_Enable;
    OutputChannel.TIM_OutputNState=TIM_OutputNState_Enable;
    OutputChannel.TIM_Pulse=val;
    OutputChannel.TIM_OCPolarity=TIM_OCPolarity_Low;
    OutputChannel.TIM_OCNPolarity=TIM_OCNPolarity_High;
    OutputChannel.TIM_OCIdleState=TIM_OCIdleState_Set;
    OutputChannel.TIM_OCNIdleState=TIM_OCIdleState_Reset;
    TIM_OC1Init(TIM2,&OutputChannel);
}
 
void delay(unsigned int del)
{
    Timer2_Counter=0;
    while(Timer2_Counter < del);
}
 
int main()
{
    u16 i;
    SystemInit();
    init_port();
    init_Timer2();
     
    while(1)
    {        
        for(i=0; i<100; i++)
        {
            TIM2->CCR1 = i;
            delay(100);
        }
         
        for(i=98; i>0; i--)
        {
            TIM2->CCR1 = i;
            delay(100);
        }
    }
}


반응형

'Busan IT > ARM Controller' 카테고리의 다른 글

USART를 활용한 LED ON/OFF  (0) 2015.10.30
Timer를 활용한 LED제어, LCD 제어  (0) 2015.10.20
Timer  (0) 2015.10.19
Advanced-control timers(TIM1&8)  (0) 2015.10.16
인터럽트 코드 분석  (0) 2015.10.13
Posted by newind2000
Busan IT/Assembly2015. 11. 2. 08:52

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

Repeat Prefixes and More String Instructions

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

 

Repeat Prefixes and More String Instructions

 

p/239

 

 

'rep' 명령어는 ‘ecx’ 레지스터를 카운터로 사용한다.

 

'rep'를 풀어서 쓰면 다음과 같다.

 

rep movsb

 

jecxz endCopy ;skip loop if count is zero

 

copy: movsb ;move 1 character

loop copy ;decrement count and continue

 

endCopy:

'ecx' 값은 'rep' 명령어 operand가 수행되기 전에 0인지 확인되고 'ZF'플래그는 operand가 수행되고 나서 검사가 된다.

 

첫 번째 문자가 같지 않으면 'ecx'값과 ‘ZF' 값이 동시에 0이 아님으로 ’repz'명령어는 멈추게 된다.

 

//‘repz’/‘repe’는 같은 명령어이다.

교재 p/244 String search program



[sca.asm]


.386
.MODEL FLAT
ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD
INCLUDE io.h
cr  equ   0dh
Lf  equ   0ah

.STACK 4096

.DATA
prompt1    BYTE   "String to search? "0
prompt2    BYTE   cr, Lf, "Key to search for? "0
target    BYTE  80 DUP (?)
key    BYTE  80 DUP (?)
trgtLength  DWORD  ?
KeyLength  DWORD  ?
lastPosn  DWORD  ?
failure    BYTE  cr, Lf, Lf, "The key does not appear in the string.", cr, Lf, 0
success    BYTE  cr, Lf, Lf, "The key appear in the string."
position  BYTE  11 DUP (?)
    BYTE  " in the string.", cr, Lf, 0

PUBLIC _start
.CODE

_start:    output   prompt1  ;
    input  target,  80 ;
    lea  eax,  target ;
    push  eax ;
    call  strlen ;
    mov  trgtLength,  eax;
    output  prompt2 ;
    input   key, 80 ;
    lea  eax,  key ;
    push  eax ;
    call  strlen ;
    mov  keyLength, eax ;

    mov  eax, trgtLength ;
    sub  eax, keyLength ;
    inc   eax ;
    mov lastPosn,  eax ;
    cld

    mov  eax, 1 ;

whilePosn:  cmp  eax, lastPosn ;
    jnle  endWhilePosn ;

    lea  esi, target ;
    add   esi, eax ;
    dec  esi ;
    lea  edi, key ;
    mov  ecx, keyLength ;
    repe  cmpsb ;
    jz  found ;
    inc  eax ;
    jmp  whilePosn ;
endWhilePosn:
    output  failure ;
    jmp  quit ;

found:    dtoa  position, eax ;
    output   success ;
quit:
    INVOKE ExitProcess,  0 ;

strlen    PROC  NEAR32 ;

    push  ebp ;
    mov  ebp, esp ;
    pushf ;
    push  ebx ;
    sub  eax, eax ;
    mov  ebx,  [ebp+8] ;

whileChar:  cmp  BYTE PTR [ebx], 0 ;
    je  endWhileChar ;
    inc   eax ;
    inc  ebx ;
    jmp  whileChar ;

endWhileChar:
    pop  ebx ;
    popf ;
    pop  ebp ;
    ret  4

strlen    ENDP

    END

 

 

 

 


반응형
Posted by newind2000
Busan IT/ARM Controller2015. 10. 30. 16:46

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

USART

USART를 활용한 LED ON/OFF

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

 

USART

- 싱크로모터 AC모터의 종류 배에 들어가는 풍향 풍속계에 사용 비쌈 사용자가 제어할 부분이 없다.

 

- 비동기 통신: asynchronous communication

 

- 통신 방식은 단방향, 양방향. 단방향의 예는 라디오. 양방향은 다시 반이중(half duplex), 전이중(full duplex)방식, 반이중은 무전기, 전이중은 전화기

 

- Baud rate4.5Mbits 이것을 바이트로 나누면 562KByte이다. 속지 말자

 

** MAX232

 

- ATmega보다 4배 빠르다. 클럭의 차이에서 온다.

 

- 송수신 비트가 나눠져 있다.

 

- 그 외의 내용은 훑어본다.

 

USART 코딩을 해보자. Keil 편집기를 실행하고 새 프로젝트를 만든다. 실행환경에서 'USART'를 추가적으로 체크해 주어야 한다.

 

 

//RCC = Reset and clock control



[USART 블록 다이어그램]

 

 

- RTS, CTS핀은 많이 사용되진 않는다. RS485제어에 사용된다. 반이중 통신에 사용된다.

 

- USART_BRRBaud Rate 설정에 사용되는데 firmware library의 레퍼런스를 사용하면 간단하다.

 

- 직렬통신 시 통신 방법은 두 가지로 나뉜다. 폴링과 인터럽트이다. 수신시에는 인터럽트 방식을 발신시에는 폴링 방식을 많이 사용한다. 데이터 수신 시 프로그램은 입력이 있을 때까지 대기하기 때문에 인터럽트 방식을 사용하는 것이 좋다. 

 

 

 

USART를 활용한 LED On/Off

 

하이퍼터미널에서 ‘+’ 키를 누르면 LED(PA0 떠는 PC12)가 켜지고 ‘-’키를 누르면 LED가 꺼지도록 코딩해보자.

 

펌웨어 라이브러리에 존재하는 함수를 사용하여 USART를 설정하고 송/수신 함수를 만들어보자.




 

//펌웨어 라이브러리에 제시된 예제를 용도에 맞게 수정하면 편하다.

]

'USART_GetFlagStatus' 함수를 사용하여 송/수신 함수를 만들 것이다. /수신 상태를 확인하는 플래그의 상태를 확인한 후 데이터가 존재하지 않을 때 ‘while'을 사용하여 프로그램을 잡아주면 된다.

USART를 설정 후 설정된 USART채널을 사용할 수 있도록 만들어주어야 한다.

 


 

 

 

 

 

/*** 코드 ***/


#include <stm32f10x.h>

void Clocks(void)
{
  /* Enable GPIOA, USART1 clocks */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | 
                        RCC_APB2Periph_USART1|
                        
                        RCC_APB2Periph_AFIO, ENABLE);
  
  return;
}

void USART1_init(void)
{
  /* The following example illustrates how to configure the USART1 */
  USART_InitTypeDef USART_InitStructure;
  USART_InitStructure.USART_BaudRate = 9600;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
  USART_Init(USART1, &USART_InitStructure);
  
  /* Enables the USART1 transmit interrupt */
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
  
  return;
}

void PA9_AF_out()
{
  /* Configure GPIO9 Input Floating mode */
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_AF_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
  return;
}

void PA10_in()
{
  /* Configure GPIO9 Input Floating mode */
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);                  
  
  return;
}

void PA0_out()
{
  /* Configure GPIO9 Input Floating mode */
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOA, &GPIO_InitStructure);               
  
  return;
}

void Tx_Data(unsigned char Tx)
{
  /* chekcing status of Tx buffer */
  while0 == USART_GetFlagStatus(USART1, USART_FLAG_TXE) );
  /* Send one HalfWord on USART1 */
  USART_SendData(USART1, Tx);  
  
  return;
}
unsigned char Rx_Data()
{
  unsigned char uiRx;  
  while0 == USART_GetFlagStatus(USART1, USART_FLAG_RXNE) );     
  uiRx = USART_ReceiveData(USART1);
      
  return uiRx;
}


void USART1_IRQHandler()
{
  unsigned char ucRx;
  
  if(USART_GetITStatus(USART1, USART_IT_RXNE) == +-SET )
  {
    ucRx = Rx_Data();
    switch(ucRx)
    {
      default:
        break;
      
      case '+':                    
        GPIOA->ODR = 0x01;
        
        break;
      
      case '-':               
        GPIOA->ODR = 0x00;
        break;        
        
    }
    
  }
  /* Clear the CTS interrupt pending bit */
  USART_ClearITPendingBit(USART1, USART_IT_RXNE);
  
  
  return;
}

void NVIC_init()
{
  NVIC_InitTypeDef NVIC_InitStructure;
  /* Enable USART1 global interrupt with Preemption Priority 1 and Sub
  Priority as 5 */

  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 5;
  NVIC_Init(&NVIC_InitStructure);
  
  return;
  
}


int main(void)
{
  unsigned char ucRx;
  Clocks();
  PA9_AF_out();
  PA10_in();
  USART1_init();
  NVIC_init();
  PA0_out();
  USART_Cmd(USART1, ENABLE);     

  while(1)
  {   
    ;    
  }
  
  return 0;
}


반응형

'Busan IT > ARM Controller' 카테고리의 다른 글

PWM를 사용한 LED 불 밝기 조절  (0) 2015.11.02
Timer를 활용한 LED제어, LCD 제어  (0) 2015.10.20
Timer  (0) 2015.10.19
Advanced-control timers(TIM1&8)  (0) 2015.10.16
인터럽트 코드 분석  (0) 2015.10.13
Posted by newind2000