Raspberry Pi (2)

環境構築

とりあえずdebian/ubuntuではお約束で

sudo apt-get update && sudo apt-get dselect-upgrade

個人的に馴染んだ環境で

sudo apt-get install emacs ruby ruby1.9.1-dev rubygems

ライブラリのインストール

WiringPiというライブラリがあるのでダウンロード
https://projects.drogon.net/raspberry-pi/wiringpi/

https://projects.drogon.net/raspberry-pi/wiringpi/download-and-install/

wget http://project-downloads.drogon.net/files/wiringPi.tgz
tar xvf wiringPi.tgz
cd wiringPi/wiringPi
make && sudo make install

ruby, pythonから使う


これをperl / python / rubyから使うには
https://github.com/WiringPi
というのがあるが、rubyの場合は

sudo gem install wiringpi

でOK。

pythonの場合は

sudo easy_install wiringPi

でOK。

おまけ Arduino

ちなみにあまり実用的とはいいがたいが、

sudo apt-get install arduino-core arduino-mk arduino

でArduino IDEをインストールすることもできる。リポジトリは純正のdebianよりもubuntuに近いようだ。
HDMIの画面はインストール時だけで、CPUがあまり速くないので、macからsshでログインして使っている。

カテゴリー: Raspbery Pi

Raspberry Pi (1)

6/1に申し込みで7/18に届きました。

BeagleBoneではSDカードが付いていましたが、こちらで最初にすることはSDカードにイメージを書き込むことです。

1 イメージのダウンロード
http://www.raspberrypi.org/downloads
からRasbian “wheezy”をダウンロードします。RaspbianはDebianをRaspberry Pi向けに最適化したもので本家の推薦となっている。
現時点では
→ 2012-07-15-wheezy-raspbian.img
http://elinux.org/RPi_Easy_SD_Card_Setup
に解説がありますが、MacOSXでコマンドラインでやる場合について書く。

2 まずdisk番号を確かめること。
SDカードを入れる前にdf -hとした後
SDカードを入れた後再びdf -hとしたとき、追加されたのは
/dev/disk3s1 (3、4など環境によって異なる)であれば、

diskutil unmount /dev/disk3s1

とする。
書き込みは

dd bs=1m if=2012-07-15-wheezy-raspbian.img of=/dev/rdisk3 

とした。
diskの取り出しは

diskutil eject /dev/rdisk3

SDカードを取り出してRaspberry Piに入れ、起動すれば無事
RaspbianOSが起動しました。

カテゴリー: Raspbery Pi

STBee Mini

買ったあと放置していてちょっと浦島ですが、質問があったので調べてみた。
Maple miniと大きさ的にはほぼ同じ。そもそも石が同じだったりします。(STM32F103CB)
Maple Mini $34.95に対して、STBee Mini 1974円と圧勝です。まあ純正のボードが秋月で1000円位で買えるのであれですが。
いろいろな方のおかげでmacでもSTBee Miniが使える環境ができているみたいなので、検証してみる。

コンパイラ

コンパイラは自分でビルドしてもいいですが、
libmapleのcommand line toolから
http://static.leaflabs.com/pub/codesourcery/gcc-arm-none-eabi-latest-osx32.tar.gz
をダウンロードして/usr/local/armに入れた。

dfu-utilのインストール

問題はdfuでminiはDFuSeとか独自の拡張がされているので、素のdfu-utilでは使えなかったのですが、
Dfu-utilのページから0.6をダウンロードします。
http://dfu-util.gnumonks.org/
(以前紹介したOpenMokoは2007年頃のものでDfuSeに対応していません。)
展開して、

./autogen.sh
./configure --prefix=/usr/local

ここで、libusbがないなどのエラーが出たらmacportsで
libusb
libusb-compat
などをインストールすればよい。
あとはmake, make installでdfu-utilができます。

STBee MiniでUSERボタンを押しながらRESETを押して離すと
DFUモードになる。この状態で

dfu-util -l

とすると、

Found DFU: [0483:df11]

というのが出て認識できた。

後は適当なbinファイルをアップロードしてみる。
まずはストロベリーリナックスのサンプルminidemo.zipを展開して
makeすると、mini-demo.elfができるので、

arm-none-eabi-objcopy -O binary mini-demo.elf mini-demo.bin

でバイナリ形式に変換。
これを書き込むには

dfu-util -a0 -d 0x0483:0xdf11 -s 0x08003000 -D mini-demo.bin

とすると

Downloading to address = 0x08003000, size = 2756

