Sim's blog

電子工作はじめてみました

Netduino miniでLチカ

2010-11-23 02:04:39 | Netduino

MTM06スイッチサイエンスさんから買ったNetduini miniでLチカしてみました。

Netduino miniは、やたらと小さいです。左側の緑の基板が秋月のFT232RL USBシリアル変換基板です。同じ24pinで幅は600milですが、高さが低いです。こんなに小さくても.Net Micro Frameworkが動いちゃいます。

小さいので、USB変換すら載っていません。基本はシリアルから使います。pin1とpin2はレベル変換ICにつながっていて、±15Vの普通のシリアルポートにつながります(UART2)。デフォルトはこのポートからプログラムしたり、デバッグしたりします。

 

Netduino miniの設定変更

今回のようにUSBシリアル変換基板を使うときは、pin11とpin12の方のUART1を使ってやる必要があります。UART1を使うには、設定を変えてやる必要があります。

まずは、秋月モジュールの設定ですが、JP1は1-2の間にジャンパーを、JP2にもジャンパーをつけます。これで、VccからはUSBからきた5Vが出力されるので全体の電源にします(JP2の設定)。念のためにリセッタブルヒューズ(ポリスイッチ)をつけるのもありです。JP1を1-2間にすることでTxDやRxDが3.3Vになります。

配線は以下のようにしました。

AE-UM232R     Netduino mini
11pin Vcc --- 21pin Vcc (5V)
14pin GND --- 23pin GND
15pin RxD --- 12pin UART1 TX0
19pin TxD --- 11pin UART1 RX0
              22pin リセット --- リセットボタン --- GND (内部でpull-up済)

必要であればAE-UM232Rのドライバをインストールします。デバイスマネージャでCOMポートの番号を覚えておきます。

設定の変更ですが、TeraTerm等で115200bps、8bit non-parity stopbit 1bitで接続します。ESCキーを押すと以下のようなメニューが出てきて、1を選んでやります。

Netduino Mini

1. TTL UART (COM1)
2. RS232 UART (COM2)

Which transport (1 or 2)? 1

Switching transport to TTL UART (COM1)...
.NetMF v4.1.2821.0
NetduinoMini, Build Date:
       
Nov  7 2010 19:47:13
ARM
Compiler version 400771

TinyCLR (Build 4.1.2821.0)

Starting...
Created EE.
Started Hardware.

以上で、設定は終わりです。

他にすることとしては、VS2010側のファイルのアップデートが必要です。最新版はこちらからダウンロードできます(Netduino SDK v4.1.0の32bit版か64bit版のどちらか)。インストールすると、新規プロジェクトの作成でNetduino Mini Applicationを選べるようになります(クリックで拡大)。

 

Lチカのソースコード

今回作ったLチカはマルチスレッド版です。メインスレッドはずっと寝てますが、裏で別スレッドがLチカをしてくれます。

using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.NetduinoMini;

namespace Netduino_mini_test1
{
    public class Program
    {
        
        static OutputPort led = new OutputPort(Pins.GPIO_PIN_13, false);
        public static void Main()
        {
            // スレッドを使って、バックグラウンドLチカ
            new Thread(delegate()
            {
                while (true)
                {
                    led.Write(!led.Read());
                    Thread.Sleep(250);
                }
            }).Start();

            // main threadはずっと寝てる
            Thread.Sleep(Timeout.Infinite);
        }
    }
}

 

とりあえず、何もついてないですが、一応デジタルpinは16本あります(アナログ入力4+デジタル12)。でもUART1で2本減るので14本になります。素直にUART2を使えば16本フルに使えます。普通のNetduinoが20本(アナログ入力6+デジタル14)なので、4本少ないです。

CPUのAT91SAM7X512は、BGAのパッケージなので多層基板と思われます。

 


NetduinoでNokia5110液晶に出力してみました

2010-09-16 00:04:46 | Netduino
以前、AVRを使ってaitendoのNokia5110液晶に出力して遊んだことがあります。

AVRでNokia5110を使ってみる (初ネギ)
Nokia5110液晶の高速描画

今回はNetduinoで出力してみました。


この液晶は、SPIで通信する必要があるので、今回初めて使ってみました。関連するクラスは次の2つです。

SPI SPIの本体
SPI.Configuration SPIの設定 (通信速度等)

通信のビット幅は指定できず8ビット固定です。4種類あるフォーマットは全てサポートされています。

