φ(. . )めもめも

技術関連の個人的な備忘録

RaspberryPi - 小ネタ

CPU温度

$ /opt/vc/bin/vcgencmd measure_temp

$ cat /sys/class/thermal/thermal_zone0/temp

CPU情報

$ cat /proc/cpuinfo

CPUクロック

$ cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq

$ /opt/vc/bin/vcgencmd measure_clock arm

メモリー情報

$ cat /proc/meminfo

電圧

/opt/vc/bin/vcgencmd measure_volts core

vcgencmd使い方

RPI vcgencmd usage

RaspberryPi - 無線LAN設定

USB無線LAN子機の設定

RaspberryPiにUSB無線LAN子機(NEC Aterm WL300NU-G)を接続した。
そのときの手順。

電源

RaspberryPi起動中に、USB機器を差すと物によっては電力不足でリセットがかかり再起動するらしい。
試しに、起動中にWL300NU-GをUSBに差してみたら、やはり再起動した。
USB機器を使用する場合は、電源投入前に差しておくのが良いかもしれない。

起動後の関連コマンドログ

pi@raspberrypi ~ $ dmesg
(省略)
[    3.143217] usb 1-1.3: new high-speed USB device number 4 using dwc_otg
[    3.302245] usb 1-1.3: New USB device found, idVendor=0409, idProduct=0249
[    3.321389] usb 1-1.3: New USB device strings: Mfr=16, Product=32, SerialNumber=48
[    3.336501] usb 1-1.3: Product: AtermWL300NU-G
[    3.343530] usb 1-1.3: Manufacturer: NEC
[    3.349906] usb 1-1.3: SerialNumber: 12345
[    4.155439] udevd[137]: starting version 175
[    5.671058] cfg80211: Calling CRDA to update world regulatory domain
[    6.493240] usb 1-1.3: reset high-speed USB device number 4 using dwc_otg
[    6.693746] usbcore: registered new interface driver carl9170
[    6.863646] usb 1-1.3: firmware not found.
(省略)

pi@raspberrypi ~ $ lsmod
Module                  Size  Used by
snd_bcm2835            12808  0
snd_pcm                74834  1 snd_bcm2835
snd_seq                52536  0
snd_timer              19698  2 snd_seq,snd_pcm
snd_seq_device          6300  1 snd_seq
snd                    52489  5 snd_seq_device,snd_timer,snd_seq,snd_pcm,snd_bcm2835
snd_page_alloc          4951  1 snd_pcm
carl9170               74651  0
mac80211              236178  1 carl9170
ath                    16648  1 carl9170
cfg80211              171957  3 ath,mac80211,carl9170

pi@raspberrypi ~ $ lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp.
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
Bus 001 Device 004: ID 0409:0249 NEC Corp. Aterm WL300NU-G

pi@raspberrypi ~ $ modinfo carl9170 | head
filename:       /lib/modules/3.2.27+/kernel/drivers/net/wireless/ath/carl9170/carl9170.ko
alias:          arusb_lnx
alias:          ar9170usb
firmware:       carl9170-1.fw
description:    Atheros AR9170 802.11n USB wireless
license:        GPL
author:         Christian Lamparter <chunkeey@googlemail.com>
author:         Johannes Berg <johannes@sipsolutions.net>
version:        1:1.9.4
srcversion:     D2411637BD7256187C65770

デバイスを認識させる

USB機器としては認識しているが、ifconfigで、該当するIFが表示されない。
原因は、dmesg

[    6.863646] usb 1-1.3: firmware not found.

これ。

無線LANデバイスは、.koファイルだけでなく、対応するファームウェアファイルが必要となる。 必要なファイルは、dmesgで表示される、

firmware:       carl9170-1.fw   ← コイツ

LinuxWirelessから、carl9170-1.fw をダウンロード
/lib/firmwareにおく。パーミッションは、644。

設定

/etc/network/interfaces を編集する。

オリジナルとの差分

pi@raspberrypi /etc/network $ diff interfaces interfaces.org
6d5
< auto wlan0
8,17c7,8
< iface wlan0 inet dhcp
< wpa-ap-scan 1
< wpa-scan-ssid 1
< wpa-key-mgmt WPA-PSK
< wpa-proto WPA2
< wpa-pariwise CCMP
< wpa-group CCMP
< wpa-ssid アクセスポイントのSSID
< wpa-psk アクセスポイントのキー
< #wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
---
> iface wlan0 inet manual
> wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf

