[Armadillo:07914] Armadillo-210で繰り返しのGPIO割り込み
埼広 村上
email@hidden
2012年 2月 24日 (金) 22:57:09 JST
お世話になります。村上と申します。
Armadillo-210で繰り返しのGPIO割り込みが思うように動作しません。
<やりたいこと>
GPIO0にパルス信号を入力し、パルス数をカウントしたい。
(C言語でプログラミングして実現したい)
<実現方法>
1.ioctl()関数を使用し、GPIO0を立ち上がりエッジで割り込みがかかるように設定。
2.ioctl()関数でINTRRUPT_WAITで割り込みを待ち、割り込みが発生する毎にカウンタをカウントアップ
3、カウンタに変化があれば、カンタ値を標準出力へ表示
<実行結果>
・実際のパルス数の倍近くをカウントする(100パルスに対し、192カウントなど)
・実際のパルスとの誤差が毎回一致しない
・1パルスに対し、1回割り込みがかかる時と2回割り込みがかかるときがある
・以下のコマンドでカーネル側の割込み回数を確認すると、プログラムの結果と一致する
[email@hidden (ttyAM1) ~]# cat /proc/interrupts
CPU0
4: 332258 timer tick
19: 2 ethphyint
39: 3799 ep93xxethernet
52: 14 ttyAM0
54: 5320 ttyAM1
59: 1490 gpio
Err: 0
入力するパルスはファンクションジェネレータで出力し、カウンタとオシロスコープで確認しました。
入力されるパルスはHiレベルが10msec以上、Lowレベル10msec以上と短いですが、
パルス幅を伸ばしても現象は変わりませんでした。
立ち上がり、立ち下りエッジの波形もきれい(チャタリングなし)で50μsec以下です。
明らかに1パルス(立ち上がりエッジは1回)しか出てないのに2回割り込みが発生します。
何が悪いのか判らない状態で困っています。
ソースを送りますのでご教授願います。
なお、割り込み発生後、GPIOの入力状態を監視し、状態変化後ioctl()関数で
INTRRUPT_WAITで割り込みを待つと正しくカウントされましたが、
このような強引な方法はとりたくありません。
以下、ソースです。
(#define PLS_GOOD 0→1に変更すると上記で書いた正しくカウントされる状態になります )
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <pthread.h>
#include <error.h>
#include <asm/arch/armadillo210_led.h>
#include <asm/arch/armadillo210_gpio.h>
#define DEVICE_LED "/dev/led"
#define DEVICE_GPIO "/dev/gpio"
#define PLS_GOOD 0
extern int errno;
int myglobal;
struct wait_param wait_param;
static int exit_flg = 0;
static unsigned long pls_cnt = 0;
static int fd_gpio0;
struct gpio_param gpio0;
//----------------------------------------------------------------------------------
// LED制御関数
//----------------------------------------------------------------------------------
static int led_action( int id )
{
int fd;
int ret;
char buf[16];
fd = open(DEVICE_LED,O_RDWR);
if(fd == -1){
perror("ledctrl: " DEVICE_LED " open");
return -1;
}
if( id == (LED_RED_STATUS | LED_GREEN_STATUS) ){
ret = ioctl(fd, id, buf);
}else{
ret = ioctl(fd, id);
}
if(ret == -1){
perror("ledctrl: ioctl");
close(fd);
return -1;
}
/*
printf("RED(%s),GREEN(%s)\n",
buf[0] & LED_RED ? "on":"off",
buf[0] & LED_GREEN ? "on":"off"
);
*/
close(fd);
return 0;
}
//----------------------------------------------------------------------------------
// 割り込み関数 Ctl+Cキー入力割り込み
//----------------------------------------------------------------------------------
static void int_ctl_c( int int_no )
{
exit_flg = 1;
}
//----------------------------------------------------------------------------------
// スレッド関数 GPIO0割り込み入力
//----------------------------------------------------------------------------------
void *thread_gpio0( void *arg )
{
int ret;
while( exit_flg==0 ){
wait_param.list = GPIO0;
wait_param.timeout = 0;
ret = ioctl( fd_gpio0, INTERRUPT_WAIT, &wait_param );
if( ret ){
printf( "err!\r\n" );
exit_flg = 1;
break;
}
if( wait_param.list & GPIO0 ){
pls_cnt++;
}
#if PLS_GOOD //ここから
do{
ioctl( fd_gpio0, PARAM_GET, &gpio0 );
}while( exit_flg == 0 && gpio0.data.i.value == 1 );
//ここまでを外すと正しくカウントされない
#endif
}
return NULL;
}
//----------------------------------------------------------------------------------
// main関数
//----------------------------------------------------------------------------------
int main( int argc, char *argv[] )
{
pthread_t mythread; //スレッド用
int retcode;
unsigned long old_pcnt = 0;
//initialize
memset( &gpio0, 0, sizeof(struct gpio_param) );
memset( &wait_param, 0, sizeof(struct wait_param) );
//GPIO設定
gpio0.no = GPIO0; //GPIO0
gpio0.mode = MODE_INPUT; //入力
gpio0.data.i.int_enable = 1; //割り込み有効
gpio0.data.i.int_type = TYPE_RISING_EDGE; //立上りエッジで割り込み
fd_gpio0 = open( DEVICE_GPIO, O_RDWR );
if( fd_gpio0 < 0 ){
perror( "open error" );
return -1;
}
ioctl( fd_gpio0, PARAM_SET, &gpio0 );
//signal()関数によるキー入力(Ctl+C)割り込みセット
if( signal( SIGINT, int_ctl_c ) == SIG_ERR ){
printf( "failed to set signal handler\n" );
exit(1);
}
//スレッド生成
retcode = pthread_create (&mythread, NULL, thread_gpio0, (void *)
"thread gpio0");
if ( retcode != 0 ) printf( "create a failed %d\n", retcode );
//パルスカウント表示
while( exit_flg == 0 ){
if( old_pcnt != pls_cnt ){
old_pcnt = pls_cnt;
if( pls_cnt%2 ) led_action(LED_RED_ON);
else led_action(LED_RED_OFF);
printf( "PLS:%10lu\r\n", pls_cnt );
}
};
//スレッド開放
if ( pthread_join ( mythread, NULL ) ) {
printf("error joining thread.");
abort();
}
close( fd_gpio0 );
printf( "\r\n" );
return 0;
}
armadillo メーリングリストの案内