amforth インストール (on Arduino uno R3)

Contents:

amforth インストール クイックスタート

用意するハードウェア

PC
今回はubuntu 12.04LTS(amd64)をインストールしたマシンを使っています。
Arduino uno R3
オープンハードなので自作しても構いません。千石電商では3000円弱(2013/3月)。
USB A-Bケーブル
Arduinoには付属してないので。今回は50cmぐらいのを近所のダイソーで買いました。100円。
ATmega328P-PU
atmel社のICです。Arduino uno R3に載っているのと同じものです。千石電商では300円ぐらい(2013/3月)。 秋月電子通商では250円のようです。 末尾のPUはパッケージの形態を示しています。ここが違うとICソケットに刺せなくなるので注意。 Arduinoのチップを直接書き換えるなら購入しなくても構いません。
AVRISPmkII
ISP(In System Programer)と呼ばれるものです。Arduino上のATmega328P-PUにあらかじめ書き込まれた ブートローダーを介さずに書き込みを行う為に利用します。ISPは通常のプログラマ(ROMライタ)に比べると Arduino上にICを装着したまま書き換えるのと、比較的安価なのが魅力です。一方、ATmega専用になってしまう ので、既にATmeagaにも対応したプログラマ(ROMライタ)を持っている人はそちらを使って構いません。 AVRISPmkIIはUSBケーブル付属しています。秋月電子通商では3000円(2013/3月)。
IC引き抜き工具
あれば便利。手元にあるのはaitendoで買ったもの。200円ぐらい。

ROMライタ&書き込みソフト準備

ROMライタ(プログラマ)を用意します。ここでは AVRISP mkII を使っています。 パラレルプログラマ等を利用する場合でもヒューズビット、ロックビット、hexファイルの転送は同じです。 以後の説明は AVRISP mkII 前提になっているので適宜読み替えてください。

次にご利用になるISPに対応した書き込みソフトを準備します。今回は AVRISP mkII を使ったので AVRISP mkII の場合は avrdude を準備します。aduino-1.0.3を入手した場合は arduino-1.0.3/hardware/tools にあります。

手元のubuntuが64bits版なので avrdude64 を使いました。

書き込みファイル準備

amforthをサイトから取得します。

サイトは http://amforth.sourceforge.net/ ダウンロードはサイトからDOWNLOADリンクで辿れます ( http://sourceforge.net/projects/amforth/ )

ダウンロードした場合は展開すると、 appl/arduino の下に *.hex ファイルが入っています(ソースの場合はmakeが必要です(後述))。

準備

Arduino uno R3 のICをIC引き抜き工具等で引き抜き、書き込みしたいATmega328P-PUをセットします。

ISPを接続します。 Arduino uno R3 は角にある白い丸印が1番ピン示していますので、これとISPのケーブルの1番ピンの位置を合わせます。

AVRISP mkII の場合はターゲットのボード側にも電源供給が必要なので、 AVRISP mkII のUSBケーブルに加えて Arduino uno R3 のUSBケーブルも接続します。

ヒューズビット(fuse)、ロックビット(lock)設定

avrdude を -P usb で使うためには root権限が必要です(udevの設定も色々試したが分からなかった)。

ヒューズビット等設定用に edit_uno.sh を定義します。例えば以下のような感じです。

#!/bin/bash
HARDWARE_TOOLS=$HOME/.arduino/arduino/hardware/tools
AVRDUDE=$HARDWARE_TOOLS/avrdude64
AVRDUDE_CONF=$HARDWARE_TOOLS/avrdude.conf
sudo $AVRDUDE -C $AVRDUDE_CONF -P usb -p atmega328p -c avrisp2 -t -v
  • -C avrdude.conf ファイルの指定。対象チップごとの情報が記述してある。
  • -P アクセスするポートの指定。rootでusbと指定した場合は avrdude が適切なポートを探し出して接続してくれる。
  • -p 指定チップ名の指定。 Arduino uno R3 の場合は atmega328p を指定する。
  • -c プログラマ(ISP)の指定。 AVRISP mkII の場合は avrisp2 と指定。
  • -t プロンプトを出して入力待ちになる。
  • -v verbose。

