2012年8月25日土曜日

Linux上でavraを使ってtiny10のアセンブラソースを書く

ATtiny2313をはじめATmega88,ATmega328などのデバイスに対応しているアセンブラ avra を利用しています。ATtiny10もavraのサポート対象に入っているのですが、先のATtiny10のライタを作ったときに添付したLチカプログラムのアセンブラソースをアセンブルしてみると下のようなエラーでアセンブルが途中で中断してしまいます。

> avra -l init.lst init.asm

AVRA: advanced AVR macro assembler Version 1.3.0 Build 1 (8 May 2010)
Copyright (C) 1998-2010. Check out README file for more info

   AVRA is an open source assembler for Atmel AVR microcontroller family
   It can be used as a replacement of 'AVRASM32.EXE' the original assembler
   shipped with AVR Studio. We do not guarantee full compatibility for avra.

   AVRA comes with NO WARRANTY, to the extent permitted by law.
   You may redistribute copies of avra under the terms
   of the GNU General Public License.
   For more information about these matters, see the files named COPYING.

Pass 1...
Pass 2...
init.asm(95) : Error   : PUSH instruction is not supported on ATtiny10
init.asm(96) : Error   : PUSH instruction is not supported on ATtiny10
init.asm(110) : Error   : POP instruction is not supported on ATtiny10
init.asm(111) : Error   : POP instruction is not supported on ATtiny10
done

Used memory blocks:
   Code      :  Start = 0x0000, End = 0x002E, Length = 0x002F

Assembly aborted with 4 errors and 0 warnings.
make: *** [init.hex] エラー 1

エラーの内容は、”ATtiny10では、push/popインストラクションをサポートしてません。”なのですが、そんな訳は無くATtiny10のデータシートのインストラクションセットのページにちゃんと紹介されています。

(ATtiny10 Datasheetより抜粋)

それではということで、AVRAのソースを調べてみる事にします。AVRAを展開したディレクトリ avra-1.3.0/src を見ると、mnemonic.c というファイルがあります。この中にはAVRAで使えるニーモニックが記述されていて、どのデバイスでどのニーモニックが利用可能かが定義されています。 230行目あたりに下のリストに示した記述が見当たります。

231         {"ror",   0x9407,          0},
232         {"asr",   0x9405,          0},
233         {"swap",  0x9402,          0},
234         {"push",  0x920f,  DF_TINY1X},
235         {"pop",   0x900f,  DF_TINY1X},
236         {"tst",   0x2000,          0},
237         {"clr",   0x2400,          0},
238         {"lsl",   0x0c00,          0},
で、この DF_TINY1X が何であるかは src/device.c の中に定義されています。
 47 struct device device_list[] =
 48 {
 49   /*        Name, Flash(words),RAM start, RAM size, EEPROM, flags */
 50   {         NULL,     4194304,      0x60,  8388608,  65536, 0}, // Total instructions: 137
 51   /* ATtiny Series */
 52   // ATtiny4
 53   // ATtiny5
 54   // ATtiny9
 55   {   "ATtiny10",         512,      0x00,        0,      0, DF_NO_MUL|DF_NO_JMP|DF_TINY1X|DF_NO_XREG|DF_NO_YREG|DF_NO_LPM_X|DF_NO_ELP    M|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP},
 56   {   "ATtiny11",         512,      0x00,        0,      0, DF_NO_MUL|DF_NO_JMP|DF_TINY1X|DF_NO_XREG|DF_NO_YREG|DF_NO_LPM_X|DF_NO_ELP    M|DF_NO_SPM|DF_NO_ESPM|DF_NO_MOVW|DF_NO_BREAK|DF_NO_EICALL|DF_NO_EIJMP},
と言うわけでどうやら ATtiny10ではこのコマンドをサポートしない様に指定されているようです。
このままでは ATtiny10で push / pop が使えないので、先の mnemonic.c の中で
234         {"push",  0x920f,          0},
235         {"pop",   0x900f,          0},
236 //      {"push",  0x920f,  DF_TINY1X},
237 //      {"pop",   0x900f,  DF_TINY1X},
として push / pop をこの制限から外してしまいます。 
DF_TINY1X はATtiny10の他にもtiny11/tiny12/tiny15/tiny28/90S1200 でも使われているので、
これらのデバイスを使う際には注意が必要ですが、当面使う予定がないのでこれをコメントアウトして
avra をコンパイルし直します。
問題なく push / pop がコンパイルされるようになります。 

2012年5月18日金曜日

Linuxで使えるATtiny10 programmerを作る



昨年から秋月電子で取扱いの始まったATMELのATtiny10をいじっています。いや、本当は取扱いが始まってあまり時間の経っていない時にデバイスは入手したのですが、デバイスにプログラムを書き込むプログラマが手に入らず、テスト用のLEDチカチカプログラムを書いたものの、それが書き込めない状態がつい最近まで続いていました。WindowsプラスATMEL純正プログラマや、USBaspを使ったプログラマでデバイス書き込みをしている記事をちらほらと見ますが、どちらも望んでいるものからは少し距離がある感じでした。仕事も一段落して時間に余裕ができ、あまり長い間ほったらかしにするのもなんだしなぁ、、などと思ったりもし、”無いものは自分で作るか!”とプログラムを書いてそれなりに動くものが出来たのでそのプログラマを公開します。


1)必要なハードウェア

