2014年12月19日金曜日

edison にvnc(debian 成功)してarduino ide

yoctoでは上手くいかないので、以前に試したdebian で進める。
以下の順番でapt-get install
xvfb (何度か試したがこれやらないと上手く動かなかった)
x11vnc
fluxbox
tightvncserver

$ tightvncserver で起動して、パスワード設定
<http://qiita.com/ryunosinfx@github/items/ad1956eafc6a94477897>

~/.vnc/xstartup
#!/bin/sh

xrdb $HOME/.Xresources
xsetroot -solid grey
#x-terminal-emulator -geometry 80x24+10+10 -ls -title "$VNCDESKTOP Desktop" &
#x-window-manager &
# Fix to make GNOME work
export XKL_XMODMAP_DISABLE=1
#/etc/X11/Xsession
amule &
fluxbox &


自動起動の設定は
/etc/init.d/tightvncserver

#!/bin/sh
### BEGIN INIT INFO
# Provides:          tightvncserver
# Required-Start:    $local_fs
# Required-Stop:     $local_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start/stop tightvncserver
### END INIT INFO

# More details see: 
# http://www.penguintutor.com/linux/tightvnc

### Customize this entry
# Set the USER variable to the name of the user to start tightvncserver under
export USER='edison'
### End customization required

eval cd ~$USER

case "$1" in
  start)
    su $USER -c '/usr/bin/tightvncserver :1'
    echo "Starting TightVNC server for $USER "
    ;;
  stop)
    pkill Xtightvnc
    echo "Tightvncserver stopped"
    ;;
  *)
    echo "Usage: /etc/init.d/tightvncserver {start|stop}"
    exit 1
    ;;
esac

exit 0


(中身はクグル)
<http://www.penguintutor.com/linux/tightvnc>
を作って、
# update-rc.d tightvncserver defaults

apt-get install iceweasel
でブラウザ入れる

ブラウザの日本語は豆腐になるので、
apt-get install ttf-takao*
で日本語表示OK

javaはOracleからバイナリを落として
/usr/local/javaに展開して
# ln -s /usr/local/java/jre..../bin/java /usr/bin/java

Arduino IDE 1.0.6も落としてきて、展開。
xtermから起動すると無事動きました!

2014年12月9日火曜日

edisonにvnc(yocto失敗中)

http://packages.yoctoproject.org

edsison-src/device-software/meta-edison-distro/conf/distro/pockey-edison.conf
DISTRO_DISTRP_FEATURES
に、x11を追加

bitbake x11vnc

http://www.yoctoproject.org/docs/current/dev-manual/dev-manual.html#usingpoky-extend-addpkg

edison-src/build/local.conf
IMAGE_INSTALL_append=" x11vnc"

UVCもついでにいれて、
ルートも1GBに拡張できました。
<http://research.itplants.com/?p=774>
を参考にしましたが、
edison.envの方は1024MiB
edison-image.bbの方は1048576
(1024 x 1024)
こうしないとedisonが起動失敗しました。

でもウインドウマネージャーが、入っていませんでした。

まだまだ先は長い。
matchboxに挑戦!?

マッチボックスはyicyoのパッケージにあるので問題ないのですが、
どうやらXbfbがインストールされてないようです。

いろいろ調べても方法がわかりません。
xorg-xserver.incのなかでは--enable-xbvfされているようです。

駄目元で、最初からやり直してみるか?

2014年12月8日月曜日

edisonのyocto bitmake

/のサイズを、変更できるらしいし、
http://research.itplants.com/?p=774
vncserverを追加したいのでbitbakeに、とらいしてみる。

mac book 2009(core2 duo)のparallels の上のubuntuではカナリツライ。。。

おまけに途中でこけた。(原因不明)
強制リセットしたが、bitbakeが失敗して進まない。
stampディレクトリーに進捗情報があるので、失敗するgettext ディレクトリーを削除して復活!

続く。

2014年11月29日土曜日

Intel Edisonでdebian

すかポーンとEdison breakout boardを買ってしまったわけですが、使い道が。。。

今はArduinoに取り組み中。

webをさまよっているとdebianが入るらしい。
おまけにvncを動かした人もいる。
<http://linyi-zatta.blogspot.jp/2014/11/edison-on-debian.html?m=1>

BBBの代わりにいいじゃん。
Wi-Fiついてるし。

