ラベル Arduino の投稿を表示しています。 すべての投稿を表示
ラベル Arduino の投稿を表示しています。 すべての投稿を表示

2014/03/01

[電子工作]Arduino Unoの裏面シルクの話

,

概要

Arduino Uno R3の裏面は、そのほとんどが白のシルク(?)で覆われています。表面を見れば、この基板は青レジストだと分かるんですけど、白シルクを上手に使うことで模様を描いたりしていて、是非真似したいものだなあと思っていました。
 
Arduino公式サイトより、http://arduino.cc/en/uploads/Main/ArduinoUno_R3_Back.jpgを引用
ですが、実際やってみようとすると大きな疑問が生じます。それは、『どうやってビアやランドに掛かるシルクだけ、消しているんだろう?』ということです。

どうして問題なのか?

『シルクとランドが重なった場合、ランドの上にシルクが印刷されてしまうので、ハンダ付け出来なくなってしまう』からです、多分。

 えー大変じゃないですか、ということで。そもそも基板の製造会社は、こういう処理をしてくれたりしないんでしょうか?
 調べてみると、シルクを避けてくれる会社はあるようです(FusionPCBとか、参考)。逆に、データに忠実に従って、重ねるところもあるみたいです(Olimaxとかダメらしい)。
 私は殆ど基板を作ってもらったことが無いので、実際に重ねてしまった例が無く分からないのですが…実際Elecrowにそんな例を作ってもらって、判断するというのも有りなのかもしれませんね。

CADでどうにか出来ない?

Google先生によると、この『パッドと重なる部分のシルクを消す』ことを、『シルクカット』などと呼ぶみたいです。
参考 : シルクが重なる場合はシルクカットを行なう | ノイズ対策.com

 なので、Eagleでシルクカットが出来ないか調べてみたのですが、あまり出来るという趣旨の記述は見当たりませんでした…そもそも、重なっていたらDRCだかでエラーになってしまうみたいです。vRestrict Layer系統も、シルクの物はないし、そもそもオートルーターのためのものですし。。
 あるとすればulp(User Language Program)とかでしょうか。それとも、シルクカットじゃない、別のもっとメジャーな呼び方が有るのかもしれません。

 もう一つ思いついた方法は、全ての基板設計が終わればランドの位置は既知となるので、その情報を用いて"予めランドを抜いたシルク"を生成するとかでしょうか。でもimport-bmp.ulp使っているとしたら画像の段階で抜かないといけないので、かなり至難の業な気がしますが…。

 スクリプト書け、ということなのでしょうか…。


 因みに、他のCADであるAltium Designerだと出来るみたいです。欲しくなってきましたね!(27万する)
ガーバーエディタの活用 | アルティウムの日替り?情報局 - Altium Designer 導入と運用の道標

Arduinoのデータだとどうなっているか?

Arduinoのデータは、公式サイトの"arduino-uno-Rev3-reference-design.zip"からDownloadすることが出来ます。試しに.brdをそのままElecrow_Gerber_Generater_DrillAlign.camに読ませ、ガーバーファイルを生成、GC-Prevueで裏面シルク(.GBO)を見てみました。
GC-Prevueで見たarduino_Uno_Rev3-02-TH.GBO
…あれ?そもそもシルクじゃないの…?

まとめ

・白シルクで絵を描くのかっこいい
・でもランドとかと重なると面倒。しかも製造会社がやってくれるとは限らない
・Eagleだと対処法がわからない…(そもそもDRCとかでエラーになるみたい)
 ということで、どなたかEagleで行う方法をご存知でしたら、是非教えて頂けると嬉しいです…。

おまけ : 基板について調べてると、結構基板設計基準みたいなものを見かけました。
ex.)プリント基板製造データ基準書 | 株式会社シグナス
コーディング規約みたいなものでしょうか。お勉強にもなるのでなかなかおもしろかったです。
Read more →

2013/09/28

[電子工作]aitendoのDDSモジュールを動かす その2