avrdude を立ち上げます。sudoのパスワードを聞かれるので適宜入力してください。

$ ./edit_uno.sh

signatrueが 0x1e950f なら正常に接続できています。0x000000 の場合は通信できていません。

lfuse, hfuse, efuse は表示されている値になっているので、指定します。

avrdude>w hfuse 0 0xd9

lock bitsは表示されていないので、まず表示します。

avrdude>d lock

次に設定します。

avrdude>w lock 0 0x3f

avrdude を終了します。

avrdude>quit

書き込み

ヒューズビット、ロックビットの設定と同様に upload_uno.sh というスクリプトを作ります。例えば以下のような感じです。

#!/bin/bash
HARDWARE_TOOLS=$HOME/.arduino/arduino/hardware/tools
AVRDUDE=$HARDWARE_TOOLS/avrdude64
AVRDUDE_CONF=$HARDWARE_TOOLS/avrdude.conf
sudo $AVRDUDE -C $AVRDUDE_CONF -P usb -p atmega328p -c avrisp2 -U flash:w:uno.hex -U eeprom:w:uno.eep.hex -v
  • -C avrdude.conf ファイルの指定。対象チップごとの情報が記述してある。
  • -P アクセスするポートの指定。rootでusbと指定した場合は avrdude が適切なポートを探し出して接続してくれる。
  • -p 指定チップ名の指定。 Arduino uno R3 の場合は atmega328p を指定する。
  • -c プログラマ(ISP)の指定。 AVRISP mkII の場合は avrisp2 と指定。
  • -U flashw:uno.hex カレントディレクトリのuno.hexをflashへ書き込む。
  • -U eeprom:w:uno.epp.hex カレントディレクトリのuno.epp.hexをEEPROMへ書き込む。
  • -v verbose。

-U で指定した順番で書き込みが行われます。それぞれverifyを行い、違いがあった場合はそこで中断します。

動作確認

ISPを取り外します。

好きなターミナルでアクセスします。ここではbyobuを使っています。

$ byobu /dev/ttyACM0

以下のとおりタイトル、プロンプトが出れば転送は出来ています(5.0のところはバージョンによって異なる)。

amforth 5.0 ATmega328p ForthDuino
>

注釈

byobuを終了したい場合は、 プレフィックス k (CTRL+A k) で殺す。

_images/forthduino.png

amforthをソースからビルドする場合

ソースコードの入手

subversionでソースコードを入手します。

svn checkout svn://svn.code.sf.net/p/amforth/code/trunk amforth-code

ソースコードを入手したら早速ビルドと行きたいところですが、 amforth はオールアセンブラで書かれていて、アセンブルにはAVRマイコン用のアセンブラを使う必要があります。

Makefileにもさらりと

wine avrasm2.exe

と書いてあったりして。linux版が無いのか探して見ましたが分かりませんでした(2013/03/21現在)。なので、 avrasm2.exeを入手します。

avrasm2.exeの入手

ググってみると、avrasm2.exeはavr studioに含まれているようです。

と言うことで最新(2013/03/21)のavr studio 6を入手してwineでインストールしようとしましたが上手くできませんでした。