でも一つ問題。
USBにArduinoを繋ぐとedisonに給電出来ません(-。-;

→http://www.amazon.co.jp/gp/aw/d/B00C0M5SFS/ref=pd_aw_sbs_computers_3?refRID=1EN8PMQ0FE3B1Z73A7JC

前に買ったこれでなんとかなるかな?

debian化して
vncは
http://qiita.com/ryunosinfx@github/items/ad1956eafc6a94477897
を参考にインストール。

自動起動は
http://d.hatena.ne.jp/lycoris_blog/touch/20130217/1361114310

2014.12.5 追記
USB OTGケーブルで電源供給とArudino接続したがにんしきしなかった。(-。-;
ケーブルか?ハードか?ソフトか?

-> breakout boardの説明をちゃんと読むと、vbusの電圧でhostにつながっているか判断している模様。
jp21とかから給電するしかないか。。
USBバッテリー使いたいが。
 5V_SYSに入れればいいのはわかっているが、パッドがない。ダイオードのパッドに繋ぐ?

3.3V作ってVSYSに入れたほうがいいかな。

あと、apt-get install rfkillしてrfkill unblock blutoothしたけどhci0は見えない。

2014年11月26日水曜日

BBBでArudino IDE

構想。

eMMCにdebianを入れて、
Arduino IDEを入れる。

VNCサーバーを立ち上げて
VNC Viewer for iOSでリモートアクセス。

bluetooth keyboardもあるといい。

2014年11月1日土曜日

Arduinoで遊ぼう(8) モーター制御

世の中的には普通でしょうが、
どうしましょうか。

前にXBeeか制御した時はTB6612FNGを使ったのですが、XBeeのPWMの周波数が15.6kHzのせいかはわかりませんが、うまく速度制御できず、PWMをinhibitにいれてやりました。
モーターのせいかもしれません。

今回は、スイッチサイエンスのDRV8835を使うのでどうなるか?

ArduinoのanalogWrite()でのPWMは約490Hz。

周波数の変更は
http://theoriesblog.blogspot.jp/2014/05/arduino-pwm.html?m=1
が参考になります。

使おうとしているのはD6,D9。
pins_arduino.hによるとD9,D10が
OC1A,OC1Bで同じ周波数になるので良さそう。
pro micro 3.3Vは8MHzなので245Hzかな。

単純にanalogWrite()で問題なく制御できました。
DRV8835はmodeを1にして制御。


2014年10月30日木曜日

Arduino で遊ぼう(7) static constは、、、

Arduinoはstatic const で宣言してもramを使うことを初めて知った!
http://www.cloverfield.jp/2014/05/06/603

そりゃ、Htmlを長くするとメモリー足らなくなりますね。

ここに分かりやす解説がありました。
https://learn.adafruit.com/memories-of-an-arduino/you-know-you-have-a-memory-problem-when-dot-dot-dot

とりあえずF()マクロで100バイトくらい節約!

次はPROGMEMの登場。

コンテンツはフラッシュにおけるようになりバッファに余裕ができました。

これでコンテンツに安心してjavascriptを追加できます。

Arduino で遊ぼう(6) ネットワークカメラ

Pro Micro 3.3V + XBee WiFi + C1098-SS
でネットワークカメラになりました。

でも、RAMが辛いのかHTMLを少し長くしたりするとうまく動かなくなる。

カメラのライブラリのチューニングが必要かな。

とりあえず、今のスケッチ

〜〜〜〜〜〜

#include <SPI.h>
#include <CameraC1098.h>

/*
 XBee WiFi Connected Serial.
 XBee works in API Mode.

 Receive Serial and Parse API packet,
 then echo back by API packet.
 */
/**
 * 送信パケットの生成
 */
int makeXBeeApiSendIp(byte* pPacket, unsigned short u16Size, byte* pbIpAddrDst,
byte* pbPortDst, byte* pbPayload, word length) {
if (u16Size < length + 16) {
Serial.println("buffer too short");
return -1;
}

// パケット生成
pPacket[0] = 0x7E;
// length
u16Size = length + 12;
pPacket[1] = u16Size >> 8;
pPacket[2] = u16Size & 0x00FF;
// API Cmd
pPacket[3] = 0x20;
// FrameID
pPacket[4] = 0x00;
// IpAddrDst
pPacket[5] = pbIpAddrDst[0];
pPacket[6] = pbIpAddrDst[1];
pPacket[7] = pbIpAddrDst[2];
pPacket[8] = pbIpAddrDst[3];
// PortDst
pPacket[9] = pbPortDst[0];
pPacket[10] = pbPortDst[1];
// PortSrc
pPacket[11] = 0x26;
pPacket[12] = 0x16;
// Protocol
pPacket[13] = 0x01; //< TCP
// Transmit Options
// pPacket[14] = 0x00; //< Leave Socket open
pPacket[14] = 0x02; //< Terminate Socket after tx complete

// Payload
for (int i = 0; i < length; i++) {
pPacket[15 + i] = pbPayload[i];
}
// チェックサム計算
byte sum = 0;
for (int i = 0; i < length + 12; i++) {
sum += pPacket[3 + i];
}
pPacket[length + 15] = 0xFF - sum;

return length + 16;
}

/**
 * 受信パケットのダンプ
 */
void printPayload(byte* pPayload, word length) {
if (0 < length) {
// Serial.println("dump");
for (word i = 0; i < length; i++) {
// Serial.print(pPayload[i], HEX);
// Serial.print(",");
Serial.print((char) pPayload[i]);
}
// Serial.println();
}
}

/**
 * 受信パケットのパース
 */
byte g_pbIpAddrSrc[4];
byte g_pbPortSrc[2];
byte* g_pbPayload;
int parseXBeeApiReceiveIp(byte* pPacket, unsigned short u16Size,
byte* pbIpAddrSrc, byte* pbPortSrc, byte** ppbPayload) {
// APIコード確認
if (0xB0 != pPacket[3]) {
// Serial.print("wrong api code:");
// Serial.println(pPacket[3]);
return -1;
}
// 送信元IPアドレス取得
pbIpAddrSrc[0] = pPacket[4];
pbIpAddrSrc[1] = pPacket[5];
pbIpAddrSrc[2] = pPacket[6];
pbIpAddrSrc[3] = pPacket[7];
//        Serial.write(pbIpAddrSrc, 4);
//        Serial.println();
// 送信元ポート取得
pbPortSrc[0] = pPacket[10];
pbPortSrc[1] = pPacket[11];
//        Serial.write(pbPortSrc, 2);
//        Serial.println();
// ペイロード取得
*ppbPayload = &pPacket[14];

//        Serial.println(pPacket[1]);
//        Serial.println(pPacket[2]);

return ((int) pPacket[1] << 8) + (int) pPacket[2] - 11;
}

/**
 * 受信処理
 */
#define RECEIVE_IP 1
unsigned char u8ReceiveMode = 0;
#define RECEIVE_MODE_IDLE 0
#define RECEIVE_MODE_LEN1 1
#define RECEIVE_MODE_LEN2 2
#define RECEIVE_MODE_DATA 3
#define RECEIVE_MODE_CS 4
#define APIPACKET_SIZE_MAX 512
byte g_pu8ApiPacket[APIPACKET_SIZE_MAX];
unsigned short g_u16ApiPacketSize;
unsigned short g_u16ApiPacketLength;
int parseXBeeApiChar(byte data) {
// Serial.println(data, HEX);

switch (u8ReceiveMode) {
case RECEIVE_MODE_IDLE:
// wait for "0x7E"
if (0x7E == data) {
g_u16ApiPacketSize = 0;
g_u16ApiPacketLength = 0;
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
u8ReceiveMode = RECEIVE_MODE_LEN1;
// Serial.println("api start");
}
break;
case RECEIVE_MODE_LEN1:
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
u8ReceiveMode = RECEIVE_MODE_LEN2;
break;
case RECEIVE_MODE_LEN2:
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
u8ReceiveMode = RECEIVE_MODE_DATA;
g_u16ApiPacketLength = ((unsigned short) g_pu8ApiPacket[1] << 8)
+ (unsigned short) g_pu8ApiPacket[2];
// Serial.print("get len :");
// Serial.println(g_u16ApiPacketLength);
if (g_u16ApiPacketLength > (APIPACKET_SIZE_MAX - 4)) {
Serial.println("invalid data len");
u8ReceiveMode = RECEIVE_MODE_IDLE;
}
break;
case RECEIVE_MODE_DATA:
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
if ((g_u16ApiPacketSize - 3) >= g_u16ApiPacketLength) {
u8ReceiveMode = RECEIVE_MODE_CS;
// Serial.println("get data");
}
break;
case RECEIVE_MODE_CS:
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
u8ReceiveMode = RECEIVE_MODE_IDLE;
// Serial.println("get cs");
return RECEIVE_IP;
break;
default:
break;
}
return 0;
}

/**
 * SPI制御
 */
byte XBEE_SPI_ATTEN = 4;
byte XBEE_SPI_CS = 5;
/**
 * SPI初期化
 */
void spiInit() {
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV4); //< 8MHz/4=2MHz
SPI.begin();

// XBee SPI ATTEN
pinMode(XBEE_SPI_ATTEN, INPUT);

// XBee SPI CS
pinMode(XBEE_SPI_CS, OUTPUT);
digitalWrite(XBEE_SPI_CS, HIGH);

}

/**
 * SPI受信
 * @note 受信のみ
 */
int spiReceive() {
int len = 0;
if (LOW == digitalRead(XBEE_SPI_ATTEN)) {
digitalWrite(XBEE_SPI_CS, LOW);
if (RECEIVE_IP == parseXBeeApiChar(SPI.transfer(0x00))) {
len = parseXBeeApiReceiveIp(g_pu8ApiPacket, g_u16ApiPacketSize,
g_pbIpAddrSrc, g_pbPortSrc, &g_pbPayload);
Serial.print("[receive ip packet:");
Serial.print(len);
Serial.print("]");
Serial.println();
printPayload(g_pbPayload, len);
}

if (HIGH == digitalRead(XBEE_SPI_ATTEN)) {
digitalWrite(XBEE_SPI_CS, HIGH);
}
}

return len;
}

/**
 * SPI送信
 * TODO 送信中の受信処理
 */
void spiSend(byte* pData, word length) {
digitalWrite(XBEE_SPI_CS, LOW);
for (int i = 0; i < length; i++) {
SPI.transfer(pData[i]);
}
digitalWrite(XBEE_SPI_CS, HIGH);
}

static const char gsc_pcHtmlHeader[] = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Connection: close\r\n"
"Content-Length: ";
#define USE_JAVASCRIPT
#ifdef USE_JAVASCRIPT
static const char gsc_pcHtmlContents1[] =
"<html>"
"<head>"
"<script type=\"text/javascript\">\r\n"
"myImage = new Image();\r\n"
"count = 0;\r\n"
"function loadImage(url) {\r\n"
"myImage.onload = function(){\r\n"
"loadImage(url);\r\n"
"document.getElementById(\"img_mine\").src = myImage.src;\r\n"
;
static const char gsc_pcHtmlContents2[] =
"}\r\n"
"myImage.src = url + \"?\" + count.toString();\r\n"
"count++;\r\n"
"}\r\n"
"</script>"
"</head>\r\n"
"<body>"
//"<h1>hello world</h1>"
//"message from Arduino<br/>"
"pro micro 3.3V<br/>"
//"with XBee WiFi<br/>"
;
static const char gsc_pcHtmlContents3[] =
//"connected by SPI<br>"
//"<address>su4yamamoto</address>"
"<br/>"
"<img id=\"img_mine\"/>\r\n"
"<script type=\"text/javascript\">\r\n"
"loadImage(\"img.jpg\");\r\n"
"</script>\r\n"
"</body>"
"</html>"
;
#else // #ifdef USE_JAVASCRIPT
static const char gsc_pcHtmlContents1[] =
"<html>"
"<head>"
"<meta http-equiv=\"Refresh\" content=\"5\">"
"</head>"
"<body>"
"<h1>hello world</h1>"
"message from Arduino<br/>"
"pro micro 3.3V<br/>"
"with XBee WiFi<br/>"
"connected by SPI<br>"
"<address>su4yamamoto</address>"
"<br/>"
"<img src='img.jpg'/>"
"</body>"
"</html>";
#endif // #ifdef USE_JAVASCRIPT
static const char gsc_pcHtmlHeaderJpeg[] = "HTTP/1.1 200 OK\r\n"
"Content-Type: image/jpeg\r\n"
"Connection: close\r\n"
"Content-Length: ";
static const char gsc_pcHtmlLineFeed[] = "\r\n\r\n";
static const char gsc_pcHtmlNotFound[] = "HTTP/1.1 404 Not Found\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 9\r\n"
"\r\n"
"Not Found\r\n";

CameraC1098 camera(&Serial1);
uint32_t pictureSizeCount = 0;
/**
 * This callback is called EVERY time a JPEG data packet is received.
 */
void getJPEGPicture_callback(uint32_t pictureSize, uint32_t packageSize,
uint16_t packageCount, byte* package) {
if (0 == pictureSizeCount) {
Serial.println();
Serial.print("jpeg size:");
Serial.println(pictureSize);
#ifndef HTML_HELLOWORLD
// first time -> send size info
char pcLength[16];
String strLength = String(pictureSize, DEC);
strLength.toCharArray(pcLength, sizeof(pcLength));
spiSend(g_pu8ApiPacket,
makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX,
g_pbIpAddrSrc, g_pbPortSrc, (byte*) pcLength,
strLength.length()));
spiSend(g_pu8ApiPacket,
makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX,
g_pbIpAddrSrc, g_pbPortSrc, (byte*) gsc_pcHtmlLineFeed,
sizeof(gsc_pcHtmlLineFeed) - 1));
#endif
}
// packageSize is the size of the picture part of the package
pictureSizeCount += packageSize;

