« Arduinoで漢字表示(3) | トップページ | Arduinoで漢字表示(4) »

GLCDシールドの制作

これまでブレッドボードに載せていたGLCDをユニバーサル基板を使ってArduinoのシールド調にしてみました。

構成

以下の部品を載せるために、ちょっと大きめですがサンハヤト ICB-97GHD(95x135mm)を使用しました。GLCDは8-bitパラレルバスで必要なピン数が多いため、Arduino Megaを使用しています。

  • GLCD(SG12864)
  • SPI Data Flash Memory(AT45DB161D:漢字フォントの格納用)
  • Ethernet Module(WIZ812MJ:純正Ethrenet shieldと同じW5100 chipを使用)
  • 3.3V3端子レギュレータ(TA48033S
  • 3.3V用リセットIC(TCM809R

Arduino純正のEthernet Shieldでよく指摘されていますが(Under Power 研究所さんの参考記事)、ArduinoのRESETピンは5VにプルアップしてあるだけでEthernet Shieldで使用しているW5100 TCP/IP処理チップのパワーオンリセット(2μs以上Lowレベルに落とす必要がある)に使えません。そのため、リセットICを使用して3.3V系のパワーオンリセットリセットパルスを作っています。

回路図を以下に示します。

 GLCD_Shield21

外観の写真はこんな感じです(漢字表示を行っていますが、こちらは別途続編を投稿します)。W5100チップと3端子レギュレータは熱対策としてヒートシンクを貼り付けています(W5100はそれほど気にする必要はないのでしょうが気休めです)。

Glcd_shield1

裏面の写真です。ピンヘッダを使って、Arduinoを裏側から接続します。

Glcd_shield2

工作テクの限界で配線が汚いです。リセットIC(米粒大)の半田付けは結構苦戦。半田の熱でチップのパッケージが溶けそうになりました、、本当に動いているのか怪しいところがありますが、WIZ812MJが正しく起動しているので多分大丈夫でしょう。

AT45DB161D Data Flashの接続

前回の記事「Arduinoで漢字表示(3)」からの変更点を以下に記載します。WIZ812MJとSPI接続を共有するための変更です。

1)SPIのSlave Select(SS)ピンをPL0に移動しました。ATMega1280のSSピン(PB0)はWIZ812MJ(Ethernet Module)で使用します。SS信号はソフト制御のためどのピンに移動してもよいと思ったのですが、単にピンアサインをPL0に変更しただけでは動いてくれませんでした。Arduino Forumを漁ってみると、オリジナルのPB0をHighに設定してからSPIレジスタ(SPCR)の設定をせよとあります。確かにこの方法で動作します。

2)オリジナルのat45db161dライブラリでは、SPI mode 3を使っています。Ethernetライブラリにあわせてmode 0に変更しました。(WIZ812MJはEthernetライブラリがそのまま使えます)

3)オリジナルのat45db161dライブラリでは、各関数の入り口でSS信号をHigh→Low(active)にトグルしてデバイスをたたいた後、SSをLowのままで放置しています。他のSPIデバイスと共存するためには、アクセス終了後SS信号をHigh(inactive)にする必要があります。

at45db161dライブラリでは、ContinuousArrayRead()関数などでデバイスにコマンドを送った後、引き続きspi_transfer()を呼び出すことでデーターの転送を行うため、この一連のアクセスの中でデバイスをactive状態に保持する必要があります。すなわち、ContinuousArrayRead()関数の出口でSSをinactiveにできません。

at45db161dライブラリには、EndAndWait()という関数があり一連のアクセス終了後この関数を呼んでSSをinactiveにすればよさそうです。EndAndWait()でもSSをactiveのまま放置しているため、inactiveにするコードを追加しました。

4) ComparePageToBuffer()のバグ修正(前回と同様の内容を再掲)

at45db161dライブラリ(オリジナルはBlokoSさんのブログ)の変更点を以下に示します。

<at45db161d.h>

#ifndef AT45DB161D_H
#define AT45DB161D_H

#include <WProgram.h>

extern "C" {
#include <avr/pgmspace.h>
#include <inttypes.h>
#include "WConstants.h"
};