,
0)前置き

 前にこんな記事を書いて以来、aitendoのDDSモジュールも放置していたのですが、そろそろケースに入れたいのでまた触り始めました。
 取り敢えず、SPIでいい加減動かさないと…ということでSPIから制御する話です。

 使ったハードはArduino Duemilanoveなので(今となっては化石…)、Master側のSPI設定に困ることはないです。


1)ハード的な話

 AD9850は、どうも2ピンがLow、3・4ピンがHighならばデフォルトでシリアル通信モードみたいです。aitendoにある回路図を見ると、2ピンに繋がっているJP1をジャンパしておけばGNDに落ちるみたいなので、パラレル→シリアルへの変換コマンドを送る必要はないみたいです。

 出力ですが、IOUTが200ΩでGNDに落ちているので、そのまま出力インピーダンスも200Ωなのでしょうか…?評価キットの回路図では、IOUTBは25ΩでGNDに、IOUTは50ΩでGNDに落ちてますが…

2)ソフト的な話

 AD9850のデータシートに書かれている、SPI通信のタイミングをみます。
AD9850 Data Sheet 英語 Rev H(http://www.analog.com/static/imported-files/data_sheets/AD9850.pdf)より転載
で、AD9850のシリアル信号線の名前は、SPIによくあるSS、MOSIなどとは違ってますが、結局役割は同じみたいです。

FQUP(FreQuency UPdate) → SS(10)
WCLK → SCLK(13)
D7 → MOSI(11)


 SPI通信をするときには、幾つか設定しないといけない事がありますが、AD9850のデータシートを見る限りでは、以下の様になってるみたいです。

・動作モード
 CLKの立ち上がりでデータをサンプリングするみたいです。又、通信していない時のCLKはLowなので、SPI_MODE0になります。

・データの送り方(BitOrder)
 BitOrderは、データの送る順番がw0(LSB)から順にw1、w2、…、w31(MSB)なので、LSBFIRSTです。

・SS(FQUP)の制御
 SPI通信では、先ず最初にSSを下げてから通信をしますが、どうも通信終わりのSS↑↓は自分でやらないといけないみたいです。

・AD9850のRESET信号
 RESETを最初に落とすことになりますが、このRESETは正論理(!)なので、Resetしたい時に0にします。最初負論理だとてっきり思っていて、動かずに困りました…

・送るデータですが、EF_AD9850に依れば、
//Calculate the frequency of the HEX value
x=4294967295/125;//Suitable for 125M Crystal
frequence=frequence/1000000;
frequence=frequence*x;
y=frequence;
らしいです。例えば40kHzであれば、0b00000000, 0b00010100, 0b11111000, 0b10110101になります。

最後のw32~39のControl Registerには、
bit[1:0] Control Serialならば00
bit2 Power Shutdown 0
bit[7:3] Phase
を書き込みます。


 ということで、ArduinoのSPIを使うように改造しました。一応クラスにしてますが、8bitレジスタ5個分を送るだけの簡単なプログラムです。
class AD9850{
 //7 reset
 //10 fqup
 //11 d7
 //13 wclk 

private:

public:
 AD9850(){};
 ~AD9850(){};

 //Initialize SPI & DDS(AD9850)
 void Init(){
  //set
  pinMode(7, OUTPUT);

  //Send Reset signal
  digitalWrite(7, 0);
  digitalWrite(7, 1);
  digitalWrite(7, 0);

  //Init SPI
  SPI.begin();
  SPI.setDataMode(SPI_MODE0);  //Idle : clk low, rising edge. 
  SPI.setBitOrder(LSBFIRST);
 };

 //freq : Frequency[Hz]
 //w0 : Control Register Value
 void SetFrequency(const unsigned char w0, const double freq){
  const double xtal_freq = 125;  //125MHz Xtal
  const double x = (4294967295 / xtal_freq)  / 1000000;
  long int y = (long int)(freq * x);
  
  SPI.transfer(y & 0xFF);
  SPI.transfer((y >> 8) & 0xFF);
  SPI.transfer((y >> 16) & 0xFF);
  SPI.transfer((y >> 24) & 0xFF);
  SPI.transfer(w0);  //Control Register
  //FQUP
  digitalWrite(10, 1);
  digitalWrite(10, 0);
 };
};
このプログラムを実機上で動かして、ロジック・アナライザで通信データを見てみたところ、下の写真のようになりました。
ロジアナで見たSPI通信

 SPI.transfer()を1byteごとに呼んで送信しているため、1byteごとに何も通信していない部分(A2のMOSIが1になっているところ)がありますが、CLKもLowのままでサンプリングされてないので問題無いと思っています。

 DigitalWrite()でSS(FQUP)を制御しているので、SPIの通信が終わってからSSが上がるまでに結構時間がかかっているみたいですが、まあ動いてるので大丈夫でしょう…

 使い方は、前のライブラリ(EF_AD9850)とほぼ一緒。
Read more →

2013/01/02

[電子工作]DAコンバーター MCP4922を動かしてみた

,
 3日坊主なので記事書くのだるいな~~~~~って思ってます

 で、秋月に売ってるDAC MCP4922を使ってみました。ブレッドボードに刺さったまま2年くらい経ってる子。動かし方は電子部品使い方:マイコンのD/A変換さんを見ました。12Bitで、電源2.7V~5.5Vまでで動きます。

#なんか後でこの記事読んだけど全くさっきのサイトさんと一緒だったのでどうしよう感に溢れてる

 一応データシートのp.18~19を見ると分かる通り、SPI通信で16bitのデータを送ることで制御します。16bitの中身は、

bit 15:DAC AかBを選ぶ。Aなら0、Bなら1
bit 14:Vrefの入力をバッファするか選ぶ。バッファするなら1、しないなら0(Vrefのインピーダンスがとても高い時に使う)。デフォルトだとUnbuffered(データシート4.1.2章より)。
bit 13:出力を2倍するかしないか。2倍するなら0、しないなら1。2倍すると単純にVout =  2 * (Vref * Data / 4096)となる。
bit 12:出力を出すかどうか?かな?0だと出力がハイインピーダンスになるみたい。
bit 11~0:出力する値のデータ(12bits)

らしいです。

MICROCHIP MCP4921/4922 Datasheet p.1より、VrefバッファとソフトウェアSHDNの位置


 制御線のタイミングはp.19のFig.5-1を見てください。
MICROCHIP MCP4921/4922 Datasheet p.19より、制御タイミング
CSを下げたら、16bitデータを送り、LDACを上げるとDACから設定した値が出力されます。LDACを下げるタイミングはどこでもいいみたい…?

Arduinoで動かすならこんな感じのクラスを作って(一応まとめてみた)
#include < SPI.h >

class MCP4922
{
  private:
  const int SDI;
  const int CS ;
  const int LDAC;
  
  public:
  MCP4922 () : SDI(11), CS(10), LDAC(9) {
  }
  
  void initialize(){
    pinMode(SCK, OUTPUT);
    pinMode(SDI, OUTPUT);
    pinMode(CS, OUTPUT);
    pinMode(LDAC, OUTPUT);
    digitalWrite(SCK, LOW);
  }
  
  void setDACvalue(unsigned int value){
    SPI.begin();
    digitalWrite(LDAC, HIGH);
    digitalWrite(CS, LOW);
    //データを送る
    SPI.transfer(0b01110000 | (0b00001111 & highByte(value)));
    //highByte()とlowByte()はArduinoで使える関数
    //使えないときはhighByte(s):(s >> 8)、lowByte(s):s & 0xFFで。
    SPI.transfer(lowByte(value));
    digitalWrite(CS, HIGH);
    digitalWrite(LDAC, LOW);
    SPI.end();
  }
};

で、呼び方はこんな感じ
void setup() { }

void loop(){
  MCP4922 dac1;
  dac1.initialize();
  for(unsigned int i = 0; i < 0x0FFF; i++){
    dac1.setDACvalue(i);
    delay(5);
  }
}

こうすると徐々に電圧が上がっていくのがわかる…それだけ

 一応出力は15(Typ.)~24(Max.)mAまで出るっぽいけど、怖いんでバッファ付けたいとは思ってる。どうやらこのDACはそれなりに使われてるようで、こんなボードを作っている方も外国にいらっしゃるみたい。うーん、出力に非反転増幅で2倍してるけど、2倍だとVccが10V近く必要になる…Bi-FETオペアンプでボルテージフォロアにしてもいいけど、短絡とか発振とか考えるとなかなか怖い、お茶目に真空管でカソードフォロアはちょっとレベル高すぎた。見た感じZout=1/gmだけどそれってそこまで下がらないよね

Read more →

2013/01/01

[電子工作][Eagle]ライブラリを追加する

,
 回路図かきかきするのに便利なソフト、Eagleですが、困ったことにデフォルトだといろいろ部品が足りません。で、まあ各自ネットで探すなり作るなりして追加してくわけですね。その方法を忘れそうなのでメモしておきます…

 えっと、今回はよく使う(?)部品のATmega328P-PUを追加してみます。

1)まずネットで探す
 
 Google先生にお尋ねします。するとこんなページが引っかかるわけです。
