AVRUSB_Tips
Tips
AVR-GCC(WinAVR)のバージョンはどれが良いの?
- とりあえず、GCC3ベースの2006-0421というのを使ってます。
USBのD+、D−の配線を下図AVRUSBと同じにしたい
- (1)usbconfig.hを編集します。
#define USB_CFG_IOPORTNAME D /* This is the port where the USB bus is connected. When you configure it to * "PORTB", the registers PORTB, PINB (=PORTB-2) and DDRB (=PORTB-1) will be * used. */ #define USB_CFG_DMINUS_BIT 3 /* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected. * This MUST be bit 0 or 7. All other values will result in a compile error! */ #define USB_CFG_DPLUS_BIT 2 /* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected. * This may be any bit in the port. Please note that D+ must also be connected * to interrupt pin INT0! */
オリジナルはB,0,1ですが、これをD,3,2にします。
- (2)ポート方向の初期化を変更します。
int main(void) { DDRD = ~(1 << 2); DDRB = ~(USBMASK|(1<<5)); /* all outputs except USB data */
のDDRDの設定を、以下のように書き換えます。DDRD = ~(3 << 2); // D2,D3を入力に。他は出力。 DDRB = ~( (1<<5)); //PB5は入力(SPIの'MOSI')
- 実は(2)の変更に気づかなかったため、HIDaspが動かない動かないとずっと悩んでいたのは秘密。
- こうすることで、I/Oピン1本と配線1本が節約できますが、
- HIDaspはじめいくつかのアプリはたいていB,0,1がデフォルトになっています。
- 何故そうなのかはいまだ不明です。(別の品種ではPORT Dが無いとか???)
コードを縮めたい。(ATtiny2313限定)
- Cランタイムのスタートアップを自分で書きます。
- といっても、WinAVRのLIBCソースからcrt1.Sを取り出して改造するだけです。
https://raw.github.com/iruka-/ATMEL_AVR/master/web/upload/crt_S.zip - 自分のソース(main.c)のMakefileにcrt.oを追加する。
OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o ↓追加する OBJECTS = crt.o usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o
- リンク時にデフォルトのcrt.oを使わないようにする。
# file targets: main.bin: $(OBJECTS) $(COMPILE) -o main.bin $(OBJECTS) ↓追加する。 $(COMPILE) -o main.bin $(OBJECTS) -nostdlib
注意:
- .data .bss セクションのサイズが非ゼロであることを前提にしています。
- どちらかがゼロのときは、.data , .bssそれぞれに対して、コピーループ、クリアループそのものを削除します。
さらに縮めたい。(機種限定なし)
- AVRUSBのPowerSwitchアプリケーションに含まれているusbdrvは、12MHz版のみでなく、16MHz、16.5MHz版が存在します。
usbdrv/usbdrvasm12.S usbdrv/usbdrvasm16.S usbdrv/usbdrvasm165.S
- これを切り替えるには、main.cディレクトリに置かれている usbconfig.h を編集します。
/* #define USB_CFG_CLOCK_KHZ (F_CPU/1000) */
- これを有効にして、F_CPUを16000000 などとします。
- どこかでCPUクロック定数=F_CPUを定義していないときは 直接
#define USB_CFG_CLOCK_KHZ 16000
としても有効ですが、usbdrv/oddebug.h にF_CPUのデフォルト定義があるので、出来れば oddebug.hをインクルードする前で#define F_CPU 16000000
もしくはMakefile中に-Dオプションで-DF_CPU=16000000UL
としたほうが良いでしょう。
- PowerSwitch のファームサイズは、クロック別で以下のようになりました。
ATtiny2313 ROM RAM 12MHz 1706 56 16MHz 1582 56 16.5MHz 1710 56
16MHzの時は12MHz時に比べて224バイトも縮んでいます。
これは美味しいかも。 - ソースコードのサイズも usbdrv/usbdrvasm16.S が小さいですね。
- クロック数に余裕があるので、8ビットの処理全部をアンロール展開せずにループ処理で対応出来ているみたいです。
AVRUSBドライバーの16.5MHzモードとは?
- クリスタルに限らず内蔵RCやセラミック発振の精度を許容する。
- 12MHz、16MHzはどちらもクリスタル発振の精度が必要です。
- 16.5MHz±1.0%の精度は必要です。
- 詳細は-AVRUSBのEasyLoggerアプリケーションにあります。
- 8ピンのATtiny45などで内蔵RC発振を選択するとピン数が節約出来るので有効。
- main.cの先頭で、校正済内蔵RCの8MHzをわずかだけオーバークロック調整して8.25MHzにしています。
- 内蔵RCの後の1/2プリスケーラを通さずに×8PLL(その後1/4されCPUに入る)に入れることでCPUクロックを16.5MHzにしています。(Fuseで設定する HF PLL)
- 残念ながらATtiny2313では16.5MHzモードを使うことは出来ません。
- tiny45とはクロックSELの回路が異なっており、x8PLLは存在しないためです。
- 参考:ATtiny2313で選択できるクロック
CKSEL3-0 意味 1111-1000 外部クリスタル/セラミック発振子 0110 128kHz内部(WDT)発振器 0100 8MHz校正付内蔵RC発振器 0010 4MHz校正付内蔵RC発振器 0000 外部クロック信号 0xx1 予約
ちなみに8MHz校正付の校正値はOSCCALの値を1〜127まで書き換えることで 約4MHzから12MHz程度まで可変できるようです。(出荷時は8MHzに校正された値になっています)
ところで、どうして16.5MHzなんていう半端なクロックなの?
- それは、1.5MHzの11倍だから。
- つまり、LowSpeed USBのベースクロックが1.5MHzなので、1ビットを送受する時間がCPUの命令数で数えてちょうど11ステップになるようにコーディングしてあるわけ。
- 12MHzの場合はそれが8ステップになるので、超絶技巧プログラミングになるのだけれど、16.5MHzの場合は3ステップの余裕があるから、受信時の同期取りコードを入れることが出来るということらしい。
- だけど送信時は完全にこっちのペースで送信することしか出来ないので、1%以内の精度は必要らしい。
では、1.5MHzの整数倍になってない16MHzで動くのは何故?
- そう、16MHzだと、10+(2/3)クロックなんだ。
- usbdrv/usbdrvasm16.Sのソースを読んでいるが、読解出来ないっす。
- コメントには凄いことが書いてある。
- 何をやろうとしているか本当に理解してないならコードに触ってはだめだ。
- とにかく、これ書いた奴ら、凄すぎ。
- 全部アセンブラなigorさんも凄いけど、この16を書いた人はもっと尊敬する。というかチャレンジャーだ。
- →usbdrvasm16.S解読