編集後

$ sudo ifup wlan0

として有効化する。

参考サイト

RaspberryPi - C言語でPWM制御。からの、Ruby用ライブラリ作成(つづき)

前回のつづき。

Rubyライブラリの作成

前回のプログラムの関数をRubyで使用できるようにライブラリ化

Swigのインストール

$ sudo apt-get install swig

定義ファイルを書く

ライブラリに登録する関数をpwm.iというファイルに記述する

登録する関数
set_range
set_duty
hw_initialize
pwm.iの内容
%module pwmlib
%{
extern volatile unsigned * io_mapping(int base_addr);
extern void hw_initialize();
extern void set_range(int range);
extern void set_duty(int duty);

%}
%init
%{
hw_initialize();
%}

extern void set_range(int range);
extern void set_duty(int duty);

ラッパー関数作成

siwgを使用し、ruby用のラッパー関数を作成する。

$ swig -ruby pwm.i

pwm_wrap.cが生成される

Makefileの生成

extconf.rbを作成して実行する

extconf.rbの内容
require 'mkmf'
create_makefile('pwmlib')
実行
$ ruby extconf.rb

Makefileが生成される

ビルドとインストール

$ make
$ sudo make install ← 生成された.soファイルをRubyのライブラリディレクトリへコピー

Rubyからの利用

C言語版と同様、Rangeを1000固定で、Dutyを0~1000まで100単位で変化させるサンプル。

require 'pwmlib'
pwm = Pwmlib
pwm.set_range(1000)
0.step(1000, 100) do |i|
sleep(1)
puts "d=#{i}"
pwm.set_duty(i)
end
view raw pwm.rb hosted with ❤ by GitHub
実行
$ sudo ruby pwm.rb

RaspberryPi - C言語でPWM制御。からの、Ruby用ライブラリ作成

雑誌インターフェースのサンプルや、 wiringPiのコードを参考にpwmのレジスタにアクセスする。

RaspberryPiのPWM

  • PWM0(GPIO18)がピンヘッダ(12pin)へ接続されている
  • PWM_RNGxレジスタで、Rangeを設定
  • PWM_DATxレジスタで、Duty(Highの期間)を設定
        |<---duty-->|
         ___________
        /           \____________/
        |<-------range---------->|
  • CM_GPxCTLレジスタ(※)で、Rangeのベースクロックを設定する。
  • OSCに19.2MHzの発信器が接続されている。(回路図参照)
  • CM_GPxCTLレジスタのSRCフィールドを1(oscillator)にすれば、OSC(19.2MHz)が使用可。
  • CM_GPxDIVレジスタで、OSCクロックを分周。WiringPiでは32分周して600KHzをRangeのベースクロックとしている。

※CM_GPxCTLレジスタのアドレスが、BCM2835のデータシートでは、0x20101070(0x7E101070)となっているが、 WiringPiのコード上では、0x201010A0にアクセスしている。

プログラム

Rangeを1000固定で、Dutyを0~1000まで100単位で変化させるサンプル。
※ただし、動作はLED(暗→明)で確認しただけで、オシロスコープなどでは確認していないので 正確なクロックが出力されているか不明。