atmega328p eagle lib file? - Arduino Forumのスクリーンショット

 ふむふむ、少ないですがあるみたいですね。どうやらメモリ容量の少ないATmega168を使えばいいよ、ってことらしいです。

リンク先に飛んでみます。
Arduino AVR Library for EAGLE Layout Editor « Rob Faludiのスクリーンショット。
画像の赤枠で囲ったところをクリックすると、ライブラリファイルの入ったzipがダウンロードできます。

2)ライブラリフォルダにライブラリファイルを入れる

 なので、それを展開し、出てきたArduino-AVR.lbrをEagleのlbrフォルダ(C:\Program Files\Eagle-6.1.0\lbr\とか)に入れます。
 ここらへんはKarappo Interaction Lab. » EAGLEにライブラリを追加するさんを参考にしました。

3)Control Panelで使用可能にする

 次にEagleを起動します。既に起動してある場合は再起動です。まず最初にControl Panelが開くと思います。Librariesメニューを展開すると、Arduino-AVRという項目があると思います。で、画像のように、灰色の○をクリックして緑色にします。

Control PanelでArduino-AVRを使用可能に

後は回路図書くときに部品の追加すればいけます。

使えるようになりましたーやったー…

 でまあなんでこんな馬鹿正直に書いたかって言うと、ここまで書かないと俺が理解できないからです(;´'-'`) 馬鹿だー
 
 スクリーンショットを載せるのってどうなんですかね、結構悩みモノです…
Read more →

2012/12/10

[電子工作]ADコンバーター MCP3002 を使ってみた。

,
放置してたので使わないと…ということで使ってみました。
MCP3002はMicrochipのADコンバーターで、入力2ch、10bitで秋月で売られているものです。
 このADコンバーターはSPIでデータを取得します。なので、SPIマスターにArduinoを使いました。

 ADコンバーターから値を読み込むには、SPIで2byteのデータを送ります。送るデータの内容と送り方は、データシートのFigure 6.1あたりを見てください。
(MCP3002 datasheet p15より抜粋)















上の図を見ると、送るデータのうち設定するのは、3~5bit目のSGL、ODD、MSBFのみということがわかります。楽ですね!
 1bit目は0です。2bit目はStartbitで、必ず1です。これは上図からわかります。
 SGLビットとODDビットは、入力信号のうちどちらのch(0または1)を使うか、差動入力にするか、を設定します。設定の仕方は、データシートp13 Table5-1を参考にしてください。
 MSBFビットは、1にするとデータがMSB(上位ビット)から、0にするとデータがLSB(下位ビット)から送られてきます。これは、データシートp13 5.1章の途中にある"If the MSBF bit is high, then the data will come
from the device in MSB first format and..."あたりを参考にしてください。

なので、例えばch0のデータを、上位ビットから順に送って欲しかったら、0b011101000、0b00000000と送るわけです。

以下Arduinoのコードです。

void setup(){
  Serial.begin(9600);
  pinMode(10, OUTPUT);
}

void loop(){
  //SPI通信を行い、ADコンバーターからデータを取得
  SPI.begin();
  //SPI.setClockDivider(SPI_CLOCK_DIV128);
  digitalWrite(10, LOW);
  byte highbyte = SPI.transfer(0b01101000);
  byte lowbyte = SPI.transfer(0x00);
  digitalWrite(10, HIGH);
  SPI.end();
  unsigned int data = ((highbyte << 8) + lowbyte) & 0x03FF;
  
  //シリアル通信でパソコンに送る
  Serial.println(data);
  delay(500);
}

17行目は、取得した2つのデータを結合しています。highbyteが上位8bitなので、シフト演算で上位8bitになるようずらします。で、データは下位10bitだけなので、0x03FF=0b0000 0011 1111 1111との論理積を取っています。 

SPI.setClockDividerは別にあってもなくても、DIV8でも128でも変わらないです…

このスケッチを書き込むと、こんな感じで、データがシリアルに送られてきます。
シリアルモニタ
























繋ぐのはSPIバスと電源だけですが、一応配線図を…
巷でArduino使いさんたちが使っている、Fritzingというエディタで、実体配線図を書いてみました。自信がないので接続するときは自分でちゃんとデータシート見てください:;(∩´﹏`∩);:
配線図






