私の定番の実験基板であるFT232RLとATtiny2313を使ってみました。ライタがホストPCとUSBで繋がっていると電源を用意する必要がなく、シリアルポートの無いPCでも使えると考えると妥当な所ではないでしょうか。他のAVRシリーズのCPU同様tiny10も単一5Vでの書き込みと、resetピンに+12Vを与える高電圧書き込みが用意されています。後者はresetピンにアサインされているPORTB-3を汎用ピンとして使用する設定にした場合、resetピンに+12Vを与えた状態でデバイスにプログラム書き込む必要があります。高電圧書き込み用にレベルシフタも用意しました。


+12V印可のために2SA1015(pnp) 2SC1815(npn)を1本づつ使用して+5Vから+12Vにレベルシフト、これだけだと出力をGNDに落せないのでオープンコレクタ動作の2SC1815(npn)をもう1本追加して、計3本のトランジスタで構成されています。
これらの回路は下の図の様になります。


書き込みのテストでは、これらをブレッドボード上で接続して行いました。写真では分かりませんが青色LEDが1秒間隔で点滅を繰り返しています。


2)コンパイル

2)-1 ホストPC側ドライバ
"tpiwrite" は、Perlスクリプトで特別なモジュールも使用していないため、Perlがインストールされていればコンパイル無しで実行できます。tiny10用のIntel hexファイルを解釈してシリアル経由でプログラマにデータを渡します。全部で55行というコンパクトなプログラム(スクリプト)なので、動作はソースをみていただければ理解できるボリュームのものだと思います。

2)-2 tiny2313ファームウェア
"tpi.c" "usart.c" "waitA.S"のコンパイルに avr-gccが必要です。これらのプログラムは"avr-gcc (GCC) 3.4.6" "avr-gcc (GCC) 4.4.4"でコンパイルを確認しています。今のところ1800バイトぐらいフラッシュを使用していて、200バイトほど空きがあるのでもう少し機能の追加が可能です。

tar/gzipファイルを展開しソースをコンパイルしてください。"make"コマンドを実行するとコンパイル、リンク、hexファイルの生成を行います。適当なプログラマを使って生成されたhexファイルをtiny2313に書き込みます。

tiny10のresetピンを汎用IOピンに変更するには、tpi.cの336行目の"#if 0"を"#if 1"に変更して、tiny2313用のファームをコンパイルしてください。一度Config Byteを書き換えると次の書き込みからは、resetピンに高電圧(+12v)を加える高電圧書き込みでのプログラムの書き込みが必要です。(Config Byteのビット0を"1"にすれば、通常電圧で書き込みができます。)高電圧(+12v)書き込みを行う場合、"Makefile"の14行目行頭を#でコメントアウトして、15行目の#を外してコンパイルして下さい。("HVRST"をdefineする)