// Serial.write(package, packageSize);
Serial.print(packageSize);
Serial.print(":");
Serial.println(pictureSizeCount);
#ifndef HTML_HELLOWORLD
spiSend(g_pu8ApiPacket,
makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX, g_pbIpAddrSrc,
g_pbPortSrc, package, packageSize));
#endif//#ifdef HTML_HELLOWORLD
if (pictureSizeCount >= pictureSize) {
spiSend(g_pu8ApiPacket,
makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX,
g_pbIpAddrSrc, g_pbPortSrc, (byte*) gsc_pcHtmlLineFeed,
sizeof(gsc_pcHtmlLineFeed) - 1));
Serial.flush();
Serial.println();
Serial.println("finished");
}
}
void getJpegImage() {

if (!camera.sync(CameraC1098::BAUD57600)) {
Serial.println("Sync failed");
return;
}

if (!camera.initial(CameraC1098::BAUD57600, CameraC1098::JR_320x240)) {
Serial.println("Initial failed");
return;
}
if (!camera.setPackageSize(64)) {
Serial.println("Package size failed.");
return;
}

if (!camera.snapshot()) {
Serial.println("Snapshot failed.");
return;
}

pictureSizeCount = 0;
if (!camera.getJPEGPicture(PROCESS_DELAY, &getJPEGPicture_callback)) {
Serial.println("Get JPEG failed.");
return;
}
}

byte toggle = 0;
void setup() {
// SPIの初期設定
spiInit();

Serial.begin(115200); //This pipes to the serial monitor
Serial1.begin(14400);
}
void loop() {
int len = spiReceive();

if (0 < len) {
// html reply
// Check Request
String strReq = String((char*) g_pbPayload);
                if (strReq.startsWith("GET /index.html")) {
spiSend(g_pu8ApiPacket,
makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX,
g_pbIpAddrSrc, g_pbPortSrc,
(byte*) gsc_pcHtmlHeader,
sizeof(gsc_pcHtmlHeader) - 1));
char pcLength[16];
#ifdef USE_JAVASCRIPT
String strLength = String(
                                          sizeof(gsc_pcHtmlContents1) - 1
                                            + sizeof(gsc_pcHtmlContents2) - 1
                                            + sizeof(gsc_pcHtmlContents3) - 1
                                            , DEC);
#else //#ifdef USE_JAVASCRIPT
String strLength = String(sizeof(gsc_pcHtmlContents1) - 1, DEC);
#endif //#ifdef USE_JAVASCRIPT
strLength.toCharArray(pcLength, sizeof(pcLength));
spiSend(g_pu8ApiPacket,
makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX,
g_pbIpAddrSrc, g_pbPortSrc, (byte*) pcLength,
strLength.length()));
spiSend(g_pu8ApiPacket,
makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX,
g_pbIpAddrSrc, g_pbPortSrc, (byte*) gsc_pcHtmlLineFeed,
sizeof(gsc_pcHtmlLineFeed) - 1));
spiSend(g_pu8ApiPacket,
makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX,
g_pbIpAddrSrc, g_pbPortSrc, (byte*) gsc_pcHtmlContents1,
sizeof(gsc_pcHtmlContents1) - 1));
#ifdef USE_JAVASCRIPT
spiSend(g_pu8ApiPacket,
makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX,
g_pbIpAddrSrc, g_pbPortSrc, (byte*) gsc_pcHtmlContents2,
sizeof(gsc_pcHtmlContents2) - 1));
spiSend(g_pu8ApiPacket,
makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX,
g_pbIpAddrSrc, g_pbPortSrc, (byte*) gsc_pcHtmlContents3,
sizeof(gsc_pcHtmlContents3) - 1));
#endif//#ifdef USE_JAVASCRIPT
spiSend(g_pu8ApiPacket,
makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX,
g_pbIpAddrSrc, g_pbPortSrc, (byte*) gsc_pcHtmlLineFeed,
sizeof(gsc_pcHtmlLineFeed) - 1));
                }