File downloded successfully
となって成功。
“-s 0x08003000” はdfuseで使われている領域の関係で必要なようです。

libmapleで使う

libmapleは

git clone git://github.com/leaflabs/libmaple.git  libmaple

でダウンロードできる。
このままではMaple board関係しか対応していないが、
リンカーまわりやピンの対応をSTBeeやSTM32VLDに対応させたものが配布されている。
http://hp.vector.co.jp/authors/VA000177/html/2011-08.html
libmapleを使ってArduino likeな開発もできる。
digitalWriteとかは遅いのでともかく、UARTやEthernetなどライブラリが使えるとかなり楽だ。

Makefileのdfu-utilの引数に-s 0x08003000を追加すると
make install
でuploadできた。ただし、makeではpythonでリセットを掛けるようになっているが、
STBee Miniでは手動でDFUモードにしないと動かない。

カテゴリー: stm32

Beaglebone(1)

とりあえずメモ

(1) MacOSXにUSBで接続する

USBに接続->BEAGLE_BONEがマウントされる。
OSX10.7 LionではFTDIドライバが動かない。

http://waxpraxis.tumblr.com/post/16772215153/talking-to-the-beaglebone-with-osx-10-7-lion

64ビットのドライバをインストールして、Info.plistを更新。

cd /System/Library/Extensions/FTDIUSBSerialDriver.kext/Contents/
mv Info.plist Info.plist.old
cp ~/Downloads/Info.plist .
chmod 644 Info.plist
kextutil ../../FTDIUSBSerialDriver.kext

/dev/tty.usbserial-*B が見えたらOK。

screen /dev/tty.usbserial-*B 115200

GPIOの番号の対応がややわかりにくい。
GPIOの各ポートは32ピンあるので、GPIO1_0~GPIO1_31,GPIO2_0~GPIO2_31,…
ユーザが使えるのはexpansion headerP8,P9のヘッダであるが、
マニュアルBONESRM_latest.pdf p.54, table 8によると
1 GND
2 GND
3 GPIO1_6
4 GPIO1_7
5 GPIO1_2

のようになっている。これを次のように読み替える。
GPIO1_6 -> 32*1+6 = 38
GPIO1_7 -> 32*1+7 = 39
GPIO1_2 -> 32*1+2 = 34

この辺はcloud9を使う場合は別のマクロで処理されているので意識する必要はない。
しかし、ファイルシステムの対応を理解する上では、ある程度UNIXに慣れていると次のようにシェルで動かした方が理解は早いと思うのだが。

(2)shellによるLチカ

# gpio38を開放する
echo 38 > /sys/class/gpio/export
# gpio38をoutputポートにする。 pinMode(38, OUTPUT)みたいな
echo out > /sys/class/gpio/gpio38/direction
# ポートを開放
echo 70 > /sys/class/gpio/export
# gpio70をinputポートにする。
echo in > /sys/class/gpio/gpio70/direction
# 以下にアクセスすると状態を得ることができる high:1, low:0
/sys/class/gpio/gpio38/value
/sys/class/gpio/gpio70/value

LEDを10回点滅させるだけのshell script

#!/bin/sh
# use P8 3pin -> GPIO1_6
# GPIO1_6 = 32*1 + 6 = 38
echo 38 > /sys/class/gpio/export
echo out > /sys/class/gpio/gpio38/direction
for i in {1..10}
do
echo 1 > /sys/class/gpio/gpio38/value
sleep 1
echo 0 > /sys/class/gpio/gpio38/value
sleep 0
done
echo 38 > /sys/class/gpio/unexport

(参考)

BeagleBone GPIO (youtube)
http://www.adafruit.com/blog/2012/03/06/beaglebone-gpio

pythonのスクリプト
https://gist.github.com/1986926

C言語による例
https://github.com/nunoalves/BeagleBone-GPIO-in-C

Make: How-To: Get Started with the BeagleBone
http://blog.makezine.com/2012/03/14/how-to-get-started-with-the-beaglebone/

Hardware Interfacing on the BeagleBone
http://www.nathandumont.com/node/250

カテゴリー: BeagleBone

ubuntuでのarduino (3)

昨年書いた「ubuntuでのarduino(2)」から進展があるので追記。
ubuntu-12.04 beta on dynabook AZ(ac100) で主にやりましたが、i386 on virtualboxでも同様。

AC100については以下
https://wiki.ubuntu.com/ARM/TEGRA/AC100
http://cdimage.ubuntu.com/daily-preinstalled/current/