#include "at45db161d_commands.h"

#ifndef SPI

#if defined(__AVR_ATmega1280__)
  #define DATAOUT     51
  #define DATAIN      50
  #define SPICLOCK    52
  #define SLAVESELECT 49     // 53(PB0)→ 49(PL0)に変更
  #define SPI_SS      53
  #define RESET        8
  #define WP           7
#else
  #define DATAOUT     11
  #define DATAIN      12
  #define SPICLOCK    13
  #define SLAVESELECT 10
  #define RESET        8
  #define WP           7
#endif
・・以下略・・

<at45db161d.cpp>

void ATD45DB161D::Init()
{
        uint8_t clr;
       
        /* Initialize pinout */
        pinMode(DATAOUT, OUTPUT);
        pinMode(DATAIN, INPUT);
        pinMode(SPICLOCK, OUTPUT);
        pinMode(SLAVESELECT, OUTPUT);
        pinMode(DATAIN, INPUT);

        /* Disable device */
        DF_CS_inactive;                    // Deactivate alternative SS
#if defined(__AVR_ATmega1280__)
     
digitalWrite(SPI_SS, HIGH);        // Deactivate original SS (Must be HIGH befor SPCR set)
#endif

        /* Setup SPI mode=0 */
        //SPCR = (1 << SPE) | (1 << MSTR) | (1 << CPOL) | (1 << CPHA);
        SPCR = (1 << SPE) | (1 << MSTR);

        /* Cleanup registers */
        clr = SPSR;
        clr = SPDR;
}

void ATD45DB161D::EndAndWait()
{
        DF_CS_inactive;  /* End current operation */
        DF_CS_active;    /* Some internal operation may occur
                          * (buffer to page transfer, page erase, etc... ) */

        /* Wait for the chip to be ready */
        while(!(ReadStatusRegister() & READY_BUSY))
        {}
        DF_CS_inactive;  /* Release SPI Bus */
}

int8_t ATD45DB161D::ComparePageToBuffer(uint16_t page, uint8_t bufferNum)
{
        uint8_t status;
       
        DF_CS_inactive;    /* Make sure to toggle CS signal in order */
        DF_CS_active;      /* to reset Dataflash command decoder     */

        /* Send opcode */
        spi_transfer((bufferNum == 1) ? AT45DB161D_COMPARE_PAGE_TO_BUFFER_1 :
                                        AT45DB161D_COMPARE_PAGE_TO_BUFFER_2);
       
        /* Page address */
        spi_transfer((uint8_t)(page >> 6));
        spi_transfer((uint8_t)(page << 2));
        spi_transfer(0x00);
       
        DF_CS_inactive;  /* Start comparaison */
        DF_CS_active;

        /* Wait for the end of the comparaison and get the result */
        while(!((status = ReadStatusRegister()) & READY_BUSY))
        {}
       
        if ( status & COMPARE )
           return 0;       /* If (COMPARE bit = 1) then Error  */
        else
           return 1;

}

WIZ812MJの接続

1)電源系統

WIZ812MJは3.3V動作かつ200mA弱電力を喰うため、3.3Vボルテージレギュレーターから給電します。ボルテージレギュレーターの入力は、VIN(ACアダプターからの給電)を使用します。5Vから電源を取るとArduino本体のボルテージレギュレーターに結構電流が流れて発熱が大きくなるためです。Data Flashも3.3V動作のためこの電源を使います。

2)MISO信号の接続

AT45DB161Dと同様に、入力は5V許容のため、SCLK, MOSI, SCS(SS)はArduinoと直結します。悩んだのはMISO(WIZ812MJ側は3.3V出力)です。Ethernet shieldではMCUと直結になっています。また、Ethernetライブラリを見ると、MISOをつなぐ入力ピンの内蔵プルアップ抵抗を有効にしています。以下に、hardware\libraries\Ethernet\utility\spi.hの抜粋を示します(コメントは私が追記)