配線てD&Dでよかったんですね…部品なくて困ってた…

詰まった点。
1)SPI通信で、CS(Chip Select)が下がらない。
最初は0しか送られてこなくて、困った挙句ロジアナで見てみると、CSが上がったまま。データシートによれば、というか普通はCSが下がるとSPIバスで通信が行われるので、しょうがないので手動でCS(10)を制御しました。
 で、そうするとデータは取得できるようになったのですが、逆にロジアナで見れなくなった…なんでだろう…
Read more →

2012/02/10

[電子工作]aitendoのDDSモジュールを動かす

,
aitendoで売っている、AD9850がのったモジュールを使ってみました。
このモジュールには、Analog DevicesのAD9850(datasheet)というDDS ICが乗っていますが、海外のサイトにこのICのArduino向けライブラリがあったので、それを使って動作確認してみました。

 AD9850のライブラリはこのページの一番下、「AD9850 Arduino Library.」からZipでDLできます。これを解凍し、Arduinoのlibrariesフォルダの中に入れる(arduino-0021/libraries/EF_AD9850のような感じ)と、Arduino IDEの[Sketch]→[Import Library]で選択できるようになり、使えるようになります。

 ※2012-12-23追記 : ArduinoIDEの更新に伴い、"WProgram.h"が"Arduino.h"になりました。そのため、ライブラリがそのままではコンパイル通らないことがあります。その時は、EF_AD9850/EF_AD9850.hの"WProgram.h"を"Arduino.h"にしてみてください。