else if (strReq.startsWith("GET /img.jpg")) {
spiSend(g_pu8ApiPacket,
makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX,
g_pbIpAddrSrc, g_pbPortSrc,
(byte*) gsc_pcHtmlHeaderJpeg,
sizeof(gsc_pcHtmlHeaderJpeg) - 1));
getJpegImage();
} else {
Serial.println("invalid http request");
spiSend(g_pu8ApiPacket,
makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX,
g_pbIpAddrSrc, g_pbPortSrc,
(byte*) gsc_pcHtmlNotFound,
sizeof(gsc_pcHtmlNotFound) - 1));
return;
}

}

#ifndef HTML_HELLOWORLD
if (0 < Serial.available()) {
while (-1 != Serial.read())
;
getJpegImage();
}
#endif
}

2014年10月29日水曜日

Arduino で遊ぼう(5) シリアルJPEGカメラをつなぐ

ふ 以前に買っていたシリアルjpegカメラをつなげます。

http://arms22.blog91.fc2.com/blog-entry-261.html
にArduinoのサンプルがあったので利用させていただきました。

C1098むけに若干の修正とハードシリアルに変更させていただきました。

※最初、pro microの容量が足らないのかうまくうごきませんでした。
電源別にしてうまく動きました。
http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Dev/Arduino/Boards/Pro_Micro_v13.pdf
によると500mAは供給出来るはずなので大丈夫そうなんですが。。。

2014/10/30 追記
よくしらべるとプレップボードでの接触不良でした。

2014年10月24日金曜日

Arduino て遊ぼう(4) SPIでXBeeとつなぐ

すシリアルでつなげたものを、SPIに移植します。

結線は
xbee             ----     Pro Micro
(slave)                       (master)
18 SPI CLK  <--- 15 SPI CLK
17 SPI SLAVE 
    #SELECT <--- 5 digital out
19 SPI SLAVE 
    #ATTEN    ---> 4 digital in
     * use interrupt 
11 SPI MOSI <--- 16 SPI MOSI
4 SPI MISO   ---> 14 SPI MISO

xbeeはDout(2)をlowに落として、強制的にSPIモードにしておきます。

Arduino は
まずは、受信処理のみ。
ATTENがlowになったらCSを落として一通り受信します。
受信完了でパケット処理します。
(SPIは高速なので先に受信してしまうことにします)

そしてエコーバック。本当は、送信中もATTENを見てやらないといけませんが、、それはまた次回。

エコーバックはうまくいったので、
定型のHTMLを返すようして
簡易webサーバーの出来上がり(^^)

Arduino で遊ぼう(3) XBeeとシリアル接続してAPIモード

Arduino とXBee wifiをシリアルで接続して、APIモードで動かしました。

XBee wifiにはtelnetで接続すると、
受信パケットをエコーバックします。

シリアルのボーレートは57600bpsまでしかうごきませんでした。

とりあえずのコード
(汚い…、。)

/*
 XBee WiFi Connected Serial.
 XBee works in API Mode.

 Receie Serial and Parse API packet,
 then echo back by API packet.
 */

/**
 * 送信パケットの生成
 */
int makeXBeeApiSendIp(byte* pPacket, unsigned short u16Size,
byte* pbIpAddrDst, byte* pbPortDst, byte* pbPayload, word length)
{
if(u16Size < length + 16)
{
Serial.println("buffer too short");
return -1;
}

// パケット生成
pPacket[0] = 0x7E;
// length
        u16Size = length + 12;
pPacket[1] = u16Size >> 8;
pPacket[2] = u16Size & 0x00FF;
// API Cmd
pPacket[3] = 0x20;
// FrameID
pPacket[4] = 0x00;
// IpAddrDst
pPacket[5] = pbIpAddrDst[0];
pPacket[6] = pbIpAddrDst[1];
pPacket[7] = pbIpAddrDst[2];
pPacket[8] = pbIpAddrDst[3];
// PortDst
pPacket[9] = pbPortDst[0];
pPacket[10] = pbPortDst[1];
// PortSrc
pPacket[11] = 0x26;
pPacket[12] = 0x16;
// Packet Type
pPacket[13] = 0x01; //< TCP, Connection Keep
//
pPacket[14] = 0x00;
// Payload
for(int i=0; i<length; i++)
{
pPacket[15 + i] = pbPayload[i];
}
// チェックサム計算
byte sum = 0;
for(int i=0; i<length + 12; i++)
{
sum += pPacket[3 + i];
}
pPacket[length + 15] = 0xFF - sum;

return length + 16;
}

/**
 * 受信パケットのダンプ
 */
void printPayload(byte* pPayload, word length)
{
  if(0 < length)
  {
    Serial.println("dump");
for(word i = 0; i<length; i++)
{
Serial.print(pPayload[i], HEX);
Serial.print(",");
}
        Serial.println();
  }
}

/**
 * 受信パケットのパース
 */
byte g_pbIpAddrSrc[4];
byte g_pbPortSrc[2];
byte* g_pbPayload;
int parseXBeeApiReceiveIp(byte* pPacket, unsigned short u16Size,
byte* pbIpAddrSrc, byte* pbPortSrc, byte** ppbPayload) {
// APIコード確認
if (0xB0 != pPacket[3]) {
// Serial.print("wrong api code:");
// Serial.println(pPacket[3]);
return -1;
}
// 送信元IPアドレス取得
pbIpAddrSrc[0] = pPacket[4];
pbIpAddrSrc[1] = pPacket[5];
pbIpAddrSrc[2] = pPacket[6];
pbIpAddrSrc[3] = pPacket[7];
//        Serial.write(pbIpAddrSrc, 4);
//        Serial.println();
// 送信元ポート取得
pbPortSrc[0] = pPacket[10];
pbPortSrc[1] = pPacket[11];
//        Serial.write(pbPortSrc, 2);
//        Serial.println();
// ペイロード取得
*ppbPayload = &pPacket[14];

//        Serial.println(pPacket[1]);
//        Serial.println(pPacket[2]);

return ((int) pPacket[1] << 8) + (int) pPacket[2] - 11;
}