// Set DDR -> SS:output, SCLK: output, MOSI: output. Others: input (default)
// Set PORTB -> SS_HIGH
// Set PORTB -> Input pin pull-up (MISO)
#define SPI0_Init()        DDRB  |= SPI0_SS_BIT|SPI0_SCLK_BIT|SPI0_MOSI_BIT;\
                                 PORTB |= SPI0_SS_BIT; PORTB &= ~(SPI0_SCLK_BIT|SPI0_MOSI_BIT);\
                                 SPCR  = 0x50

MCUのMISOピンを5VにプルアップしてしまえばHighレベルの閾値電圧の問題はなくなりますが、SPIデバイス側で問題が出ないかです。WIZ812MJに載っているW5100 TCP/IPチップはVIN(DC Input Voltage)を5.5Vまで許容しているため、MISOを5Vにプルアップしても問題なさそうです。

一方AT45DB161D Data Flashの方は、出力を5Vにプルアップできるという記載はありませんでした。そのため、AT45DB161Dはレベルシフターをかませて3.3V→5V変換を行っています。レベルシフターのピンが余っていたのでWIZ812MJ側もレベルシフターを介して接続しています(W5100チップの5V入力許容に気がつく前に、レベルシフター経由で配線してしまったというのが実情ですが、、)。

(2009/7/22追記)
複数のSPIデバイスが存在する場合、MISO信号をMCUの手前で束ねる必要があります。このために、レベルシフターの5V出力側で、WIZ812MJとAT45DB161DのMISO信号をワイヤードオアしています。レベルシフターの5V出力側はMOS FETを使っており、オープンドレインのワイヤードオア回路相当になっているので出力をぶつけても問題ないかと思っています。AT45DB161DはSSがinactiveになるとMISOをtri-state(ハイインピーダンス)にするという記述がデーターシートにあります。複数デバイスのの出力を接続する場合は以下の方法がありますが、SPIは(b)の形態になるようです(I2Cはaでしょうか);

(a)各デバイスのオープンドレインをワイヤードオア(プルアップ要)
(b)各デバイスで出力ピンのハイインピーダンス制御を行ってバス接続

今にして思えば、WIZ812MJとAT45DB161DのMISOを3.3V側で束ねてやるのが正しい設計のように思えます。とりあえず動いていますが、どこかで修正して動作確認してみます。

(2009/7/31追記)
WIZ812MJとAT45DB161DのMISOを3.3V側で束ねる形態に回路を変更。問題なく動いています。回路図も修正しました。

(2009/8/15追記)
Arduino Forumにて次のスレッドを見つけました。
Arduino + Ethernet Shield + Another SPI device
W5100チップにてMISOをハイインピーダンスにするためには、SS(SCS)の制御でなくSEN(SPI enable)信号をLowレベルに落としてやる必要があるとのことです(データーシートには記載がないのですが)。WIZ812MJはSS信号をモジュール内で反転してSENに入力しているため、MCUからSSをInactive(High)にすると自動的にSENがLowに落ちてくれます。そのため、WIZ812MJではSS信号に連動してMISOをハイインピーダンスにすることができるため、他のSPIデバイスとの混在が可能です。

Official Ethernet ShieldではSENをプルアップしているのみです。そのため、Official Ethernet ShieldではMISOをハイインピーダンスにすることができず、他のSPIデバイスと混在して使用する際は注意が必要です。

3)Ethernet Libraryの修正

Arduino IDE添付のライブラリはATMega168/328用です。Arduino Megaが使用しているATMega1280はSPI関連のピン収容が異なるためそのままでは動作しません。hardware\libraries\Ethernet\utility\spi.hを以下のように修正することでArduino Megaでも動作するようになります。

//------------------------------------------------------------------------
//AVR Mega168/1280 SPI HAL
#define BIT0                            0x01
#define BIT1                            0x02
#define BIT2                            0x04
#define BIT3                            0x08
#define BIT4                            0x10
#define BIT5                            0x20
#define BIT6                            0x40
#define BIT7                            0x80

