= ATTiny85を使ったI2C USB変換+温度センサ基板の作成 = 以前作成した[wiki:/epics/weather_sensor USB 温湿度/大気圧センサ]の修正版として作成。[[br]] 以前作成した基板の問題点として、 * 温湿度センサと他のチップがベタグランドでつながっていて、熱が回ってきていないか不安 * センサとCPUが物理的に分離していないので、センサの種類を変えられない 等があったので、その辺りを考慮した。 今回使用するのは、温度センサ[http://www.analog.com/jp/products/analog-to-digital-converters/integrated-special-purpose-converters/digital-temperature-sensors/adt7410.html (ADT7410)]のみなので、センサ基板にはこれだけを実装することにする。 == 回路図 == 回路図はこんな感じになった。 [[Image(i2cduino_sch_1.png, 400)]] [[Image(i2cduino_sch_2.png, 400)]] == アートワーク == 基板のアートワークはこんな感じ。 [[Image(i2cduino_pcb.png, 400)]] USB+CPUとセンサ基板を分離して作成することで、熱的に分離するのと、センサが変わってもプログラムの変更だけで対応できるように考慮した。[[br]] CPUへのファームウェアの書き込みは、裏面に付けたパッドから行う。 == ファームウェア == ファームウェアは arduino を使って作成するので、開発環境を構築。 === Arduino === [https://www.arduino.cc/ arduinoの本家]から開発環境(Arduino IDE)をダウンロードしてインストール。[[br]] ダウンロードは、[https://www.arduino.cc/en/Main/Software ここ]から、自分の環境に合わせたものを持ってくる。[[br]] 2017/12/12現在、最新版は 1.8.5。今回は Windows Installer を使った。 === Board Manager === 最近は色々なマイコンがarduinoで開発できるようになっていて、対応するボードマネージャーを使えば、環境構築を自動でやってくれる。いい時代になったもんだ、、、[[br]] 今回使うCPUは Atmel ATTiny85、書き込みは Arduino ISP で行う。 実際の環境設定は以下のサイトが詳しいので、それを参照。 [http://make.kosakalab.com/make/electronic-work/arduino-ide-dev/ Arduino IDE で ATtiny 他の開発] CPUの開発環境は以下のページを参照。 [http://make.kosakalab.com/make/electronic-work/arduino-ide/attiny-dev/ Arduino IDE に ATtiny45/85/2313 他の開発環境を組み込む] CPUへの書き込みを行う Arduino ISP は、Arduino UNO R3をArdunio書き込み装置にして使用する。(ややこしいですが) [https://www.arduino.cc/en/Tutorial/ArduinoISP Using an Arduino as an AVR ISP (In-System Programmer)] これを使えばAVRライターがなくても、arduino対応のCPU設定が簡単にできる。 === 開発環境テスト === 開発環境が動作するかをチェックする。[[br]] [http://make.kosakalab.com/make/electronic-work/arduino-ide/test_arduinoisp/ 【 Arduino IDE 】ArduinoISP 使い方・書き込みテスト]を参考に行うが、多少違っていた(古い?)ので相違点を記載する。[[br]] {{{ ArduinoISP -> Arduino as ISP(ATTinyCore) }}} 設定は画像のようにする。シリアルポートの設定は、ArduinoISPがつながっているものを選択。 [[Image(arduino_isp.png,400)]] テスト用のソースは、 {{{ #define PIN 3 #define DTIME 500 void setup() { pinMode(PIN, OUTPUT); } void loop() { digitalWrite(PIN, HIGH); delay(DTIME); digitalWrite(PIN, LOW); delay(DTIME); } }}} これをArduinoISPに以下の様につないで書き込み。 [[Image(http://make.kosakalab.com/arduino/use/45_85.gif)]] 書き込みが完了すると、LEDが2秒間隔ぐらいで点滅する。[[br]] 点滅しなかったり、書き込み時にエラーが表示された場合には、設定か回路が間違っているのでチェックする。 本来このプログラムだと0.5秒間隔で点滅するが、クロックに対するカウンタが合っていないのでこのようになる。[[br]] これを合わせるために、メニューから"ツール -> ブートローダーを書き込む"を実行し、再度テストプログラムを書き込むと、今度は0.5秒毎に点滅するようになる。 == 測定用ファームウェア == === TinyWireM === 今回は ATTiny85 + ADT7410なので、前回と同じようにADT7410のサンプルソースを[https://github.com/adafruit/TinyWireM TinyWireM]に対応させる方法で作成する。[[br]] 前回と違うのは、TinyWireMが"ライブラリマネージャー"でインストールできるようになっている点。[[br]] ライブラリマネージャーは、メニューから"スケッチ -> ライブラリをインクルード -> ライブラリを管理"で表示されるダイアログで"tinywire"で検索すると表示される。 [[Image(arduino_lib.png,400)]] これをインストール。 === ADT7410 === ADT7410用のライブラリもライブラリマネージャーでインストールできるが、使われているのがATMega用のWire(I2C)ライブラリなので、そのままでは使用できない。[[br]] なので、これを基にWireをTinyWireMに変更したライブラリを作成した。[[br]] 元のライブラリは[https://github.com/FaBoPlatform/FaBoTemperature-ADT7410-Library FaBoPlatform/FaBoTemperature-ADT7410-Library][[br]] 作成したライブラリファイルは[attachment:ADT7410-TinyWire-Library.zip ADT7410-TinyWire-Library.zip]として置いておくので、必要ならダウンロードして使用すること。 === Firmware === Firmwareは、以前作成したものとほぼ同じ。[[br]] {{{ #include #include #include #include ADT7410_TinyWireM ADT7410; SoftwareSerial SwSerial(3, 4); // RX, TX void setup() { SwSerial.begin(9600); ADT7410.begin(); } void loop() { float temp = ADT7410.readTemperature(); SwSerial.print("T:"); SwSerial.print(temp, 4); SwSerial.print("\r\n"); delay(5000); } }}} 5秒毎にセンサから読み取ったデータを温度に変換し、文字列としてUSBシリアルに出力する。[[br]] 以前のソースコードでは、メモリの使用量の問題でprintを使わずに自前でfloatを出力していたが、新しいバージョンではほとんど変わらなかったので、ソースコードを簡素化した。[[br]] 今回は温度だけなので、出力する文字列は、 {{{ T:xx.xxxx\r\n }}} となる。 '''5秒では遅すぎるとの意見があったので、実装基板に書き込む際には1秒間隔に変更。''' == BBBとの接続 == このボードを実際に使用(運用)する場合には、BBB(又はRaspberryPI)とはUSBで接続するが、最大5個程度の複数接続をする予定なので、udevでデバイス名を固定する必要がある。[[br]] USB HUBを経由して、BBBと接続した時のdmesgは、 {{{ [ 4503.229147] usb 1-1.4: new full-speed USB device number 3 using musb-hdrc [ 4503.330429] usb 1-1.4: New USB device found, idVendor=0403, idProduct=6015 [ 4503.330493] usb 1-1.4: New USB device strings: Mfr=1, Product=2, SerialNumber=3 [ 4503.330526] usb 1-1.4: Product: FT231X USB UART [ 4503.330556] usb 1-1.4: Manufacturer: FTDI [ 4503.330584] usb 1-1.4: SerialNumber: DC00xxxx [ 4503.552556] usbcore: registered new interface driver usbserial [ 4503.552905] usbcore: registered new interface driver usbserial_generic [ 4503.557348] usbserial: USB Serial support registered for generic [ 4503.586971] usbcore: registered new interface driver ftdi_sio [ 4503.587143] usbserial: USB Serial support registered for FTDI USB Serial Device [ 4503.587503] ftdi_sio 1-1.4:1.0: FTDI USB Serial Device converter detected [ 4503.587845] usb 1-1.4: Detected FT-X [ 4503.617619] usb 1-1.4: FTDI USB Serial Device converter now attached to ttyUSB0 }}} となっていて、ttyUSB0としてアクセスできるようになっていることがわかる。[[br]] 更に詳細な情報を見てみる。[[br]] {{{ debian@beaglebone:~$ udevadm info -a -p $(udevadm info -q path -n /dev/ttyUSB0) : looking at parent device '/devices/platform/ocp/47400000.usb/47401c00.usb/musb-hdrc.1.auto/usb1/1-1/1-1.4': KERNELS=="1-1.4" SUBSYSTEMS=="usb" DRIVERS=="usb" ATTRS{authorized}=="1" ATTRS{avoid_reset_quirk}=="0" ATTRS{bConfigurationValue}=="1" ATTRS{bDeviceClass}=="00" ATTRS{bDeviceProtocol}=="00" ATTRS{bDeviceSubClass}=="00" ATTRS{bMaxPacketSize0}=="8" ATTRS{bMaxPower}=="90mA" ATTRS{bNumConfigurations}=="1" ATTRS{bNumInterfaces}==" 1" ATTRS{bcdDevice}=="1000" ATTRS{bmAttributes}=="a0" ATTRS{busnum}=="1" ATTRS{configuration}=="" ATTRS{devnum}=="3" ATTRS{devpath}=="1.4" ATTRS{idProduct}=="6015" ATTRS{idVendor}=="0403" ATTRS{ltm_capable}=="no" ATTRS{manufacturer}=="FTDI" ATTRS{maxchild}=="0" ATTRS{product}=="FT231X USB UART" ATTRS{quirks}=="0x0" ATTRS{removable}=="unknown" ATTRS{serial}=="DC00xxxx" ATTRS{speed}=="12" ATTRS{urbnum}=="16" ATTRS{version}==" 2.00" : }}} 他にも色々出てくるが、重要なのはここ。[[br]] そして、udevの定義に必要は情報は、以下の3つの情報。[[br]] {{{ ATTRS{idProduct}=="6015" ATTRS{idVendor}=="0403" ATTRS{serial}=="DC00xxxx" }}} この情報を基にudevのルールを設定する。 === udev === udevの設定ファイルは{{{/etc/udev/rules.d/99-ftdi.rules}}}としておく。 {{{ root@beaglebone:/etc/udev/rules.d# emacs -nw 99-ftdi.rules SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", ATTRS{serial}=="DC00xxxx", SYMLINK+="ttyUSBSens0", MODE="0666" }}} ファイルを作成したら、設定を反映させる。 {{{ root@beaglebone:/etc/udev/rules.d# /etc/init.d/udev reload }}} Raspberry Pi2(centos7)では、 {{{ [root@centos-rpi2 rules.d]# udevadm control --reload }}} USBを挿抜すると、 {{{ root@beaglebone:/etc/udev/rules.d# ls -la /dev/ttyUSB* crw-rw-rw- 1 root dialout 188, 0 May 22 02:37 /dev/ttyUSB0 lrwxrwxrwx 1 root root 7 May 22 02:37 /dev/ttyUSBSens0 -> ttyUSB0 }}} デバイスファイルに対してシンボリックリンクが作成され、デバイスファイルのパーミッションが0666に設定される。[[br]] デバイスを増やす時には、同様の設定をファイルに追加してやればいい。[[br]] 追加したデバイスには、後で混乱しないように、デバイスのシリアル番号とデバイス番号のシールを張っておいたほうがいい。 == EPICS IOC == EPICS IOCは、asyn + streamdeviceで作成。但し、複数デバイスになることを考慮する必要がある。 === configure/RELEASE === {{{ EPICS_BASE = /opt/epics/R315.5/base ASYN=$(EPICS_BASE)/../modules/soft/asyn/4-31 STREAM=$(EPICS_BASE)/../modules/soft/stream/2.7.7 }}} === DB === {{{ debian@beaglebone:~/epics/usbTemp/usbTempApp/Db$ more usbtemp.db record(ai, "$(user):temp") { field(DESC, "Get temperature") field(DTYP, "stream") field(INP, "@usbtemp.proto getTemp $(dev)") field(SCAN, "$(scan)") field(EGU, "degC") field(PREC, "3") } debian@beaglebone:~/epics/usbTemp/usbTempApp/Db$ more usbtemp.proto TERMINATOR = CR LF; getTemp { in "T:%f"; } }}} === src/Makefile === シリアルを使うので、DBDには{{{drvAsynSerialPort.dbd}}}を設定。 {{{ debian@beaglebone:~/epics/usbTemp/usbTempApp/src$ more Makefile TOP=../.. include $(TOP)/configure/CONFIG #---------------------------------------- # ADD MACRO DEFINITIONS AFTER THIS LINE #============================= #============================= # Build the IOC application PROD_IOC = usbTemp # usbTemp.dbd will be created and installed DBD += usbTemp.dbd # usbTemp.dbd will be made up from these files: usbTemp_DBD += base.dbd # Include dbd files from all support applications: usbTemp_DBD += asyn.dbd usbTemp_DBD += stream.dbd usbTemp_DBD += drvAsynSerialPort.dbd # Add all the support libraries needed by this IOC usbTemp_LIBS += asyn usbTemp_LIBS += stream # usbTemp_registerRecordDeviceDriver.cpp derives from usbTemp.dbd usbTemp_SRCS += usbTemp_registerRecordDeviceDriver.cpp # Build the main IOC entry point on workstation OSs. usbTemp_SRCS_DEFAULT += usbTempMain.cpp usbTemp_SRCS_vxWorks += -nil- # Add support from base/src/vxWorks if needed #usbTemp_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary # Finally link to the EPICS Base libraries usbTemp_LIBS += $(EPICS_BASE_IOC_LIBS) #=========================== include $(TOP)/configure/RULES #---------------------------------------- # ADD RULES AFTER THIS LINE }}} === st.cmd === {{{ debian@beaglebone:~/epics/usbTemp/iocBoot/iocusbTemp$ more st.cmd #!../../bin/linux-arm/usbTemp ## You may have to change usbTemp to something else ## everywhere it appears in this file < envPaths epicsEnvSet("DEV1", "PS1") epicsEnvSet("USER", "TEST:USBTEMP") epicsEnvSet("USER1", "${USER}:DEV1") epicsEnvSet("SCAN", "5 second") cd "${TOP}" epicsEnvSet("STREAM_PROTOCOL_PATH", ".:${TOP}/usbTempApp/Db" ) ## Register all support components dbLoadDatabase "dbd/usbTemp.dbd" usbTemp_registerRecordDeviceDriver pdbbase ## Load record instances dbLoadRecords("db/usbtemp.db","user=$(USER1),dev=$(DEV1),scan=$(SCAN)") dbLoadRecords("db/timestamp.db","user=$(USER)") drvAsynSerialPortConfigure ("PS1","/dev/ttyUSBSens0") asynSetOption("$(DEV1)", -1, "baud", "9600") asynSetOption("$(DEV1)", -1, "parity", "none") asynSetOption("$(DEV1)", -1, "bits", "8") asynSetOption("$(DEV1)", -1, "stop", "1") asynSetOption("$(DEV1)", -1, "clocal", "Y") asynSetOption("$(DEV1)", -1, "crtscts", "N") cd "${TOP}/iocBoot/${IOC}" iocInit }}} == 制作 == [http://pcb-center.com/ プリント基板センターPB]にて基板作成と部品実装を依頼。[[br]] 2017/12/11に発注し、2017/12/26に到着。[[br]] 出来上がったものがこれ。 [[Image(temp_sensor.png,400)]] CPU部とセンサー部にはスリットを入れて分離できるようにしたが、今回は分離せずにスズメッキ線でジャンパするだけにしておいた。 ファームウェアの書き込みは、裏面のテスト用パッドに8pinソケットを簡易的に半田付けした状態にして行った。[[br]] 始めは、ソケットのピンを適当に押さえておけば大丈夫かと考えたが、ダメだった。[[br]] 本来は凹ピンを使う必要があるが、それをケチったためにこのように対処する必要が出てきた。[[br]] == 参照HP == [http://d.hatena.ne.jp/pyopyopyo/20160223/p1 usb-serial のデバイスファイル名を固定する方法][[br]] [https://qiita.com/caad1229/items/309be550441515e185c0 udevでデバイス名を固定する][[br]]