3)tiny10用hexファイルの書き込み

tiny2313 と tiny10 を接続して tiny2313 をリセットします。この状態で tiny2313 はホストPCからのデータ待ちになります。Perlスクリプト"tpiwrite"のあるディレクトリでターゲットhexファイル "hoge.hex"を引数にして以下のようにコマンドを実行します。

./tpiwrite hoge.hex

"tpiwrite"の44行目、

select(undef, undef, undef, 0.05);

が、writeデータの送出インターバルを決めています。hexファイルの書き込みに失敗する場合は、この"0.05"を少し大きめの値に設定して送出インターバルをあけてください。現環境で"0.01"での書き込みを確認しています。コマンドを実行すると、1word(2byte)ごとに書き込んだデータを"w12C0" "w2BC0"のように表示していきます。プログラムをすべて書き終えると、ホストPC上に"End of data"と表示されプログラムが終了し、tiny10上で書き込んだプログラムが実行されます。

tiny10用のサンプルプログラムとそのhexファイルを同梱しています。テスト書き込み用にお使いください。


4)それ以外のインフォメーション

制御コマンドや書き込みデータは、バイナリ化されずにそのままホストPCとtiny2313の間を行き来しています。ターミナルソフト(TeraTermなど)を、"38400bps/ストップビット1/8ビットデータ/パリティ無し/ハードフロー制御" に設定して、ホストPCとtiny2313を繋ぐとデータのやりとりを見ることができます。

このプログラムの作成にあたって、ATMELのATtiny 10 DocumantAtmel AVR918: Using the Atmel Tiny Programming Interface (TPI)そのサンプルプログラム 、 個人のWebページSimon Says Game Using an ATtiny10を参考にさせていただきました。

プログラムソース一式は、ここからダウンロードしてください。 このプログラムは、無保証、無サポートです。

2011年3月8日火曜日

avr-gccをgcc-4.5.2でビルドする

このブログをアップデートする時は、なぜかgccのビルドの話題が多いですが、特別最新のgccを追っかけているわけではありません。たしかに新しい方がサポートされているデバイスが多いのでついつい最新のものになっているだけなんですが、、

今回は binutils-2.21 gcc-4.5.2 avr-libc-1.7.1 でビルドしてみました。最新のものにつきもののハマりどころがやっぱり有ったのでその記録です。

gcc-4.5.x 以降は gmp / mpfr に加えて mpc をあらかじめインストールしておく必要があります。

Fedora14のLive版ではデフォルトでmpcのヘッダファイル(mpc.h)がインストールされていないので、yum でインストールしておきます。

1) yum search mpc-devel
libmpc-devel.i686 : Header and shared development libraries for MPC

2) yum install libmpc-devel.i686


* binutils-2.21 *

1) mkdir AVR_binutils-2.21
2) cd AVR_binutils-2.21
3) ../binutils-2.21/configure --target=avr --prefix=/usr/local/avr4
4) make
5) sudo make install


* gcc-4.5.2 *

gcc-4.5.2のビルド自体には問題無いのですが、これを使った次の avr-libc に問題が出るので、パッチを当てておきます。

問題はgcc-4.5.2ではサポートされていないattiy2313aを、avr-libcがライブラリをコンパイルしようとするため、make時にエラーで止まります。 すでにgccにはバグリポートが出ているのでこの辺↓を参考にしてみてください。
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=45261

パッチを当てるファイルは、

gcc-4.5.2/gcc/config/avr/avr.c

で、当てたパッチは、

*** avr.c_ORG 2011-03-08 19:51:12.986668845 +0900
--- avr.c 2011-03-08 19:53:32.175401145 +0900
***************
*** 206,217 ****
--- 206,222 ----
break;