ソースコードです。
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace Netduino_Nokia5100
{
    public class Program
    {
        static byte [] pic = new byte[48 * 6]{
            0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x4c,0xb0,0x0c,0x38,0x08,0x18,0x58,0x30,0x60,0xe0,0xe0,0xe0,0xf0,0xe0,0xf0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,0xb0,0x18,0x38,0x08,0x3c,0xec,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
            0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0x33,0xdc,0xf0,0xd3,0xfc,0xfe,0xfc,0xff,0x7f,0xff,0xff,0x4c,0xf7,0xdf,0xff,0xff,0xff,0xff,0xff,0xff,0xfa,0xee,0xb8,0x60,0xf0,0xe8,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
            0x00,0x00,0x00,0x00,0x00,0xc0,0xf0,0xfc,0xfe,0x7b,0x7c,0xff,0xff,0xff,0xff,0x3f,0x87,0x7f,0x83,0x84,0x8b,0x17,0x3f,0xff,0xff,0x3f,0x07,0x00,0x5f,0x83,0xc7,0xbf,0x1f,0xff,0xff,0xff,0xff,0x1f,0xff,0xfe,0xf8,0xb0,0xc0,0x00,0x00,0x00,0x00,0x00,
            0x00,0x00,0x00,0x50,0xee,0xfb,0x3e,0x07,0x00,0x00,0x01,0x57,0x7f,0xff,0xef,0x89,0x00,0x07,0x07,0x07,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x01,0x07,0x03,0x07,0x01,0x45,0xff,0xff,0xef,0x0a,0x00,0x00,0x17,0x7f,0xff,0xff,0xfe,0xe8,0xa0,0x00,0x00,
            0x00,0xf0,0xff,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x0d,0x77,0xff,0xff,0x0a,0x00,0x00,0x00,0xa0,0x40,0x20,0xc0,0x00,0xc0,0x20,0x40,0x80,0x00,0x00,0x00,0xff,0x7f,0x7b,0x0e,0x00,0x00,0x00,0x00,0x00,0x07,0x7f,0xff,0xff,0xff,0xe8,0x00,
            0x14,0xff,0xef,0x9f,0xea,0x00,0x00,0x00,0x80,0xc0,0xc0,0xc0,0xe0,0xf0,0xf0,0xfd,0xfc,0xff,0xfb,0x82,0x80,0x35,0x52,0xac,0x4f,0x9c,0x61,0x82,0x40,0xff,0xfe,0xfc,0xf8,0xf1,0xe0,0xc0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0xc3,0xff,0xff,0xff,0xa0,
        };

        // Nokia5110 <-> Netduino
        // pin1 Vcc ------ 3.3V
        // pin2 GND ------ GND
        // pin3 SCE ------ D8    pull-up w/ 10k ohm resister
        // pin4 RESET ---- D9    pull-down w/ 10k ohm resister
        // pin5 D/C ------ D10
        // pin6 SDIN ----- D11
        // pin7 SCLK ----- D13
        // pin8 LED+ ----- open or 3.3V
        public static void Main()
        {
            // write your code here

            // initialize
            // rst = D9; dc = D10; sce = D8
            Nokia5100 lcd = new Nokia5100(Pins.GPIO_PIN_D9, Pins.GPIO_PIN_D10, Pins.GPIO_PIN_D8);

            // draw picture
            uint x, y, p;

            p = 0;
            for (y = 0; y < 6; y++)
            {
                lcd.locate(18, y);
                for (x = 0; x < 48; x++) lcd.write(pic[p++]);
            }

            // loop forever
            Thread.Sleep(Timeout.Infinite);
        }

    }

    public class Nokia5100
    {
        OutputPort rst, dc;
        SPI spi;
        byte[] buf = new byte[1];

        public Nokia5100(Cpu.Pin rst, Cpu.Pin dc, Cpu.Pin sce)
        {
            this.rst = new OutputPort(rst, false);  // rst = low
            this.dc = new OutputPort(dc, true);     // d/c = high (data)

            spi = new SPI(new SPI.Configuration(
                sce,    // ChipSelect_Port
                false,  // ChipSelect_ActiveState : active low
                0,      // ChipSelect_SetupTime
                0,      // ChipSelect_HoldTime
                false,  // Clock_IdleState : the idle state of the clock is low
                true,   // Clock_Edge : rising edge
                1000,   // Clock_Rate : 1000KHz
                SPI.SPI_module.SPI1 // SPI_mod : D11 MOSI, D12 MISO, D13 SCK
            ));

            // initialize
            Thread.Sleep(100);      // wait 100ms
            this.rst.Write(true);   // rst = high

            sendcmd(0x20 | 1);      // FSET : PD = 0, H = 1
            sendcmd(0x10 | 3);      // BIAS : BS = 3 (1/48 duty)
            sendcmd(0x80 | 16);     // VOP  : Vop = 16 (contrast)
            sendcmd(0x04 | 1);      // TMP  : TC = 1
            sendcmd(0x20);          // FSET : PD = 0, H = 0
            sendcmd(0x08 | 4);      // DISP : D = 1, E = 0

            clear();
        }
        
        void sendcmd(uint cmd)
        {
            dc.Write(false);    // d/c = low (command)
            buf[0] = (byte)cmd;
            spi.Write(buf);
            dc.Write(true);     // d/c = high (data)
        }

        public void locate(uint x, uint y)
        {
            sendcmd(0x80 | (x & 0x7f)); // SETX 0-83
            sendcmd(0x40 | (y & 7));    // SETY 0-5
        }

        public void clear()
        {
            int i;
            for (i = 0; i < 84 * 6; i++) write(0);
            locate(0, 0);
        }

        public void write(uint data)
        {
            buf[0] = (byte)data;
            spi.Write(buf);
        }

        public void write(byte[] data)
        {
            spi.Write(data);
        }
    }
}


今回は、ジャンプワイヤーの色に凝ってみました。3pinがオレンジ、4pinが黄色、5pinが緑、6pinが青、7pinが紫です。実に分かりやすいですね(笑)。

いつもながら何を出力するのか困りましたが、最近は触覚が生えていて猫耳なのがいいらしいです。

参考
.NET Micro Framework WikiのSPI
Lynx-EyEDの電音鍵盤さんの「netduinoでOLED制御してみた
ニコニコ大百科「中野梓とは

Arduinoに移植してみました

2010-09-15 19:05:33 | Netduino
NetduinoでI2Cの続きになります。

前回は秋月のリアルタイムクロックモジュールRTC8564NBを使った液晶時計をNetduinoで作ってみました。

