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
ICCR이 기본 상태이고 프로세서가 IDLE 상태인지 점검. 혹은 ICMR의 해당 비트가 인터럽트를 금지하는지 점검. 즉, 인터럽트 제어기가 인터럽트 마스크의 상태를 점검하는 것.
인터럽트가 발생하면 ICPR의 한 비트가 설정됨. 설정되는 비트는 인터럽트를 야기한 입출력 디바이스에 해당.
발생한 인터럽트와 ①의 결과를 논리적으로 AND 연산을 수행. 즉, 발생한 인터럽트가 ①에 의해 금지되지 않아야 함.
ICLR을 사용해 발생한 인터럽트가 IRQ 혹은 FIQ인지 선택.
발생한 인터럽트가 IRQ 모드이면 ICIP, FIQ 모드이면 ICFP의 해당 비트를 설정. 따라서 ICIP와 ICFP를 읽으면 발생한 인터럽트의 종류를 알 수 있음.
주변장치 우선순위 처리기(peripheral priority processor)는 IPR을 참조하여 모든 인터럽트의 우선순위를 결정하며 인터럽트 제어기는 우선순위에 따라 ICHP를 갱신.
프로세서 코어는 ICHP를 참조하여 가장 높은 우선순위의 인터럽트를 처리
#define IRQ_SSP3 PXA_IRQ(0) /* SSP3 service request */
#define IRQ_MSL PXA_IRQ(1) /* MSL Interface interrupt */
#define IRQ_USBH2 PXA_IRQ(2) /* USB Host interrupt 1 (OHCI) */
#define IRQ_USBH1 PXA_IRQ(3) /* USB Host interrupt 2 (non-OHCI) */
#define IRQ_KEYPAD PXA_IRQ(4) /* Key pad controller */
#define IRQ_MEMSTK PXA_IRQ(5) /* Memory Stick interrupt */
#define IRQ_PWRI2C PXA_IRQ(6) /* Power I2C interrupt */
#define IRQ_HWUART PXA_IRQ(7) /* HWUART Transmit/Receive/Error(PXA26x) */
#define IRQ_OST_4_11 PXA_IRQ(7) /* OS timer 4-11 matches (PXA27x) */
#define IRQ_GPIO0 PXA_IRQ(8) /* GPIO0 Edge Detect */
#define IRQ_GPIO1 PXA_IRQ(9) /* GPIO1 Edge Detect */
#define IRQ_GPIO_2_x PXA_IRQ(10) /* GPIO[2-x] Edge Detect */
#define IRQ_USB PXA_IRQ(11) /* USB Service */
인터럽트 등록과 해제
#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) 정의
DECLARE_WAIT_QUEUE_HEAD(wq)
인터럽트 허가와 금지
#include <asm/irq.h>
void disable_irq(int irq); // 인터럽트 금지
void enable_irq(int irq); // 인터럽트 해제
기타 인터럽트 관련 함수
set_GPIO_IRQ_edge(): GPIO 단자를 사용해 인터럽트 실행 시 감지할 상태를 설정
set_irq_type(): 인터럽트 종류를 설정
pxa_gpio_mode(): GPIO 모드 설정
set_trap_gate(): 소프트웨어 인터럽트인 트랩을 설정
set_system_gate(), set_intr_gate(): 여러 인터럽트를 설정
타겟 시스템 X-HYPER270-TKU에는 GPIO 35, 41, 36, 37번
단자를 사용하는 4개의 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 }
……
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
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 }
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);
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 }
'IT > 리눅스마스터1급' 카테고리의 다른 글
SPI (0) | 2022.05.04 |
---|---|
I2C (0) | 2022.05.04 |
Streams (0) | 2022.05.03 |
Memo Management Unit (0) | 2022.05.03 |
opengl 1.1 2.0 비교 (0) | 2022.05.03 |