2009/02/28

インターフェース誌9月号付録ColdFire基板(6):Nokia6100 LCD表示プログラム

ターゲット上のLCD初期化&表示プログラムです。
init()関数でターゲットおよびLCDを初期化します。
loadimg()関数がLCD表示を行う関数で、付録基板のGDBスタブ領域(0x20000)から一画面分のデータを決めうちで読み出して、LCDへ転送します。

実行例:
OK
init()
Init ColdFire Ports
Init LCD Driver (Philips PCF8833)

OK
loadimg()
Load Image to LCD from 0x20000 (takes long time...)
.....
OK

しかし、この最後のLCDへの転送が非常に遅くて、数十分のオーダの時間が掛かります。コード自体はもう少し最適化できると思いますし、CodeWarriorでユーザドライバというのも考えたのですが、そこまでの気力はありませんでした。
// LCD Display for Interface magazine's ColdFire Board
//
// * Silent-C (very slow...)
// * Nokia 6100 breakout board from Sparkfun electronics
//
// Taipapa

// Pin assignment
// 55 (AN0) <-> #CS (brown)
// 54 (AN1) <-> SCK (green)
// 53 (AN2) <-> DIO (blue)
// 52 (AN3) <-> #RESET (yellow)

char *ispbar = 0x40000000;
char *panpar = 0x4010006a;
char *ddran = 0x40100022;
char *portan = 0x4010000a;

// set signals
sigs(char cs, char sck, char dio, char reset)
{
char v;

v = ((reset<<3) | (dio << 2) | (sck << 1) | cs);
*portan = v;
}

// set signals, assume reset=1 and cs=0
sigs2(char sck, char dio)
{
*portan = (8 + (dio<<2) + (sck<<1));
}

// send 1 byte to LCD
// 0: command, 1: data
send(char cmd, char val)
{
int i;
char bit;

sigs(0, 0, 0, 1);

sigs2(0, cmd);
sigs2(1, cmd);

for(i=0; i<8; i++) {
bit = (val >> (7-i)) & 1;
sigs2(0, bit);
sigs2(1, bit);
}

sigs(1, 0, 0, 1);
}

// Initialization for Philips PCF8833
lcdinit()
{
PrStr("Init LCD Driver (Philips PCF8833)\r\n");

send(0, 0x11); // SLPOUT
send(0, 0x20); // INVON
send(0, 0x3A); // COLMOD
send(1, 0x3);
send(0, 0x36); // MADCTL
send(1, 0xc8);
send(0, 0x25); // SETCON
send(1, 0x30);
send(0, 0x29); // DISPON
}

// Initialization for ColdFire board
sysinit()
{
PrStr("Init ColdFire Ports\r\n");

// AN for digital out
*panpar = 0x0;

// AN for output
*ddran = 0xf;

// #RESET and #CS
sigs(1, 0, 0, 1);
}

init()
{
sysinit();
lcdinit();
}

loadimg()
{
int i;
char *p = 0x20000; // GDB stub area!!

PrStr("Load Image to LCD from 0x20000 (takes long time...)\r\n");

send(0, 0x2b); // PASET
send(1, 0);
send(1, 131);

send(0, 0x2a); // CASET
send(1, 0);
send(1, 131);

send(0, 0x2c); // RAMWR

for(i=0; i<26136; i++) {
if ((i & 0xff) == 0) {
PrStr(".");
}
send(1, *p);
p++;
}

send(0, 0); // NOP
}


以下、132x132のJPEGファイルをLCD転送用に変換する使い捨てスクリプトです。
これにJPEGファイルを食わせると、result.binというバイナリファイルが出来ます。それをCOLDFIRE.BINにリネームしてtftpでボードに転送すると、tftpサーバ側で自動的に0x20000からの領域に転送してくれます(転送後、PrHex(*0x20000)などで確認できます)。

スクリプト自体は、最近別の目的で作ったpythonスクリプトの流用で、ウィンドウを開くわけでもないのにGtkのPixmapを経由して変換を行うという、へなちょこスクリプトです。まあ使えれば良いのさ、ということにしておきます。

#!/usr/bin/env python