//
// BCM2835 pwm lib
//
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define BCM2708_PERI_BASE 0x20000000
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
#define PWM_BASE (BCM2708_PERI_BASE + 0x20C000) /* PWM controller */
#define CLOCK_BASE (BCM2708_PERI_BASE + 0x101000)
// PWM controller offset
#define PWM_CONTROL 0
#define PWM_STATUS 1
#define PWM0_RANGE 4
#define PWM0_DATA 5
#define PWM1_RANGE 8
#define PWM1_DATA 9
// GPIO clock reg offset
#define PWMCLK_CNTL 40
#define PWMCLK_DIV 41
// BCM Magic
#define BCM_PASSWORD 0x5A000000
#define PWM1_MS_MODE 0x8000 // Run in MS mode
#define PWM1_USEFIFO 0x2000 // Data from FIFO
#define PWM1_REVPOLAR 0x1000 // Reverse polarity
#define PWM1_OFFSTATE 0x0800 // Ouput Off state
#define PWM1_REPEATFF 0x0400 // Repeat last value if FIFO empty
#define PWM1_SERIAL 0x0200 // Run in serial mode
#define PWM1_ENABLE 0x0100 // Channel Enable
#define PWM0_MS_MODE 0x0080 // Run in MS mode
#define PWM0_USEFIFO 0x0020 // Data from FIFO
#define PWM0_REVPOLAR 0x0010 // Reverse polarity
#define PWM0_OFFSTATE 0x0008 // Ouput Off state
#define PWM0_REPEATFF 0x0004 // Repeat last value if FIFO empty
#define PWM0_SERIAL 0x0002 // Run in serial mode
#define PWM0_ENABLE 0x0001 // Channel Enable
#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)
// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
#define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
#define GPIO_GET *(gpio+13) // read bits
// I/O access
volatile unsigned *gpio;
volatile unsigned *pwm;
volatile unsigned *clk;
static int mem_fd = 0;
//
// Set up a memory regions to access GPIO
//
volatile unsigned * io_mapping(int base_addr)
{
char *gpio_mem, *gpio_map;
/* open /dev/mem */
if (!mem_fd) {
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
printf("can't open /dev/mem \n");
exit (-1);
}
}
/* mmap GPIO */
// Allocate MAP block
if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
printf("allocation error \n");
exit (-1);
}
// Make sure pointer is on 4K boundary
if ((unsigned long)gpio_mem % PAGE_SIZE)
gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE);
// Now map it
gpio_map = (char *)mmap(
(caddr_t)gpio_mem,
BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
base_addr
);
if ((long)gpio_map < 0) {
printf("mmap error %d\n", (int)gpio_map);
exit (-1);
}
// Always use volatile pointer!
return (volatile unsigned *)gpio_map;
}
//
void hw_initialize()
{
gpio = io_mapping(GPIO_BASE);
pwm = io_mapping(PWM_BASE);
clk = io_mapping(CLOCK_BASE);
// GPIO18をPWMに
SET_GPIO_ALT(18, 5);
*(pwm + PWM_CONTROL) = 0; // Stop PWM
*(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x01; // Stop PWM Clock
usleep(110000); // See comments in pwmSetClockWPi
while ((*(clk + PWMCLK_CNTL) & 0x80) != 0) // Wait for clock to be !BUSY
usleep(1000) ;
*(clk + PWMCLK_DIV) = BCM_PASSWORD | (32 << 12); // set pwm div to 32 (19.2/32 = 600KHz)
*(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x11; // enable clk
usleep(110000);
// Default range register of 1024
*(pwm + PWM0_RANGE) = 1024;
usleep(10000);
*(pwm + PWM1_RANGE) = 1024;
usleep(10000);
*(pwm + PWM0_DATA) = 0;
usleep(10000);
*(pwm + PWM1_DATA) = 0;
usleep(10000);
// Enable PWMs in balanced mode (default)
*(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE;
usleep(100000);
}
// Range設定
void set_range(int range)
{
*(pwm + PWM0_RANGE) = range;
usleep(1000);
}
// Duty設定
void set_duty(int duty)
{
*(pwm + PWM0_DATA) = duty;
usleep(1000);
}
int main(void)
{
int i;
hw_initialize();
set_range(1000);
for(i = 0; i <= 1000; i += 100) {
usleep(1000000);
set_duty(i);
printf("d=%d\n", i);
}
return 0;
}
view raw pwm.c hosted with ❤ by GitHub
コンパイルと実行
$ gcc pwm.c
$ sudo ./a.out

つづく…

RaspberryPi - WiringPiライブラリのインストール

WiringPiライブラリ

Raspberry Piの低レベル周辺回路を制御するライブラリ、 WiringPiをインストールする。
C言語用ライブラリをベースに各言語のラッパーも公開されている。
(元々Arduino向けのライブラリ?をRaspberry Piに移植した?よくわからん)

また、コマンドラインからGPIOを制御できるユーティリティも付属している。

$ git clone git://github.com/WiringPi/WiringPi.git
$ cd WiringPi
$ ./build

ユーティリティの使い方

GPIOの番号指定がArduinoライクになっているらしい。
BCMの番号指定もできる。

wiringPi番号での指定
$ gpio mode 7 out  ← Pin7(GPIO4)を出力モードに
$ gpio write 7 1   ← Pin7(GPIO4) High
$ gpio write 7 0   ← Pin7(GPIO4) Low
BCM番号での指定
$ gpio -g mode 4 out ← GPIO4を出力モードに
$ gpio -g write 4 1  ← GPIO4 High
$ gpio -g write 4 0  ← GPIO4 Low

ピンヘッダとwiringPi番号とBCM番号の対応はこちら

RaspberryPi - C言語でLチカ(レジスタ直接制御)

雑誌インターフェース 2012年12月号の サンプルプログラム (おそらくオリジナルはここ)を、 Rev2基板用にすこし修正して動作させた。(48行目~)
それと、サンプルプログラムのGPIO4が無効になっていた(何故?)ので使えるように。
※下記のコードもGPIO4を10回トグルさせるようにしている。

Rev2のピンヘッダのGPIO情報はこちらの少し下あたり。

$ gcc gpio_c.c
$ sudo ./a.out

レジスタへ直接アクセス出来るようにする手順

  1. malloc()で、仮想メモリ空間のメモリ領域を確保
  2. 確保したメモリ領域内から、4Kバウンダリのアドレスを求める
  3. /dev/mem と mmap()で、確保したメモリ領域をレジスタ領域にマッピング
  4. mmap()からマッピングされたレジスタのアドレスが返る
  5. mmap()が返したアドレス+オフセットで各レジスタにアクセスする
//
// How to access GPIO registers from C-code on the Raspberry-Pi
// Example program
// 15-January-2012
// Dom and Gert
//
// Access from ARM Running Linux
#define BCM2708_PERI_BASE 0x20000000
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)
int mem_fd;
char *gpio_mem, *gpio_map;
char *spi0_mem, *spi0_map;
// I/O access
volatile unsigned *gpio;
// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
#define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0
#define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
#define GPIO_GET *(gpio+13) // read bits
#define REV2 // for rev2 board
#ifdef REV2
#define MAX_PORTNUM 27
char valid_port[] = {
0,0,1,1, // 0..3
1,0,0,1, // 4..7
1,1,1,1, // 8..11
0,0,1,1, // 12..15
0,1,1,0, // 16..19
0,0,1,1, // 20..23
1,1,0,1, // 24..27
};
#else
#define MAX_PORTNUM 25
char valid_port[] = {
1,1,0,0,
0,0,0,1,
1,1,1,1,
0,0,1,1,
0,1,1,0,
0,1,1,1,
1,1
};
#endif
void setup_io();
int port_avail(int port)
{
if ((port < 0) || (port > MAX_PORTNUM))
return (0);
return ((int)valid_port[port]);
}
int gpio_read(int port)
{
if (!port_avail(port))
return(0);
return( (GPIO_GET & (1<<port)) ? 1 : 0);
}
void gpio_write(int port, int data)
{
if (!port_avail(port)) {
printf("illigal port:%d\n", port);
return;
}
if (data == 0)
GPIO_CLR = 1<<port;
else
GPIO_SET = 1<<port;
}
//
// Set up a memory regions to access GPIO
//
int initcount= 0;
void setup_io()
{
initcount++;
/* open /dev/mem */
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
printf("can't open /dev/mem \n");
exit (-1);
}
/* mmap GPIO */
// Allocate MAP block
if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
printf("allocation error \n");
exit (-1);
}
// Make sure pointer is on 4K boundary
if ((unsigned long)gpio_mem % PAGE_SIZE)
gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE);
// Now map it
gpio_map = (char *)mmap(
(caddr_t)gpio_mem,
BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
GPIO_BASE
);
if ((long)gpio_map < 0) {
printf("mmap error %d\n", (int)gpio_map);
exit (-1);
}
// Always use volatile pointer!
gpio = (volatile unsigned *)gpio_map;
} // setup_io
void gpio_init()
{
int i;
setup_io();
#if 1 // modify. test gpio4
INP_GPIO(4); // must use INP_GPIO before we can use OUT_GPIO
OUT_GPIO(4);
#else
for (i=0; i<1; i++) {
INP_GPIO(i);
}
for (i=7; i<=11; i++) {
INP_GPIO(i); // must use INP_GPIO before we can use OUT_GPIO
OUT_GPIO(i);
}
#endif
}
void testmain()
{
#if 1 // modify. test gpio4
int i;
for(i = 0; i < 10; i++) {
gpio_write(4, 1);
sleep(1);
gpio_write(4, 0);
sleep(1);
}
#else
int p;
for (p=7; p<=11; p++) {
gpio_write(p,1);
sleep(1);
}
for (p=0; p<2; p++) {
printf("%d:",gpio_read(p));
}
printf("\n");
for (p=7; p<=11; p++) {
gpio_write(p,0);
sleep(1);
}
for (p=0; p<2; p++) {
printf("%d:",gpio_read(p));
}
printf("\n");
#endif
}
int main(int argc, char **argv)
{
gpio_init();
testmain();
return 0;
} // main
view raw gpio_c.c hosted with ❤ by GitHub