if (!t->name)
+ /*
{
fprintf (stderr, "unknown MCU '%s' specified\nKnown MCU names:\n",
avr_mcu_name);
for (t = avr_mcu_types; t->name; t++)
fprintf (stderr," %s\n", t->name);
}
+ */
+ error ("Unknown MCU %qs specified. See --target-help for "
+ "known MCU names.", avr_mcu_name);
+

avr_current_device = t;
avr_current_arch = &avr_arch_types[avr_current_device->arch];

です。

(バグリポートにはgcc-4.5.2では解決済って書いてあるんですが、、なぜ?)

パッチが当たったら、

1) mkdir AVR_gcc-4.5.2
2) cd AVR_gcc-4.5.2
3) ../gcc-4.5.2/configure --target=avr --prefix=/usr/local/avr4 --enable-languages=c --with-dwarf2 --disable-nls
4) make
5) sudo make install

で、gccのインストール。


* avr-libc-1.7.1 *

gccにちゃんとパッチが当たっていればavr-libcは普通にコンパイルできるはずです。

1) mkdir AVR_avr-libc-1.7.1
2) cd AVR_avr-libc-1.7.1
3) ../avr-libc-1.7.1/configure --prefix=/usr/local/avr4 --host=avr --build=i686-pc-linux-gnu
4) make
5) sudo make install

出来上がったビルドをチェック、、ちゃんとコンパイルできるようです。

2010年9月27日月曜日

avr-gdbをインストールした、、

avr-gdbをインストールしました。 ターゲットマシンはFC13 x86_64

1) ftp://ftp.ring.gr.jp/pub/GNU/gdb/ から gdb-7.2.tar.bz2 をダウンロード
2) mkdir gdb-7.2_AVR
3) cd gdb-7.2_AVR
4) ../gdb-7.2/configure --prefix=/usr/local/avr-gcc4/ --target=avr
5) 途中で error: no termcap library found でおちる
6) ftp://ftp.ring.gr.jp/pub/GNU/termcap/ から termcap-1.3.1.tar.gz をダウンロード、インストール
7) make , make install

**情報追加
4) ../gdb-7.2/configure --prefix=/usr/local/avr-gcc4/ --target=avr --disable-nls

--disable-nlsを追加してコンパイルし直し、、

2010年9月26日日曜日

ひさしぶりに秋月に行ってきました

組み込み勉強会(別途この内容は書きます)のついでに、八潮の秋月に行ってきました。以前行ったときはもっとジャンクな物があって面白かったけれど、昨日は"普通の"秋月だったのがちょっと残念。FT2232のボードが欲しかっただけなのに、なんか気がついたらいろいろな物がかごに入っていて、お会計してびっくり。とりあえずこのボードが手に入ったのでJTAGkey cloneが作れる。またしばらく遊べそうです。

2010年7月2日金曜日

下で、kitaxさんからコメントをいただいている通り、じつはこれ、リンカ最適化の"-O"オプションで制御されます。
前回の結果はMakefileのこのオプションがコメントアウトされていて、"-O0"な状態でコンパイルされていたわけです。
で、これを"-Os"でやり直してみると、、

ver 3.4.6 では、

138 PORTB = 0x55;
139 84: 85 e5 ldi r24, 0x55 ; 85
140 86: 88 bb out 0x18, r24 ; 24

ver 4.4.3 でも、

120 64: 25 e5 ldi r18, 0x55 ; 85
:
152 PORTB = 0x55;
153 7c: 28 bb out 0x18, r18 ; 24

と、ちゃんと outを使った内容にコンパイルされます。コードサイズはそれぞれ、
ver 3.4.6

1 /usr/local/avr-gcc3/bin/avr-size led.elf
2 text data bss dec hex filename
3 154 0 0 154 9a led.elf

ver 4.4.3

1 /usr/local/avr-gcc4/bin/avr-size led.elf
2 text data bss dec hex filename
3 148 0 0 148 94 led.elf

と、ぎゅっと小さくなっています。 おそまつさま、、
割り込みを使わないこのプログラム、実はさらにコードサイズを小さくする秘策が、、

2010年6月20日日曜日

avr-gcc4の吐き出すコードって、、