今回は、ほぼ同じ機能をもつ液晶時計をArduinoに移植してみました。



一部違うのは、Netduinoでは、1秒割り込みを使って、1秒毎に時刻を拾いにいって表示していましたが、Arduino版では無条件に100ミリ秒毎に時刻を拾いにいっていることです。Arduinoでもピン割り込みの機能はあるのですが、ちょうどキャラクタLCDのピンとぶつかっていて使うことができませんでした。

RTC8564NBのCLKOUT出力(1秒割り込み)は、ArduinoのD7につないで、読み取ってLED(D13)でモニターできるようにしています。

RTC8564NBをArduinoから使うには、なんでも作っちゃう、かも。さんのRTC8564ライブラリ(記事)を使うのが便利でいいのですが、今回は比較の意味もこめて、全部自分で書いています。

ArduinoでI2Cを使うにはWireというライブラリを使います。仕様からすると、マルチマスタは考えられていないようですが、その分、.Net Microframeworkより使い方が簡単になっています。WireライブラリのマニュアルはArduino 日本語リファレンスにあります。

ソースコードです。
#include <LiquidCrystal.h>
#include <Wire.h>

#define RTC 0x51

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
uint8_t year, month, day, wday, hour, minute, second;
const char *weekday[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

// RTC-8564NB
// 1pin CLKOE  - open
// 2pin CLKOUT - Arduino D7
// 3pin INT    - open
// 4pin Vss    - Arduino GND
// 5pin SDA    - Arduino A4
// 6pin SCL    - Arduino A5
// 7pin NC     - open
// 8pin Vdd    - Arduino 5V <<<

void setup(){
  lcd.begin(16, 2);
  Wire.begin(); // init as master

  sendcmd(0x00, 0x20);  // stop
  sendcmd(0x01, 0x00);  // Control2
  sendcmd(0x0e, 0x00);  // Timer Control
  sendcmd(0x0d, 0x83);  // CLKOUT frequency
  
  sendcmd(0x02, 0x00);  // sec
  sendcmd(0x03, 0x05);  // min
  sendcmd(0x04, 0x23);  // hour
  sendcmd(0x05, 0x05);  // day
  sendcmd(0x06, 0);     // weekday 0:Sun
  sendcmd(0x07, 0x09);  // month
  sendcmd(0x08, 0x10);  // year low

  sendcmd(0x00, 0x00);  // start

  pinMode(13, OUTPUT);
  pinMode(7, INPUT);
}

void loop(){
  digitalWrite(13, digitalRead(7));
  readTime();
  lcd.home();
  hex2(0x20); // year high
  hex2(year);
  lcd.write('/');
  hex2(month);
  lcd.write('/');
  hex2(day);
  lcd.write(' ');
  lcd.print(weekday[wday]);
  
  lcd.setCursor(0, 1);
  hex2(hour);
  lcd.write(':');
  hex2(minute);
  lcd.write(':');
  hex2(second);

  delay(100);
}

void readTime(void)
{
  Wire.beginTransmission(RTC);
  Wire.send(0x02);
  Wire.endTransmission();
  
  Wire.requestFrom(RTC, 7);
  second = Wire.receive() & 0x7f;
  minute = Wire.receive() & 0x7f;
  hour   = Wire.receive() & 0x3f;
  day    = Wire.receive() & 0x3f;
  wday   = Wire.receive() & 0x07;
  month  = Wire.receive() & 0x1f;
  year   = Wire.receive();
}

void sendcmd(uint8_t addr, uint8_t data)
{
  Wire.beginTransmission(RTC);
  Wire.send(addr);
  Wire.send(data);
  Wire.endTransmission();
}

char hexchar[] = "0123456789abcdef";
void hex2(uint8_t x)
{
  lcd.write(hexchar[x >> 4]);
  lcd.write(hexchar[x & 15]);
}

思いつきで、同じものをNetduinoとArduinoの両方に実現してみました。VS2010の補完機能になれてしまうと、全部キータイプしないといけないArduinoが不安になってきます(笑)。このくらいのものだと、何で作ってもそうたいした違いはないですが、やはりデバッグ機能のあるNetduinoが安心して作れると思いました。

NetduinoでI2C

2010-09-05 22:00:22 | Netduino
NetduinoでキャラクタLCDの続きになります。

秋月のリアルタイムクロックモジュールRTC-8564NBを使って液晶時計を作ってみました。


RTC8564-NBはI2Cで制御してやる必要があります。以前、RTC-8564NBを使ってみるという記事でAVRから制御したことがあります。

.NET Micro FrameworkにはI2Cのクラスがあるので、これを使えばI2Cで通信ができます(APIリファレンス)。とはいっても、使い方が分かるまで結構紆余曲折でした。

Microsoft.SPOT.HardwareというNamespaceの下にはI2C関連の5つのクラスがあります。
- I2CDevice I2Cデバイスのインスタンスを作るためのクラス
- I2CDevice.Configuration I2Cインタフェースの通信速度等の設定を行うクラス
- I2CDevice.I2CReadTransaction I2Cデバイスからの読み込みを行うトランザクション
- I2CDevice.I2CTransaction I2Cデバイスとのトランザクション
- I2CDevice.I2CWriteTransaction I2Cデバイスへの書き込みを行うトランザクション

まずは、インスタンスを作ります。I2CDeviceクラスとI2CDevice.Configurationクラスを使って、次のように初期化します。

 rtc8564 = new I2CDevice(new I2CDevice.Configuration(0x51, clockRate));

ここで0x51というのはRTC-8564NBのデバイスのアドレスです。clockRateはKHz単位の速度です。今回はint clockRate = 100;としているので100KHzで通信することになります。

実際の通信はrtc8564.Execute(トランザクションの配列, タイムアウト);のようにして行います。タイムアウトはミリ秒単位で指定します。さて、トランザクションって何でしょう?というところで出てくるのが残りの3つのクラスです。

何バイトか読む、もしくは書くというのが一つのトランザクションです。これを束ねて何バイト書いてから、何バイト読むみたいな一連の流れをトランザクションの配列で指定してやります。I2Cはマルチマスタが可能なので、通信している途中に別のマスタが割り込んでこないように、ある程度の読み書きをまとめてする必要があります。そのために、こんな面倒なことをします。

実際のトランザクションの例です。まずはトランザクションの配列を作ります。

 I2CDevice.I2CTransaction[] actions = new I2CDevice.I2CTransation[2];

ここでは2つの要素が含まれる配列actionsを作っています。次に配列の要素を初期化してやります。

 byte[] addr = new byte[1]{ 0x02 };
 byte[] data = new byte[7];

 actions[0] = I2CDevice.CreateWriteTransaction(addr);
 actions[1] = I2CDevice.CreateReadTransaction(data)

actions[0]はI2Cデバイスへの書き込みトランザクションです。書き込む内容はaddrという1バイトの配列です。書き込む長さは配列の長さです。
書き込む内容が変わるときはaddr[0]の内容を書き換えます。書き換えるバイト数が変わるときには別の配列を用意してやる必要があります(結構面倒)。例えばaddr = new byte[2]みたいなことをします。
actions[1]はI2Cデバイスから読み出すトランザクションです。読み込む長さは配列の長さになります。上の例だとdataの長さである7バイトを読み込みます。配列の一部だけ読み込むといった動作はできません。

今回書いたコードです。
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace NetduinoI2C
{
    // RTC8564クラスのサンプル by Sim
    public class Program
    {
        static CLCD lcd;
        static string[] WeekDay = new string[] { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };

        public static void Main()
        {
            // write your code here
            lcd = new CLCD(Pins.GPIO_PIN_D12, Pins.GPIO_PIN_D11, Pins.GPIO_PIN_D5, Pins.GPIO_PIN_D4, Pins.GPIO_PIN_D3, Pins.GPIO_PIN_D2);

            // RTCの宣言(通信速度kbps, タイムアウト ミリ秒)
            RTC8564 rtc = new RTC8564(100, 500);

            // 時間の設定 BCDで設定する(stop()してから設定する)
            rtc.year  = 0x10; // 年の下位2桁
            rtc.month = 0x09; // 月
            rtc.day   = 0x02; // 日
            rtc.wday  = 4;    // 曜日 0:日 1:月 2:火 3:水 4:木 5:金 6:土
            rtc.hour  = 0x01; // 時
            rtc.min   = 0x46; // 分
            rtc.sec   = 0x30; // 秒
            rtc.write();

            // start()で開始
            rtc.start();

            // 1HzのCLKOUTの立ち上がりで割り込みがかかるようにする
            InterruptPort clkout = new InterruptPort(Pins.GPIO_PIN_D7, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeHigh);
            // 割り込み処理ルーチンの設定
            clkout.OnInterrupt += new NativeEventHandler(delegate(uint data1, uint data2, DateTime time)
            {
                // 割り込み処理ルーチン。D7の立ち上がりで呼び出される。匿名メソッド

                // RTC8564NBから時刻を読み出す
                rtc.read();

                // 表示
                // 1行目
                lcd.home();
                hex2(0x20);
                hex2(rtc.year);
                lcd.write('/');
                hex2(rtc.month);
                lcd.write('/');
                hex2(rtc.day);
                lcd.write(' ');
                lcd.puts(WeekDay[rtc.wday]);

                // 2行目
                lcd.setCursor(0, 1);
                hex2(rtc.hour);
                lcd.write(':');
                hex2(rtc.min);
                lcd.write(':');
                hex2(rtc.sec);
            });

            // 無限ループ
            Thread.Sleep(Timeout.Infinite);
        }

        // 16進2桁出力
        static char[] hexchar = new char[16] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
        static public void hex2(byte x)
        {
            lcd.write(hexchar[x >> 4]);
            lcd.write(hexchar[x & 15]);
        }
    }

    // RTC8564NBドライバ by Sim : EPSON TOYOCOM I2C bus real time clock module
    // 秋月電子 通販コード I-00233 (http://akizukidenshi.com/catalog/g/gI-00233/)
    //
    // 接続例
    // 1pin CLKOE  - open          内部でpull-upされている
    // 2pin CLKOUT - Netduino:D7   1Hzの矩形波出力
    // 3pin INT    - open          未使用
    // 4pin GND    - Netduino:GND
    // 5pin SDA    - Netduino:A4   2.2kΩでpull-up
    // 6pin SCL    - Netduino:A5   2.2kΩでpull-up
    // 7pin NC     - open
    // 8pin Vdd    - Netduino:3.3V パスコンはモジュール上に実装されているので外部には不要

    public class RTC8564 : IDisposable
    {
        I2CDevice rtc8564;

        public byte year, month, day, wday, hour, min, sec;
        public int timeout;

        // トランザクション用
        private byte[] cmd  = new byte[2];
        private byte[] addr = new byte[1] { 0x02 }; // 秒から7バイト読み始める
        private byte[] data = new byte[7];
        private I2CDevice.I2CTransaction[] wr = new I2CDevice.I2CTransaction[1];
        private I2CDevice.I2CTransaction[] rd = new I2CDevice.I2CTransaction[2];

        // コンストラクタ。初期化する(newしたときに呼ばれる)
        // 時刻は未設定、停止状態になる
        public RTC8564(int clockRate, int timeout)
        {
            this.timeout = timeout;

            // define transaction
            wr[0] = I2CDevice.CreateWriteTransaction(cmd);  // for sendcmd()
            rd[0] = I2CDevice.CreateWriteTransaction(addr); // for read()
            rd[1] = I2CDevice.CreateReadTransaction(data);  // for read()

            rtc8564 = new I2CDevice(new I2CDevice.Configuration(0x51, clockRate));

            stop();
            sendcmd(0x01, 0x00); // Control 2 : 0x00
            sendcmd(0x0e, 0x00); // Timer Control : 0x00
            sendcmd(0x0d, 0x83); // CLKOUT frequency : 0x83 (1Hz)
        }

        // 動作開始
        public void start()
        {
            sendcmd(0x00, 0x00); // Control 1 : 0x00
        }

        // 動作停止
        public void stop()
        {
            sendcmd(0x00, 0x20); // Control 1 : 0x20
        }

        // RTC8564にコマンドを送る
        private void sendcmd(byte address, byte data)
        {
            cmd[0] = address;
            cmd[1] = data;
            rtc8564.Execute(wr, timeout);
        }

        // 時刻の読み出し
        public void read()
        {
            rtc8564.Execute(rd, timeout);
            sec   = (byte)(data[0] & 0x7f);
            min   = (byte)(data[1] & 0x7f);
            hour  = (byte)(data[2] & 0x3f);
            day   = (byte)(data[3] & 0x3f);
            wday  = (byte)(data[4] & 0x07);
            month = (byte)(data[5] & 0x1f);
            year  = data[6];
        }

        // 時刻の設定
        public void write()
        {
            sendcmd(0x02, sec);
            sendcmd(0x03, min);
            sendcmd(0x04, hour);
            sendcmd(0x05, day);
            sendcmd(0x06, wday);
            sendcmd(0x07, month);
            sendcmd(0x08, year);
        }

        // デストラクタ
        public void Dispose()
        {
            rtc8564.Dispose();
        }
    }

    // Character LCD Arduino like API by Sim
    public class CLCD
    {
        // 前回と同じなので省略
    }

}

RTC-8564NBにはCLKOUTという1Hz出力端子があります。今回はCLKOUTの立ち上がりで割り込みをかけて、1秒毎に時刻を読み込んで表示するようにしました。
割り込み処理ルーチンは匿名メソッドを使ってMainの中に直接書きました。
A5がSCL、A4がSDAというのはArduinoとピンコンパチです。
トランザクションの配列を事前に用意しておくのが結構面倒です。

Netduinoでマルチスレッド(2)

2010-09-01 21:25:54 | Netduino
NetduinoでキャラクタLCDの続きになります。というか、その一つ前のNetduinoでマルチスレッドの続きになります。

Netduinoというよりは、C#の小ネタです。C#には匿名メソッド(anonymous method)という機能があります。

前回のマルチスレッドでは、マルチスレッドで動かすflashというメソッドを作っていました。どうせ1ヶ所からしか呼ばれないし、1回しか使わないメソッドにわざわざ名前をつけるのはめんどくさい、というときに使えるのが匿名メソッドです。具体的にはメソッドの名前を書いているところに、直接メソッドの中身を書けます。

Thread thread = new Thread(flash);
のように書いていたのを
Thread thread = new Thread( delegate(){ メソッドの中身 } );
のように書くことができます。

前回のマルチスレッドの例題を書き直したものになります。
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace ThreadTest2
{
    public class Program
    {
        static OutputPort LED1 = new OutputPort(Pins.ONBOARD_LED, false);
        static OutputPort LED2 = new OutputPort(Pins.GPIO_PIN_D13, false);

        public static void Main()
        {
            // write your code here
            Debug.Print("Hello, Multi-Threading");

            // 今回の新しい部分
            new Thread(delegate()
            {
                // スレッドの本体(並列実行になる)
                while (true)
                {
                    LED1.Write(!LED1.Read());       // LED1反転
                    Thread.Sleep(250);              // 250ミリ秒待つ
                }
            }).Start();

            // 本スレッド側でもLED2をチカチカ
            while (true)
            {
                LED2.Write(!LED2.Read());       // LED2反転
                Thread.Sleep(150);              // 150ミリ秒待つ
            }
        }

    }
}

なんというか、NetduinoじゃなくてもいいC#のお話ですね。
もしかして、これってクロージャっていうものなんでしょうか?

NetduinoでキャラクタLCD

2010-08-28 03:26:31 | Netduino
Netduinoでマルチスレッドの続きになります。

Lチカの次というと、やはりキャラクタLCD出力です。小林茂さん(@kotobuki)に頂いたLCD Shieldを使ってみました。元々はArduino用のシールドですが、Netduinoでも使えるか試してみたかったのが動機です。

NetduinoのI/Oピンは入力は5Vトレラントで、出力は3.3Vです。秋月のSD1602HUOB(通販コード P-01797)はVIHのmin(LCDが入力電圧をHとみなす最小の電圧)が2.2Vなので3.3Vでも動作します。



せっかくなのでArduinoのLiquidCrystalクラスとなるべく似せてみました(Arduino 日本語リファレンス)。手抜きなので全機能は含まれていません。
書いたソースです。
using System;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace NetduinoLCD1
{
    public class Program
    {
        public static void Main()
        {
            // write your code here
            Debug.Print("Hello, netduino");

            CLCD lcd = new CLCD(Pins.GPIO_PIN_D12, Pins.GPIO_PIN_D11, Pins.GPIO_PIN_D5, Pins.GPIO_PIN_D4, Pins.GPIO_PIN_D3, Pins.GPIO_PIN_D2);

            lcd.puts("Hello, Netduino!");

            OutputPort LED = new OutputPort(Pins.GPIO_PIN_D13, false);
            int count = 0;

            while(true)
            {
                lcd.setCursor(0, 1);
                lcd.puts(count++.ToString());
                LED.Write(!LED.Read());

                Thread.Sleep(200);  // wait 200ms
            }
        }
    }

    // Character LCD Arduino like API by Sim
    public class CLCD
    {
        OutputPort rs, e, d4, d5, d6, d7;

        public CLCD(Cpu.Pin rs, Cpu.Pin e, Cpu.Pin d4, Cpu.Pin d5, Cpu.Pin d6, Cpu.Pin d7)
        {
            this.rs = new OutputPort(rs, false);
            this.e  = new OutputPort(e,  false);
            this.d4 = new OutputPort(d4, false);
            this.d5 = new OutputPort(d5, false);
            this.d6 = new OutputPort(d6, false);
            this.d7 = new OutputPort(d7, false);

            begin(16, 2);
        }

        public void begin(uint cols, uint lines){
            Thread.Sleep(50);   // 15ms
            rs.Write(false);
            e.Write(false);
            write4bit(0x03);
            Thread.Sleep(4);    // 4.1ms
            write4bit(0x03);
            Thread.Sleep(4);    // 4.1ms
            write4bit(0x03);
            Thread.Sleep(1);    // 0.15ms
            write4bit(0x02);

            // function set
            //    +----- DL 1:8bit 0: 4bit
            //    |+---- N  1:2line 0:1line
            //    ||+--- F  1:5x11 0:5x8
            // 00101000
            command(0x28);      // 39us

            // display control
            //
            //      +--- D 1:display on 0:display off
            //      |+-- C 1:cursor on 0:cursor off
            //      ||+- B 1:blink on 0:blink off
            // 00001100
            command(0x0c);      // 39us

            clear();

            // entry mode
            //
            //       +-- I/D 1:increment 0:decrement
            //       |+- S   1:shift on 0:shift off
            // 00000110
            command(0x06);      // 39us
        }

        public void clear()
        {
            command(0x01);
            Thread.Sleep(2);     // 1.53ms
        }

        public void home()
        {
            command(0x02);
            Thread.Sleep(2);    // 1.53ms
        }

        public void setCursor(uint x, uint y)
        {
            if(y != 0) y = 0x40;
            x &= 0x3f;
            command(0x80 | y + x);  // 39us
        }

        public void write(uint x)
        {
            rs.Write(true);     // RS = 1
            write4bit(x >> 4);
            write4bit(x);
        }

        public void puts(string s)
        {
            foreach(uint c in s) write(c);
        }

        private void command(uint x)
        {
            rs.Write(false);    // RS = 0
            write4bit(x >> 4);
            write4bit(x);
        }

        private void write4bit(uint x)
        {
            d7.Write((x & 8) != 0);
            d6.Write((x & 4) != 0);
            d5.Write((x & 2) != 0);
            d4.Write((x & 1) != 0);
            e.Write(true);
            Thread.Sleep(1);    // 450ns
            e.Write(false);
            Thread.Sleep(1);    // 37us
        }
    }
}

困ったことは、あまり細かい時間の単位で待てないというのがあります。Thread.Sleep()は1ミリ秒単位の指定しかできません。一応、ミリ秒単位に繰り上げてます。とりあえず動いているのでよしとします。

最初、write4bitやcommandのパラメータはbyteにしてたんですが、(byte)にcastしろというwarningが出ます。command(x + 1);みたいなことをすると、xがbyte型の変数でもx + 1の結果はintになってしまって、command((byte)(x + 1));のように書けというwarningになるというお話です。結局面倒になってbyteはやめてunsignedにしてしまいました。

puts()のところのforeachはかっこいいです。さすがC#って感じです。

classライブラリとかはどうやって作ればいいのか、まだ分かっていません。たぶんnamespaceとかが関係してそうです。

さて、次は何をしようかな。

Netduinoでマルチスレッド

2010-08-25 01:15:20 | Netduino
Netduinoがきましたの続きになります。

マルチスレッドで遊んでみました。マルチスレッドがあると並列実行(実際はCPUは一つなので時分割で交互に動作)を簡単に記述できます。
以下の例題では、2つのLEDを、LED1はスレッドで250ミリ秒毎、LED2はメインスレッドで150ミリ秒毎に反転します。
using System;
using System.Threading; // Thread
using Microsoft.SPOT;   // Debug
using Microsoft.SPOT.Hardware; // OutputPort
using SecretLabs.NETMF.Hardware;
using SecretLabs.NETMF.Hardware.Netduino; // Pins

namespace ThreadTest1
{
    public class Program
    {
        static OutputPort LED1 = new OutputPort(Pins.ONBOARD_LED, false);
        static OutputPort LED2 = new OutputPort(Pins.GPIO_PIN_D13, false);

        public static void Main()
        {
            // write your code here
            Debug.Print("Hello, Multi-Threading");
            
            Thread thread = new Thread(flash);  // 新しいスレッドの作成
            thread.Start();                     // スレッドの実行開始(ここで実行が並列になる)

            // 本スレッド側でもLED2をチカチカ
            // 無限ループ
            while (true)
            {
                LED2.Write(!LED2.Read());       // LED2反転
                Thread.Sleep(150);              // 150ミリ秒待つ
            }
        }

        // スレッド本体
        static void flash()
        {
            // 無限ループ
            while (true)
            {
                LED1.Write(!LED1.Read());       // LED1反転
                Thread.Sleep(250);              // 250ミリ秒待つ
            }
        }
    }
}

スレッドを使うには、まず準備として「using System.Threading;」をすることでThreadクラスを使えるようにします。
次に「Thread thread = new Thread(flash);」とすることでスレッドを実行するメソッド(flash)を指定します。スレッドを実行するメソッドはvoid f()という形でないといけません。この段階ではスレッド自体はスタートしていません。
最後に「thread.Start();」とすることでスレッドが実行開始されます。この段階で処理は2つに分かれて並列実行(CPUは一つなので時分割で交互に実行)されます。
すごく簡単です。

今回はスレッドの優先順位を変えたりとか、スレッドの終了待ちとかをしないので、「new Thread(flash).Start();」のように書いても動きます。1行で済んじゃいます。

残念ながら、RTOSのかわりに使えるほどではありません。RTOS(リアルタイムOS)は時間制約に関する最悪値が保証されていますが、.Net Microframeworkでは保証されていません。RTOS的な機能が必要なときは、RTOS上に.Net Microframeworkを実装することになるみたいです。例えば日立超LSIでT-Kernel上に.Net Microframeworkを載せるというソリューションを提供しています(ニュースリリース)。

通常の.Net Frameworkではdelegateを作ってBeginInvokeをする方法でもマルチスレッドを実現できるそうですが、.Net Micro Frameworkで動かそうとするとサポートしていないというエラーが出て実行できませんでした。


参考にしたのは以下の3つの記事です。
@ITの連載「.NETマルチスレッド・プログラミング入門
PS3とLinux、電子工作もさんのブログ「FEZ Dominoでマルチスレッドを動かす
TinyCLRの「Beginners Guide to C# and .NET Micro Framework」(pdf)のThreadingの章

Netduinoがきました

2010-08-23 03:35:39 | Netduino
スイッチサイエンスさんで話題のnetduinoの取り扱いが始まりました。
スイッチサイエンスさんはArduinoやSparkFun製品の通販をしている会社で、秋葉原で無料の「はんだづけカフェ」をされていることでも有名です(はんだづけカフェのTwitter)。はんだづけカフェについては中の人が書かれているブログが詳しいです。

発売記念ということで、数名のモニターを募集していました。当選したのでブログでレポートします。


netduinoの特徴

- Arduinoとピン配置が同じ。全てではありませんが転用できるArduino用シールドもあります。出力は3.3Vで入力は5Vトレラントです。
- Microsoftの.Net Micro Framework環境が実装されているのでC#を使った開発が可能。
- 開発環境は全て無料。特にnetduinoではファームウェアもオープンソースとして公開しています(ダウンロードページ)。
- 本体価格が安い。3495円と、Arduino Duemilanoveとほとんど同じ値段です。

同じ特徴をもつ製品としてはFEZ Dominoがあります。こちらも同じスイッチサイエンスさんで取り扱っています(商品ページ)。


パッケージは黒です。USBケーブルが付属しています。


パッケージを開けました。中にはゴム足と謎の紙が同梱されています。

Arduinoそっくりですね。

というわけで並べてみました。

左から、Arduino DuemilanoveJapaninonetduinoFEZ Dominoです。


開発環境のインストール

CDはないので、開発ソフトやドライバーは全てネット経由でnetduinoのホームページ(netduino.com)
からダウンロードします。

netduinoをPCにつなぐ前にソフトウェアのインストールを完了しておかないといけません。インストールするものは3つで、インストールする順番も決まっています。間違えないようにしないといけません。

(1) Microsoft Visual C# Express 2010
(2) .NET Micro Framework SDK v4.1
(3) Netduino SDK v4.1.0 (32bit版64bit版)

簡単に言うとnetduinoのダウンロードページを上から順にインストールします。ちなみにOSはwindows XP, Windows Vista, Windows 7の32bit/64bit環境です。


マイクロUSB

netduinoのUSBケーブルはマイクロUSBです。

海外では携帯用によくあるらしいのですが、日本ではあまり見かけません。マイクロUSBのケーブルは秋月で入手可能です(通販コード C-02429)。マイクロUSBについてはhamayanさんと熾火研究所さんにtwitterで教えていただきました。ありがとうございます。


MFDeproy.exe

.NET Micro Framework SDKをインストールするとMFDeproy.exeというツールがPCにインストールされます。Pingという接続テストをしたり、ターゲットの情報を取得したりできます。ファームウェアの消去みたいな怖いコマンドもあるので使うときには注意が必要です。

MFDeproyを起動したところです。

DeviceをUSBにして、Targetメニュー→Device Capabilitiesを実行した画面です。ファームウェアのバージョンが確認できます。SolutionReleaseInfo.solutionVendorInfoを見ると4.1.0.1になっています(写真はスクロールして見えなくなっています)。netduinoの最新のファームウェアは4.1.0.2なので一つ古いファームウェアです。
最新のファームウェアはnetduino.comのCommunityのこちらの記事からダウンロードできます(ダウンロードにはCommunityへの参加が必要です)。


FEZ Dominoとの共存

せっかく両方とも持っているので、試してみました。電源付きのハブで2つも問題なく動いています。

ソフト開発も、新しいプロジェクトの作成時に「FEZ Domino Application」と「Netduino Application」を選択するだけです。Microsoftが作った部分は共通ですが、ボードメーカーが拡張した部分のクラスライブラリは勝手に作っているので微妙に仕様が違ったりします。


情報源

開発環境のインストールや初めてのプログラム作成(Lチカ)を解説した、ネットからダウンロードできる資料が既にいくつかあります。まだ日本に上陸してから数日なのに日本語情報も色々出始めています。

- 本家netduinoの「getting start guide」(pdf) 英語です。
- Microsoftの.NET Micro Frameworkのページ。.NET Micro FrameworkのAPIリファレンス。日本語の開発者向け情報
- FEZ Dominoの開発元のTINYCLRのチュートリアルも役に立ちます(ダウンロードページ)。You Tubeのビデオもあります(ただし英語)。特にBeginners E-Book(pdf)にはC#の解説があります(英語)。
- TINYCLRの輸入販売代理店株式会社デバイスドライバーズにはFEZ Dominoの日本語情報ページTINYCLR.jpがあります。

- NETMFProjects。色々なサンプルがいっぱいあります。
- .NET Micro Framework Wiki。色々なサンプルがいっぱいあります。

- MAKE:Japanの記事「Maker Shedの新製品 Netduino - .NETベースのオープンソースエレクトロニクスプラットフォーム
- PS3とLinux、電子工作もさんのブログ、「Netduino Get」、他にもFEZ Domino関連の有用な情報があります。
- CuBeatSystemsさんのブログ「Netduinoを始めよう(環境構築編)」「Netduinoを始めよう(プログラミング初めの一歩編)
- Lynx-EyEDの電音鍵盤さんのブログ「netduinoでOLED制御してみた」。最近各所で人気のaitendoOLEDをさっそく使っています。
- 同じくモニターに当たった「冬斗のつぶやき」さんも日記風にnetduino情報を公開されています。
- Java Enthusiastさん「Netduinoを触ってみる (1)
- 同じくモニターに当たったひとりぶろぐさん、「Netduino始めました」「NetduinoをMacで使いたい!
- いつもお世話になっている、いしかわきょ-すけさんや森秀樹さんもさっそく試されたようです。

- やまねこのマイコン実験室さんのwiki。とても丁寧な解説があります。

- EDK。他の.NET Micro Framework対応マイコンボード。これも$50と安い。ただしArduino互換ではありません。

- Interface 2009年12月号の記事「.NET Micro Frameworkによるネットワーク端末の製作」

- Twitter 中の人 @netduino タグ #netduino

- C# によるプログラミング入門
- 改訂版 C#入門


雑感

なんといってもC#を使えるのがいいです。マルチスレッドとかstringクラスとか使えちゃいます。なんとカベージコレクタまでいます。もっともガベージコレクタが動くとやたら時間がかかります。netduinoにも含まれているかどうか分かりませんが、.NET Micro Framework自体はグラフィックスやTCP/IPのプロトコルスタックもサポートしているらしいです。

.NET Frameworkは、色々な言語を中間言語(IL)にコンパイルして、ILを実行します。ILを直接動かせるCPUはないのでJITでネイティブコードに落として実行したり、インタプリタで実行したりします。PCの場合はJITなので速度的に不利な点はあまりないのですが、.NET Micro Frameworkだとインタプリタ方式なので、かなり遅くなります。
また、.NET Micro Frameworkでは開発言語としてC#のみをサポートしているようです(要確認)。VBとかC++とかでも開発できるようになってほしいところです。後はネイティブコンパイラかな。

Arduinoと較べると、デバッグができるのが一番うれしいです。エミュレータもあります。複雑なロジックなんかはPC上でC#で作っちゃうなんてこともできます。

プロトタイピングということだと、netduinoで試作品を作ったものを他の環境(製品とか)に持っていこうとすると、.NET Micro Frameworkそのものの移植も作業に含まれるので結構たいへんそうです。Arduinoの場合だと、スケッチを書き込んだATMega328を抜いて他の環境に挿してしまえば、それで終わりです。もっともこれだけ安いと他の環境にもっていかずにそのまま組み込んで使ってもいいくらいです。

Arduinoと違う点で注意しないといけないのは、I/Oの電圧と最大流せる電流です。netduinoはかなり少ないみたいです(後で調べる、netduino固有な点)。

.NET Micro Framework自体の移植もporting kitを使うことで行えます。STBeeだとぎりぎり載せれます。

スイッチサイエンスさんで、発売記念価格で限定40セット売り出したところ、次の日には売り切れてました。ちょこっと試してみるにはお手ごろな感じです。

とにかく、これからが楽しみなデバイスです。
特に1社ではなく複数の会社からボードが出てきているあたりは期待が持てます。

モニターということで、このような楽しいデバイスで遊ぶ機会をくださったスイッチサイエンスさんに感謝いたします。

8/25 追記 NETMFProjectsと.NET Micro Framework Wikiを追加。C#入門関連を追加。
8/28 追記 ひとりぶろぐさんを追加