/**
 * 受信処理
 */
#define RECEIVE_IP 1
unsigned char u8ReceiveMode = 0;
#define RECEIVE_MODE_IDLE 0
#define RECEIVE_MODE_LEN1 1
#define RECEIVE_MODE_LEN2 2
#define RECEIVE_MODE_DATA 3
#define RECEIVE_MODE_CS 4
#define APIPACKET_SIZE_MAX 1024
byte g_pu8ApiPacket[APIPACKET_SIZE_MAX];
unsigned short g_u16ApiPacketSize;
unsigned short g_u16ApiPacketLength;
int parseChar(byte data) {
// Serial.println(data, HEX);

switch (u8ReceiveMode) {
case RECEIVE_MODE_IDLE:
// wait for "0x7E"
if (0x7E == data) {
g_u16ApiPacketSize = 0;
g_u16ApiPacketLength = 0;
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
u8ReceiveMode = RECEIVE_MODE_LEN1;
// Serial.println("api start");
}
break;
case RECEIVE_MODE_LEN1:
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
u8ReceiveMode = RECEIVE_MODE_LEN2;
break;
case RECEIVE_MODE_LEN2:
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
u8ReceiveMode = RECEIVE_MODE_DATA;
g_u16ApiPacketLength = ((unsigned short) g_pu8ApiPacket[1] << 8)
+ (unsigned short) g_pu8ApiPacket[2];
// Serial.print("get len :");
// Serial.println(g_u16ApiPacketLength);
if (g_u16ApiPacketLength > (APIPACKET_SIZE_MAX - 4)) {
Serial.println("invalid data len");
u8ReceiveMode = RECEIVE_MODE_IDLE;
}
break;
case RECEIVE_MODE_DATA:
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
if ((g_u16ApiPacketSize - 3) >= g_u16ApiPacketLength) {
u8ReceiveMode = RECEIVE_MODE_CS;
// Serial.println("get data");
}
break;
case RECEIVE_MODE_CS:
g_pu8ApiPacket[g_u16ApiPacketSize++] = data;
u8ReceiveMode = RECEIVE_MODE_IDLE;
// Serial.println("get cs");
return RECEIVE_IP;
break;
default:
break;
}
return 0;
}

byte RXLED = 13;
byte toggle = 0;

void setup() {
pinMode(RXLED, OUTPUT);  // Set RX LED as an output
// TX LED is set as an output behind the scenes

Serial.begin(115200); //This pipes to the serial monitor
Serial1.begin(4800); //This is the UART, pipes to sensors attached to board
}

void loop() {
if (0 < Serial.available()) {
                byte data = Serial.read();
Serial1.write(g_pu8ApiPacket, makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX, g_pbIpAddrSrc, g_pbPortSrc, &data, 1));
if (0 == toggle) {
digitalWrite(RXLED, LOW);   // set the LED on
TXLED0; //TX LED is not tied to a normally controlled pin
toggle = 1;
} else {
digitalWrite(RXLED, HIGH);    // set the LED off
TXLED1;
toggle = 0;
}
}
if (0 < Serial1.available()) {
// Serial.write(parseChar(Serial1.read()));
if (RECEIVE_IP == parseChar(Serial1.read())) {
int len = parseXBeeApiReceiveIp(g_pu8ApiPacket, g_u16ApiPacketSize,
g_pbIpAddrSrc, g_pbPortSrc, &g_pbPayload);
Serial.print("receive ip packet:");
Serial.println(len);

printPayload(g_pbPayload, len);

// echo
                        byte data = *g_pbPayload;
Serial1.write(g_pu8ApiPacket, makeXBeeApiSendIp(g_pu8ApiPacket, APIPACKET_SIZE_MAX, g_pbIpAddrSrc, g_pbPortSrc, &data, 1));
}
}
}

2014年10月21日火曜日

Arduino で遊ぼう(2) xbee とspiで接続[情報編]

xbee ---- Pro Micro
(slave)     (master)
18 SPI CLK  <--- 15 SPI CLK
17 SPI SLAVE 
    #SELECT <--- 5 digital out
19 SPI SLAVE 
    #ATTEN    ---> 4 digital in
     * use interrupt 
11 SPI MOSI <--- 16 SPI MOSI
4 SPI MISO   ---> 14 SPI MISO

xbee wifiのspiは
spi mode 0, MSB first

pin2(dout)をlowで起動すると強制的にspiモードになる。

arduinoは
SPI.setBitOrder(MSBFIRST)
SPI.setDataMode(SPI_MODE0)
SPI.setClockDivider(SPI_CLOCK_DIV4)
   -> 8MHzの4分周で2MHz

XBeeのAPIモードでの送信コマンドは

最後のチエックサムが。。。

digiにドキュメントがありました。
<http://www.digi.com/support/kbase/kbaseresultdetl?id=2206>
普通にlength bytes の後ろからの和をFFから引けばいいですね。

2014.10.23 追記
まずは、シリアルでxbeeをapiモードで動かした。
xbee 192.168.111.200:9750
pc 192.168.111.210で接続
xbeeからtcp送信時のシリアルデータ例
(pcのポートはcb 9b)
7E 00 0d 20 01 c0 a8 6f d2 cb 9b 26 16 01 00 31 61
"1"を送信
 



Arudinoで遊ぼう(1) 構想

今更だけど、arduinoを触ってみようと思う。

xbeeと前に買ったシリアル出力JPEGカメラをつなげてカメラ付きたまロボwebサーバー版を作りたい。
(以前はxbeeのapiモードをudpで使ったりシリアル透過でカメラ制御していたので専用のiosアプリだった。ディベロッパーライセンスは切れたので、もうiosアプリ作れない。。。し)

arduino はpro micro 3.3Vでxbeeにもカメラにも直結。電源は前のたまロボ同様にDCDCで昇圧。モータードライバはスイッチサイエンスの
POLOLU-2135 デュアルモータードライバDRV8835
で、前のより小さい。

シリアルは、arduino のハードシリアルとソフトシリアルでいいかと思ってもいたが、ソフトシリアルは9600bpsがいいとこらしい。

これは厳しいです。

で、xbeeはspiで行けないかと考えています。
こんな文書がありました。
<a href=http://www.digi.com/support/kbase/kbaseresultdetl?id=3362>An Introduction to SPI on XBee</a>
いけるかな?

xbeeは3.5MHzまで対応しているみたいなのでpro microは1/4分周で、
うまく行けば、2MHz⁈

2014年7月3日木曜日

BeagleBoneBlackでモーター制御3

ちゃんとまっすぐ進むように左右の速度をトリムしたいので、左右それぞれPWMで制御するように修正する。

eHRPWM1Bも使う(AとBは同じモジュールなので周期が同じになるが、ちゃんとdutyが違えばいいので)