apt-cache search arduino
で検索すると、arduino-mk というパッケージが増えていた。
これは”ubuntuでのarduino(2)”で紹介したMakefileの雛形だが、ard-parse-boardsというperlスクリプトで
boards.txtからボード毎の変数を取り出すようになっている。

プロジェクトのデイレクトリhelloを作り、ソースはhello.ino(hello.pde)に書いて、
make, make uploadとするのは前と同じ。

●Linuxの場合は
Makefileに

BOARD_TAG = uno
ARDUINO_PORT = /dev/ttyACM3 # dmesgなどで調べる
ARDUINO_DIR = /usr/share/arduino
AVRDUDE_ARD_PROGRAMMER = arduino
include /usr/share/arduino/Arduino.mk 

と書くだけで動いた。
ubuntu-12以前の場合は以下のmacの場合と同様にインストールして、Makefileは上と同じでよいはず。

●Macの場合は
http://mjo.tc/atelier/2009/02/arduino-cli.html
からversion 0.8をダウンロードして展開し、ard-parse-boardsを適当な場所にインストールする。

ARDUINO_DIR = /Applications/Arduino.app/Contents/Resources/Java
BOARD_TAG = uno
ARDUINO_PORT = /dev/cu.usb*
include ../Arduino.mk

とするだけでよく、去年よりも自動化が進んだ。

(追記)ライブラリを使う場合は
例:Ethernetライブラリ
ARDUINO_LIBS = Ethernet Ethernet/utility SPI
などを加える。

カテゴリー: Arduino

AVR timer(1)

タイマーについてまとめてみる。タイマーにはノーマルモード、CTCモード、PWMなどあるが今回はノーマルモードに限定する。
参考になるのはLUFAの作者であるDean Camera氏のチュートリアルで
http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106
および
http://www.fourwalledcubicle.com/AVRArticles.php
にPDF化された文書もある。

_delay_ms(), _delay_us()などがあるので、遅延するだけなら不要だが、
割り込みを使ってマイコンらしい効果的な使い方ができる。

Timer0 (8bit)

AVRのタイマーには8ビットのタイマー(通常はTimer0)と16ビットのタイマー(Timer1,etc)がある。
まず8ビットタイマーTimer0を使ってみる。
tiny13にはTimer0しかない。(tiny10もTimer0しかないが、16bitで他のCPUではTimer1に相当する。)
また、ArduinoではTimer0はmillis()などで使われている。
以下ではtiny13のFUSEを変更していない状態で考える。デフォルトではクロックを内蔵9.6MHzの8分周で使うので、TCNT0というレジスタは1/1.2MHz=83us毎に増えていき、255の次にオーバーフローして0に戻るということを繰返す。
まず、この仕組みだけを使って最も単純なコードを書いてみる。
256/1200000=21.33msのタイマー(4.7kHz)にしかならないので、Lチカでは点滅しているかどうかわからない。(オシロがあれば確認できる)

割り込みベクタはgrep vect iotn13.hとかで調べると、TIM0_OVF_vectである。(世代によってTIMER0だったり、TIM0だったりするので注意)
他の動作によらずTCNT0がオーバーフローしたときに割り込みが実行される。

タイマーに関するレジスタはTCCR0A, TCCR0B, TIMSK, TIFRなどである。

TCCR0A: Timer/Counter Control Register A

bit 7 6 5 4 3 2 1 0
TCCR0A COM0A1 COM0A0 COM0B1 COM0B0 WGM01 WGM00
default 0 0 0 0 0 0 0 0

TCCR0B: Timer/Counter Control Register B

bit 7 6 5 4 3 2 1 0
TCCR0B FOC0A FOC0B WGM02 CS02 CS01 CS00
default 0 0 0 0 0 0 0 0

TIMSK: Timer/Counter Interrupt Mask Register

bit 7 6 5 4 3 2 1 0
TIMSK TOIE1 OCIE1A OCIE1B ICIE1 OCIE0B TOIE0 OCIE0A
default 0 0 0 0 0 0 0 0

TIFR: Timer/Counter Interrupt Flag Register

bit 7 6 5 4 3 2 1 0
TIFR TOV1 OCF1A OCF1B ICF1 OCF0B TOV0 OCF0A
default 0 0 0 0 0 0 0 0

設定すべきことは
(1)timerのモード(ノーマル、CTC、PWMなど)
(2)クロック分周比
(3)タイマー割り込みの許可(TIMSK0: Timer Interrupt Mask RegisterのTOIE0:Timer/Counter0 Overflow Interrupt Enable)
(4)全ての割り込みの許可(sei)

(1)についてはWGM02:0で行なう。

