RaspberryPiのパラレルI/O

シフトレジスタ編


RaspberryでのパラレルI/Oのやり方はいくつかあります。
まずは74HC595(シフトレジスタ)を使ったパラレルI/Oを紹介します。
Raspberryとの結線は以下の様になります。



最初はwiringPiライブラリの sr595Setup() と digitalWrite() を使った8BitのパラレルI/Oの例です。

//
// test program for 74HC595 with sr595Setup
// cc -o test1 test1.c -l wiringPi
//
#include <stdio.h>
#include <time.h>
#include <wiringPi.h>
#include <sr595.h>

#define pinBase     100
#define numPin      8
#define dataPin     4
#define clockPin    5
#define latchPin    6

int main(int argc, char **argv) {
 int i;
 int loop,loopm;
 time_t      start_time;
 time_t      end_time;

 loopm=30000;
 if (argc == 2) loopm=1;

 if (wiringPiSetup() == -1){
   printf("wiringPiSetup Fail\n");
   return 1;
 }

 if(sr595Setup(pinBase,numPin,dataPin,clockPin,latchPin) == -1) {
   printf("sr595Setup Fail\n");
   return 1;
 }

 for(i=0;i<8;i++) {
   pinMode(pinBase+i,OUTPUT);
 }

 start_time = time(NULL);
 for(loop=0;loop<loopm;loop++) {
  for(i=0;i<8;i++) {
   digitalWrite(pinBase+i,1);
  }
  if (argc == 2) getchar();
  for(i=0;i<8;i++) {
   digitalWrite(pinBase+i,0);
  }
 }
 end_time = time(NULL);
 printf("time:%.1fSec\n",difftime(end_time,start_time));
}

適当な引数を指定して実行すると1回だけ処理を行います。
引数無しで実行すると30000回の処理を行います。
上記のコードでは、digitalWrite()毎に、毎回ラッチ処理を行うので30000回になるとそこそこ時間が掛かります。

$ sudo ./test1
time:21.0Sec

次にラッチ処理を8ビットで1回だけ行うように処理を変更します。
1回に処理できる最大ビット数は32ビットです。
//
// test program for 74HC595 with wiringPi
// cc -o sr595w sr595w.c -l wiringPi
//
#include <stdio.h>
#include <time.h>
#include <wiringPi.h>

#define dataPin     4
#define clockPin    5
#define latchPin    6

void HC595Byte (unsigned int output, int bits)
{
  int  bit;
  digitalWrite (latchPin, LOW) ;
  for (bit = bits - 1 ; bit >= 0 ; --bit) {
    digitalWrite (dataPin, output & (1 << bit)) ;
    digitalWrite (clockPin, HIGH) ;
    digitalWrite (clockPin, LOW) ;
  }
  digitalWrite (latchPin, HIGH) ;
}

void HC595Bit (unsigned int output, int bits)
{
  int  bit;
  for (bit = bits - 1 ; bit >= 0 ; --bit) {
    digitalWrite (latchPin, LOW) ;
    digitalWrite (dataPin, output & (1 << bit)) ;
    digitalWrite (clockPin, HIGH) ;
    digitalWrite (clockPin, LOW) ;
    digitalWrite (latchPin, HIGH) ;
  }
}

int main(int argc, char **argv) {
 int i;
 int loop,loopm;
 time_t      start_time;
 time_t      end_time;

 loopm=30000;
 if (argc == 2) loopm=1;

 if (wiringPiSetup() == -1){
   printf("wiringPiSetup Fail\n");
   return 1;
 }

 pinMode(dataPin,OUTPUT);
 pinMode(clockPin,OUTPUT);
 pinMode(latchPin,OUTPUT);

 start_time = time(NULL);
 for(loop=0;loop<loopm;loop++) {
   HC595Byte(0xff,8);
   if (argc == 2) getchar();
   HC595Byte(0x00,8);
 }
 end_time = time(NULL);
 printf("time:%.1fSec\n",difftime(end_time,start_time));
}

適当な引数を指定して実行すると1回だけ処理を行います。
引数無しで実行すると30000回の処理を行います。

$ sudo ./sr595w
time:2.0Sec

8ビットで1回のラッチ処理を行うので10倍ほど高速に処理することができます。

次にbcm2835ライブラリで同じ処理を行います。
bcm2835ライブラリのインストールは以下の手順で行います。

$ wget http://www.open.com.au/mikem/bcm2835/bcm2835-1.49.tar.gz
$ tar xvfz bcm2835-1.49.tar.gz
$ cd bcm2835-1.49
$ ./configure
$ make
$ sudo make install

1回に処理できる最大ビット数は32ビットです。
//
// test program for 74HC595 with bcm2835
// cc -o sr595b sr595b.c -l bcm2835
//
#include <stdio.h>
#include <time.h>
#include <bcm2835.h>

#define dataPin        23    // GPIO23
#define clockPin       24    // GPIO24
#define latchPin       25    // GPIO25

void HC595Write (unsigned int output, int bits)
{
  int  bit;

  bcm2835_gpio_write (latchPin, LOW) ;
    for (bit = bits - 1 ; bit >= 0 ; --bit)
    {
      bcm2835_gpio_write (dataPin, output & (1 << bit)) ;
      bcm2835_gpio_write (clockPin, HIGH) ;
      bcm2835_gpio_write (clockPin, LOW) ;
    }
  bcm2835_gpio_write (latchPin, HIGH) ;
}

int main(int argc, char **argv) {
 int i;
 int loop,loopm;
 time_t      start_time;
 time_t      end_time;
 int byte;

 loopm=30000;
 if (argc == 2) loopm=1;

 if (bcm2835_init() == -1) {
   printf("bmc2835_init Error\n");
   return 1;
 }

 bcm2835_gpio_fsel(dataPin,BCM2835_GPIO_FSEL_OUTP);
 bcm2835_gpio_fsel(clockPin,BCM2835_GPIO_FSEL_OUTP);
 bcm2835_gpio_fsel(latchPin,BCM2835_GPIO_FSEL_OUTP);

 start_time = time(NULL);
 for(loop=0;loop<loopm;loop++) {
  for(i=0;i<8;i++) {
   HC595Write(0xff,8);
  }
  if (argc == 2) getchar();
  for(i=0;i<8;i++) {
   HC595Write(0x00,8);
  }
 }
 end_time = time(NULL);
 printf("time:%.1fSec\n",difftime(end_time,start_time));
}

適当な引数を指定して実行すると1回だけ処理を行います。
引数無しで実行すると30000回の処理を行います。

$ sudo ./sr595b
time:1.0Sec

wiringPiライブラリよりも2倍ほど高速に処理することができます。
多量のパラレルデータを扱う場合は、こちらのほうが高速です。

今回は入力電圧として3.3Vを使いましたが、74HC595 のデータシートを見ると7Vまでいけるので
入力電圧として5Vを使うと、3.3V→5Vのレベルシフターとして使うこともできます。
入力電圧として5Vを使ったときの出力は4.5Vぐらいでした。

<余談>
単純な3.3V→5Vのレベルシフターならば74HC244などの、バッファーチップを使うことが多いです。
逆方向の5V→3.3Vのレベルシフターは74AHC244などの、CMOS ICを使うことが多いです。
レベル変換用ICについては、こちらに 詳しく紹介されています。
</余談>

続く...