#if defined(__AVR_ATmega1280__)            //Arduino Mega用ピン収容
#define SPI0_SS_BIT                    BIT0
#define SPI0_SS_DDR                    DDRB
#define SPI0_SS_PORT                    PORTB
#define SPI0_SCLK_BIT                    BIT1
#define SPI0_MOSI_BIT                    BIT2
#define SPI0_MISO_BIT                    BIT3

#else
#define SPI0_SS_BIT                    BIT2
#define SPI0_SS_DDR                    DDRB
#define SPI0_SS_PORT                    PORTB
#define SPI0_SCLK_BIT                    BIT5
#define SPI0_MOSI_BIT                    BIT3
#define SPI0_MISO_BIT                    BIT4
#endif

#define SPI0_SCLK_DDR                    DDRB
#define SPI0_SCLK_PORT                    PORTB

#define SPI0_MOSI_DDR                    DDRB
#define SPI0_MOSI_PORT                    PORTB

#define SPI0_MISO_DDR                    DDRB
#define SPI0_MISO_PORT                    PORTB


#define SPI0_WaitForReceive()
#define SPI0_RxData()                     (SPDR)

#define SPI0_TxData(Data)                (SPDR = Data)
#define SPI0_WaitForSend()                while( (SPSR & 0x80)==0x00 )

#define SPI0_SendByte(Data)                SPI0_TxData(Data);SPI0_WaitForSend()
#define SPI0_RecvBute()                    SPI0_RxData()

// PB4(MISO), PB3(MOSI), PB5(SCK), PB2(/SS)         // CS=1, waiting for SPI start // SPI mode 0, 4MHz
// Set DDR -> SS:output, SCLK: output, MOSI: output. Others: input (default)
// Set PORTB -> SS_HIGH
// Set PORTB -> Input pin pull-up (MISO)
#define SPI0_Init()                        DDRB  |= SPI0_SS_BIT|SPI0_SCLK_BIT|SPI0_MOSI_BIT;\
                                        PORTB |= SPI0_SS_BIT; PORTB &= ~(SPI0_SCLK_BIT|SPI0_MOSI_BIT);\
                                        SPCR  = 0x50

//------------------------------------------------------------------------

//------------------------------------------------------------------------
//IInChip SPI HAL
#define IINCHIP_SpiInit                    SPI0_Init
#define IINCHIP_SpiSendData                SPI0_SendByte   
#define IINCHIP_SpiRecvData                SPI0_RxData


#if defined(__AVR_ATmega1280__)
#define IINCHIP_CS_BIT                    BIT0
#define IINCHIP_CS_DDR                    DDRB
#define IINCHIP_CS_PORT                PORTB

#else
#define IINCHIP_CS_BIT                    BIT2
#define IINCHIP_CS_DDR                    DDRB
#define IINCHIP_CS_PORT                PORTB
#endif

#define IINCHIP_CSInit()                    (IINCHIP_CS_DDR |= IINCHIP_CS_BIT)
#define IINCHIP_CSon()                    (IINCHIP_CS_PORT |= IINCHIP_CS_BIT)
#define IINCHIP_CSoff()                    (IINCHIP_CS_PORT &= ~IINCHIP_CS_BIT)
//------------------------------------------------------------------------

その他

at45db161d, Ethernet libraryの両方を使って、漢字表示(SPI Data Flash memoryへのアクセス)とTCP/IP接続の併用ができるようになりました。

GLCDはピンソケットを使いユニバーサル基板面から持ち上げて実装しているため、GLCDの下側に広大な敷地があります。この敷地に生AVR(ATMega644あたり)を載せてしまえば、高価なArduino Megaを占有せずに回路が組めそうです。最終目的のRSSリーダー用ファームができるまでは頻繁にライブラリやスケッチの更新を行うためMegaを使うとして、安定版ができたら、ATMega644 + SanguinoにスイッチしてMegaを浮かせるという道もありそうです。

あと、コストパフォーマンスを考えると、ストロベリー・リナックスさんで販売しているWIZ200Webという選択肢もおもしろそうです。W5300とATMEGA128,フラッシュROM(4Mビット),外部RAM(256Kビット)がついて4300円と大変お得です。TCP/IPチップがW5300のため、Arduino Ethernet libraryはそのままでは使えないと思いますが。

