wiki:epics/bbb/debian/thermometer/attiny

Version 13 (modified by michkawa, 7 years ago) (diff)

--

ATTiny85を使ったI2C USB変換+温度センサ基板の作成

以前作成したUSB 温湿度/大気圧センサの修正版として作成。
以前作成した基板の問題点として、

  • 温湿度センサと他のチップがベタグランドでつながっていて、熱が回ってきていないか不安
  • センサとCPUが物理的に分離していないので、センサの種類を変えられない

等があったので、その辺りを考慮した。

今回使用するのは、温度センサ(ADT7410)のみなので、センサ基板にはこれだけを実装することにする。

回路図

回路図はこんな感じになった。

アートワーク

基板のアートワークはこんな感じ。

USB+CPUとセンサ基板を分離して作成することで、熱的に分離するのと、センサが変わってもプログラムの変更だけで対応できるように考慮した。
CPUへのファームウェアの書き込みは、裏面に付けたパッドから行う。

ファームウェア

ファームウェアは arduino を使って作成するので、開発環境を構築。

Arduino

arduinoの本家から開発環境(Arduino IDE)をダウンロードしてインストール。
ダウンロードは、ここから、自分の環境に合わせたものを持ってくる。
2017/12/12現在、最新版は 1.8.5。今回は Windows Installer を使った。

Board Manager

最近は色々なマイコンがarduinoで開発できるようになっていて、対応するボードマネージャーを使えば、環境構築を自動でやってくれる。いい時代になったもんだ、、、
今回使うCPUは Atmel ATTiny85、書き込みは Arduino ISP で行う。

実際の環境設定は以下のサイトが詳しいので、それを参照。

Arduino IDE で ATtiny 他の開発

CPUの開発環境は以下のページを参照。

Arduino IDE に ATtiny45/85/2313 他の開発環境を組み込む

CPUへの書き込みを行う Arduino ISP は、Arduino UNO R3をArdunio書き込み装置にして使用する。(ややこしいですが)

Using an Arduino as an AVR ISP (In-System Programmer)

これを使えばAVRライターがなくても、arduino対応のCPU設定が簡単にできる。

開発環境テスト

開発環境が動作するかをチェックする。

【 Arduino IDE 】ArduinoISP 使い方・書き込みテストを参考に行うが、多少違っていた(古い?)ので相違点を記載する。

ArduinoISP -> Arduino as ISP(ATTinyCore)

設定は画像のようにする。シリアルポートの設定は、ArduinoISPがつながっているものを選択。

テスト用のソースは、

#define PIN 3
#define DTIME 500

void setup() {
  pinMode(PIN, OUTPUT);
}

void loop() {
  digitalWrite(PIN, HIGH);
  delay(DTIME);
  digitalWrite(PIN, LOW);
  delay(DTIME);
}

これをArduinoISPに以下の様につないで書き込み。

http://make.kosakalab.com/arduino/use/45_85.gif

書き込みが完了すると、LEDが2秒間隔ぐらいで点滅する。
点滅しなかったり、書き込み時にエラーが表示された場合には、設定か回路が間違っているのでチェックする。

本来このプログラムだと0.5秒間隔で点滅するが、クロックに対するカウンタが合っていないのでこのようになる。
これを合わせるために、メニューから"ツール -> ブートローダーを書き込む"を実行し、再度テストプログラムを書き込むと、今度は0.5秒毎に点滅するようになる。

測定用ファームウェア

TinyWireM

今回は ATTiny85 + ADT7410なので、前回と同じようにADT7410のサンプルソースをTinyWireMに対応させる方法で作成する。
前回と違うのは、TinyWireMが"ライブラリマネージャー"でインストールできるようになっている点。
ライブラリマネージャーは、メニューから"スケッチ -> ライブラリをインクルード -> ライブラリを管理"で表示されるダイアログで"tinywire"で検索すると表示される。

これをインストール。

ADT7410

ADT7410用のライブラリもライブラリマネージャーでインストールできるが、使われているのがATMega用のWire(I2C)ライブラリなので、そのままでは使用できない。
なので、これを基にWireをTinyWireMに変更したライブラリを作成した。

元のライブラリはFaBoPlatform/FaBoTemperature-ADT7410-Library
作成したライブラリファイルはADT7410-TinyWire-Library.zipとして置いておくので、必要ならダウンロードして使用すること。

Firmware

Firmwareは、以前作成したものとほぼ同じ。

#include <TinyWireM.h>
#include <USI_TWI_Master.h>
#include <SoftwareSerial.h>
#include <ADT7410_TinyWireM.h>

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シリアルに出力する。
以前のソースコードでは、メモリの使用量の問題でprintを使わずに自前でfloatを出力していたが、新しいバージョンではほとんど変わらなかったので、ソースコードを簡素化した。
今回は温度だけなので、出力する文字列は、

T:xx.xxxx\r\n

となる。

5秒では遅すぎるとの意見があったので、実装基板に書き込む際には1秒間隔に変更。

BBBとの接続

このボードを実際に使用(運用)する場合には、BBB(又はRaspberryPI)とはUSBで接続するが、最大5個程度の複数接続をする予定なので、udevでデバイス名を固定する必要がある。
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としてアクセスできるようになっていることがわかる。
更に詳細な情報を見てみる。

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"
     :

他にも色々出てくるが、重要なのはここ。
そして、udevの定義に必要は情報は、以下の3つの情報。

    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に設定される。
デバイスを増やす時には、同様の設定をファイルに追加してやればいい。
追加したデバイスには、後で混乱しないように、デバイスのシリアル番号とデバイス番号のシールを張っておいたほうがいい。

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;
ExtraInput = Ignore;

