PSoC CY8C29466のI2Cモジュールを試した。
特に仕様書pdfはちゃんと読んでみたらかなり勉強になったのでオススメ。
プログラムはCypress公式のUser Module Datasheetのp.39,40ものを参考にした。
■作った物
PSoC Designer 5.0+SP6で作ったプロジェクトまるごと
githubに置いた 。
git clone git://github.com/shokai/i2c-uart-cy8c29466.git 
で取得できる。
3つ並んでいるPSoCマイコンのうち一番下がmasterで、上2つがslaveデバイス。デバイスが接続されている2つの線は2kΩの抵抗(1kΩ2つ)を介してVCCと接続されpull upされている。
I2Cの接続構成とプルアップ抵抗 に適切なプルアップ抵抗の計算方法が書かれている。電源5Vで100kbpsか400kbpsなら2kΩ〜5kΩが最適値とのこと。
masterに付いているボタンを押すと、2つのslaveにLED点灯命令を送る。ボタンを離すと消灯する。
slave側のボタンは、それぞれmasterの2つのLEDの点灯/消灯に対応している。
masterはslaveをコントロールするだけでなく、I2Cとシリアル通信のブリッジになっている。
slaveからのデータをslaveのアドレス名と共にUARTでパソコンに中継する。また、パソコンからmasterマイコンに’U’か’D’の文字を送る事と、masterは全slaveにLED点灯/消灯を送る。
UARTとRS232Cのレベル変換にはADM3202を使った。
だいたいそういう内容のビデオ
■デバイス設定
master側。
パソコンとのシリアル通信で9600bpsを作るためにVC1,VC3を設定している。動作電圧やCPUクロックなどはデフォルト値。
single masterモードでモジュールを置いた。
100kbpsでPORT1の5番と7番ピンをI2Cに使う。bufferはプログラム中で自分で用意したBYTE配列を使ってもらうように設定。
シリアル通信で9600bpsが出るようにUARTモジュールを設定。
橋本商会  PSoC – CY8C29466でUART受信割り込み でくわしく書いた。
3つのLEDに使うピンは出力をStrongにして3V出るようにした。
タクトスイッチにつなぐPort2の2番ピンは両エッジ入力割り込みを設定しつつ内部でプルアップして、ブレッドボード上でも100Ωの抵抗でプルダウンする。こうするとチャタリングが起きない。
ピン配置図
アナログブロックは使っていないので上の方だけ。
UARTがPort2の4,5番ピンから出るように引き出した。
slave側。
Global Resourceは初期値のまま
I2CHWモジュールををslaveで置いた。速度はmasterに合わせる。
slaveデバイスのアドレスは7bitだが、0x00~0x10までの16個のアドレスはプロトコルに予約されているので、0x11からの112個が使える。
今回はmasterのプログラムで0x11~0x20のデバイスがいるか確認しながら動作するようにしているので、アドレス17~32のどれかを使えばいい。
masterと同じ様にLEDとタクトスイッチ用のピンを設定。LEDは1つだけ。
なにも結線していない
■プログラム
master側
slaveアドレス0x11から0x20までのデバイスに、順にTXバッファを書き込み、RXバッファに読み込む。送受信を待っている間、timeout_countをカウントアップし続けて、閾値以上になるとタイムアウトするようにしている。これで存在するかわからないslaveとやりとりできるし、動作中にslaveデバイスが増えても問題なくネットワークに参加させられる。
UARTの受信やピン入力の検出は割り込みで処理している(
橋本商会  PSoC – CY8C29466でUART受信割り込み で書いた)のだが、I2Cはメインループの中で処理している。I/OからのイベントでUARTぐらいなら使ってもいいけど、16個のslaveとのやりとりを割り込みの中でやると多重割り込みが起こりやすいので、各ルーチンからbufferを読み書きしてそれを定期的にslaveと共有するという方式にした。
本番ではdigital blockを1つ消費するだけで使える8bit Timerモジュールで定期的に回すようにすると良いと思う。
main.c 
// I2C-UART master 
slave側
slaveもmasterと同じ様にglobalにバッファを用意して、そこに適当に現在の状態を読み書きし、定期的にメインループ内でmasterと通信し共有している。この方が素直に書きやすい。
LEDとボタンの状態を結びつける情報を1byte目に置いているが、それ以外の情報をやりとりする場合もシリアライズとかして通信するのではなく2byte目以降を使う方がいい。あくまで必要な変数を定期的に同期させられる、分散オブジェクト風に書いた方がすっきりする(PSoCのstring.hがおかしいという理由もあるけど)
あと、ややこしいのがslaveなのでI2CHW_1_InitWrite関数を呼ぶとmasterからslaveへの書き込みが起こる。受信する。送信ではない。また、I2CHW_1_bReadI2CStatus() での状態チェックも、dataに使っている信号線1本の状態のチェックのためなので呼び出すタイミングがmasterと逆になる。このへんややこしいのであまり触りたくないから、通信は隔離された別ループでやってglobalに置いた共用bufferを同期させるという方法にした。
main.c 
// I2C-UART slave