回路設計が終わっていたので、朝から基板のアートワーク~プリント基板作り~組み立てまで1日で一気に仕上げました。回路もシンプルだし、専用ICはラクで良いです。
基板作りはMinimal Board Editorを駆使して、ベタアースを描いてみました。簡単操作でそれらしい基板ができあがりました。ただ、ベタアースと他のランドとの離隔(Gap)を0.3mmなどと目一杯狭くしてしまったため、ショートしてしまわないよう半田付けに注意が必要でした。特に2012チップコンのピン間にもベタアースが出来てしまっていて実体顕微鏡で何度も確認しました。たぶん大丈夫と思っていますが実際に動かすまで正直なところ不安です。
2011年4月17日日曜日
2011年3月19日土曜日
新潟精密 NS73M FMトランスミッタ
FMトランスミッタモジュール NS73Mを試してみることにしました。メーカの新潟精密は、経営悪化に伴う民事再生手続きの中で同製品の製造を中止してしまったようですが、秋月電子ではまだ購入可能です。組み立てキットもありますが、趣味なのであえて基板から作ってみます。
ところで、韓国Young Tech Systemが類似品YTS-5003Tを製造しています。会社概要には、新潟精密と技術提携しているとありますから同じ技術が使われているかもしれません。
NS73Mの内部ブロック図によると、音声信号はまずA/D変換され、プリエンファシス・ステレオ変調・FM変調はデジタル処理されています。デジタル処理されたFM変調波は304kHzのIF信号としてD/A変換され、その後のIQミキサで所定の周波数までアップコンされるというものです。
送信周波数は87.5~108MHzと海外仕様ですから国内では87.5~89.9MHzでしか使えません。音声特性は、歪率0.4%(モノラル/ステレオ)、SN比55dB(モノラル/ステレオ)、ステレオセパレーション35dB、周波数特性-3~+1.5dB(50~15kHz)とポータブル機器への組み込み用途としては申し分のない特性です。
NS73Mは、I2Cまたは3線シリアルインターフェースで、送信周波数や送信出力レベルの変更はもちろん、プリエンファシス有無、ミュート操作、入力レベルの変更、モノラル/ステレオ切替等が可能です。下図に製作予定の回路図を示します。
ところで、韓国Young Tech Systemが類似品YTS-5003Tを製造しています。会社概要には、新潟精密と技術提携しているとありますから同じ技術が使われているかもしれません。
NS73Mの内部ブロック図によると、音声信号はまずA/D変換され、プリエンファシス・ステレオ変調・FM変調はデジタル処理されています。デジタル処理されたFM変調波は304kHzのIF信号としてD/A変換され、その後のIQミキサで所定の周波数までアップコンされるというものです。
送信周波数は87.5~108MHzと海外仕様ですから国内では87.5~89.9MHzでしか使えません。音声特性は、歪率0.4%(モノラル/ステレオ)、SN比55dB(モノラル/ステレオ)、ステレオセパレーション35dB、周波数特性-3~+1.5dB(50~15kHz)とポータブル機器への組み込み用途としては申し分のない特性です。
NS73Mの内部ブロック図(仕様書より)
NS73Mは、I2Cまたは3線シリアルインターフェースで、送信周波数や送信出力レベルの変更はもちろん、プリエンファシス有無、ミュート操作、入力レベルの変更、モノラル/ステレオ切替等が可能です。下図に製作予定の回路図を示します。
製作予定の回路図
2010年2月22日月曜日
USB FMトランスミッタ: Si4710制御ソフト
Si4710を使うときにまず困るのが、データシートの入手です。Silicon Laboratoriesや販売店のサイトからは概要版のような2ページしかないものしかダウンロードできません。必要なのは、デバイスのデータシートとプログラミングガイドの2種類です。直接リンクは避けますが、良く探すとネット上から拾うことができます。
Si4710の制御
I2Cで制御します。AVRに埋め込まれた専用ハードを使っています。エラー処理は行っていませんが、I2C_comm() で簡単な関数化を行い、init_si4710() から呼び出しています。I2Cについてはエレキジャック誌の記事が大変参考になりました。
void I2C_comm(uint8_t rw, uint8_t word_length)
{
// rw: 0->read, 1->write
uint8_t n;
if (rw ==1) { // Write
// I2C "STRAT"
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
// 送信完了TWINTフラグまで待機
while(!(TWCR & _BV(TWINT)));
for (n = 0; n<word_length; n++) { //一部全角にしています
TWDR = I2C_data[n];
// 送信実行
TWCR = _BV(TWINT) | _BV(TWEN) ;
// 送信完了TWINTフラグまで待機
while(!(TWCR & _BV(TWINT)));
}
// I2C "STOP"
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN) ;
} else { // Read
// I2C "STRAT"
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
// 送信完了TWINTフラグまで待機
while(!(TWCR & _BV(TWINT)));
TWDR = I2C_data[0];
// 送信実行
TWCR = _BV(TWINT) | _BV(TWEN) ;
// 送信完了TWINTフラグまで待機
while(!(TWCR & _BV(TWINT)));
for (n = 0; n<word_length; n++) { //一部全角にしています
if (n == (word_length - 1)) {
// 送信実行
TWCR = _BV(TWINT) | _BV(TWEN);
} else {
// 送信実行
TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWEA);
}
// 送信完了TWINTフラグまで待機
while(!(TWCR & _BV(TWINT)));
I2C_data[n] = TWDR;
}
// I2C "STOP"
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN) ;
}
}
void init_si4710(void)
{
/*
// Power up as Digital input
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x01; // POWER UP
I2C_data[2] = 0xC2;
I2C_data[3] = 0x0F;
I2C_comm(1, 4);
// Read Response, Wait for "Clear to Send"
do{
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
// Digital input setting
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x01; // DIGITAL_INPUT_SAMPLE_RATE
I2C_data[4] = 0x03;
I2C_data[5] = 0x00; // (Clock must be available on DCLK/DFS pin)
I2C_data[6] = 0x00; // 32kHz: 0x7D00, 44.1kHz: 0xAC44, 48kHz: BB80
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do{
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
// Digital input setting
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x01; // DIGITAL_INPUT_SAMPLE_RATE
I2C_data[4] = 0x03;
I2C_data[5] = 0xAC; // (Clock must be available on DCLK/DFS pin)
I2C_data[6] = 0x44; // 32kHz: 0x7D00, 44.1kHz: 0xAC44, 48kHz: BB80
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do{
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
// Digital input setting
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x01; // DIGITAL_INPUT_FORMAT
I2C_data[4] = 0x01;
I2C_data[5] = 0x00; // I2S, Stereo, 16bit
I2C_data[6] = 0x00;
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do{
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
*/
// Power up as Analog input
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x01; // POWER UP
I2C_data[2] = 0xC2;
I2C_data[3] = 0x50;
I2C_comm(1, 4);
// Read Response, Wait for "Clear to Send"
do{
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
// Analog input setting
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x21; // TX_LINE_INPUT_LEVEL
I2C_data[4] = 0x04;
I2C_data[5] = 0x20; // Line Attenuation LIATTEN[1:0] = 0b11 (Max 636mVpk)
I2C_data[6] = 0x0C; // Line Level LILEVEL[9:0] = 0x27C (636mVpk)
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do {
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
/*
// Get Revison
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x10; // GET_REV
I2C_comm(1, 2);
// Read Response
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 9);
*/
//Set RCLK
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x02; // REFCLK_FREQ
I2C_data[4] = 0x01;
I2C_data[5] = 0x7D; // REFCLKF[15:0] = 0x7D00 (32kHz)
I2C_data[6] = 0x00;
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do {
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
//Set REFCLK_PRESCALE
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x02; // REFCLK_PRESCALE
I2C_data[4] = 0x02;
I2C_data[5] = 0x01; // REFCLKP[11:0] = 0x177 (12MHz/32kHz=375)
I2C_data[6] = 0x77;
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do {
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
//Set TX_LINE_INPUT_MUTE
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x21; // TX_LINE_INPUT_MUTE
I2C_data[4] = 0x05;
I2C_data[5] = 0x00; // L,R No mute
I2C_data[6] = 0x00;
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do {
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
// Preemphasis
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x21; // TX_PREEMPHASIS
I2C_data[4] = 0x06;
I2C_data[5] = 0x00; // 50us
I2C_data[6] = 0x01;
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do {
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
// Audio Deviation
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x21; // TX_AUDIO_DEVIATION
I2C_data[4] = 0x01;
I2C_data[5] = 0x1A; // transmit auidio deviation
I2C_data[6] = 0xA9; // 6825(68.25kHz @90%MOD)
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do {
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
// FM Transmit Frequency
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x30; // TX_TUNE_FREQ
I2C_data[2] = 0x00;
I2C_data[3] = 0x22; // Frequency must be a mutiple of 50kHz
I2C_data[4] = 0x92; // 8850(88.5MHz)
I2C_comm(1, 5);
// Read Response, Wait for "Clear to Send"
do {
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
// Transmit Power
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x31; // TX_TUNE_POWER
I2C_data[2] = 0x00;
I2C_data[3] = 0x00;
I2C_data[4] = 0x73; // 115dBuV, antenna auto tuning
I2C_data[5] = 0x00; // 00: Auto Tuning
I2C_comm(1, 6);
// Read Response, Wait for "Clear to Send"
do {
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
}
音声サンプルレートの測定
サンプルレートを知るためにPCM2707から出力されるLRクロックの周期を測定します。やり方としては、LRクロックをAVRのICP1端子に接続して、LRクロックの立ち上がりエッジで割り込み TIMER1_CAPT_vect をかけて、カウンタをキャプチャ/リセットする方法を考えています。本来はアセンブラを使わなくてはいけないとおもいますが、実用になるのか試してみたところです。
このプログラムでの各サンプルレートでの計数値は次の通り。(Cですのでコンパイラの都合で変動する場合があります)
48kHz(83システムクロック) => 計数値60
44.1kHz(91システムクロック) => 計数値67
32kHz(125システムクロック) => 計数値101
なお、コールドスタート時のPCM2707のLRクロックは44.1kHzでした。
// 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);
ISR (TIMER1_CAPT_vect)
{
TCCR1B = 0b000; // Counter Stop
TCNT1 = 0x0000; // Counter Reset
TCCR1B = 0b001; // Counter Start
ICR1 の処理
}
Si4710の制御
I2Cで制御します。AVRに埋め込まれた専用ハードを使っています。エラー処理は行っていませんが、I2C_comm() で簡単な関数化を行い、init_si4710() から呼び出しています。I2Cについてはエレキジャック誌の記事が大変参考になりました。
void I2C_comm(uint8_t rw, uint8_t word_length)
{
// rw: 0->read, 1->write
uint8_t n;
if (rw ==1) { // Write
// I2C "STRAT"
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
// 送信完了TWINTフラグまで待機
while(!(TWCR & _BV(TWINT)));
for (n = 0; n<word_length; n++) { //一部全角にしています
TWDR = I2C_data[n];
// 送信実行
TWCR = _BV(TWINT) | _BV(TWEN) ;
// 送信完了TWINTフラグまで待機
while(!(TWCR & _BV(TWINT)));
}
// I2C "STOP"
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN) ;
} else { // Read
// I2C "STRAT"
TWCR = _BV(TWINT) | _BV(TWSTA) | _BV(TWEN);
// 送信完了TWINTフラグまで待機
while(!(TWCR & _BV(TWINT)));
TWDR = I2C_data[0];
// 送信実行
TWCR = _BV(TWINT) | _BV(TWEN) ;
// 送信完了TWINTフラグまで待機
while(!(TWCR & _BV(TWINT)));
for (n = 0; n<word_length; n++) {
if (n == (word_length - 1)) {
// 送信実行
TWCR = _BV(TWINT) | _BV(TWEN);
} else {
// 送信実行
TWCR = _BV(TWINT) | _BV(TWEN) | _BV(TWEA);
}
// 送信完了TWINTフラグまで待機
while(!(TWCR & _BV(TWINT)));
I2C_data[n] = TWDR;
}
// I2C "STOP"
TWCR = _BV(TWINT) | _BV(TWSTO) | _BV(TWEN) ;
}
}
void init_si4710(void)
{
/*
// Power up as Digital input
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x01; // POWER UP
I2C_data[2] = 0xC2;
I2C_data[3] = 0x0F;
I2C_comm(1, 4);
// Read Response, Wait for "Clear to Send"
do{
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
// Digital input setting
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x01; // DIGITAL_INPUT_SAMPLE_RATE
I2C_data[4] = 0x03;
I2C_data[5] = 0x00; // (Clock must be available on DCLK/DFS pin)
I2C_data[6] = 0x00; // 32kHz: 0x7D00, 44.1kHz: 0xAC44, 48kHz: BB80
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do{
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
// Digital input setting
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x01; // DIGITAL_INPUT_SAMPLE_RATE
I2C_data[4] = 0x03;
I2C_data[5] = 0xAC; // (Clock must be available on DCLK/DFS pin)
I2C_data[6] = 0x44; // 32kHz: 0x7D00, 44.1kHz: 0xAC44, 48kHz: BB80
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do{
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
// Digital input setting
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x01; // DIGITAL_INPUT_FORMAT
I2C_data[4] = 0x01;
I2C_data[5] = 0x00; // I2S, Stereo, 16bit
I2C_data[6] = 0x00;
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do{
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
*/
// Power up as Analog input
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x01; // POWER UP
I2C_data[2] = 0xC2;
I2C_data[3] = 0x50;
I2C_comm(1, 4);
// Read Response, Wait for "Clear to Send"
do{
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
// Analog input setting
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x21; // TX_LINE_INPUT_LEVEL
I2C_data[4] = 0x04;
I2C_data[5] = 0x20; // Line Attenuation LIATTEN[1:0] = 0b11 (Max 636mVpk)
I2C_data[6] = 0x0C; // Line Level LILEVEL[9:0] = 0x27C (636mVpk)
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do {
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
/*
// Get Revison
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x10; // GET_REV
I2C_comm(1, 2);
// Read Response
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 9);
*/
//Set RCLK
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x02; // REFCLK_FREQ
I2C_data[4] = 0x01;
I2C_data[5] = 0x7D; // REFCLKF[15:0] = 0x7D00 (32kHz)
I2C_data[6] = 0x00;
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do {
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
//Set REFCLK_PRESCALE
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x02; // REFCLK_PRESCALE
I2C_data[4] = 0x02;
I2C_data[5] = 0x01; // REFCLKP[11:0] = 0x177 (12MHz/32kHz=375)
I2C_data[6] = 0x77;
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do {
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
//Set TX_LINE_INPUT_MUTE
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x21; // TX_LINE_INPUT_MUTE
I2C_data[4] = 0x05;
I2C_data[5] = 0x00; // L,R No mute
I2C_data[6] = 0x00;
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do {
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
// Preemphasis
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x21; // TX_PREEMPHASIS
I2C_data[4] = 0x06;
I2C_data[5] = 0x00; // 50us
I2C_data[6] = 0x01;
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do {
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
// Audio Deviation
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x12; // Set property
I2C_data[2] = 0x00;
I2C_data[3] = 0x21; // TX_AUDIO_DEVIATION
I2C_data[4] = 0x01;
I2C_data[5] = 0x1A; // transmit auidio deviation
I2C_data[6] = 0xA9; // 6825(68.25kHz @90%MOD)
I2C_comm(1, 7);
// Read Response, Wait for "Clear to Send"
do {
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
// FM Transmit Frequency
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x30; // TX_TUNE_FREQ
I2C_data[2] = 0x00;
I2C_data[3] = 0x22; // Frequency must be a mutiple of 50kHz
I2C_data[4] = 0x92; // 8850(88.5MHz)
I2C_comm(1, 5);
// Read Response, Wait for "Clear to Send"
do {
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
// Transmit Power
I2C_data[0] = 0x22; // ADDR+W
I2C_data[1] = 0x31; // TX_TUNE_POWER
I2C_data[2] = 0x00;
I2C_data[3] = 0x00;
I2C_data[4] = 0x73; // 115dBuV, antenna auto tuning
I2C_data[5] = 0x00; // 00: Auto Tuning
I2C_comm(1, 6);
// Read Response, Wait for "Clear to Send"
do {
I2C_data[0] = 0x23; // ADDR+R
I2C_comm(0, 1);
} while (bit_is_clear(I2C_data[0], 7));
}
音声サンプルレートの測定
サンプルレートを知るためにPCM2707から出力されるLRクロックの周期を測定します。やり方としては、LRクロックをAVRのICP1端子に接続して、LRクロックの立ち上がりエッジで割り込み TIMER1_CAPT_vect をかけて、カウンタをキャプチャ/リセットする方法を考えています。本来はアセンブラを使わなくてはいけないとおもいますが、実用になるのか試してみたところです。
このプログラムでの各サンプルレートでの計数値は次の通り。(Cですのでコンパイラの都合で変動する場合があります)
48kHz(83システムクロック) => 計数値60
44.1kHz(91システムクロック) => 計数値67
32kHz(125システムクロック) => 計数値101
なお、コールドスタート時のPCM2707のLRクロックは44.1kHzでした。
// 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);
ISR (TIMER1_CAPT_vect)
{
TCCR1B = 0b000; // Counter Stop
TCNT1 = 0x0000; // Counter Reset
TCCR1B = 0b001; // Counter Start
ICR1 の処理
}
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ルートハブのプロパティで”電力”タブを選べば確認できます。セルフパワーなのに指定することに意味があるのかは?ですが。
その他の問題
内蔵のミュート回路が動作しているのかと、いろいろ原因を調べましたが問題なし。
ダメもとでググってみたら、森秀樹氏のブログのコメントにI2S出力モード(FSEL=L)では、
アナログ出力なしと書いてある。他の人のところでも同じ現象が起きるなら、それで正解か。
でもデータシートにはそんな記述は見あたらないように見える。俺の1日を返せという気分。
詳しく調べていませんが、お気楽オーディオキットの記事にヒントがあるかも知れません。
PCM2707はデバイスディスクリプタ情報をSPIインターフェース経由で変更できます。情報を変更後、USBのD+ピンを3.3V系にプルアップすると、PCからUSB機器が接続されたことが認識され、PCM2707はそのデバイスディスクリプタ情報をPCに通知します。
プログラム
CPUはATmega8Lです。以下にプログラムを示します。後ほど説明するプログラムに必要な項目も含んでいます。
※プログラムをブログにコピペすると、タブを削除したり、一部のコードが勝手に変更されてしまいます。どうなってるんでしょう?(#includeの括弧を全角に変更しています)
#define F_CPU 4.000E6 // マスタクロック4MHz
#include <avr/io.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<
// 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コードです。おそらくプログラムでそのまま書けると思うのですが、よくわからなかったので
このほか、USB電流の指定もでき、PC直結の場合USBルートハブのプロパティで”電力”タブを選べば確認できます。セルフパワーなのに指定することに意味があるのかは?ですが。
その他の問題
- I2S出力時にアナログ音声が出ない
内蔵のミュート回路が動作しているのかと、いろいろ原因を調べましたが問題なし。
ダメもとでググってみたら、森秀樹氏のブログのコメントにI2S出力モード(FSEL=L)では、
アナログ出力なしと書いてある。他の人のところでも同じ現象が起きるなら、それで正解か。
でもデータシートにはそんな記述は見あたらないように見える。俺の1日を返せという気分。
- アナログ出力レベルが低い
詳しく調べていませんが、お気楽オーディオキットの記事にヒントがあるかも知れません。
2010年2月20日土曜日
USB FMトランスミッタ: お手上げ!
Si4710を使ったFMトランスミッタですが、うまく動かせないでいます。
ソフトとハードの両方の問題を抱えているようで、ひとまず作業ストップ。
とりあえず、現時点までの成果を備忘録がてら掲載します。
問題点
- Si4710をアナログ入力とした場合、Lチャンネルの音がまったく出ない。
QFNのはんだ付け不良でLチャンネル入力がつながっていない?
- Si4710をデジタル入力とした場合、送信出力が出ない。
QFNのはんだ付け不良でDCLK入力がつながっていない?
基板の外観
製作後の設計変更や修正でジャンパが増えてしまいました。

基板うら
回路図
画像をアップしたら、見にくくリサイズされてしまいました。
電源
PCからUSB経由で電源の供給を受けます。USBのVBUS端子の電圧は5Vで、ローパワーデバイスは100mA、ハイパワーデバイスは500mA(USB2.0)までです。500mAまで使用するには、PCのUSBコントローラと通信して使用電流を設定する必要があります。今回は、動作の自由度を考えてPCM2707をセルフパワーとして設定していますが、PC側で電源を遮断されることもなく、実際にはUSBから電源供給を受けるバスパワーとして動作させています。
それに、(高級なPCはともかく)現実的にはUSBコントローラ側で詳細に電流を管理しているとは思えず、実際にはセルフパワー扱いでも100mA以上の電流が取り出せるのではと思っています。(巷で売られているUSB携帯充電器とかUSB扇風機にコントローラチップが入っているとは思えません)
なお、USBの規格書は、usb.orgからダウンロードできます。が、ドキュメントが膨大でとても読み込めません。
USB miniBコネクタ
HDDケースにもともとついていたコネクタはUSB miniBコネクタでした。今まで使ったことのあるBコネクタは4ピンですが、このminiBコネクタは5ピンです。どうもUSB On-The-GoというUSB2.0を補足する規格に対応した"ID"端子が追加されている模様で、ホスト側(ID端子をGNDに接続)あるいはデバイス側(ID端子はオープン)かの判別に使われるそうです。とりあえずオープンにしておきます。
USBの信号電圧
VBUSは5Vですが、2つの信号線D+, D-の信号電圧は3.3V系です。USB機器が接続されたことをPC側に伝えるためD+端子のプルアップは3.3V系のロジックに接続します。
Si4710に内蔵されたバリキャップと外付けのコイルとで同調回路が構成されています。このコイルから2pFのコンデンサで出力を取り出すわけですが、2pFのインピーダンスはFM帯でも1kΩくらいあるのでかなり出力が低下します。図面では、さらに10dBのアッテネータを挿入しているので、出力レベルは実測で77dBuV(出力115dBuV設定時)くらいでした。
また、I2Cインターフェースは、バスラインをプルアップする必要があります。このプルアップ抵抗の決め方は、AVRのデータシートに記載されていました。SCLクロック周波数が100kHz以下なら、最小 (Vcc - 0.4V)/3mA から 最大1000 ns/Cbです。AVRの電源電圧は3.3Vなので、最小値は(3.3V-0.4V)/3mA = 約1kΩ。AVRの入力ピン容量は10pF、Si4710は50pF、I2Cバスの静電容量はよくわかりませんが、仮にこれらの合計を100 pFとすれば、最大1000 ns/100pF = 10kΩとなります。今回は、間をとって4.7kΩとしました。
PCM2707のROMに書かれたUSBディスクリプタ情報の書き換えを、SPIインターフェース経由で行います。前述のとおり、AVRに組み込まれた専用ハードは使用しませんでした。
AVRのクロック
Si4710をデジタル入力で使用するには、サンプルレート値を設定する必要があります。ところが、PCM2707からはそのような情報が直接的には出てきません。そこで、I2SのLRクロック周期を測定することにしました。
AVRには校正済みのRC発振器が内蔵されていますが、校正前の公称精度は±3%と役不足なのでクリスタルを使用しました。
AVRのISPコネクタ
AVR-ISPの標準コネクタは、2.5mmピッチの6ピンタイプです。しかし、このコネクタは高さが高過ぎてケースに入りません。そこで高さの低い、日本圧着端子製造(JST)のPHシリーズ(2mmピッチ)を選定しました。Digi-Keyで割安に買えるので今後の工作には同じメーカのXHシリーズ(2.5mmピッチ)やVHシリーズ(3.96mmピッチ)を使っていこうと思っています。ちなみにXHやVHがTDKラムダやコーセルの基板単体タイプの電源で採用されていることを意識しています。
2010年2月18日木曜日
USB FMトランスミッタ: 仕様の検討
Si4710の特徴は、音声デジタル入力を備え、さらにFM変調までも(おそらく)デジタル処理されていることです。音源からデジタル接続できれば電波までをフルデジタル処理できます。しかし、せっかく専用ICを使用するわけですから、手軽さが命。極力シンプルな構成となるよう仕様を絞り込みました。
音声入力
手元の音源としては、CD/DVDプレーヤとPCのMP3があります。FM電波で音楽信号を伝送する場合、プリエンファシスにより高域信号のレベルが持ち上がってしまうので、そのぶん音量を絞り込む必要があります。しかしそれでは、S/Nが不足し一般の放送局と比べ大幅に聞き劣りすることになります。このため、FM放送局と同様な音質とするにはコンプレッサ/リミッタ等の前処理が必要になります。FM放送の特性に適したコンプレッサ/リミッタの専用ハードは業務用に限定されますが、PC用のソフトウェアなら安価に入手できます。そこでPCに接続することを前提とします。PCのデジタル音声出力としては、主にUSBとS/PDIFがありますが、後者は一般的ではありません。USBなら電源も取れますし、USBオーディオICも入手容易ですのでUSB接続を前提としました。なお、S4710には、シングルバンド構成ながら本格的なコンプレッサ/リミッタを内蔵していますので、その能力も聴いてみたいと思っています。USBオーディオICとしては、テキサスインスツルメンツのPCM2704がキット等でも広く使われています。このシリーズからI2Sフォーマット出力に対応しUSBディスクリプタ情報をSPI経由で変更できるPCM2707を選定しました。音声入力信号の仕様は、USBオーディオICの都合により対応サンプルレートは32/44.1/48kHz、16ビットとなります。
法規制
FMト ランスミッタは、免許が不要な微弱電波の範疇で使用しなくてはなりません。今回使用するケースは金属製のため、外部端子を設けて ケース外にアンテナを取り付けます。電波法の規制は、送信出力ではなく電界強度の上限が定められているため、その範囲を逸脱しないよう慎重に決めることに します。
ケースなど
以前、じゃんぱらで購入した2.5インチ用のUSB HDDケースです。USBコネクタやLEDの穴はそのまま使います。このケース、厚みが薄いので高さ制限を気にしながら部品選定します。付加機能
ケースの内部の基板上にDIPスイッチを設け、周波数の変更、モノラル・ステレオ切替、Si4710内蔵コンプレッサ/リミッタのオン・オフができるようにします。
Si4710とは関係ないですが・・・
AVRマイコンでステレオ変調器を作っている人のページを見つけました。こんな方法があるとは!
2010年2月14日日曜日
FMトランスミッタICいろいろ
最近のFMトランスミッタICをピックアップしてみました。ポータブルナビゲーションや携帯音楽プレーヤ等への組み込みを想定しているらしく、小型なQFNパッケージを採用している場合が多いようです。
THG4649
ザインエレクトロニクス(東京のファブレス半導体メーカ - THine Elecdtronics)の製品です。2006年のプレスリリースによると、PLL/VCO内蔵・アナログ音声入力、S/N 70dBを誇るということです。Webの製品情報に掲載されていないので生産中なのかディスコンなのかよくわかりません。チップワンストップでは取り扱いがあるようですが要問い合わせとなっています。なお、このICを採用した製品がバッファローコクヨサプライから販売されています。後継機種も同様な仕様を謳っているのでキーパーツは同じかもしれません。
SN761634
テキサスインスツルメンツ製です。SN761634のほかラジオ付きのSN761633もあります。15kHzの音声ローパスフィルタ、PLL回路も内蔵しており、2.5~4V動作、アナログ音声入力、送信周波数76-108MHz、歪み率1%、SN55dB、セパレーション30dB。パッケージはQFN24ピン。
Si47xxシリコンラボラトリーズのSi4710は、QFN20ピンの小さなパッケージながら、デジタル音声入力に対応し、詳細は不明ながらおそらくデジタル処理型のFM変調を行っているものと思われます。このほか、音声コンプレッサ・リミッタを備えています。同社のFMトランスミッタチップには6種類の製品があります。
- Si4710
- Si4711
- Si4712
- Si4713
- Si4720
- Si4721
いま、現時点で入手可能なFMトランスミッタICとしては最も先進的に見えるSi4710を使ったUSB FMトランスミッタの製作に取り組んでいます。
2010年1月18日月曜日
QFNパッケージのはんだ付け
Si4710(FMトランスミッタIC)のはんだ付けで苦労しています。
このICは、リード線のないQFN20ピン。3mm角のチップでピンピッチは0.5mmです。QFNには2種類あって、BGAパッケージのようにパッドがチップ底面だけに出ているタイプと、側面にも出ているタイプとがありますが、Si4710は側面にもパッドが出ているタイプです。
QFNのはんだ付けは、つい先日もSDR基板の製作で経験しており、位置合わせさえ確実であれば無洗浄タイプのフラックスを使ってはんだ付けが可能です。初めてQFNを見たときは、オーダミスで手はんだできないタイプを頼んでしまったと勘違いしましたが、実のところ見た目ほど難しくないという印象です。
ところが、Si4710のチップ側面パッドは、申し訳程度のごく小さなもので、はんだが乗らず手を焼きました。SDR基板ではラクラクだったのに、Si4710でなぜ苦労するのか違いを考えてみたところ、側面パッドが底面パッドとつながっているかどうかの差があります。どうも側面パッドが基板のパターンから0.1~0.2mmほど高い位置に付いているのが原因のようで、わずかな距離ながらはんだがブリッジしてくれないので、はんだでパターンと接続できません。
Si4710のはんだ付けには、かなり頑張ったのですが、うまく行かず失敗を覚悟しました。こうなっては、裏返しにしてジャンパ線で接続してやろうかと取り外そうとしましたが、強固にくっついていてはがれません。それなら、底面パッドがパターンにはんだ付けできているのではと淡い期待を抱きつつ基板のパターンとチップ側面パッドの間の導通を確認します。テスタ棒はパッドに対して大きすぎるので先端が針状の特殊プローブを急遽準備して、全ピンの導通を確認できました。ただ、たび重なるはんだごての熱でチップが焼死していなければ良いのですが、こればかりは組み上げてみるまで結果はわかりません。
このICは、リード線のないQFN20ピン。3mm角のチップでピンピッチは0.5mmです。QFNには2種類あって、BGAパッケージのようにパッドがチップ底面だけに出ているタイプと、側面にも出ているタイプとがありますが、Si4710は側面にもパッドが出ているタイプです。
QFNのはんだ付けは、つい先日もSDR基板の製作で経験しており、位置合わせさえ確実であれば無洗浄タイプのフラックスを使ってはんだ付けが可能です。初めてQFNを見たときは、オーダミスで手はんだできないタイプを頼んでしまったと勘違いしましたが、実のところ見た目ほど難しくないという印象です。
ところが、Si4710のチップ側面パッドは、申し訳程度のごく小さなもので、はんだが乗らず手を焼きました。SDR基板ではラクラクだったのに、Si4710でなぜ苦労するのか違いを考えてみたところ、側面パッドが底面パッドとつながっているかどうかの差があります。どうも側面パッドが基板のパターンから0.1~0.2mmほど高い位置に付いているのが原因のようで、わずかな距離ながらはんだがブリッジしてくれないので、はんだでパターンと接続できません。
(側面と底面パッドがつながっている)
Si4710のはんだ付けには、かなり頑張ったのですが、うまく行かず失敗を覚悟しました。こうなっては、裏返しにしてジャンパ線で接続してやろうかと取り外そうとしましたが、強固にくっついていてはがれません。それなら、底面パッドがパターンにはんだ付けできているのではと淡い期待を抱きつつ基板のパターンとチップ側面パッドの間の導通を確認します。テスタ棒はパッドに対して大きすぎるので先端が針状の特殊プローブを急遽準備して、全ピンの導通を確認できました。ただ、たび重なるはんだごての熱でチップが焼死していなければ良いのですが、こればかりは組み上げてみるまで結果はわかりません。
登録:
投稿 (Atom)

