getTemp {
    in "T:%f";
    @mismatch{}
}

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",  "USB0")
epicsEnvSet("USER",  "TEST:USBTEMP")
epicsEnvSet("USER1", "${USER}:DEV1")
epicsEnvSet("SCAN",  "I/O Intr")

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 ("$(DEV1)","/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

制作

プリント基板センターPBにて基板作成と部品実装を依頼。
2017/12/11に発注し、2017/12/26に到着。
出来上がったものがこれ。

CPU部とセンサー部にはスリットを入れて分離できるようにしたが、今回は分離せずにスズメッキ線でジャンパするだけにしておいた。

ファームウェアの書き込みは、裏面のテスト用パッドに8pinソケットを簡易的に半田付けした状態にして行った。
始めは、ソケットのピンを適当に押さえておけば大丈夫かと考えたが、ダメだった。
本来は凹ピンを使う必要があるが、それをケチったためにこのように対処する必要が出てきた。

実運用に向けた準備

実運用する場合には、複数のセンサー基板を取り付けるが、BBBでは通常の状態ではUSBが1つしかないので、今回はUSBが4つあるRaspberryPi2を使う。
今回の目的には、BBBでもRaspberryPiでもほとんど同じ設定で大丈夫だった。
OSインストール等の環境設定は、RaspberryPi に EPICS をインストールを参照して行った。

RaspberryPi2を裸で置くわけにはいかないので、3Dプリンタでケースを作ってみた。ケースのデータはここにあるものを使わせてもらった。

No image "IMG_6308.JPG" attached to epics/bbb/debian/thermometer/attinyNo image "IMG_6309.JPG" attached to epics/bbb/debian/thermometer/attiny

上の所が白くなっているのは、テプラを張る面を作ろうとして紙やすりで削ったため。結局、平滑にならずに積層が出てくるだけだったので、テプラを張る際には厚みのある両面テープか接着剤等で編面を作る必要がある。

今回はセンサー基板のケースは作らずに、カプトンテープを巻いて簡易的に絶縁するだけにした。

No image "IMG_6316.JPG" attached to epics/bbb/debian/thermometer/attiny

動作検証

今回作成した全センサー基板の相関や、実動作試験を行った。
10台のセンサ基板を接続するために、4Port USBハブを2台接続して対応した。

No image "IMG_6315.JPG" attached to epics/bbb/debian/thermometer/attiny

リファレンスはGraphtec GL840にK型熱電対を接続したものを使用。
当初は、Ch1で室温を測定していたが、最終的にはCh1は温度センサー基板のセンサー部の温度を、Ch2は周辺の温度を測定するようにした。

No image "IMG_6318.JPG" attached to epics/bbb/debian/thermometer/attiny

No image "002_add_GL840_CH2.png" attached to epics/bbb/debian/thermometer/attiny

青線(Graphtec:GL840:GL820:PORT_01)が中心付近で温度が上がっているのは、この時点で熱電対を温度センサーに接触させるように変更したため。

熱電対の温度データは、GRAPHTEC GL820(GL840)用EPICS IOCを使用することでEPICS化した。
温度センサー基板のIOCはRaspberryPi2上で動かし、データの保存はcERLサーバー上のPortableArchiverを使用した。

測定

定常状態での温度センサー自体のバラツキは、0.5℃程度に収まっている。
しかし、温度センサーで測定した温度は、熱電対よりも1.5~2℃ほど高くなっている。
この温度差がどこにあるのか検証するために、センサー部とCPU部を分離して調べてみることにした。

基板自体は、設計の段階から分離できるようにしてあるので、ジャンパー線を外して約9㎝のビニル被覆線で接続し直したもので測定してみた。

No image "IMG_0226.JPG" attached to epics/bbb/debian/thermometer/attiny

No image "004_separate_sensor_after.png" attached to epics/bbb/debian/thermometer/attiny

その結果、熱電対とほぼ同じ温度が測定できるようになった。
このことから、温度差の原因はCPU側の発熱によるものであることがわかる。

次に、どの程度離せば影響を抑えられるかを実験してみた。

No image "IMG_0222.JPG" attached to epics/bbb/debian/thermometer/attiny No image "IMG_0223.JPG" attached to epics/bbb/debian/thermometer/attiny No image "IMG_0224.JPG" attached to epics/bbb/debian/thermometer/attiny No image "IMG_0225.JPG" attached to epics/bbb/debian/thermometer/attiny No image "IMG_0226.JPG" attached to epics/bbb/debian/thermometer/attiny

センサーとCPUを分離した基板を接続する電線の長さを変えたものを用意した。
1番目と2番目は線材による違いを確認するために、1cm程度のスズメッキ線とビニル被覆線を用意した。
3番目は線材の長さが約3cm、4番目が6cm、5番目が9cmとした。

  • 1番目 (TEST:USBTEMP:DEV8:temp)
  • 2番目 (TEST:USBTEMP:DEV7:temp)
  • 3番目 (TEST:USBTEMP:DEV6:temp)
  • 4番目 (TEST:USBTEMP:DEV5:temp)
  • 5番目 (TEST:USBTEMP:DEV10:temp)

結果のグラフが次のようなものになった。

No image "005_separate_sensor_any.png" attached to epics/bbb/debian/thermometer/attiny

1,2番目は切り離していないものに比べて、0.5℃程度下がってはいる。しかし、線材の違いによる変化はあまり見られない。
3,4,5番目は他のものと比べて1.5℃程度温度が下がっており、室温測定の熱電対の値に近くなっている。
また、長さの違いでも温度差があることがわかる。

この結果から、このセンサー基板の場合、センサー部を10cm程度延長すれば、熱電対とほぼ同等の室温値が測定ができることが分かった。

参照HP

usb-serial のデバイスファイル名を固定する方法
udevでデバイス名を固定する

Attachments (7)

Download all attachments as: .zip