250 likes | 698 Views
GPIO 프로그래밍. PXA270의 GPIO GPIO 동작과 GPIO 레지스터 기능 PXA270과 인터럽트 인터럽트 처리 함수 GPIO를 이용한 디바이스 드라이버 . PXA270 의 GPIO. PXA270 의 GPIO 개요 GPIO(General Purpose Input Output) 는 하나의 연결 단자를 입력이나 출력으로 고정시키지 않고 선택적으로 사용할 수 있게 융통성을 높인 범용 입출력 단자 PXA270 은 121 개의 GPIO 단자를 제공하고 이 중 119 개만 사용 .
E N D
GPIO 프로그래밍 • PXA270의 GPIO • GPIO 동작과 GPIO 레지스터 기능 • PXA270과 인터럽트 • 인터럽트 처리 함수 • GPIO를 이용한 디바이스 드라이버
PXA270의 GPIO • PXA270의 GPIO 개요 • GPIO(General Purpose Input Output)는 하나의 연결 단자를 입력이나 출력으로 고정시키지 않고 선택적으로 사용할 수 있게 융통성을 높인 범용 입출력 단자 • PXA270은 121개의 GPIO 단자를 제공하고 이 중 119개만 사용. • 각 단자는 입력 혹은 출력으로 설정하거나 부가 기능을 위해 양방향으로 설정. 32비트 레지스터 36개를 사용하여 설정. • GPIO 단자를 입력으로 프로그램하면 인터럽트 소스로 사용 가능 • 일부 GPIO 단자는 프로세서를 휴면 상태에서 깨우는 사건(event)를 생성
GPIO 레지스터의 기능 • 입출력 방향 설정 레지스터(GPDR, GPIO Pin Direction Register) • GPIO port pins의 각각에 대한 방향 제어 비트로 구성 • 해당 비트가 0이면 입력, 1이면 출력 • 하드웨어 리셋 후에는 모든 비트가 0로 설정 • 출력 설정 레지스터(GPSR, GPIO Pin Set Register) 및 출력 제거 레지스터(GPCR, GPIO Pin Clear Register) • GPDR에 의하여 출력으로 설정된 경우에만 동작 • 만약 GPDR의 해당 비트가 0으로 설정되어 있을 경우 무영향 • GPSR 혹은 GPCR의 임의 비트에 1을 쓰면 해당 output pin이 set 혹은 clear • GPSR 혹은 GPCR의 임의의 비트에 0을 쓰는 것은 무영향 • write-only register • 상승 에지 검출 허가 레지스터(GRER, GPIO Rising Edge Detect Enable Register) 및 하강 에지 검출 허가 레지스터(GFER, GPIO Falling Edge Detect Enable Register) • 각 GPIO port는 상승천이(rising edge) 혹은 하강천이(falling edge)로 입력을 감지할 수 있도록 프로그램 가능 • GPIO 핀의 천이(transition) 방식을 설정 • edge가 발생하면 status bit가 set • status bits 중 하나가 set될 때 인터럽트를 CPU에 걸거나 혹은 깨어나기 위하여 인터럽트제어기를 프로그램할 수 있음
GPIO 레지스터의 기능(계속) • 에지 입력 검출 레지스터(GEDR, GPIO Edge Detect Status Register) • GRER 혹은 GFER이 설정되었을 때 동작 • 해당 비트가 1이면 GRER 혹은 GFER에 따라 상승천이 혹은 하강천이된 입력이 발생했음을 의미 • 부가 기능 사용 허가 레지스터(GAFR, GPIO Alternate Function Register) • 해당 비트가 0이면 대응하는 pin을 일반적인 I/O, 1이면 특수목적 • 특수 목적에 관련된 기능은 Intel, PXA27x Processor Family Developer’s Manual, 2004 참조 • 단자 상태 검출 레지스터(GPLR, GPIO Pin Level Register) • 각각의 GPIO port pin에 대한 현재 상태를 제공, 즉 현재 pin의 상태가 low 혹은 high인지 표현 • read-only register
일반적인 인터럽트 처리 과정 • 일반적인 인터럽트 처리 과정
PXA270의 인터럽트 처리 • PXA270의 인터럽트 처리
ICCR이 기본 상태이고 프로세서가 IDLE 상태인지 점검. 혹은 ICMR의 해당 비트가 인터럽트를 금지하는지 점검. 즉, 인터럽트 제어기가 인터럽트 마스크의 상태를 점검하는 것. • 인터럽트가 발생하면 ICPR의 한 비트가 설정됨. 설정되는 비트는 인터럽트를 야기한 입출력 디바이스에 해당. • 발생한 인터럽트와 ①의 결과를 논리적으로 AND 연산을 수행. 즉, 발생한 인터럽트가 ①에 의해 금지되지 않아야 함. • ICLR을 사용해 발생한 인터럽트가 IRQ 혹은 FIQ인지 선택. • 발생한 인터럽트가 IRQ 모드이면 ICIP, FIQ 모드이면 ICFP의 해당 비트를 설정. 따라서 ICIP와 ICFP를 읽으면 발생한 인터럽트의 종류를 알 수 있음. • 주변장치 우선순위 처리기(peripheral priority processor)는 IPR을 참조하여 모든 인터럽트의 우선순위를 결정하며 인터럽트 제어기는 우선순위에 따라 ICHP를 갱신. • 프로세서 코어는 ICHP를 참조하여 가장 높은 우선순위의 인터럽트를 처리
프로그램 상태 레지스터(CPSR, Current Program Status Register) • IRQ 인터럽트 서비스 준비를 위한 유사 코드
ICPR 레지스터와 IRQ 헤더 파일(<linux>/include/asm-arm/arch-pxa/irqs.h)
인터럽트처리 함수 • 인터럽트 등록과 해제 • 인터럽트 대기 및 깨우기 #include <linux/interrupt.h> int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long flags, const char *device, void *dev_id); void free_irq(unsigned int irq, void *dev_id); #include <linux/sched.h> // 대기 상태로 만드는 함수 void interruptible_sleep_on(struct wait_queue **q); void sleep_on(struct wait_queue **q); // 대기 상태의 프로세스를 깨우는 함수 void wake_up_interruptible(struct wait_queue **q); void wake_up(struct wait_queue **q);
대기큐(wait queue) 정의 • 인터럽트 허가와 금지 • 기타 인터럽트 관련 함수 • set_GPIO_IRQ_edge(): GPIO 단자를 사용해 인터럽트 실행 시 감지할 상태를 설정 • set_irq_type(): 인터럽트 종류를 설정 • pxa_gpio_mode(): GPIO 모드 설정 • set_trap_gate(): 소프트웨어 인터럽트인 트랩을 설정 • set_system_gate(), set_intr_gate(): 여러 인터럽트를 설정 DECLARE_WAIT_QUEUE_HEAD(wq)
타겟 시스템 X-HYPER270-TKU에는 GPIO 35, 41, 36, 37번 단자를 사용하는 4개의 GPIO 버튼을 테스트용으로 제공
실습 GPIO 디바이스 드라이버 및 테스트 프로그램 작성 001 #include <linux/module.h> …… 016 #define IRQ_KEY1 IRQ_GPIO(35) 017 #define IRQ_KEY2 IRQ_GPIO(41) 018 #define IRQ_KEY3 IRQ_GPIO(36) 019 #define IRQ_KEY4 IRQ_GPIO(37) 020 021 #define LED_PHYS 0x12400000 022 023 static void *mem_base; 024 unsigned long mem_addr, mem_len; 025 026 #define GPIO_MAJOR 241 027 #define GPIO_NAME "GPIO" 028 029 #define GPIO_KEY_READ 0x1000 030 031 #define GPIO_LED1_ON 0x2000 032 #define GPIO_LED2_ON 0x2100 033 #define GPIO_LED3_ON 0x2200 034 #define GPIO_LED4_ON 0x2300 …… 038 char key_buf; 039 char led_on=0xff; 040 041 DECLARE_WAIT_QUEUE_HEAD(key_queue); 042 043 int gpio_open(struct inode *inode, struct file *filp) 044 { 045 printk("%s\n", __func__); 046 return 0; 047 } 048 049 int gpio_release(struct inode *inode, struct file *filp) 050 { 051 printk("%s\n", __func__); 052 return 0; 053 } ……
실습 GPIO 디바이스 드라이버 및 테스트 프로그램 작성 060 ssize_t gpio_read (struct file *filp, char *buf, size_t count, loff_t *f_pos) 061 { 062 interruptible_sleep_on ( &key_queue); 063 copy_to_user( buf, &key_buf, sizeof(key_buf)); 064 return 0; 065 } 066 067 int gpio_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) 068 { 069 int data = 0; 070 071 switch (cmd) { 072 case GPIO_LED1_ON: 073 copy_from_user(&data, (void *)arg, sizeof(data)); 074 if( data == 0) 075 { led_on |= 0x01; 076 (*((volatile unsigned char *)(mem_base))) = led_on;} 077 else 078 { led_on &= 0xfe; 079 (*((volatile unsigned char *)(mem_base))) = led_on;} 080 break; 081 case GPIO_LED2_ON: …… 110 } 111 return 0; 112 } 113 114 static irqreturn_t key_interrupt(int irq, void *dev_id, struct pt_regs *regs) 115 { 116 if(GPLR1 & GPIO_bit(35)) 117 key_buf = 1; 118 if(GPLR1 & GPIO_bit(41)) 119 key_buf = 2; 120 if(GPLR1 & GPIO_bit(36)) 121 key_buf = 3; 122 if(GPLR1 & GPIO_bit(37)) 123 key_buf = 4; 124 wake_up_interruptible(&key_queue); 125 return IRQ_HANDLED; 126 } 127
실습 GPIO 디바이스 드라이버 및 테스트 프로그램 작성 128 struct file_operations gpio_fops = { 129 .owner = THIS_MODULE, 130 .open = gpio_open, 131 .read = gpio_read, 132 .write = gpio_write, 133 .ioctl = gpio_ioctl, 134 .release = gpio_release, 135 }; 136 137 static int __init gpio_init(void) 138 { 139 int result, ret; 140 141 result = register_chrdev(GPIO_MAJOR, GPIO_NAME, &gpio_fops); 142 mem_addr = LED_PHYS; 143 mem_len = 0x1000; 144 mem_base = ioremap_nocache ( mem_addr, mem_len); 145 if( !mem_base) { 146 printk("Error mapping OHCI memery\n"); 147 release_mem_region(mem_addr, mem_len); 148 return -EBUSY; } 149 (*((volatile unsigned char *)(mem_base))) = (0xFF); 150 set_irq_type(IRQ_KEY1, IRQT_RISING); …… 153 set_irq_type(IRQ_KEY4, IRQT_RISING); 154 if ((ret = request_irq(IRQ_KEY1, key_interrupt, SA_INTERRUPT, "GPIO35_KEY1", NULL))) { 155 printk("failed to register IRQ KEY1\n"); 156 return ret; 157 } …… 166 if ((ret = request_irq(IRQ_KEY4, key_interrupt, SA_INTERRUPT, "GPIO37_KEY4", NULL))) { …… 169 } 170 key_buf = 0; 171 printk("%s MAJOR %d\n", GPIO_NAME, GPIO_MAJOR); 172 173 return 0; 174 }
실습 GPIO 디바이스 드라이버 및 테스트 프로그램 작성 176 static void __exit gpio_exit(void) 177 { 178 disable_irq(IRQ_KEY1); 179 free_irq(IRQ_KEY1, NULL); …… 184 disable_irq(IRQ_KEY4); 185 free_irq(IRQ_KEY4, NULL); 186 unregister_chrdev(GPIO_MAJOR, GPIO_NAME); 187 } 188 MODULE_LICENSE("GPL"); 189 module_init(gpio_init); 190 module_exit(gpio_exit);
실습 GPIO 디바이스 드라이버 테스트 프로그램 작성 01 #include <stdio.h> …… 06 #define GPIO_KEY_READ 0x1000 07 #define GPIO_LED1_ON 0x2000 08 #define GPIO_LED2_ON 0x2100 09 #define GPIO_LED3_ON 0x2200 10 #define GPIO_LED4_ON 0x2300 11 12 static char gpio_testDev[] = "/dev/GPIO"; 13 static int gpio_testFd = -1; 14 int ON = 1; …… 17 int main() 18 { 19 char buf; 20 21 if((gpio_testFd = open(gpio_testDev, O_RDWR )) < 0) { 22 perror("open failed /dev/GPIO_TEST\n"); 23 exit(-1); 24 } 25 26 while(1) { 27 read(gpio_testFd , &buf, sizeof(buf)); 28 printf("KEY %x PUSH \n",buf); 29 ON ^= 0x0001; 30 switch(buf) { 31 case 1: 32 ioctl(gpio_testFd , GPIO_LED1_ON, &ON); 33 break; 34 case 2: …… 43 default: break; 44 } 45 } 46 return 0; 47 }