avr-gcc ver.3 (3.4.6) と ver.4 (4.4.3) の吐くコードがどのくらい違うのか調べてみたくなって、簡単なプログラムを書いて実際にコンパイルしてみた。 プログラム自体はたわいもないもので、attiny2313のPORTBに繋がっているLED8個を1つおきに交互に点滅させるというもの。 で、実際のプログラムはこんな感じ。

1 /* led.c, test program for LED on and off */
2
3 #include <avr/io.h>
4

5 int main(void)
6 {
7 unsigned int i;
8
9 DDRB = 0xff;
10 DDRD = 0x00;
11 PORTD = 0xff;
12
13 for(;;){
14 PORTB = 0x00;
15 PORTB = 0xaa;
16 for( i=0; i&lt;30000; i++){
17 asm volatile ("nop");
18 }
19
20 unsigned int j=30000;
21 PORTB = 0x00;
22 PORTB = 0x55;
23 do{
24 asm volatile ("nop");
25 }while(j--);
26 }
27 }


最初は for() と do-while でどのくらい吐き出すコードが違うのか調べたかったのだが、こちらは期待どおりというか、大した違いは無かった。片方は順番に変数がインクリメントされていくし、片方はディクリメントされていく。 ところが、面白かったのは、何気に使っている PORTB = 0x55; がどんな風に変換されているのか調べてみたら、使っている avr-gcc のバージョンによって吐かれるコードが結構違うことに気がついた。 使ったavr-gccのバージョンは上に書いた通り。 実際に吐かれたコードは、

ver 3.4.6 は、

PORTB = 0x55;
a8: 85 e5 ldi r24, 0x55 ; 85
aa: 80 93 38 00 sts 0x0038, r24

レジスタ24に0xaaをロードしてSRAMの0x0038番地にr24を出力。AVRはmemory maped IOなので PORTBもメモリマップ上にいる。

ver 4.4.3 だと、これが↓こうなる。

PORTB = 0x55;
c2: 88 e3 ldi r24, 0x38 ; 56
c4: 90 e0 ldi r25, 0x00 ; 0
c6: 25 e5 ldi r18, 0x55 ; 85
c8: fc 01 movw r30, r24
ca: 20 83 st Z, r18


ver.3 では 6バイトで書けたものが ver.4では 10バイトも必要になっている。で、最終結果にもそれがちゃんと(?)反映されていて、それぞれ

ver.3.4.6
avr-size led.elf
text data bss dec hex filename
198 0 0 198 c6 led.elf


ver.4.4.3
avr-size led.elf
text data bss dec hex filename
238 0 0 238 ee led.elf


ちなみに、アセンブラで書くならきっとこう書くはず。

ldi r18, 0x55
out PORTB, r18

4バイトか、、、 何かのコンパイルオプションでこの状況は解決されるのだろうか?

2010年5月3日月曜日

gcc4.4.3 for avr-gcc インストール

** gcc-4.4.3 (avr-gcc) インストールメモ **

atmega32u4とat90usb1286を使いたいので、これらのデバイスに対応しているgcc4.4.3をインストールした。
gcc4以降、gmpとmpfrがgccコンパイル時に必要となっているのでそれらも同時にインストールした。


gmp
gmp-4.2.4
./configure


mpfr
mpfr-2.4.2
./configure --with-gmp-lib=/usr/local/lib --build=i686
configオプションに--with-gmp-libを追加。このオプションがないとgmpが見付からずにconfig時にエラーで落ちる。


binutils
binutils-2.20
../binutils-2.20/configure --target=avr --prefix=/usr/local/avr-gcc4


gcc
gcc-core-4.4.3
../gcc-4.4.3/configure --target=avr --prefix=/usr/local/avr-gcc4 \
--enable-languages=c --with-dwarf2 --disable-nls \
--with-mpfr-include=/usr/local/include --with-mpfr-lib=/usr/local/lib
configオプションに--with-mpfr-includeと--with-mpfr-libを追加。このオプションがないとmpfrが見付からずに
config時にエラーで落ちる。