# JPEG to xfer format converter for Nokia 6100 LCD

# USAGE: nomia6001img.py jpg-file
# * Jpeg-file must be 132x132 jpeg file.
# * Output file is "result.bin"

import sys
import gobject
import math
try:
import pygtk
pygtk.require("2.0")
except:
pass
try:
import gtk
import gtk.glade
except:
sys.exit(1)

buf = gtk.gdk.pixbuf_new_from_file(sys.argv[1])
x = buf.get_width()
y = buf.get_height()

# Size check
print "x =",x, "y =", y;
if (x!=132 or y!=132):
print "Size mismatch"
exit(1)

# Create pixmap
pix = gtk.gdk.Pixmap(None, x, y, 24)
vis = gtk.gdk.Visual(24, gtk.gdk.VISUAL_TRUE_COLOR);
cm = gtk.gdk.Colormap(vis, False)
pix.set_colormap(cm);

pix.draw_pixbuf(None, buf, 0, 0, 0, 0)

# Output result.bin
img = pix.get_image(0, 0, x, y)
f = open("result.bin", "wb")
for j in xrange(y):
for i in xrange(x/2):
p = img.get_pixel(i*2, j)
col = cm.query_color(p)
print "r1:", col.red, "g1:", col.green, "b1:", col.blue
r1 = col.red >> 12
g1 = col.green >> 12
b1 = col.blue >> 12

p = img.get_pixel(i*2+1, j)
col = cm.query_color(p)
print "r2:", col.red, "g2:", col.green, "b2:", col.blue
r2 = col.red >> 12
g2 = col.green >> 12
b2 = col.blue >> 12

# format is bgr
byte1 = b1 << 4 | g1
byte2 = r1 << 4 | b2
byte3 = g2 << 4 | r2

f.write(chr(byte1))
f.write(chr(byte2))
f.write(chr(byte3))

f.close

インターフェース誌9月号付録ColdFire基板(5):Nokia6100 LCD表示成功

Sparkfunの液晶(Nokia 5100 の)に画像を表示することができました。


以下のような流れになります。他のCPUでも同様になると思います。
  1. 132x132ピクセルの大きさのJPEGファイルを用意する。
  2. Pythonスクリプトで画像データをRGB各4bitに変換。
    LCDへの転送フォーマットはRGB各4ビットを1ピクセルとして、1ピクセル12ビット、2隣接ピクセルで24ビット=3バイトとなります。各色のパッキングはRGBとBRGの二通りありますが、今回はSparkfunの資料に従いBRGにしました。
    なお、Silent-Cは非常に遅いので、ターゲット側でバイト順の変換をかけたりすると酷いことになります。そのままLCDに転送できるフォーマットで保存。それでも、一画面出すのに数十分(!!!!)掛かります。
  3. 変換したバイナリファイルをCOLDFIRE.BINという名前にして転送。すると、0x20000から始まるGDBスタブ領域に自動的に書き込まれる。
  4. Silent-Cのプログラムで、0x20000からの26136バイトを、RAMWRコマンドを使って順次ピクセルデータとして書き込む(26136 = 132*132)

インターフェース誌9月号付録ColdFire基板(4):Nokia6100 LCD接続

インターフェース誌のColdFire付録基板に、以前、Sparkfun Electronicsで購入したカラー液晶ブレークアウトボードLCD-08600を接続してみました。


液晶本体はこんな感じです。


この液晶は、配線を引き出しやすいように0.1インチピッチのコネクタが付いていることを除くと、Color LCD 128x128 Nokia Knock-Offと同じ液晶になっています。ドキュメント類は、ノックオフボードのページに集約されています。

配線は、
  • #CS<->AN0(55番ピン)
  • SCK<->AN1(54番ピン)
  • DIO<->AN2(53番ピン)
  • #RESET<->AN3(52番ピン)
としています。AN0をディジタル出力ピンにする方法は前回のとおりです。

ドキュメントの中の"Interface tutorial by Jim Lynch"が詳しくてお勧め。
これによると、乗っているLCDドライバにはエプソン製とフィリップス製の二種類があって、どちらが乗っているかは一般には判らないとのこと。Webページには「エプソン製が乗っている」と書かれていたので、そのように思い込んでいたのですが、実はフィリップス製でした。エプソン用の初期化手順ではどうやっても画面が出ないので、試しにフィリップス手順を試したら動きました。orz...。