※ そういえば、あまり見かけないけど型修飾子のintは省略できる。

volatile unsigned *gpio;

RaspberryPi - CRubyでLチカ

デバイスファイルを使用した、GPIO制御。

#!/usr/bin/ruby
system('echo "4" > /sys/class/gpio/export')
system('echo "out" > /sys/class/gpio/gpio4/direction')
[0, 1].cycle do |sw|
system("echo #{sw} > /sys/class/gpio/gpio4/value")
sleep(0.5)
end
view raw gpio4.rb hosted with ❤ by GitHub
$ sudo ruby gpio4.rb

RubyでLチカ

RaspberryPi - CRubyとmrubyのインストール

環境

事前に

$ sudo apt-get update
$ sudo apt-get upgrade

を実施済み

gitのインストール

$ sudo apt-get install git-core

CRubyのインストール

$ sudo apt-get install ruby

mrubyのインストール・ビルド

$ git clone git://github.com/mruby/mruby.git
$ sudo apt-get install build-essential bison

mrubyディレクトリ下で

$ make

※先にCRubyを入れていないと途中でエラーになる

環境変数

$ export MRUBY_HOME=(makeしたディレクトリ)  
$ export PATH=$PATH:$MRUBY_HOME/bin  

※.bashrcにも

参考サイト

