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のデバイスです。

2007年9月24日月曜日

タイマーとスリープモード (その1)

ワンチップマイコンを使っていると、NOPとその回数の計数によって作るループを良く使います。手軽ですしなにより直観的にループの回数(遅延時間)が分かりやすいのがメリットでしょう。ただし、遅延している時間のあいだ中 NOP を実行している訳なので消費電力の観点からもったいない気がします。そこで今回は内蔵のタイマーとスリープモードを組み合わせて遅延時間を作る wait ルーチンを組んで、NOP の空回しとで、どの程度消費電力に差が出るかを実験してみる事にしました。


;;; Wait Routine for 40us ;;;
;;; fosc = 10MHz, 400cycle loop ;;;
;;; 0.1usec * 2 * 200 = 40usec ;;;
WAIT40u:
LDI R19,200
W_LOOP40: ; Wait Loop
DEC R19 ; 1cycle
BRNE W_LOOP40 ; 1cycle
RET


上の例は AVR のアセンブラで マイコンから LCD へのコマンドとコマンドの送出間隔をコントロールするための wait ルーチンで、ここでは、10MHzで駆動している ATtiny2313 を 40usec 遅延させています。 上にも書きましたが、直観的に遅延時間が分かりやすいのが特徴です。 この wait ルーチンと 同じように NOP だけで作った100msec の wait ルーチンを組み合わせて 1/10秒ステップのストップウォッチもどきを作って消費電流を測定します。

電源電圧5V、繋がっている周辺回路は16行2列のLCD一つで、(基板上には他の回路も載っていますが、機能はオフしてあります) 消費電流は、10.0mA です。

こんどは、同じように 40usec の waitルーチンですが、遅延時間内は idle sleep の状態にしておきます。


;;; Timer-0 overflow interrupt ;;;
;;; exit sleep mode ;;;
Timer0Int:
reti

;;; Wait Routine for 40us, sleep ver. ;;;
;;; fosc = 10MHz ;;;
;;; 0.1usec * 8 * 50 = 40usec ;;;
;;; 1/8 prescale, 50cycle ;;;
WAIT40u:
ldi R19,0xCE ; 0xFF(256) - 0x32(50) = 0xCE(206)
out TCNT0,R19 ; set counter value : 50
ldi R19,0b00000010 ; prescaler : 1/8
out TCCR0B,R19 ; set timer0
sleep ; enter sleep mode
ret


wait ルーチンが呼ばれると TCNT0 にカウント回数を、TCCR0B にプリスケーラーの値をセットしてタイマールーチンに入ります。直後にsleepコマンドが実行され timer-0 の割り込み (Timer0Int) がかかるまで sleep モードにいます。 この一つ大枠のwaitルーチンで タイマーとsleepモードを組み合わせた 100msec waitループが組んであります。動作状況としては 100msec のうち ほぼ100usec だけ内部クロックが動作している事になります。この状態での消費電流は 5.9mA でした。約4mAの電流低減がはかれます。

これが正しいかどうか、マニュアルで確かめてみましょう。




動作周波数10MHz、電源電圧5Vの時のactive電流はおおよそ6mA、idle電流は2mAとなっているので差分としてはだいたい正しそうです。 絶対値として少し大きめに出ている原因の一つはLCDの消費電流がありますが、それでも少し大きすぎです。この件に関しては追実験が必要のようです。

このように、比較的待ち時間の長い waitループでは積極的に タイマーとsleepモードを組み合わせて利用すると消費電流の低減をはかれます。

次回はもう少しインターバルの長い条件 (1sec wait)では、どのような結果が出るか実験してみます。

2007年9月11日火曜日

USBasp (改)をつくりました




Linuxで使えるライター(フラッシュへの書き込み)が欲しかったので作ってみました。以前はELMさんのところのCOMポート制御ISPアダプタを使っていましたが、AVRSP が DOS/Win しかサポートしておらず、Linux と Win で開発と書き込みの環境が分かれてしまうのが、つらくなってしまいました。 AVRDUDE がCOMポート制御ISPアダプタの書き込みソフトとして使えるという情報があり実験してみましたが、残念ながらこちらでは上手く動きませんでした。しばらくしたら追実験をしてみる予定です。で、USBasp ですが、部品点数も少なく書き込みスピードも早くて申し分ないものです、、、と書きたかったのですが、手を入れたい部分もあります。現在ファームの変更と追加ハードの実験をしています。
参考サイトはこちら↓
http://elm-chan.org/index_j.html (えるむ - Electronic Lives Mfg.)
http://yuki-lab.jp/ (ゆきの研究室)
http://www.fischl.de/usbasp/ (fischl.de - USBasp - USB programmer for Atmel AVR controllers)

2007年9月7日金曜日

スクラッチからAVR-GCC構築中 on Linux (その3)

解決しました、avr-gccの構築問題。

いずれもFedraCore4(kernel 2.6.x) & gcc4.x(4.0.0)ベース