avr-libc
avr-libc-1.6.2
../avr-libc-1.6.2/configure --build=i686-pc-linux-gnu --host=avr --prefix=/usr/local/avr-gcc4
avr-libc-1.6.8を試したが、どうしてもコンパイルが通らず断念。


atmega32u4もat90usb1286もソースをコンパイルが出来ることを確認した。

2007年10月19日金曜日

中間報告 (その1) -- 7seg LED Clock --



LEDの表示部分の動作を確認しました。バックグランドでSRAMにデータを書き込むとそれを表示します。ハーフトーンのフィルムを貼ってそれをすかしてLEDだけ光っているように仕上げたかったのですが、思ったほど見た目LEDが輝いていません。フィルムの透過率が思ったよりも低かった事、LEDが高輝度でない事、ダイナミック点灯でやはり輝度を落している事、などが原因として考えられます。割り込みでLED表示ルーチンをまわす当初の目論見は崩れ、表示部分がメインでぐるぐるまわってます。現在、RTC(秋月電子のRTC-8564NB)とのインタフェース部分を書いています。I2C初挑戦です。プラス、4つのタクトスイッチをつかったユーザーインターフェースです。

実験中のファームなので最終形には必要の無い部分があります。約1秒おきに2種類の数字が交互に表示されればOKです。

;;; 7seg LED clock ver 0.07 ;;;
;;; initial check for LED on/off ;;;
;;; store data into SRAM ;;;
;;; read out data from SRAM, ;;;
;;; serial parallel conversion, ;;;
;;; and put it on LED ;;;
;;; timer interval : 1 second ;;;
;;; as of Oct/18/2007 ;;;

; 0 1 2 3 4 5 6 7
; SCK (PB2): ~~~\_/~\_/~\_/~\_/~\_/~\_/~\_/~\_/~~~~~~~
; SegBit (PB1): --------[g]-[f]-[e]-[d]-[c]-[b]-[a]_*1___
; Trans (PB0): ____________________________________/~\__
;
; *1 SegBit=0 (1st cycle), SegBit=1(2nd-7th cycle)

.device ATtiny2313

.equ SramUse = 8
.equ STACKTOP = RAMEND - SramUse
.equ SCK = 2
.equ SegBit = 1
.equ Trans = 0

;;; Below 8 bytes are the register for ;;;
;;; contents of the LED digit data ;;;
.dseg
.org RAMEND - (SramUse - 1)
Digits:
.byte 8 ; data container of LED

.cseg
RJMP RESET ; 00 reset handler
RETI ; 01 external interupt0 handler
RETI ; 02 external interupt1 handler
RETI ; 03 timer1 capture handler
RETI ; 04 timer1 compare A handler
RJMP Timer1Int ; 05 timer1 overflow handler
RJMP Timer0Int ; 06 timer0 overflow handler
RETI ; 07 USART0 RX complete handler
RETI ; 08 USART0 UDR empty handler
RETI ; 09 USART0 TX complete handler
RETI ; 0A Analog comparator handler
RETI ; 0B Pin change interrupt
RETI ; 0C timer1 compare B handler
RETI ; 0D timer0 compare A handler
RETI ; 0E timer0 compare B handler
RETI ; 0F USI start handler
RETI ; 10 USI overflow handler
RETI ; 11 EEPROM ready handler
RETI ; 12 watchdog overflow handler


RESET:
ldi r16, STACKTOP
out SPL, r16 ; set low end address for stack pointer
ldi r16, 0b10000010 ; enable timer-0&1 overflow interrupt request
out TIMSK, r16
sei ; enable global interrupt

;;; Port Setting ;;;
;;; PB0-PB7 is used for LED output ;;;
;;; PD0-PD6 is set as input ;;;
ldi r16, 0b11111111 ; set all PORTB as Output
out DDRB, r16 ;
ldi r16, 0x00
out PORTB, R16
ldi r16, 0x00
out DDRD, r16
ldi r16, 0x7F ; set all PORTD Pull-up Active
out PORTD, r16

rcall DataForm

