AVR で USB デバイスを作れる AVR-USB というソフトウェア USB プロトコルスタックがあります。<凄すぎる!
(V-USB という名前に変わったみたいですね。
以下に書いてる問題も既に修正されていました。
ので、以下はあんまり意味無いです^^;)
これのサンプルの hid-data を ATtiny45 の内蔵 RC オシレータで動作させる方法を紹介します。
というか、元々対応はされてるのですが、使い方の説明が無いのと、ちょっと修正が必要なのとで、
手間がかかったので、調べた結果を紹介します。
AVR-USB を使えば、CP2103 とか、FT232 とかで USB → RS232C 変換することなく、
直接 USB の HID デバイスとして PC からアクセスできるようになります。
ただし、Low Speed (1.5Mbps) だけです。
サンプルの hid-data は、PC から 128 Byte のデータを送ると、AVR の中の EEPROM に保存でき、
それを、PC から読み取れるサンプルです。
この EEPROM を読み書きする部分を、独自の処理に変更すれば、
USB 経由で制御できるデバイスが作れるわけです。
サンプルの Makefile を少し修正(デバイスを atmega168 から attiny45 に変えるとか)すれば、
簡単に attiny45 で動かすことはできます。
でも、それだけだと、16MHz か 12MHz のクリスタル&負荷コンデンサx2を外付けする必要があって、ちょっと面倒です。
さらに、ATtiny45 は 8 pin しかないので、クリスタルで 2 pin 取られると、
電源で 2 pin、USB で 2 pin 必要なので、あと 2 pin しか残りません。
なので、内蔵 RC オシレータで動作させて、4 pin 使えるようにしようという訳です。
AVR-USB は、avrusb-20081126.zip を使わせて頂きました。
これより新しいものでは、以下で出てくる問題も修正されているかもしれないです。修正されていると期待したいです。
AVR-USB をコンパイルするには、WINAVR と cygwin が必要です。
WINAVR を普通にインストールして、cygwin をインストールするときに、Devel の中の
gcc
make
libusb-win32
の3つにチェックを入れて、インストールします。(関係するモジュールは勝手にチェックが付きます。)
cygwin を起動して、avrusb-20081126/examples/hid-data/firmware に移動して、
$ make hex
で、コンパイルできれば OK です。
libs-device フォルダの中のコードは、そのままではコンパイルが通らないので修正します。
以下、"Salt" とコメントが入っている部分が修正部分です。
avrusb-20081126/libs-device/osccal.c
usbdrv.h のインクルードが必要。
/* Name: osccal.c * Author: Christian Starkjohann * Creation Date: 2008-04-10 * Tabsize: 4 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) * This Revision: $Id: osccal.c 692 2008-11-07 15:07:40Z cs $ */ #include <avr/io.h> #include "usbdrv.h" // Salt added /* ------------------------------------------------------------------------- */ /* ------------------------ Oscillator Calibration ------------------------- */ /* ------------------------------------------------------------------------- */
avrusb-20081126/libs-device/osccal.c
コメント(/* ... */)がネストされてて、エラーが出るので、
#ifndef __ASSEMBLER__ #include <avr/interrupt.h> /* for sei() */ extern void calibrateOscillator(void); #endif #define USB_RESET_HOOK(resetStarts) if(!resetStarts){cli(); calibrateOscillator(); sei();}
これを、
#ifndef __ASSEMBLER__ #include <avr/interrupt.h> // for sei() extern void calibrateOscillator(void); #endif #define USB_RESET_HOOK(resetStarts) if(!resetStarts){cli(); calibrateOscillator(); sei();}
と、修正。
gcc のオプションに、コメントのネストを許す -C や -CC があるけど、これではダメでした。
あとは、サンプルの hid-data を変更するだけです。
他のサンプルでも同様の変更でいけるはずです。
avrusb-20081126/examples/hid-data/firmware/main.c
キャリブレーションライブラリを使うので、osccal.h をインクルードする。
#include <avr/pgmspace.h> /* required by usbdrv.h */ #include "usbdrv.h" #include "oddebug.h" /* This is also an example for using debug macros */ #include "../../../libs-device/osccal.h" // Salt added
avrusb-20081126/examples/hid-data/firmware/usbconfig.h
ポートを変更する。(ATtiny45 には PortB しかないので。)
USB_CFG_DMINUS_BIT は、回路と整合性が取れてればいいので、適当に。
USB_CFG_DPLUS_BIT は、INT0 の必要があるので、2 から変更できない。
(INT1 とかがあれば、一応変更できるらしいが、ATtiny45 には INT0 しか無い。)
/* ---------------------------- Hardware Config ---------------------------- */ // Salt changed from #define USB_CFG_IOPORTNAME D #define USB_CFG_IOPORTNAME B /* This is the port where the USB bus is connected. When you configure it to * "B", the registers PORTB, PINB and DDRB will be used. */ // Salt changed from #define USB_CFG_DMINUS_BIT 4 #define USB_CFG_DMINUS_BIT 1 /* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. * This may be any bit in the port. */ #define USB_CFG_DPLUS_BIT 2
USB_RESET_HOOK の登録 (上で修正したコメントがネストされている部分の説明通り、usbconfig.h に追記。)
/* #define USB_RESET_HOOK(resetStarts) if(!resetStarts){hadUsbReset();} */ /* This macro is a hook if you need to know when an USB RESET occurs. It has * one parameter which distinguishes between the start of RESET state and its * end. */ // Salt added { #ifndef __ASSEMBLER__ #include <avr/interrupt.h> // for sei() extern void calibrateOscillator(void); #endif #define USB_RESET_HOOK(resetStarts) if(!resetStarts){cli(); calibrateOscillator(); sei();} // } Salt added
キャリブレーションを有効に。
// Salt changed from #define USB_CFG_HAVE_MEASURE_FRAME_LENGTH 0 #define USB_CFG_HAVE_MEASURE_FRAME_LENGTH 1 /* define this macro to 1 if you want the function usbMeasureFrameLength() * compiled in. This function can be used to calibrate the AVR's RC oscillator. */
avrusb-20081126/examples/hid-data/firmware/Makefile
デバイスの変更、クロックの変更、キャリブレーションライブラリの追加。
# Name: Makefile # Project: hid-data example # Author: Christian Starkjohann # Creation Date: 2008-04-07 # Tabsize: 4 # Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH # License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) # This Revision: $Id: Makefile 692 2008-11-07 15:07:40Z cs $ # Salt changed from DEVICE = atmega168 DEVICE = attiny45 # Salt changed from F_CPU = 16000000 # in Hz F_CPU = 16500000 # in Hz FUSE_L = # see below for fuse values for particular devices FUSE_H = AVRDUDE = avrdude -c usbasp -p $(DEVICE) # edit this line for your programmer CFLAGS = -Iusbdrv -I. -DDEBUG_LEVEL=0 # Salt changed from OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o ../../../libs-device/osccal.o main.o
以上で、firmware はコンパイルできるはずです。
あとは焼くだけですが、FUSE bit は適切に設定する必要があります。
当然、CKSEL は内蔵 RC オシレータ(0001b)にする必要があります。
ということで、FUSE_H = 0xdd, FUSE_L = 0xe1 にしています。
Makefile の
############################## ATTiny25/45/85 ############################### # ATMega*5 FUSE_L (Fuse low byte): # 0xef = 1 1 1 0 1 1 1 1 # ^ ^ \+/ \--+--/ # | | | +------- CKSEL 3..0 (clock selection -> crystal @ 12 MHz) # | | +--------------- SUT 1..0 (BOD enabled, fast rising power) # | +------------------ CKOUT (clock output on CKOUT pin -> disabled) # +-------------------- CKDIV8 (divide clock by 8 -> don't divide) # ATMega*5 FUSE_H (Fuse high byte): # 0xdd = 1 1 0 1 1 1 0 1 # ^ ^ ^ ^ ^ \-+-/ # | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V) # | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved) # | | | +-------------- WDTON (watchdog timer always on -> disable) # | | +---------------- SPIEN (enable serial programming -> enabled) # | +------------------ DWEN (debug wire enable) # +-------------------- RSTDISBL (disable external reset -> enabled) #
このコメントの通りで、CKSEL = 0001b にした値です。
ATMega*5 と書かれているのは、ATTiny*5 の間違いでしょう。
でも、これだと、PB5 (Pin1) が使えないのですよね。。。
RSTDISBL を 0 にすれば、使えるようになるのですが、今度は、ISP で焼き込みができなくなります;;
HVS なライタが無いと、復旧できなくなるのですよね。<拙作の USB-IO-Mini のテストプログラムと 12V 電源を用意することでリセットできます。
回路は、サンプルの avrusb-20081126/circuits/tiny45-rc.png の通りで動きます。
この回路には、コンデンサ2つ(C1, C4)付いてますが、無くても動いてます。
1.5KΩ(R3) の代わりに 1.0KΩ、68Ω(R1, R2) の代わりに 47Ω、ダイオードx2 の代わりに赤色 LED で、 特に問題無く動いています。
もちろん、ちゃんと合わせるべきですけど、手持ちが無いのと、ブレッドボード上で組んでるのもあって、手抜きしてます。
また、後で。
とりあえず、普通に HID をアクセスするコードで、HidD_SetFeature(handle, data, 128 + 1) で書き込み、HidD_GetFeature(handle, buffer, 128 + 1) で読み込み、ができます。
report number は 0 だけに対応するので、
data[0] = 0x00 にして、データを data[1]〜[129] に入れて
HidD_SetFeature(handle, data, 128 + 1) で書き込み、
buffer[0] = 0x00 にして HidD_GetFeature(handle, buffer, 128 + 1) で読み込むと、
buffer[1]〜[129] に返ってくる、という感じです。