duty, polarityは個別設定できるが、
periodは共通。

runはなんだか取り扱い注意。AとBを合わせてオンオフしないと変な状態になる。



以下は古い。

eHRPWM2Aも使う。




BeagleBone Blackでロボット

似たようなタイトルの本もあり、参考にさせてもらったし、この本に著者関連のショップからBeagleBone Blackを購入できた。

ただ、構成はいろいろ違う。
Wifiで繋がりブラウザで操作できる。
Mjpegのストリートで画像が見れる。
モータードライバーも違う。

モバイルバッテリーで駆動しているが、モーター1A、本体+USB機器で2Aなので、
http://www.amazon.co.jp/gp/aw/d/B00ASSGJ3Q/ref=redir_mdp_mobile?ref_=pe_492632_48821362_TE_M3T1_dp_1
を使った。


今後は、距離センサーを使った自動運転、バンパースイッチによる緊急停止を追加予定。

2014年6月25日水曜日

超信地旋回

BeaglaBone Blackをタミヤのキャタピラのキットとギヤボックスに乗せて走らせた。

前後は問題無いが、
旋回するとキャタピラが外れた。

なんかいい回避策はないかとググったら、
 超信地旋回:左右を逆転
 信地旋回:片方を停止
と呼ぶらしく、
いずれも負荷が高く実機ではやらないことも多いらしい。

接地抵抗が小さければ信地旋回できそうだけど、ウチのはソコソコ重いし、キャタピラはゴムなのでむりなのかな。

左右は独立して速度調整できるので信地じゃない旋回にしよう。

2014年5月19日月曜日

BeaglBone BlackにMARY OLDEボードを接続(SPIを使う)

トラ技のMARYのOLEDボード(128x128のカラーLCD)をBeableBone Blackにつなげる。


OLEDはUG-2828GDEDF11。
これはSPIで制御される。

制御方法は
http://mbed.org/users/kanpapa/notebook/mary-oled-board/
が参考になる。
データシートは
http://www.adafruit.com/datasheets/UG-2828GDEDF11.pdf
でもSSD1351で検索して見つかったデータシートが一番いい。

また、加速度センサ
LIS33DE
がのっているらしい。
これはI2C。アドレスは0x1C。

OLEDはSPIのほかにresetとVCC_ONを制御する必要があるが、
resetはP8_14、VCC_ONはP8_12を使うことにする。

beaglebone blackでspiを有効にするには
http://www.nagavenkat.adurthi.com/2014/02/spi-communication-beaglebone-black-as-master-to-arduino-as-slave/

http://elinux.org/BeagleBone_Black_Enable_SPIDEV

SPI0はI2C0とぶつかるので、
HDMIを殺して、SPI1を使うことにする。

/boot/uboot/uEnv.txtを編集して
optargs=quiet drm.debug=7 capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN
capemgr.enable_partno=BB-SPIDEV1
を追加する。
なお、ubuntu13.10には/lib/firmwareに
BB-SPIDEV0-00A0.dtdo、BB-SPIDEV1-00A0.dtdoがあったので、今回はSPIDEV1を使った。
念のためにcat /sys/kernel/debug/pinctrl/44e10800.pinmux/pinsを確認すると
pin 100 (44e10990) 00000033 pinctrl-single 
pin 101 (44e10994) 00000033 pinctrl-single 
pin 102 (44e10998) 00000013 pinctrl-single 

pin 103 (44e1099c) 00000013 pinctrl-single
なので、
pin 100 -> P9_31 : SPI1_SCLK -> input
pin 101 -> P9_29 : SPI1_D0 -> input = MISO
pin 102 -> P9_30 : SPI1_D1 -> output = MOSI
pin 103 -> P9_28 : SPI1_CS0 -> output

spidevの利用例は
http://manual.atmark-techno.com/armadillo-guide/armadillo-guide-3_ja-2.0.0/ch02.html#sec_using_spi_with_adc
を参考にする。

OLEDの初期化はSDD1351のデータシートに説明があるが、
mbed向けのサンプルが参考になる。
<https://mbed.org/users/nxpfan/notebook/MARMEX_OB_oled_lib/>
<https://mbed.org/users/nxpfan/code/MARMEX_OB_oled__HelloWorld/>
制御そのものも参考になるし、文字データもある。

[oledspi.cpp]
/*
 * oledspi.cpp
 *
 *  Created on: 2014/05/20
 *      Author: yamamoto
 */

#include "oledspi.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <math.h>
#include <signal.h>
#include <string.h>

#include "font.h"

oled_spi::oled_spi(const char* a_pcharDevice, unsigned char a_u8Mode,
unsigned char a_u8Bits, unsigned long a_u32Speed,
unsigned short a_u16Delay, unsigned char a_u8CsCnage) :
mc_u8SpiMode(a_u8Mode), mc_u8SpiBitsWrite(a_u8Bits), mc_u8SpiBitsRead(
8), mc_u32SpiSpeedHz(a_u32Speed), mc_u16SpiDelay(a_u16Delay), mc_u8CsChange(
a_u8CsCnage), m_gpioReset(26), m_gpioVccOn(44), m_iColorForeground(
0xFFFFFF), m_iColorBackground(0), m_u8TextPositionColumn(0), m_u8TextPositionRow(
0) {
/// open device file
if (0 > (m_iDeviceHandle = open(a_pcharDevice, O_RDWR))) {
fprintf(stderr, "error: device open, %s\n", a_pcharDevice);
exit(1);
}

/// reset oled
reset();

/// initialize oled
initialize();
}

oled_spi::~oled_spi() {
/// shutdown oled
shutdown_oled();

/// close device file
close(m_iDeviceHandle);
}

void oled_spi::reset() {
printf("oled reset\n");
m_gpioReset.set(0);

// wait 2us
usleep(2);

m_gpioReset.set(1);

// VCC_OFF
m_gpioVccOn.set(0);
}

void oled_spi::initialize() {
printf("oled initialize\n");

init_spi();

init_oled();

clear();
}

void oled_spi::init_spi() {
// mode
if (0 > ioctl(m_iDeviceHandle, SPI_IOC_WR_MODE, &mc_u8SpiMode)) {
fprintf(stderr, "error: spi set write mode\n");
exit(1);
}
if (0 > ioctl(m_iDeviceHandle, SPI_IOC_RD_MODE, &mc_u8SpiMode)) {
fprintf(stderr, "error: spi set read mode\n");
exit(1);
}
// bit length
if (0
> ioctl(m_iDeviceHandle, SPI_IOC_WR_BITS_PER_WORD,
&mc_u8SpiBitsWrite)) {
fprintf(stderr, "error: spi set write bit length\n");
exit(1);
}
if (0
> ioctl(m_iDeviceHandle, SPI_IOC_RD_BITS_PER_WORD,
&mc_u8SpiBitsRead)) {
fprintf(stderr, "error: spi set read bit length\n");
exit(1);
}
// max speed Hz
if (0
> ioctl(m_iDeviceHandle, SPI_IOC_WR_MAX_SPEED_HZ,
&mc_u32SpiSpeedHz)) {
fprintf(stderr, "error: spi set write speed\n");
exit(1);
}
if (0
> ioctl(m_iDeviceHandle, SPI_IOC_RD_MAX_SPEED_HZ,
&mc_u32SpiSpeedHz)) {
fprintf(stderr, "error: spi set read speed\n");
exit(1);
}
}