ldi r24, 0 ;;; Temp for TEST
rcall Timer1Set ;;; Temp for TEST

;*******************************************************************
;;; Main Loop ;;;
MAIN:
rcall LEDdisp
rjmp MAIN


;*******************************************************************
;;; Data Formatting ;;;
;;; r16 point out 7seg data ;;;
;;; r17 point out SRAM store address ;;;
DataForm:
ldi r16, 9 ; set data = 9
ldi r17, 0 ; set address = 0
rcall DataSet
ldi r16, 7 ; set data = 7
ldi r17, 1 ; set address = 1
rcall DataSet
ldi r16, 5 ; set data = 5
ldi r17, 2 ; set address = 2
rcall DataSet
ldi r16, 3 ; set data = 3
ldi r17, 3 ; set address = 3
rcall DataSet
ldi r16, 8 ; set data = 8
ldi r17, 4 ; set address = 4
rcall DataSet
ldi r16, 6 ; set data = 6
ldi r17, 5 ; set address = 5
rcall DataSet
ldi r16, 4 ; set data = 4
ldi r17, 6 ; set address = 6
rcall DataSet
ldi r16, 2 ; set data = 2
ldi r17, 7 ; set address = 7
rcall DataSet
ret

;*******************************************************************
;;; Data Formatting ;;; T E M P T E M P
;;; r16 point out 7seg data ;;;
;;; r17 point out SRAM store address ;;; T E M P T E M P
DataForm2:
ldi r16, 8 ; set data = 8
ldi r17, 0 ; set address = 0
rcall DataSet
ldi r16, 9 ; set data = 9
ldi r17, 1 ; set address = 1
rcall DataSet
ldi r16, 9 ; set data = 9
ldi r17, 2 ; set address = 2
rcall DataSet
ldi r16, 9 ; set data = 9
ldi r17, 3 ; set address = 3
rcall DataSet
ldi r16, 4 ; set data = 4
ldi r17, 4 ; set address = 4
rcall DataSet
ldi r16, 8 ; set data = 8
ldi r17, 5 ; set address = 5
rcall DataSet
ldi r16, 0 ; set data = 0
ldi r17, 6 ; set address = 6
rcall DataSet
ldi r16, 4 ; set data = 4
ldi r17, 7 ; set address = 7
rcall DataSet
ret
;;; T E M P T E M P T E M P T E M P T E M P T E M P ;;;


;*******************************************************************
;;; Data Setting ;;;
;;; from program domain (flash) : r16 ;;;
;;; to SRAM domain (memory) : r17 ;;;
;;; called via r16(data) & r17(adrs) ;;;
DataSet:
ldi ZH, high(2*LEDdata) ; get data address on the program domain
ldi ZL, low(2*LEDdata)
ldi YH, high(Digits) ; get data address on the SRAM domain
ldi YL, low(Digits)

add ZL, r16 ; set target 7seg data
add YL, r17 ; set destination address of SRAM

lpm r18, Z ; load program memory to r18
st Y, r18 ; r18 data store into SRAM (no post inc.)
ret

;*******************************************************************
;;; C A U T I O N ;;;
;;; Do NOT change other of PB0/1/2 ;;;
;;; Need to keep state for SCL & SDA ;;;