ハードウェア

ライブラリの使い方、モジュールとArduino間の結線も、上で紹介したページに書かれています。DDSモジュールのピン配置は、このページにあります。一応書いておくと、
DDS module - Arduino Duemilanoveで
GND - GND
Vcc - Vcc(3.3V)
D7 - Digital 8
CLK - Digital 9
FQUP - Digital 10
REST - Digital 11
です。一応Vcc=3.3Vなので、Arduino側のI/O電圧も3.3Vにしました。5Vな方は自分で調べてください。

ジャンパの設定は、J1、J3がジャンパ。J2は無くても大丈夫っぽいです。

ソフトウェア

プログラムは簡単で、
#include < EF_AD9850.h >

EF_AD9850 AD9850(9,10,11,8);

void setup()
{
  AD9850.init();
  AD9850.reset();
  AD9850.wr_serial(0x00, 1000);
}

void loop()
{
}
です。これも上のページのサンプルコードこのまんまですね。
 これを実行したところ、DDSモジュールのOUT-GND間からsin波が出力されました。クリスタルイヤホンを直繋ぎでも確認できます。

 AD9850は"それなりに"高性能なDDSで、最大60MHzまでのsin波を出力することができます。わざわざ発振器を買わなくても、手軽な信号源とすることができるので便利ですね。簡易network analyzer(作例pdf)を作る試みをしてる人もいるみたいです。