Waveform Generation Mode Bit

Mode WGM02 WGM01 WGM00 Timer/Counter Mode operation TOP update OCRx at TOV flag set on
0 0 0 0 normal 0xFF immediate MAX
1 0 0 1 PWM, phase correct 0xFF TOP BOTTOM
2 0 1 0 CTC OCR0A immediate MAX
3  0 1 1 Fast PWM 0xFF TOP MAX
4  1 0 0 reserved
5  1 0 1 PWM, phase corect OCR0A TOP BOTTOM
6  1 1 0 reserved
7  1 1 1 Fast PWM OCR0A TOP TOP

(2)についてはCS02:0で行なう。
Clock Select Bit

CS02 CS01 CS00 description
0 0 0 no clock source (Timer/Counter stopped)
0 0 1 clkIO (no prescaling)
0 1 0 clkIO/8
0 1 1 clkIO/64
1 0 0 clkIO/256
1 0 1 clkIO/1024
1 1 0 external clock source on T0. falling edge
1 1 1 external clock source on T0. rising edge

ノーマルモードでWGM02|WGM01|WGM00=000。
プリスケーラなしでCS02|CS01|CS00=001。
タイマーのオーバフロー割り込みを許可(TOIE0=1)することで、TCNT0=255の次にオーバーフローするとISR(TIM0_OVF_vect)が呼ばれる。

// for ATtiny13
#include <avr/io.h>;
#include <avr/interrupt.h>;

ISR(TIM0_OVF_vect)
{
    PORTB ^= (1<<PB0);
}

void init_timer()
{
    TCCR0A = 0; // normal mode
    TCCR0B = (1<<CS00); // prescaler = 1
    TIMSK0 |= (1<<TOIE0);
    //TCNT0 = 0;
}

int main()
{
    DDRB =(1<<PB0);
    init_timer();
    sei(); // enable global interrupts
    while(1) {
    }
}

次に肉眼でも動作がわかるようにしたい。
16bitタイマなら65535まで数えることができるが、8bitタイマでは255が限界なので分周を使う。

TCCR0B = (1<<CS00); // FCPU
TCCR0B = (1<<CS01); // FCPU/8
TCCR0B = (1<<CS01)|(1<<CS00); // FCPU/64
TCCR0B = (1<<CS02); // FCPU/256
TCCR0B = (1<<CS02)|(1<<CS00); // FCPU/1024

のように変えることで、TCNT0の進み方を遅くする。
分周比1024の場合は1tick=1024/120000=85msで256カウントで0.22s(約4.6Hz)になる。

Timer1 (16bit)

16ビットタイマーについても同様だが、tiny13にはないので、以下では定番のtiny2313を使う。
世代によってレジスタ名が微妙に違うので、ヘッダファイルなりデータシートなりで調べる。
上のコードでは
TIM0_OVF_vect → TIMER0_OVF_vect, TIMSK0→TIMSK
などとする。

// for ATtiny2313
#include <avr/io.h>;
#include <avr/interrupt.h>;
ISR(TIMER0_OVF_vect)
{
    PORTB ^= (1<<PB0);
}

void init_timer0()
{
    TCCR0A = 0; // normal mode
    TCCR0B = (1<<CS02)|(1<<CS00); // prescaler 1024
    TIMSK |= (1<<TOIE0);
    TCNT0 = 0;
}

int main()
{
    DDRB = (1<<PB0);
    init_timer0();
    sei();
    while(1) {
    }
    return 0;
}

Timer1の場合も0->1とする程度でほぼ同様に書ける。
ただし、TCNT1は16ビットで0-65535までを取るので、prescalerなしでも54.6ms=18Hzになる。

// for ATtiny2313
#include <avr/io.h>;
#include <avr/interrupt.h>;
ISR(TIMER1_OVF_vect)
{
   PORTB ^= (1<<PB0);
}

void init_timer1()
{
    TCCR1A = 0; // normal mode
    TCCR1B = (1<<CS10);    // prescaler 1
    TIMSK |= (1<<TOIE1);
    //TCNT1 = 0;
}

int main()
{
    DDRB = (1<<PB0);
    init_timer1();
    sei();
    while(1) {
    }
    return 0;
}

2つのLEDを別のタイミングで動かすような場合に_delay_ms()を使うと、かえって難しいが、
割り込みを使えば、設定しておいて、sei()で一気に動き出す。

timer0のレジスタを見ただけでもかなり微妙な名前の違いがあり、一つのコードでいろいろなCPUに使いまわそうとすると、CPUごとに場合分けして書くということになる。そういうときに