;;; LED Display Update ;;;
;;; 1) disable any interrupts this term ;;;
;;; 2) load 1digit(8bit) data from SRAM ;;;
;;; 3) 7segment data transfer (loop2) ;;;
;;; 4) serial to parallel, Disp. update ;;;
;;; 5) cyclic func. for 8digits (loop1) ;;;
;;; 6) accept interrupt after Disp. ;;;
LEDdisp:
cli ; disable any interrupts
in r21, PORTB ; load data in PORTB register
sbi PORTB, SCK ; set bit2 for SCK high
ldi r16, 7 ; set number of digits
ldi r18, 7 ; set distination number for comparison
ldi YH, high(Digits) ; get data address on the program domain
ldi YL, low(Digits)
LEDdisp_loop1:
ldi r17, 7 ; set number of segment
ld r20, Y+ ; store data into r20, and post increment
LEDdisp_loop2:
cbi PORTB, SCK ; clear bit2 for SCK falling edge
bst r20, 7 ; MSB of r20 put into T-flg
bld r21, SegBit ; T-flg store into Segment Bit of r21
out PORTB, r21 ; output segment sequential data
sbi PORTB, SCK ; set bit2 for SCK rising edge
rol r20 ; rotate left through carry
dec r17 ; decrement segment loop counter
brge LEDdisp_loop2 ; finish all segment data sending?
ori r21, 0b00000010
; sbr r21, SegBit ; sent 1 to sifter on other digit
cp r16, r18
brne LEDDataTrans ; 1st digit or other?
andi r21, 0b11111101
; cbr r21, SegBit ; sent 0 to sifter on 1st digit
LEDDataTrans:
out PORTB, r21 ; set segment bit
sbi PORTB, Trans ; Serial to Parallel transfer start
cbi PORTB, Trans ; Serial to Parallel transfer end
dec r16
brge LEDdisp_loop1
ldi r16, 34 ; for equalize the brightness
LEDFinalize: ; among each digits of LED
dec r16 ;
brge LEDFinalize
sbi PORTB, SegBit ; set bit2 = 1
sbi PORTB, Trans ; shift digit position counter by 1
cbi PORTB, Trans ; for turnning off last digit LED
sei ; enable interrupts
ret

;*******************************************************************
;;; Set Timer0 for 250000us(250ms) ;;;
;;; fosc = 1MHz ;;;
;;; 1.0usec * 1024 * 244 = 249856usec ;;;
;;; 1/1024 prescale, 244cycle ;;;
Timer0Set:
ldi r16, 0x0C ; 256 - 244 = 12(0x0C)
out TCNT0, r16 ; set counter value : 0x0C
ldi r16, 0b00000101 ; prescaler : 1/1024
out TCCR0B, r16 ; set timer0
ret

;*******************************************************************
;;; Set Timer-1 for 1000000us(1s) ;;;
;;; fosc = 1MHz ;;;
;;; 1.0usec * 256 * 3907 = 1000192usec ;;;
;;; 1/256 prescale, 3907cycle ;;;
Timer1Set:
ldi r16,0xF0 ; 65535 - 3907 = 61628(0xF0BC)
out TCNT1H,r16 ; set upper counter value : 0xF0
ldi r16,0xBC ; 65535 - 3907 = 61628(0xF0BC)
out TCNT1L,r16 ; set lower counter value : 0xBC
ldi r16,0b00000100 ; prescaler : 1/256
out TCCR1B,r16 ; set timer1
ret

;*******************************************************************
Timer0Int:
reti

;*******************************************************************
Timer1Int:
in r19, SREG
rcall Timer1Set ;;; Temp for TEST

cpi r24, 0
breq Fin
rcall DataForm
ldi r24, 0
rjmp End
Fin:
rcall DataForm2
ldi r24, 1
End:
out SREG, r19
reti

;*******************************************************************
LEDdata:
; 0,1,2,3,4,5,6,7,8,9 --- already reversed...
;.db 0x77,0x06,0x5b,0x1f,0x2e,0x3d,0x7d,0x27,0x7f,0x3f
.db 0x88,0xf9,0xa4,0xe0,0xd1,0xc2,0x82,0xd8,0x80,0xc0

2007年10月7日日曜日



次の省電力レポートも書かないまま、こんなモノを作り始めています。部品の配置を決めるためにのっかる部品を基板に差してみました。裏面にはバックアップの電池と操作用のスイッチが数個のります。このサイズの基板にはもうこれ以上デバイスは乗せられません。ソケットの付いているところにはEpsonのRTCとATtiny2313が刺さります。基板の隣に写っているのはフリス犬ですが、使うのはAtmelのデバイスです。

++ Myself ++

普通(?)のサラリーマン -- 生活のすきま時間にキーボードとはんだごてを持ち替えてプログラミングと電子工作してます