2009/02/25

インターフェース誌9月号付録ColdFire基板(3):LED1実装

いまさらながらのインターフェース誌9月号付録 ColdFire (MCF52233)基板ですが、実装されていないLED1を実装してみました。


マルツで購入した青色の1608のチップLEDです。ちっちゃすぎて一つ吹き飛ばしてしまいました。文字通り息で飛ぶような大きさです。

これまでの最低サイズは3216程度だったので、ちょっと苦労しました。

インターフェース誌9月号付録ColdFire基板(2):GPIO(汎用汎用IO)出力

折角組み立てたので、インターフェースのColdFire付録基板にピンヘッダを付けました。その上で、ちょっと接続したいものがあって、基板の外部ピンを汎用IOとして使うテストをしてみました。


MCF52235(というかColdFireコア)は、ほとんどのすべてピンを汎用IO(GPIO)として設定することができます。MCF52235のマニュアルを参考にしながらテストプログラムを作成しました。
main()
{
char *ispbar = 0x40000000;
long panpar = 0x10006a;
long ddran = 0x100022;
long portan = 0x10000a;

char *p, v, c;

PrStr("Show PANPAR\r\n");
p = ispbar + panpar;
v = *p;
PrHex(v);
PrStr("\r\n");

PrStr("Set and Show DDRAN\r\n");
p = ispbar + ddran;
*p = 0xf;
v = *p;
PrHex(v);
PrStr("\r\n");

PrStr("Write to PORTAN...\r\n");
p = ispbar + portan;
for(c=0;;c+=3) {
*p = c & 0xf;
}
}
ispbarというのはメモリマップドレジスタの先頭アドレスで、今回の基板では0x40000000になっています。

マニュアル中のレジスタの位置などは、大体このレジスタの値へのオフセットとして表記されています。

その次のpanparというのは、ispbarからオフセット0x10006Aにあるレジスタで、ポートANのPAR (Pin Assignment Register)という意味です。今回は、ANポート(アナログ入出力ポート)をIOピンとして使うのですが、panparはリセット後は0になっていますから、何もしなくても汎用ディジタルIOピンとなっています(確認のために読み出しています)。

ちなみに、付録基板に搭載されている3軸加速度センサはAN5、AN6、AN7に接続されています。ad::adinitを実行すると、panparの値が0x70に変化することがわかります。

さて、ANポートを出力ピンにするにはDDRAN(Data Direction Register AN)を使います(オフセット0x100022)。各ビットがAN0~An7の各ポートに対応していて、0の場合にはそのANポートは入力、1だと出力となります。今回下位4ビットを出力で使用するので0xfを書き込みます。

これで書き込みの準備はOKです。最後に、書き出したい値をPORTAN(オフセット0x10000A)に書き込んでやると、任意の値をディジタルIOとして出力することが出来ます。今回は+3しながら値を書き込んでいます。

このプログラムをtftpで基板に転送し、runで実行させると
run
Show PANPAR
00000000
Set and Show DDRAN
0000000f
Write to PORTAN...
となって、PANPAR、DDRANなどのレジスタが期待通りの値になっていることがわかります。


こちらは、カメレオンUSBで計測したAN0~AN4の値です。正しく3ずつ増加しているので、正しく動いているものと思われます。

ループ一回あたり約1m秒掛かっていることが判ります。ちょっと遅い気もしますが、インタプリタだし仕方ないといえば仕方ないかもしれません。

2009/02/24

VMWare ゲスト上のLinux(ubuntu)デバッグ

ここしばらく、VMWareゲスト上の ubuntu(Ubuntu 8.04.2)がストールしてしまうという現象に頻繁に遭遇しています。

ゲストの再起動とかも出来なくなって、Windowsのタスクマネージャから見るとvmware-vmx.exeがCPU100%になっていることが判るので、雰囲気的にはVMWareのバグのようです。