#if defined(__AVR_ATtiny13__) || defined(__AVR_ATtiny10__)
    TIMSK0 |= (1<<TOIE0);
#else defined(__AVR_ATtiny2313__)
    TIMSK |= (1<<TOIE0);
#endif

のように書くことである程度ポータブルにできる(が読みにくくなる)。

カテゴリー: AVR

AVR入門(3) ピン入力と割り込み

ピン入力と割り込みの基礎をまとめておく。
ATtiny13を使うが、他のCPUでもほぼ同じである。(ATtiny10はピン数が少なくより制約が大きいが、tiny13のTimer0は8ビットであるのに対し、tiny10のTimer0は16ビットであるといった違いもある。次回はタイマー割り込みを考えている。)

もっとも簡単なのはスイッチ入力であるが、ガイガーカウンタのようなパルス入力も原理は同じである。
機械的なスイッチではバウンスの処理が必要であるが、ここでは省略する。(数msec程度の間にON,OFFを繰り返しが起こるので、割り込みを検出してから短い時間は無効にするなど、工夫が必要)

スイッチを押すとLOW、はなすとHIGHになるようにする回路を考える。スイッチの片側はVCCに10kΩの抵抗を介してプルアップし、スイッチの反対側はGNDに落とす。プルアップされた側をPB1と接続して、スイッチを押すとPB0のLEDが点灯するようにする。

ATtiny13

1 PB5/RESET 8 VCC
2 PB3 7 PB2
3 PB4 6 PB1/INT0
4 GND 5 PB0
#include <avr/io.h>

void led_on()
{
    PORTB |= (1 << PB0);
}
void led_off()
{
    PORTB &= ~(1 << PB0);
}

int main()
{
    DDRB |= (1 << PB0);
    led_off();
    while(1) {
        if (bit_is_set(PINB, 1)) {
            led_off();
        } else {
            led_on();
        }
    }
}

bit_is_setはavr/sfr_defs.hで定義されていて、

#define bit_is_set(sfr, bit) (_SFR_BYTE(sfr) & _BV(bit))

であり、bit_is_set(PINB, 1)は

PINB & (1<<PB1)

と同じで、PINBの1ビット目が1であれば、trueである。

これが普通のやりかたであるが、ずっと変化がないときに毎回ピンの状態をチェックしているのは無駄に思える。
マイコンにはハードウェア割り込みという機能があるので、これを使う方法で書き直してみる。

INT0による割り込み

tiny13では外部割り込みはPB1にINT0が割り当てられている。上で入力にPB1を使ったのはこのためである。
割り込みに関するレジスタは
MCUCR,GIMSK
である。INT0に割り込みがあったときに呼ばれるルーチンは

ISR(INT0_vect)
{
}

に書く。interrupt.hをインクルードする必要がある。

MCUCR: MCU Control Register

Bit 7 6 5 4 3 2 1 0
MCUCR PUID SE SM1 SM0 ISC01 ISC00
ISC01 ISC00
0 0 INT0がLOWのとき割り込みが発生
0 1 INT0に任意の変化で割り込みが発生
1 0 INT0にfalling edge(HIGH→LOW)で割り込みが発生
1 1 INT0にrising edge(LOW→HIGH)で割り込みが発生

GIMSK: General Interrupt Mask Register

Bit 7 6 5 4 3 2 1 0
GIMSK INT0 PCIE

INT0=1のとき、割り込みが有効
(PCIEはINT0以外のPCINT5..0を有効にするときに使う)

以下はINT0=PB1でfalling edge(HIGHからLOWへの変化)の割り込みがあると、
10msだけLEDをONにするだけのコード。whileループでは何もしないことに注意する。

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

ISR(INT0_vect)
{
    PORTB |= (1<<PB0);
    _delay_ms(10);
    PORTB &= ~(1<<PB0);
}

int main()
{
    DDRB |= (1<<PB0);

    MCUCR |= (1<<ISC01);  // falling edge of INT0
    GIMSK |= (1<<INT0);       // enable INT0 interrupt    
    sei(); // enable global interrupts

    while(1) {
    }

    return 0;
}

tiny13を2個用意して、1個は単なる発振(Lチカ)にしておき、その出力をもう1個のtinyのINT0に入力するという風にして、ISC01|ISC00=00,01,10,11の違いをLEDで視覚的に見ることができるので、比較してみるとわかりやすいと思う。

カテゴリー: AVR
カテゴリー
2017年8月
« 11月    
 123456
78910111213
14151617181920
21222324252627
28293031