Building mruby on the Raspberry Pi

Github+Octopressデプロイ

デプロイ前の環境

  • Windows7
  • Ruby Installerの Ruby 1.9.2-p290 インストール済み
  • msysgit 1.7.10 インストール済み
  • GitHubアカウント登録済み

大まかな流れ

  • Ruby DevKitのインストール
  • GitHub-Pageのリポジトリをつくる
  • Octopressをインストール
  • ブログの設定
  • 記事の投稿

手順

Ruby DevKitのインストール

  • 上記のRuby Installerのサイトから、DevKitをダウンロード→実行(解凍)
    ※ダウンロードしたファイルを実行すると、わらわらと沢山のファイルが展開されるので、専用のディレクトリ(C:\DevKitとか)を作成して、そこで実行(解凍)するのがよい。

解凍したディレクトリに移動し下記コマンドを入力

ruby dk.rb init  
ruby dk.rb review  
ruby dk.rb install  

GitHub-Pagesのリポジトリをつくる

リポジトリ作成画面のRepository nameの項目に

アカウント名.github.com  

と、いうリポジトリを作成する

Octopressをインストール

git clone git://github.com/imathis/octopress.git octopress  
cd octopress  
sudo gem install bundler  ← DevKitが無いとエラー  
sudo bundle install  
rake install  

ブログの設定

_config.ymlを編集

とりあえず、title:subtitle:くらい?

記事の投稿

rake generate  
rake deploy  
rake gen_deploy  ← generate と deploy を同時に行う
rake preview  ← localhost:4000でWebサーバ起動

関連情報

Windows環境で _config.ymlファイルや記事ファイルに日本語が含まれていて rake gen_deploy コマンドで

invalid byte sequence in Windows-31J 

とエラーになる場合、環境変数 LANGを設定する。

c:\>set LANG=ja_JP.utf8

みたいに。

参考サイト

Githubを使って独自ブログをはじめる方法メモ
githubとjekyllとoctopressで作る簡単でモダンなブログ
Octopress + Github Pages + Dropbox でブログを構築
Octopressの使い方
DevKitを使わないとgemが入らない場合(pikを使っていてもだいじょうぶ)