しかし、ひょっとしてゲストOSの問題かも、ということで念のため解析しておくことにしました。この手のストールの場合、まずはsysrqで情報を取る(取れるかどうか確認する)のですが、シリアルコンソール+Named Pipe Proxy経由という構成だと、どうもBreak信号がうまく飛んでくれないようです。Magic Sysrqは、シリアルコンソールからだと「Break信号+コマンド文字」になります。

仕方なく、じゃあNMIで止めてみるかと思ったのですが、VMWareからはNMIを入れることも出来ないようです。こちらも諦めて駄目モトでnmi-watchdogを有効にしてみたところ、NMIそのものはきちんと入っているようです。ついでに、kdumpも入れて様子を見ることにしました。

# cat /boot/grub/menu.list
:
kernel /boot/vmlinuz-2.6.24-22-generic root=.... ro nmi_watchdog=1 crashkernel=64M@16M
:

# cat /proc/interrupts
:
16: 45 0 IO-APIC-fasteoi uhci_hcd:usb1, Ensoniq AudioPCI
17: 45 1 IO-APIC-fasteoi ioc0
18: 110 514 IO-APIC-fasteoi eth0
NMI: 235702 235650 Non-maskable interrupts
LOC: 0 235513 Local timer interrupts
RES: 2804 3013 Rescheduling interrupts
さて無事に釣れるでしょうか...。

ちなみに、kdumpは2ndカーネルが上がりませんでした。ATAの認識が出来ずにエラーになってしまいます。まあ、そこまでくれば何か起きたんだということは判るので、とりあえずそのままにしています。

2009/02/21

インターフェース誌9月号付録ColdFire基板(1)

若松通商でパルストランス付きのRJ-45コネクタと3.3VのACアダプタ他を購入しましたが、その目的は(言うまでもない感じですが)今更ながらに、インターフェース誌9月号付録のColdFire基板(ethernet付き)で遊ぶことです。
MCF52233というColdFire(68000の互換アーキテクチャのプロセッサ)が載っています。


本当は、死蔵しているenc28J60を何とかしないといけないのですが...。

付属基板ですが、基板にDCジャックとRJ-45コネクタをつなぐだけで、あっさり通信できるようになります。httpでつないだり、telnetでつないだりとアクセス方法が色々あります。

ROMにはSilent-CというC言語風?インタプリタとgdbのスタブが入っているようです。Webページをちらちら見ると、ちょっと遊ぶだけならSilent-Cでやるのがよさそうです。ソケット通信のレベルであれば、組み込みの関数を使って簡単に書けそうです。
ただ、新しく独自言語を覚えるというのは出来れば避けたいので、CodeWarriorで直にハードを叩くようなことも考えようと思います。

電子工作ショップ

新しくWeb上で見つけたショップです(もう部品は買わずに、すでに買ったものを作れ、という声が聞こえますが...)。

SpeedStudio

品揃えの雰囲気はSparkfunに似ています。

2009/02/20

若松通商でお買い物

若松通商のウェブ通販サイトでお買い物をしました。
  • パルストランス内蔵のRJ-45コネクタ
  • 3.3V出力のACアダプタとDCジャック
出社前に購入ボタンを押して、その日の夜には連絡があり、翌日の夜には到着しましたから充分なレスポンスと言えます。

こんな梱包で来ました。
ゆうぱっくというと小包という印象が強いのですが、封筒形式でした。中身が中身なので問題なく、適切な選択。

アプリケーションのバックトレース (execinfo)

ちょっと必要があって、実行中のアプリケーションプログラムから、特定の走行箇所でのバックトレースを取る方法が必要になって調べましたので、備忘録。

カーネル内であれば、show_stack()を呼び出すことで走行時のスタックトレースを簡単に得ることが出来ますが、アプリケーションプログラムでもexecinfoを使うと同様のことが出来ます。

