2010年2月21日日曜日

USB FMトランスミッタ: PCM2707 USBディスクリプタ変更

概要
  PCM2707はデバイスディスクリプタ情報をSPIインターフェース経由で変更できます。情報を変更後、USBのD+ピンを3.3V系にプルアップすると、PCからUSB機器が接続されたことが認識され、PCM2707はそのデバイスディスクリプタ情報をPCに通知します。


プログラム
 CPUはATmega8Lです。以下にプログラムを示します。後ほど説明するプログラムに必要な項目も含んでいます。
※プログラムをブログにコピペすると、タブを削除したり、一部のコードが勝手に変更されてしまいます。どうなってるんでしょう?(#includeの括弧を全角に変更しています)


#define F_CPU 4.000E6 // マスタクロック4MHz
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/twi.h>
#include <util/delay.h>


volatile uint8_t I2C_data[7];
/*
PD7 O SS(PCM2707) <1>

PD6 I SSPND(PCM2707)<0>

PD5 O USB(D+) <0>

PD4 O LED, "Status" <0>

PD3 O LED, "Over modulation"<1>

PD2 I DIP SW, Left -1

PD1 I DIP SW, Left -2

PD0 I DIP SW, Left -3

PC6 I Reset

PC5 O I2C SCL(Si4710)

PC4 I/O I2C SDA(Si4710)
PC3 I DIP SW, Right -1

PC2 I DIP SW, Right -2

PC1 I DIP SW, Right -3

PC0 I DIP SW, Right -4

PB7 (Xtal)

PB6 (Xtal)

PB5 O SCLK(PCM2707) <0>

PB4 I N/A

PB3 O MOSI(PCM2707) <0>

PB2 O FSEL(PCM2707) <1>
PB1 O RESET(Si4710) <0>

PB0 I LRCK
*/

void init_devices(void) {
// ポート設定 0:入力, 1:出力
DDRB = 0b101110;
DDRC = 0b1100000;

DDRD = 0b10111000;

// 出力ポート初期化
// 入力ポート、1:プルアップ

PORTB = 0b010100;

PORTC = 0b1111111;

PORTD = 0b10000111;


PORTB |= _BV(1);
// RESET(Si4710) => 1

// I2C SCL周波数: 100kHz (Si4710: <400khz data-blogger-escaped-span="">
// 100kHz = 4MHz/(16+2*TWBR*PRESCALER)

TWBR = 0x0C;

TWCR = 1<
// TWI enable

// 16bit Timer/Counter
// Timer/Counter1 Control Register A

// TCCR1A = 0b00000000;

// Timer/Counter1 Control Register B

// ICES1: Rise Edge

// Clock Select: Start

// TCCR1B = 0b01000001;

// Timer/Couter Input Capture Interrupt Enable

// TIMSK |= _BV(TICIE1);

}

void init_pcm2707(void) {
// PCM2707 Device Descriptor ROM write (56bytes)


uint8_t m, n;
uint16_t SPI_PROCESS = 0x2040; // Process: Descriptor ROM address reset

uint8_t SPI_PROCESS2 = 0x10;// Process: Descriptor ROM data write

uint8_t ROMDATA[57] = {

0xBB, 0x08, // Vendor ID(2bytes): 0x08BB

0x07, 0x27, // Product ID(2bytes): 0x2707

// Product string: Product strings.(16bytes in ANSI ASCII code): "Si4710 USB FM-TX"

0x53, 0x69, 0x34, 0x37, 0x31, 0x30, 0x20, 0x55, 0x53, 0x42, 0x20, 0x46, 0x4D, 0x2D, 0x54, 0x58,

// Vendor string: Vendor strings are placed here.

// (32 bytes in ANSI ASCII code): "Burr-Brown from TI /w tamago"

0x42, 0x75, 0x72, 0x72, 0x2D, 0x42, 0x72, 0x6F, 0x77, 0x6E, 0x20, 0x66, 0x72, 0x6F, 0x6D, 0x20,
0x54, 0x49, 0x20, 0x2F, 0x20, 0x74, 0x61, 0x6D, 0x61, 0x67, 0x6F, 0x20, 0x20, 0x20, 0x20, 0x20,
0xC0, // Power attribute (bmAttribute): 0x80 (Bus-powered), 0xC0(self-powered)

0x32, // Max power (maxPower): 0x0A(20mA), 0x32(100mA), 0x7D(250mA), 0xFA(500mA) 0x0A, 0x93, 0x01 // Auxiliary HID usage ID: 0x0A, 0x93, 0x01 (AL A/V capture)
};

// Note that the data bits must be sent from LSB to MSB on bus.

// This means that each data byte must be stored with its bits in reverse order.


PORTD &= ~_BV(7); // MS -> 0

for (n = 0; n < n="n+1){">
// MD write
if(bit_is_set(SPI_PROCESS, n)){
PORTB |= _BV(3);

}else{

PORTB &= ~_BV(3);

}


// MC write
PORTB |= _BV(5); // MC -> 1

PORTB &= ~_BV(5); // MC -> 0

}


PORTD |= _BV(7); // MS -> 1

PORTD &= ~_BV(7); // MS -> 0


for (m = 0; m < m="m+1){"> for (n = 0; n < n="n+1){ // MC -> 0
}


for (n = 0; n<8 data-blogger-escaped-n="n+1){ <span style=">
PORTB &= ~_BV(5); // MC -> 0

}

}


PORTD |= _BV(7); // MS -> 1

PORTD |= _BV(5); // USB(D+) -> 1

}



int main(void)

{

init_devices();
init_pcm2707();
init_si4710();

while(1); // 無限ループ
}


補足  PCM2707では、USBディスクリプタ情報のProduct StringとVendor StringをSPIで変更できるということで、上記の様な処理 init_pcm2707() を行っています。(必須の処理ではありません)
 ただ、Vendor Stringは表示されませんでした。Product Stringは、当方が設定した文字列が出ているのがわかると思います。この文字列の文字コードは、ANSI ASCIIコードです。おそらくプログラムでそのまま書けると思うのですが、よくわからなかったので
Wikipediaを見ながら書き写しました。
 このほか、USB電流の指定もでき、PC直結の場合USBルートハブのプロパティで”電力”タブを選べば確認できます。セルフパワーなのに指定することに意味があるのかは?ですが。


USBオーディオデバイスのプロパティ


サウンドとオーディオデバイスのプロパティ


USBルートハブのプロパティ(”電力”タブ)


生成したSPI波形(全体)


生成したSPI波形(拡大)


その他の問題

  • I2S出力時にアナログ音声が出ない
    これは悩みました。I2Sのデジタルデータは出力されるのに、アナログ出力は無音のままです。
    内蔵のミュート回路が動作しているのかと、いろいろ原因を調べましたが問題なし。
    ダメもとでググってみたら、森秀樹氏のブログのコメントにI2S出力モード(FSEL=L)では、
    アナログ出力なしと書いてある。他の人のところでも同じ現象が起きるなら、それで正解か。
    でもデータシートにはそんな記述は見あたらないように見える。俺の1日を返せという気分。

  • アナログ出力レベルが低い
    10kΩ負荷で1.8Vp-p出ると書いてあるのに、80mVp-pくらいしか出ません。
    詳しく調べていませんが、お気楽オーディオキットの記事にヒントがあるかも知れません。

0 件のコメント:

コメントを投稿