2012年12月30日日曜日

RaspberryPiでIRリモコンを読む(GPIOCLKの設定)

やはりGPIOをユーザーランドから読み込むことは難しいことがわかったので、RaspberryPiのPeripheralで使えそうなものがないか調べてみました。
候補はUART,SPIとPCMあたりですが、SPI、UARTはフォーマットの自由度があまりないのでちょっとむずかしそうです。
PCMなら32bit x 64段のFIFOがあるので100KHzでsamplingしたとしても20ms程度はバファリングされます。裏で重たい処理が動いてなければユーザーランドでもなんとかなるかも。
overflowも検知できるので試してみる価値はありそうです。

BCM2835にはgpio_clkというclock発生器があるのでPCMCLKを赤外リモコンの変調周波数である38kHzにしてPCMを動かすとうまくいくのではないかと思います。

とりあえず、使えそうなGPIO4にGPIOCLK0を繋いで出力設定してみます。
手元にオシロもロジアナもないので先日試しに作ったgpioからのデータをgettimeofday()でタイミングとりながら取り込むソフトと組み合わせてサンプリングして正しい周波数が出ていることを確認していきます。GPIO4からGPIOCLK0を出す設定にし、GPIO23に繋いでサンプリング周期を3us程度で取り込むようにして遅めの10kHzと目的の38kHz、早めの100kHzを出してみてちゃんと周期があっているかをチェックし、下記のコードで正しく出ていることを確認しました。
とりあえず、これでPCMCLKを確保できました。

-----

#define BCM2835_PERI_BASE    0x20000000
#define GPIOCLK_BASE         (BCM2835_PERI_BASE + 0x101000)
#define   GPCLKCTL           0x70/4
#define   GPCLKDIV           0x74/4
#define   GPCLKCTLSET(n,d)   gpioclk[GPCLKCTL + (n)*8] = d
#define   GPCLKCTLGET(n)     gpioclk[GPCLKCTL + (n)*8]
#define   GPCLKDIVSET(n,d)   gpioclk[GPCLKDIV + (n)*8] = d

int GPClkOutput(int f) {

  int clk = 19200000; // osc clk 19.2MHz
  int divi = clk / f;
  int divf = (clk % f) * 1024 / f;
  if(divi > 0xfff) return -1;
  GPCLKCTLSET(0, (0x5a << 24) | (1 << 9) | 1); // disable clk gen
  int i;
  for(i = 0; i < 10000; i++) if(!(GPCLKCTLGET(0) & (1 << 7))) break;
  if(i >= 10000) return -1;
  GPCLKDIVSET(0, (0x5a << 24) | (divi << 12) | divf);
  GPCLKCTLSET(0, (0x5a << 24) | (1 << 9) | (1 << 4) | 1); // enable clk gen
  return 0;
}

0 件のコメント:

コメントを投稿