1) gcc4.xを使う場合
binutils-2.17 / gcc-4.0.4 / avr-libc-1.4.6 を使えば普通にコンパイルできます。gcc-4.1.x以上を使うとコンパイルに失敗するのでいまのところ4.0.4止まり(4.0.xの最新版)。このavr-gccでATtiny2313もATmega48もコンパイル可能です。

2) gcc3.xを使う場合
binutils-2.17 / gcc-3.4.6 / avr-libc-1.4.6 を利用する場合、gccに利用デバイスを追加するpatchが必要です。"真似して足す"のが簡単なので、gcc-3.4.6/gcc/config/avr/ の下にある avr.c avr.h t-avr に gcc-4.0.4あたりのソースを参考にしながら利用したいデバイスを追加します。binutils / avr-libc はこのバージョンではこのままATtiny2313もatmega48も利用可能です。gccをコンパイルしたのち、必ずavr-libcもコンパイルし直します。所望のデバイスが利用可能かどうかは、avr-gccをインストールしたディレクトリ(/usr/local/avr-gcc3/avr/lib, うちの場合)下に、リンカがリンクするオブジェクトファイルが存在するかどうかを調べます。たとえば、ATtiny2313の場合は、crttn2313.o が、ATmega48の場合はこの階層のさらにひとつ下 avr4/ に crtm48.o が正しくコンパイルさせていれば存在します。

で、gcc-3.xとgcc-4.xを比べた結果ですが、やはりgcc-4.xの方が5%程度おおきく仕上ります。下の比較はUSBaspのソースをatmega48でコンパイルしたものです。
10200 9月 6 23:18 main.hex_3.4.6
10683 9月 7 07:52 main.hex-4.0.4

2007年9月6日木曜日

スクラッチからAVR-GCC構築中 on Linux (その2)

前回、binutil / gcc-core / avr-libc の使っているバージョンを書くのを忘れてしまいました。各々 binutils-2.18 / gcc-core-3.4.6 / avr-libc-1.4.6 です。これらの組合せでavr-gccをFC4の上に構築できますが、ATtiny2313がサポートされていないのは前回書いた通りで、原因はgcc-core-3.x以前のavr.cにはATtiny2313が定義されていないためです。gcc-core-4.x以降ではその部分は以下のようになってます。

(gcc-4.2.1の場合)
static const struct mcu_type_s avr_mcu_types[] = {
/* Classic, <= 8K. */
{ "avr2", ARCH_AVR2, NULL },
{ "at90s2313", ARCH_AVR2, "__AVR_AT90S2313__" },

-- snip --

/* Classic + MOVW, <= 8K. */
{ "avr25", ARCH_AVR25, NULL },
{ "attiny13", ARCH_AVR25, "__AVR_ATtiny13__" },
{ "attiny2313", ARCH_AVR25, "__AVR_ATtiny2313__" },


ほかにも

/* List of all known AVR MCU types - if updated, it has to be kept
in sync in several places (FIXME: is there a better way?):
- here
- avr.h (CPP_SPEC, LINK_SPEC, CRT_BINUTILS_SPECS)
- t-avr (MULTILIB_MATCHES)
- gas/config/tc-avr.c
- avr-libc */

と書かれているので、このあたりの変更が必要のようです。パッチを探しているのですがmcuの追加だけのパッチは今のところ見つかっていないのでリスク覚悟で"手直し"かもしれません。WinAVRのgcc-3.xバージョンでもATtiny2313はサポートされていないのだろうか? ネット検索してもそんな話題がひっかからないのでおそらくサポートされているんでしょう。

gcc-3.4.6とgcc-4.0.4でavr-gccを作ってみたので、ATtiny2313ではありませんがATmega8でコンパイルして違いを比較してみました。ものは、USBaspのソースです。出来上がりは、

10155 9月 4 05:32 main.hex_3.4.6
10638 9月 6 06:06 main.hex_4.0.4

位の差が出ました。ATtiny2313のようにROM容量の少ないデバイスには5%の差が大きくのしかかる状況も出て来るかも知れません。さて、この先どうしましょう、、、悩ましいところです。

2007年9月5日水曜日

DS18B20-PAR と DS2417





ダラスマキシム社が出している1-wireのDigital ThermometerとTime Chipです。ATtiny2313のファームをアセンブラで書いている最中です。
参考サイトはこちら↓。
http://frank.bol.ucla.edu/index.htm

スクラッチからAVR-GCC構築中 on Linux

現在スクラッチからAVR-GCCをLinux(Fedra Core 4)で構築中です。一通りbinutil / gcc-core / avr-lib などのコンパイルが終了しました。 が、問題発生。主力のATtiny2313がavr-gccでコンパイルできません。unknown deviceと言われてしまいます。 現在原因調査中。 今のところ分かっているのはどうやらgcc-coreに使えるデバイスを増やすパッチを当ててコンパイルする必要があるらしい、事です。

電子工作あれこれ

ハードウェア、ソフトウェアについてチマチマと書き貯めていこうと思っています。
最近の自分的流行はAtmel AVRを使っての"いろんなモノ"作りです。
工作の過程で知り得た知識なども残していきます。

++ Myself ++

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