#まだデータシート見てないのに動かせるなんて…
(2014/05/01 加筆修正)
Read more →

2011/10/21

[電子工作]TEA5767搭載FMモジュールを、Arduinoから動かす

,
 Arduinoから、aitendoから発売されているTEA5767モジュールを動かしてみました。
 TEA5767はFMレシーバICで、I2C or SPI機能を持つので、スレーブとしてマイコンに接続することができます。しかし、aitendoのモジュールは、最初からI2C専用の設計になっています(PinがSDAとSCLしかない)。なので、今回は、ArduinoからI2C経由で制御します。

 ところでこのモジュール、アンテナ端子がイヤホンのGNDと100Ωで繋がってる気がするんですが、これってどうなんでしょう?ELMさんのMP3プレーヤーの作例では、イヤホンアンテナとするためなのか、RDA5800のアンテナ端子とイヤホンのGNDを1pでつないでるみたいですが。アナログ高周波回路、よくわかりません…

配線

I2Cのバス2本、Vcc、GNDをArduinoに接続します。Arduino Duemilanoveの場合、
SDAはAnalog 4
SCLはAnalog 5
です。

コード

以下にコードを置いておきます。参考程度にどうぞ。
 内容は、指定した周波数を受信するようにさせるだけのシンプルなものです。各パラメータは、データシートのp11-p17あたりが詳しいです。
 設定するPLLの値は、このサイトさんに、周波数との対応表があるので参考にさせて頂きました。

#include <Wire.h>

//82.5 NHK-FM 2772
//81.3 J-WAVE 26DF
//write addr
const int addr = 0b1100000;
const char data1 = 0x27;
const char data2 = 0x72;
const char data3 = 0x10;
const char data4 = 0x36;
const char data5 = 0b00000000;

void setup()
{
  delay(1000);
  
  Serial.begin(9600);
  Wire.begin();
  //Serial.print(Wire.requestFrom(addr, 5));
  Wire.beginTransmission(addr);
  //Wire.send(0b11000000);
  Wire.send(data1);
  Wire.send(data2);
  Wire.send(data3);
  Wire.send(data4);
  Wire.send(data5);
  Wire.endTransmission();
  Serial.print("end");
}

void loop()
{
}

悩んだこと

Wire.beginTransmission(addr);
のaddrは0~127までの値です。I2Cのアドレスは大抵Lower bit(LSB?)が0か1かでRead/Writeの判断をすると思うのですが、この場合その最下位1bitを切り捨て、残り7bitを右シフトさせ0~127の範囲に収めてaddrに指定するみたいです。詳細は公式リファレンスをどうぞ。

「Wire.beginTransmission(addr);はアドレスをI2Cバスに送るか?」
実はここでかなり悩み、時間をとられました。何しろアマチュアなので原因の切り分けがなかなかできません。
日本語リファレンスには、「指定したアドレスのI2Cスレーブに対して送信処理を始めます。」とあります。
実際、TEA5767はI2Cの場合、addr, data[0], data[1], data[2], data[3], data[4]の6byteをたてつづけに送る必要があるみたいですが、Wire.send()を用いてaddrからもう一度送ると、上手く動きません。どうやら、Wire.beginTransmission()では特定のスレーブを受信体制にするために、I2Cバスにaddrを送信すると思うのですが、どうなんでしょう…。
Read more →