void oled_spi::init_oled() {
#define GAMMA_LUT_SIZE 63
unsigned char gamma_LUT[GAMMA_LUT_SIZE];

for (int i = 0; i < GAMMA_LUT_SIZE; i++)
gamma_LUT[i] = (unsigned char) (powf(((float) i / 62.0), (1.0 / 0.58))
* 178.0 + 2.0);

sendCommand(SET_DISPLAY_MODE_ALL_OFF);
sendCommand(SET_COMMAND_LOCK);
sendData(0x12);

sendCommand(SET_COMMAND_LOCK);
sendData(0xb1);

sendCommand(SET_SLEEP_MODE_ON);

sendCommand(FRONT_CLOCK_DRIVER_OSC_FREQ);
sendData(0xF1);

sendCommand(SET_MUX_RATIO);
sendData(0x7F);

sendCommand(SET_DISPAY_OFFSET);
sendData(0x00);

sendCommand(SET_DISPAY_START_LINE);
sendData(0x00);

sendCommand(SET_REMAP_COLOR_DEPTH);
sendData(0x74);

sendCommand(SET_GPIO);
sendData(0x00);

sendCommand(FUNCTION_SELECTION);
sendData(0x01);

sendCommand(SET_SEGMENT_LOW_VOLTAGE);
sendData(0xA0);
sendData(0xB5);
sendData(0x55);

sendCommand(SET_CONTRAST_CURRENT_FOR_COLOR_ABC);
sendData(0xC8);
sendData(0x80);
sendData(0xC8);

sendCommand(MASTER_CONTRAST_CURRENT_CONTROL);
sendData(0x0F);

sendCommand(LOOKUP_TABLE_FOR_GRAYSCALE_PULSE_WIDTH);
for (int i = 0; i < GAMMA_LUT_SIZE; i++)
sendData(gamma_LUT[i]);

sendCommand(SET_RESET_PRECHARGE_PERIOD);
sendData(0x32);

sendCommand(ENHANCE_DRIVING_SCHEME_CAPABILITY);
sendData(0x04);
sendData(0x00);
sendData(0x00);

sendCommand(SET_PRECHARGE_VOLTAGE);
sendData(0x17);

sendCommand(SET_SECOND_PRECHARGE_VOLTAGE);
sendData(0x01);

sendCommand(SET_VCOMH_VOLTAGE);
sendData(0x05);

sendCommand(SET_DISPLAY_MODE_RESET);

#if 0
sendCommand( SET_COLUMN_ADDRESS );
sendData( 0x00 );
sendData( 0x7F );

sendCommand( SET_ROW_ADDRESS );
sendData( 0x00 );
sendData( 0x7F);

sendCommand( WRITE_RAM_COMMAND );
for ( int i = 0; i < WIDTH * HEIGHT; i++ )
sendData( 0x00 );
#endif

// TODO cls();

// VCC_ON
m_gpioVccOn.set(1);

// wait 100msec
usleep(100 * 1000);

sendCommand(SET_SLEEP_MODE_OFF);
}

void oled_spi::sendCommand(unsigned char a_u8Command) {
if (1 > send(0x00FF & (unsigned short) a_u8Command)) {
fprintf(stderr, "error: send command, 0x%2.0X\n", a_u8Command);
}
}

void oled_spi::sendData(unsigned char a_u8Data) {
if (1 > send(0x0100 | (unsigned short) a_u8Data)) {
fprintf(stderr, "error: send Data, 0x%2.0X\n", a_u8Data);
}
}

void oled_spi::shutdown_oled() {
printf("oled shutdown\n");

// send display off
sendCommand(SET_SLEEP_MODE_ON);

// VCC_OFF
m_gpioVccOn.set(0);
}

void oled_spi::clear() {
  fillRect(0, 0, msc_u8OledWidth, msc_u8OledHeight, 0);
  m_u8TextPositionColumn = 0;
  m_u8TextPositionRow = 0;
}

void oled_spi::drawPixel(unsigned char x, unsigned char y, int rgb888) {
setWindow(x, y, 1, 1);
setPixel(rgb888);
}

void oled_spi::drawLine(unsigned char x1, unsigned char y1, unsigned char x2,
unsigned char y2, int rgb888) {
// TODO
}

void oled_spi::drawRect(unsigned char x1, unsigned char y1, unsigned char x2,
unsigned char y2, int rgb888) {
drawLine(x1, y1, x1, y2, rgb888);
drawLine(x1, y1, x2, y1, rgb888);
drawLine(x2, y1, x2, y1, rgb888);
drawLine(x1, y2, x2, y2, rgb888);
}

void oled_spi::drawImage(unsigned char x, unsigned char y, unsigned char width,
unsigned char height, int* pRgb888) {
setWindow(x, y, width, height);
for (int i = 0; i < width * height; i++) {
setPixel(pRgb888[i]);
}
}

void oled_spi::drawBitmap(unsigned char x, unsigned char y, unsigned char width,
unsigned char height, const unsigned char* bitmap) {
setWindow(x, y, width, height);
for (int i = 0; i < height * width; i++) {
int byte = i / 8;
int bit = i % 8;
int color =
((bitmap[byte] << bit) & 0x80) ?
m_iColorForeground : m_iColorBackground;
setPixel(color);
}
}

void oled_spi::setColor(int foreground, int background) {
setColorForeground(foreground);
setColorBackground(background);
}

void oled_spi::setColorForeground(int rgb888) {
m_iColorForeground = rgb888;
}

void oled_spi::setColorBackground(int rgb888) {
m_iColorBackground = rgb888;

}

void oled_spi::drawText(unsigned char column, unsigned char row,
unsigned char length, char* text) {
for (unsigned char i = column;
i < (column + length) && i < msc_u8TextColumnNum; i++) {
drawChar(i, row, text[i - column]);
}
}

void oled_spi::drawChar(unsigned char column, unsigned char row, char text) {
unsigned char x = column * (msc_u8TextWidth + 1);
unsigned char y = row * (msc_u8TextHeight + 1);
drawBitmap(x, y, msc_u8TextWidth, msc_u8TextHeight,
  font::FONT8x8[text - 0x20]);
}

int oled_spi::send(unsigned short a_u16Buf) {
spi_ioc_transfer trans = { 0 };
unsigned short u16Read;
trans.tx_buf = (unsigned long) &a_u16Buf;
trans.rx_buf = (unsigned long) NULL;
trans.len = 2;
trans.delay_usecs = mc_u16SpiDelay;
trans.speed_hz = mc_u32SpiSpeedHz;
trans.bits_per_word = mc_u8SpiBitsWrite;
trans.cs_change = mc_u8CsChange;

int ret = ioctl(m_iDeviceHandle, SPI_IOC_MESSAGE(1), &trans);
if (1 > ret) {
printf("error : send : %4.0X\n", a_u16Buf);
}

return ret;
}

