wiki:epics/bbb/debian/thermometer/attiny

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ソケットを簡易的に半田付けした状態にして行った。
始めは、ソケットのピンを適当に押さえておけば大丈夫かと考えたが、ダメだった。
本来は凹ピンを使う必要があるが、それをケチったためにこのように対処する必要が出てきた。

参照HP

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

Last modified 7 years ago Last modified on 01/16/18 18:03:26

Attachments (7)

Download all attachments as: .zip