[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 メーリングリストの案内