候補は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 件のコメント:
コメントを投稿