2009/7/22追記:
MISO信号のバス接続に関する記述を追加。

2009/7/31追記:
MISO信号の接続を変更。

« Arduinoで漢字表示(3) | トップページ | Arduinoで漢字表示(4) »

Arduino」カテゴリの記事

コメント

イーサネットシールドが電源 ON 時に自動的にリセットされない問題で困っている電子工作初心者です。本ページの作者様と同じ対処をしたいと思っているのですが、回路図が理解できないでいます。
TCR809R という IC をどこかで買ってきて、回路図のとおりにつなげればいいのでしょうが、RC809R で Google 検索しても 1 件もヒットしませんで、これは何者でどうやって入手すればよいのか、また、その IC につながっている 3V3 とは何者でどこからその線を引っ張ってくればよいのか、よく分からないでいます。
勝手ながら、もう少しレベルを下げていただけると助かるのですが...。
よろしくお願いします。

ちょっと確認ですが、Arduino Duemilanove(もしくは互換機)とOfficial Ethernet Sheildの組み合わせをお使いでしょうか。そうであれば、リセットICを追加するより、Ethernet Sheild側のGND - RESETピン間に0.047μFのコンデンサーを半田付けするほうが対策として楽だと思います。実はOfficial Ethernet shieldでこの対策を行ってうまく動いているので、別途新規エントリとしてアップしますね。

ちなにみ、リセットICのTCM809Rは、ブログのリンクにもあるように秋月電子さんで購入できます(通販コード:I-02533)。このブログ記事では、Ethernet shield相当を自作したため、リセット回路を追加していますが、できあいのEthernet sheildを使う場合、リセットICの追加よりコンデンサ追加の方が楽だと思います。

3V3は3.3Vの電源で、GLCDシールド上のボルテージレギュレーター(TA48033S)を使って作っています。3.3V電源の目的はリセット対策というよりGLCDシールに載せているEthernetモジュール(WIZ812MJ)とFlash ROMに3.3V電源を供給するためです(こいつらは5Vでなく3.3V動作なのと、WIZ812MJは150mA以上の電源容量が必要です)。ついでにこの3.3V電源を使ってリセット信号を作っています。TA48033Sの入力はArduinoの外部電源(VIN)です。私は7.5VのACアダプターをMegaの外部電源ジャックに接続しているため、7.5V→VINピン→TA48033S→3.3V(3V3)というルートで3.3V電源を作っています。できあいのEthernet sheildには3.3V電源が乗っていますので、市販品を使う場合この電源部分は必要ありません。

Arduinoのリセットに関しては、こんな情報もあります。
http://labo-section9.blogspot.com/2010/05/arduino.html

MTM05で販売していたようです。

リンクいただいたブログ参考になりました。情報ありがとうございました。

コンデンサーを追加した私の環境では、Aruduinoの外部電源ジャックを抜き差しする場合は正しくEthernet sheildをリセットできますが、ACアダプターのACプラグを抜き差しする場合は正しく起動しません。リンクいただいたブログにあるように、DC入力の立ち上がりが遅く、リセットが働かないのだと思います。

もう一つ問題として指摘があったスケッチダウンロード時のFT232からのリセットですが、私は0.047uFと小さめのコンデンサを追加しているためか、今のところ問題なく動いています。

こんにちは

この投稿をWIZNETにほんブログの方に紹介したいのですが、よろしいでしょうか

doublesk@wiznettechnology.com

以上のメールやコメント返答おねがいします。

こんにちは

この投稿をWIZNETにほんブログの方に紹介したいのですが、よろしいでしょうか

doublesk@wiznettechnology.com

以上のメールやコメント返答おねがいします。

SKさん

WIZNETブログへの掲載問題ありません。
よろしくお願いします。

Todotani様

いつもお世話になっております、WIZNETのKIMです。

今回新製品の体験評価のために案内事項があるのですが
よろしければ上のメールアドレスでメールを頂けますか。

この記事へのコメントは終了しました。

« Arduinoで漢字表示(3) | トップページ | Arduinoで漢字表示(4) »

2018年10月
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
無料ブログはココログ