よって、バージョンを下げて、 4.19 をインストールしました( http://www.atmel.jp/ja/jp/tools/AVRSTUDIO4.aspx )

注釈

入手時にメアドとか尋ねられるので入力してやってください。入力したメアド宛にダウンロードリンクをメールしてくるので メアドは使えるものを入力しましょう。

Makefile改造

amforth-code/appl/arduino/Makefile は avrasm2.exe のファイルパス等、そのままでは動かないので改造します(Makefile全文は節末参照)。

105行〜150行を抜粋。

# AMFORTH VERSION TO USE
# 'code' for trunk and x.y for the releases (i.e 5.0)
#VERSION=5.0
VERSION=code
AMFORTH=$(HOME)/work/amforth-$(VERSION)
CORE=$(AMFORTH)/core


# directories
ATMEL="$(HOME)/.wine/drive_c/Program Files (x86)/Atmel/AVR Tools/AvrAssembler2"
# ------------------------
# PROGRAMMER CONFIGURATION
# ------------------------

PROGRAMMER=avrisp2
PORT=usb

AVRDUDE=sudo $(HOME)/.arduino/arduino/tools/avrdude64
AVRDUDE_FLAGS=-q -P $(PORT) -c $(PROGRAMMER)

# ----------------
# ASSEMBLER TO USE
# ----------------

# give to avrasm2.exe path is windows like path format :-)
#AS_INCLUDE=-I $(ATMEL)/Appnotes -I $(CORE)
AS_INCLUDE=-I "C:\\Program Files (x86)\\Atmel\\Avr Tools\\AvrAssembler2\\Appnotes" -I "..\\..\\core"

ASM=wine $(ATMEL)/avrasm2.exe
# flags Specific to avrasm2.exe
#AS_FLAGS=$(AS_INCLUDE) -fI -v0
AS_FLAGS=$(AS_INCLUDE) -fI -v0

#ASM=avra $(AS_FLAGS)

#$(CORE)/devices/$(MCU)
ASM_MCU="..\\..\\core\devices\\$(MCU)"

#--------------------------
# Generic assemble patterns
#--------------------------

# Assemble the target
%.hex : %.asm
     @echo "Producing Hexfiles for Arduino $*"
     @$(ASM) $(AS_FLAGS) -I $(ASM_MCU) -e $*.eep.hex -m $*.map -l $*.lst $<
  • 105行のコメントの通り、releaseバージョンでは無いので、 VERSION=code と設定。
  • $(AVRDUDE)は -P usb なのでhexの書き込みと同様、sudoで実行。
  • $(ASM)はwineでの実行なので、インクルードパスはWindowsが認識できる形で相対パス指定した(/からの指定はNGだったので)。

ビルド

$ make uno.hex

アセンブルが終了すると、uno.hex, uno.epp.hex, uno.lst, uno.map が生成される。

エラーのあり無しは uno.lst を参照。

注釈

2013/03/21(JST)のソースではwarningsが2つ。いずれも XT_NOOP への前方参照で、ソース末尾まで追ったらちゃんと定義があったので問題無しとした。

この uno.hex, uno.epp.hex をクイックスタートの手順で実機へ転送してください。

Makefile全文

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# Simple makefile for building the
# Arduino amforth vor various targets

# Examples of usage for Arduino leonardo:
#
# 1) Assemble the whole flash and eemprom files
#     make leonardo.hex
#
# 2) Backup the current flash & eeprom values
#     make leonardo.bak
#
# 3) Erase the whole MCU Flash
#    make leonardo.era
#
# 4) Upload the new firmware using the hex file generated
#    make leonardo
#
# 5) Set the appropiate MCU fuses
#    make leonardo.fuse
#
# 6) Clear files (except backup)
#    make leonardo.clr


SHELL=/bin/bash

##############################
# TARGET DEPENDANT VARIABLES #
##############################

# 1) MCU should be identical to the device
#    Look at the /core/devices/ folder
# 2) PART is the device model passed to avrdude.
# 3) LFUSE, HFUSE, EFUSE are the device-specific fuses
#    there is a useful fuse calc tool at:
#    http://www.engbedded.com/fusecalc/
# --------------------------------------
# Example fuse settings for 'leonardo'
# Low Fuse LFUSE=0xFF
#  - No Div8 prescaler,
#  - No ouptput Clock,
#  - Low Crystal mode: >=8 MHz + start-up time: 16K CK cycles + 65 ms
# High Fuse HFUSE=0xD9
# - Enable Serial Programming & Downloading
# - Bootsize 2048 words (4096 bytes)
# Extended Fuse EFUSE=0xF9
# - Brown-out detection @ 3.5V
# - no Hardware Boot Vector (=boot at $0000)
# --------------------------------------

leonardo:         PART=m32u4
leonardo.hex:     MCU=atmega32u4
leonardo.era:     PART=m32u4
leonardo.bak:     PART=m32u4
leonardo.fuse:    PART=m32u4
leonardo.fuse:    LFUSE=0xFF
leonardo.fuse:    HFUSE=0xD9
leonardo.fuse:    EFUSE=0xE9

uno:              PART=m328p
uno.hex:          MCU=atmega328p
uno.era:          PART=m328p
uno.bak:          PART=m328p
uno.fuse:         PART=m328p
uno.fuse:         LFUSE=0xFF
uno.fuse:         HFUSE=0xD9
uno.fuse:         EFUSE=0x05

mega128:        PART=m1280
mega128.hex:    MCU=atmega1280
mega128.era:    PART=m1280
mega128.bak:    PART=m1280
mega128.fuse:   PART=m1280
mega128.fuse:   LFUSE=0xFF
mega128.fuse:   HFUSE=0xD9
mega128.fuse:   EFUSE=0xF7

sanguino:         PART=m644p
sanguino.hex:     MCU=atmega644p
sanguino.era:     PART=m644p
sanguino.bak:     PART=m644p
sanguino.fuse:    PART=m644p
sanguino.fuse:    LFUSE=0xFF
sanguino.fuse:    HFUSE=0xF9
sanguino.fuse:    EFUSE=0xFD

duemilanove:      PART=m328p
duemilanove.hex:  MCU=atmega328p
duemilanove.era:  PART=m328p
duemilanove.bak:  PART=m328p
duemilanove.fuse: PART=m328p
duemilanove.fuse: LFUSE=0xFF
duemilanove.fuse: HFUSE=0xD9
duemilanove.fuse: EFUSE=0x05

diecimila:        PART=m168
diecimila.hex:    MCU=atmega168
diecimila.era:    PART=m168
diecimila.bak:    PART=m168
diecimila.fuse:   PART=m168
diecimila.fuse:   LFUSE=0xFF
diecimila.fuse:   HFUSE=0xDD
diecimila.fuse:   EFUSE=0xF9

# AMFORTH VERSION TO USE
# 'code' for trunk and x.y for the releases (i.e 5.0)
#VERSION=5.0
VERSION=code
AMFORTH=$(HOME)/work/amforth-$(VERSION)
CORE=$(AMFORTH)/core


# directories
ATMEL="$(HOME)/.wine/drive_c/Program Files (x86)/Atmel/AVR Tools/AvrAssembler2"
# ------------------------
# PROGRAMMER CONFIGURATION
# ------------------------

PROGRAMMER=avrisp2
PORT=usb

AVRDUDE=sudo $(HOME)/.arduino/arduino/tools/avrdude64
AVRDUDE_FLAGS=-q -P $(PORT) -c $(PROGRAMMER)

# ----------------
# ASSEMBLER TO USE
# ----------------

# give to avrasm2.exe path is windows like path format :-)
#AS_INCLUDE=-I $(ATMEL)/Appnotes -I $(CORE)
AS_INCLUDE=-I "C:\\Program Files (x86)\\Atmel\\Avr Tools\\AvrAssembler2\\Appnotes" -I "..\\..\\core"

ASM=wine $(ATMEL)/avrasm2.exe
# flags Specific to avrasm2.exe
#AS_FLAGS=$(AS_INCLUDE) -fI -v0
AS_FLAGS=$(AS_INCLUDE) -fI -v0

#ASM=avra $(AS_FLAGS)

#$(CORE)/devices/$(MCU)
ASM_MCU="..\\..\\core\devices\\$(MCU)"

#--------------------------
# Generic assemble patterns
#--------------------------

# Assemble the target
%.hex : %.asm
     @echo "Producing Hexfiles for Arduino $*"
     @$(ASM) $(AS_FLAGS) -I $(ASM_MCU) -e $*.eep.hex -m $*.map -l $*.lst $<

# Flash the target
% : %.hex
     @echo "Uploading Hexfiles to Arduino $*"
     $(AVRDUDE) $(AVRDUDE_FLAGS) -p $(PART) -e -U flash:w:$*.hex:i -U eeprom:w:$*.eep.hex:i

# Set the fuse bits
%.fuse :
     @echo "Setting fuses to Arduino $*"
     $(AVRDUDE) $(AVRDUDE_FLAGS) -p $(PART) -U efuse:w:$(EFUSE):m -U hfuse:w:$(HFUSE):m -U lfuse:w:$(LFUSE):m

# Erase the whole MCU
%.era :
     @echo "Erasing entire Arduino $*"
     $(AVRDUDE) $(AVRDUDE_FLAGS) -p $(PART) -e

# Clear assembled & auxilars files
%.clr:
     @echo "Cleaning all aux files"
     @rm -f $*.hex ; rm -f $*.eep.hex ; rm -f $*.lst ; rm -f $*.map ; rm -f $*.cof ; rm -f $*.obj

# Backup arduino Flash & EEPROM files
%.bak:
     @echo "Backup Flash & EEPRON from Arduino $*"
     $(AVRDUDE) $(AVRDUDE_FLAGS) -p $(PART) -U flash:r:$*.hex.bak:i -U eeprom:r:$*.eep.hex.bak:i

# ----------------------------------------------------------

GENERIC_DEPENDECIES=*.inc words/*.asm $(CORE)/*.asm $(CORE)/words/*.asm $(CORE)/drivers/*.asm

# Assemble all targets is the default action

TARGET = leonardo.hex uno.hex duemilanove.hex mega128.hex sanguino.hex diecimila.hex

%.asm: MCU=atmega328p

default: $(TARGET)

$(TARGET) :  $(GENERIC_DEPENDENCIES)  $(CORE)/devices/*/*.asm $(CORE)/devices/*/*.inc


# Cleans everything
clean:
     rm -f *.hex ; rm -f *.eep.hex ; rm -f *.lst ; rm -f *.map ; rm -f *.cof ; rm -f *.obj

# All other rules are target specific and must be typed one by one
# as shown in the top.

カスタマイズ(プリミティブ追加)

Users Guideから抜粋します。詳細はそちらをご覧下さい。

関連incファイル
ファイル名 配置領域 備考
dict_appl.inc フラッシュ下位領域 アドレス下位から上位方向に向かって伸びる
dict_appl.core.inc NRWW領域 ブートローダーセクション。unoの場合は0x3800〜0x3FFF

NRWW領域はdict_wl.incを追加した時点でほぼ満杯なので、以後追加するものはdict_appl.incに追加することになります。

ワード marker の追加

uno用の構成ではデフォルトではワードの削除を行うワードを入れていません。つまり、定義しちゃうと消せなくて、 最初のバイナリ転送からやり直しになります。 フラッシュは書き込み回数制限もありますし、現在では母艦となるPCがあるのが当たり前ですのでこの開発スタイルで使いつづけても構いません。

バイナリイメージの再転送無しにワード削除も行いたいと言う場合はワードMARKERを定義します。 amforth では伝統的なFORGETと言うワードは準備してなくて、代わりにMARKERというワードを使います。

説明はamforthのサイトの RECIPES/Un-Doing Definitions にある通りですので 詳細はそちらを見ていただくとして、ここでいくつか補足します。

説明を見れば分かる通り、dict_wl.inc を追加してアセンブルしてから所定のFORTHワード定義をincludeする必要があります。

amforth-code/appl/arduino/dict_appl_core.inc の、 ;.include "dict_wl.inc" のコメント ; を外して make してください。

$ make clean ; make uno.hex

makeしたバイナリイメージを実機に入れてから、

amforth-shell.py で登録するためのファイルを用意します。たとえばextends.frt

#include postpone.frt
#inclue marker.frt
marker sketches

といった具合です。これを amforth-shell.py で取り込みます。