具体的には、
  1. backtrace()関数でスタック情報を取得します。
    スタック情報はvoidのポインタへの配列として用意します。この配列の大きさが、取得できるスタックの深さ(ネスト)の最大値を規定することになります。backtrace()関数の戻り値が実際に取得したスタックの深さになります。
    void *trace[100];
    nr = backtrace(trace, 100);
  2. backtrace_symbol()関数で、取得したスタック情報をシンボル化します。
    char **ents;
    ents = backtrace_symbols(trace, nr);
  3. 取得したスタック情報を表示
      for(i=0; i<nr; i++) {
    printf("#%d : [%s]\n", i, ents[i]);
    }
  4. 後始末(シンボル配列の開放)
    backtrace_symbols()関数はchar *の配列を返却しますが、この配列はbacktrace_symbols()関数が内部的にmalloc(3)で確保したものなので、最後にfreeしてあげる必要があります。
以下にサンプルコードと実行例を乗せておきます。


#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>

#define MAXFRAME 64
void show_stack(void)
{
int i, nr;
void *trace[MAXFRAME];
char **ents;

nr = backtrace(trace, MAXFRAME);

if (nr>=MAXFRAME) {
printf("Stack too deep, some entries are stripped off\n");
}

ents = backtrace_symbols(trace, nr);
if (ents == NULL) {
perror("backtrace_symbols");
exit(1);
}

for(i=0; i<nr; i++) {
printf("#%d : [%s]\n", i, ents[i]);
}

free(ents);
}

void b(void)
{
show_stack();
}

void a(void)
{
b();
}

main()
{
a();
}

実行例です。正しくスタック情報が取れていることが判ります。
# cc execinfo.c -o execinfo
# ./execinfo
#0 : [./execinfo(show_stack+0x1f) [0x8048743]]
#1 : [./execinfo(b+0xb) [0x80487dd]]
#2 : [./execinfo(a+0xb) [0x80487ea]]
#3 : [./execinfo(main+0x16) [0x8048802]]
#4 : [/lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe0) [0xb7e6b450]]
#5 : [./execinfo [0x80486c1]]

なお、エクスポートしていないシンボルは当然ながら表示されないので、確実に表示したい場合には ld に -rdynamic オプションを付与しなければなりません。

2009/02/18

avast!安定中

先日導入したウィルス対策ソフトavast!ですが、安定して動いています。
Windows7にも入れていますが、特に悪さはしていないようです。

まあ、検知率とか本当は気にしないといけないファクターはあるのでしょうけど、所詮は非機能要件なので、パーソナルユースだとほとんど気にしなくなってしまいますね。そういう状態で一人がタダと言い出すと厳しい。マスマーケットは厳しそうですね。バグだし用か宣伝用にしかなりませんね。

2009/02/14

DirectXプログラミング(1)

以前に買った書籍に追加して、別のDirectXの本を買い求めました。こちらは影の扱いが充実しています。DirectXはいろいろプログラミングしていますが、中々綺麗な絵になりません。難しいですね。



後、静電気防止袋も。これは作った基盤などを入れるのに使います。

2009/02/11

アマゾンで購入できる電子部品

アマゾンをつらつらと見ていたら、デンシ電気店という出品者さんがいて、セラミックコンデンサーセットとか抵抗セットなどをお手ごろな値段で売っていることに気づきました(気づいただけで買っていません)。








この手のセットをまじめに買い求めようとすると、大体福沢さん数枚コースになってしまいますから、それに比べると野口さんコースということで、アマチュアでも使いやすいのではないでしょうか(そのかわりにこちらは含まれている部品の点数も少なそうなのですが、プロではないので沢山あってもどうせ使い切れませんし)

ウィルス対策ソフト

関わっているプロジェクトが火を吹いていて、中々時間が取れません。
大体、S-inしてからこんな状態で本当に大丈夫だろうかと心配です。


さて、これまでトレンドマイクロのウィルスバスターを使っていたのですが、今月、ライセンスが失効するのを契機にフリーのアンチウィルスソフトに乗り換えることにしました。

乗り換え先はAvast!というソフトで、個人用途であれば無償で使用できます。
無償のウィルスソフトというと機能制限が多そうですが、ざっと使った限りだとオンラインスキャンや定期スキャンなど一通りの機能はあるようです。そもそもあまりウィルスソフトの機能を使い倒そうという気はないので、無償版で十分です。

個人に対してはプロモーションとバグチェッカーも兼ねてタダで出す、という戦略なのでしょうね。