void key_handler(int irq, void *dev_id, struct pt_regs *regs) {
unsigned long *keyport;
keyport = (unsigned long *)ioremap(KEY_BASE, 0x10);
key_value = *(keyport) & 0xf;
iounmap(keyport);
// FALLING EDGE Detect...
free_irq(KEY_IRQ, NULL);
set_GPIO_IRQ_edge(0, GPIO_FALLING_EDGE);
request_irq(KEY_IRQ, key_handler1, SA_INTERRUPT, "Keypad", NULL);
wake_up_interruptible(&wq);
}
void key_handler1(int irq, void *dev_id, struct pt_regs *regs) {
key_value = 0xff;
// Rising Edge Detect...
free_irq(KEY_IRQ, NULL);
set_GPIO_IRQ_edge(0, GPIO_RISING_EDGE);
request_irq(KEY_IRQ, key_handler, SA_INTERRUPT, "Keypad", NULL);
wake_up_interruptible(&wq);
}
int dev_open(struct inode *inode, struct file *fp) {
// set keypad interrupt handler
GPDR0 &= ~(GPIO_0);
GAFR0_L &= ~(0x3);
set_GPIO_IRQ_edge(0, GPIO_RISING_EDGE);
return request_irq(KEY_IRQ, key_handler, SA_INTERRUPT, "Keypad", NULL);
}
ssize_t dev_read(struct file *fp, char *buf, size_t len, loff_t *pos) {
interruptible_sleep_on(&wq); // wait until key pressed
copy_to_user(buf, &key_value, 1);
return len;
}
ssize_t dev_write(struct file *fp, const char *buf, size_t len, loff_t *pos) {
return 0;
}
int dev_close(struct inode *inode, struct file *fp) {
free_irq(KEY_IRQ, NULL);
return 0;
}
void SinGenerator(double *buffer, int BUFFSIZE, double f0, double fs, short ampl)
{
double w0;
double m_2cosW0;
const double PI = 4.0 * atan(1.0);
int i;
w0 = 2 * PI * f0 / fs; // fs: sampling frequency, f0 : tone frequency
m_2cosW0 = 2 * cos(w0);
buffer[BUFFSIZE-2] = (double)(ampl * -sin(w0));
buffer[BUFFSIZE-1] = 0;
buffer[0] = (double)(m_2cosW0 * buffer[BUFFSIZE-1] - buffer[BUFFSIZE-2]);
buffer[1] = (double)(m_2cosW0 * buffer[0] - buffer[BUFFSIZE-1]);
for(i = 2 ; i < BUFFSIZE ; i++)
buffer[i] = (double)(m_2cosW0 * buffer[i-1] - buffer[i-2]);
}
먼저 키패드 드라이버 작성은 교수님이 제공해 주신 키패드 드라이버 관련 문서를 보고 작성하였다. 이를 바탕으로 작성된 디바이스 드라이버를 올리고 프로그램 내에서 open한 후 read를 하여 결과를 출력 하는데, 프로그램을 처음 실행 할 때는 아무 문제없이 잘 작동하였다. 하지만 이 프로그램의 두 번째 실행에서 부터는 인터럽트 발생이 폭주 하는 듯, 키를 누르지도 않았는데 이상한 결과가 계속해서 출력이 되는 것이었다. 문제는 프로그램 실행에서 open시 인터럽트를 활성화 시키는데 반해 close시 이 인터럽트를 다시 비활성화 시키지 않는데서 비롯된 것이었다. 첫 번째 실행에서 활성화된 인터럽트를 두 번째 실행에서 다시 활성화함으로써 발생한 것이었다. 이에 close 시스템 콜 구현 부분에서 free_irq()함수를 이용하여 활성화된 인터럽트를 비활성화 시킴으로써 해결할 수 있었다.
톤 발생기 구현은 첨에 막막한 상태였다. 어디서부터 시작해야 될지 몰랐다. 여러 자료를 검색하던 중 MultiMedia Sound Programming 이라는 영진닷컴에서 출판된 책에 특정 주파수 신호 발생에 대한 내용을 찾을 수 있었다. 이 책을 참조하여 특정주파수 신호를 만들어 내는 모듈을 작성할 수 있었다.
첨에 신호를 만들어 호스트 컴퓨터에서 소리를 발생 시켰다. 원하는 결과가 잘 나왔다. 하지만 임베디드 컴퓨터에서는 소리가 나오지 않는 것이었다. 이것 때문에 상당한 시간을 허비하였는데, 알고 보니 임베디드 컴퓨터의 mixer 초기 설정 상태가 mute(음소거)상태였던 것이었다. "mixer vol unmute", "mixer pcm unmute" 명령으로 mute 상태를 해제하니 소리가 잘 나왔다.
마지막으로 키패드 마다 각기 다른 주파수 톤을 발생시키기 위해 처음에는 일반 전화기에서 사용하는 DTMF(Dual Tone Multi-Frequency)를 이용하여 구현하였으나, 약간의 문제로 인해 그냥 각 키마다 임의로 다른 주파수를 발생시키도록 구현하였다. 여기서 DTMF 란 여러 개의 주파수를 가진 이중톤이라는 의미로 서로 다른 2개의 주파수를 합성하여 하나의 주파수로 할당되게 된다. 약간의 문제란 DTMF 원리를 이용하여 신호를 발생시키면, 전화기 버튼을 눌렀을 때 발생하는 톤과 비슷하였지만, 서로 다른 주파수 신호를 합성하는 과정에서 잡음이 상당히 많이 발생해서 듣기가 별로 좋진 않았다. 또한 서로 다른 2개의 신호를 생성하고 합성하는데 상당한 시간이 걸려서, 키패드 버튼을 빠르게 누르고 땠을 경우 Falling Edge 인터럽트를 놓치는 경우가 발생하여, 오동작하는 경우도 생겼다. 물론 키를 누르기 전에 미리 신호를 다 생성시켜 놓으면 되지만, 그렇게 되면 각 키마다 신호를 저장해야 될 버퍼가 필요하게 되므로 비효율적이다. 이러한 문제로 인해 DTMF를 사용하지 않고 각 키마다 임의로 다른 주파수의 신호가 발생되게 하였다.