void oled_spi::setWindow(unsigned char x, unsigned char y, unsigned char width,
unsigned char height) {
unsigned char x1 = x;
unsigned char x2 = (unsigned char) (x + width - 1);
unsigned char y1 = y;
unsigned char y2 = (unsigned char) (y + height - 1);

sendCommand(SET_COLUMN_ADDRESS);
sendData(x1);
sendData(x2);
sendCommand(SET_ROW_ADDRESS);
sendData(y1);
sendData(y2);
sendCommand(WRITE_RAM_COMMAND);
}

void oled_spi::setPixel(int rgb888) {
unsigned short rgb565 = 0;
rgb565 = (unsigned short) ((rgb888 >> 8) & 0xf800);
rgb565 |= (unsigned short) ((rgb888 >> 5) & 0x07e0);
rgb565 |= (unsigned short) ((rgb888 >> 3) & 0x001f);

sendData((unsigned char) (rgb565 >> 8));
sendData((unsigned char) rgb565);
}

void oled_spi::fillRect(unsigned char x, unsigned char y, unsigned char width,
unsigned char height, int rgb888) {
setWindow(x, y, width, height);
for (int i = 0; i < width * height; i++) {
setPixel(rgb888);
}
}

int main(int argc, char* argv[]) {

oled_spi oled("/dev/spidev1.0", 0, 9, 16 * 1000 * 1000 /* 16MHz */, 0, 0);

// TODO for debug
char text[] = "Hello World!";
oled.drawText(0, 0, strlen(text), text);
sleep(5);

for (int i = 0; i < 5; i++) {
oled.fillRect(0, 0, 128, 128, 0xFF0000);
//usleep(100000);
oled.fillRect(0, 0, 128, 128, 0x00FF00);
//usleep(100000);
oled.fillRect(0, 0, 128, 128, 0x0000FF);
//usleep(100000);
}

oled.clear();
oled.fillRect(0, 0, 128, 128, 0x505050);
oled.setColorForeground(0xFF0000);
oled.drawText(0, 0, strlen(text), text);
sleep(10);
return 0;

}

[oledspi.h]
/*
 * oledspi.h
 *
 *  Created on: 2014/05/20
 *      Author: yamamoto
 */

#ifndef OLEDSPI_H_
#define OLEDSPI_H_

#include <gpio.h>
/*
 *
 */
class oled_spi {
public:
oled_spi(const char* a_pcharDevice, unsigned char a_u8Mode,
unsigned char a_u8Bits, unsigned long a_u32Speed,
unsigned short a_u16Delay, unsigned char a_u8CsCnage);
virtual ~oled_spi();

void setColor(int foreground, int background);
void setColorForeground(int rgb888);
void setColorBackground(int rgb888);
void clear();
void fillRect(unsigned char x, unsigned char y, unsigned char width,
unsigned char height, int rgb888);
void drawPixel(unsigned char x, unsigned char y, int rgb888);
void drawLine(unsigned char x1, unsigned char y1, unsigned char x2,
unsigned char y2, int rgb888);
void drawRect(unsigned char x1, unsigned char y1, unsigned char x2,
unsigned char y2, int rgb888);
void drawImage(unsigned char x, unsigned char y, unsigned char width,
unsigned char height, int* pRgb888);
void drawBitmap(unsigned char x, unsigned char y, unsigned char width,
unsigned char height, const unsigned char* bitmap);
void drawText(unsigned char column, unsigned char row, unsigned char length,
char* text);
void drawChar(unsigned char column, unsigned char row, char text);

protected:
void reset();
void initialize();

void setWindow(unsigned char x, unsigned char y, unsigned char width,
unsigned char height);
void setPixel(int rgb888);

private:
int m_iDeviceHandle;

static const unsigned char msc_u8OledWidth = 128;
static const unsigned char msc_u8OledHeight = 128;
static const unsigned char msc_u8TextWidth = 8;
static const unsigned char msc_u8TextHeight = 8;
static const unsigned char msc_u8TextColumnNum = msc_u8OledWidth
/ (msc_u8TextWidth + 1);
static const unsigned char msc_u8TextRowNum = msc_u8OledHeight
/ (msc_u8TextHeight + 1);

const unsigned char mc_u8SpiMode;
const unsigned char mc_u8SpiBitsWrite;
const unsigned char mc_u8SpiBitsRead;
const unsigned long mc_u32SpiSpeedHz;
const unsigned short mc_u16SpiDelay;
const unsigned char mc_u8CsChange;

CGpioControl m_gpioReset; //< P8-14(GPIO0_26->26)
CGpioControl m_gpioVccOn; //< P8-12(GPIO1_12->44)

int m_iColorForeground;
int m_iColorBackground;

unsigned char m_u8TextPositionColumn;
unsigned char m_u8TextPositionRow;

void init_spi();
void init_oled();
void shutdown_oled();
void sendCommand(unsigned char a_u8Command);
void sendData(unsigned char a_u8Data);
int send(unsigned short a_u16Buf);

/** Command list for the OLED controller */
enum {
SET_DISPLAY_MODE_ALL_OFF = 0xA4,
SET_DISPLAY_MODE_ALL_ON = 0xA5,
SET_DISPLAY_MODE_NORMAL = 0xA6,
SET_DISPLAY_MODE_INVERSE = 0xA7,
SET_COMMAND_LOCK = 0xFD,
SET_SLEEP_MODE_ON = 0xAE,
FRONT_CLOCK_DRIVER_OSC_FREQ = 0xB3,
SET_MUX_RATIO = 0xCA,
SET_DISPAY_OFFSET = 0xA2,
SET_DISPAY_START_LINE = 0xA1,
SET_REMAP_COLOR_DEPTH = 0xA0,
SET_GPIO = 0xB5,
FUNCTION_SELECTION = 0xAB,
SET_SEGMENT_LOW_VOLTAGE = 0xB4,
SET_CONTRAST_CURRENT_FOR_COLOR_ABC = 0xC1,
MASTER_CONTRAST_CURRENT_CONTROL = 0xC7,
LOOKUP_TABLE_FOR_GRAYSCALE_PULSE_WIDTH = 0xB8,
SET_RESET_PRECHARGE_PERIOD = 0xB1,
ENHANCE_DRIVING_SCHEME_CAPABILITY = 0xB2,
SET_PRECHARGE_VOLTAGE = 0xBB,
SET_SECOND_PRECHARGE_VOLTAGE = 0xB6,
SET_VCOMH_VOLTAGE = 0xBE,
SET_DISPLAY_MODE_RESET = 0xA6,
SET_COLUMN_ADDRESS = 0x15,
SET_ROW_ADDRESS = 0x75,
WRITE_RAM_COMMAND = 0x5C,
SET_SLEEP_MODE_OFF = 0xAF
};
};

#endif /* OLEDSPI_H_ */