目次

LPC1114利用

 LPC1114はARMプロセッサで、48MHzで動作します。

 MCR_VCのBrain部分は、Arduino化したLPC1114で実現し
 下位レベルの処理は、素のままのLPC1114を利用すると
 並列動作をさせられます。

 階層構造をもったハードウエアの構成を以下としました。



 LPC1114は、単体で¥180なので、3個利用したところで
 ¥540です。超高速プロセッサ1個でMCR_VCに関係する
 処理を実現するよりも、コストを下げられると判断して
 LPCXpressoでファームウエアを開発してみます。

 FlashMagicは用意したので、LPCXpressoでHEXファイルを
 生成すれば、簡単にファームウエアを入れられます。

 LPC1114のポートに関して調べました。



 ピンアサインから、次のポートがあると判断できます。

 最近のマイコンは、1ピンで複数ハードウエアモジュールの
 入出力を兼用するので、ピンのコンフィグレーションが必要
 です。

 LPC1114のポートの扱いは、GPIO、A/D変換器、タイマーカウンタ
 の入出力のどれかにします。

 ピンアサインを見ていくと、A/D変換器は次のように
 大部分はPORT1に割り当てられています。



 タイマーカウンタに関係するピンアサインは、以下。



 MCR_VCマシンをシステムとして動かすには、何が必要かと
 考えると、足と目。

 足はDCモータ、サーボモータを使ったとしてタイマー
 カウンタ出力が3ピンあれば、手持ちのメカに対応可能。

 LPC1114はタイマーカウンタは、16ビットと32ビットの
 2種があり、各々2チャネルずつもつので、16ビットの
 2チャネルをDCモータ、32ビットの1チャネルをサーボ
 モータに割り当てることにします。

 目として、GameBoyCameraを利用すると、7ピン必要に
 なります。そのうちの1ピンはアナログ入力を扱える
 ことが必須。

 足回りと目に関係する信号処理はできたとして、Brainの
 プロセッサとの情報交換は、どうするのかが問題。

 モータ専用とセンサー専用に分けて、データ交換を考えます。

 DCモータ、サーボモータは、アナログスイッチを利用して
 データ3ビット、アドレス3ビットの合計6ビットあれば
 DUTY比をBrainからSubのプロセッサに渡せます。

 各モータへの出力3ピンと合わせ、合計9ピン使えば
 インターフェースは完成。



 センサーは、なるべくピン数を少なくしてデータを渡したい
 ので、4ビットでコード化した値を出力すればよいでしょう。



 ここまで仕様を決めたので、C/C++で利用するステートメントを
 考えていきます。

 GPIO、A/D変換器、タイマーカウンタ関係の入出力を指定する
 には、レジスタを使って指定します。

 GPIOの機能に関係するレジスタは、以下。

  LPC_IOCON->PIO0_0
  LPC_IOCON->PIO0_1
  LPC_IOCON->PIO0_2
  LPC_IOCON->PIO0_3
  LPC_IOCON->PIO0_4
  LPC_IOCON->PIO0_5
  LPC_IOCON->PIO0_6
  LPC_IOCON->PIO0_7
  LPC_IOCON->PIO0_8
  LPC_IOCON->PIO0_9
  LPC_IOCON->PIO0_10
  LPC_IOCON->PIO0_11
  LPC_IOCON->PIO1_0
  LPC_IOCON->PIO1_1
  LPC_IOCON->PIO1_2
  LPC_IOCON->PIO1_3
  LPC_IOCON->PIO1_4
  LPC_IOCON->PIO1_5
  LPC_IOCON->PIO1_6
  LPC_IOCON->PIO1_7
  LPC_IOCON->PIO1_8
  LPC_IOCON->PIO1_9

 8ビット中の3ビットを機能の指定(000)に利用
 プルアップとプルダウンを2ビットで指定
 1ビットでヒステリシスを指定します。



 方向を指定するには、ポート全体で12ビットとして
 1で出力、0で入力を指定します。
 LPC_GPIO0->DIR、LPC_GPIO1->DIRの32ビットレジスタ
 を2個利用。

 特定ピンに1、0を出力するには、専用関数を作って
 対応した方が簡単になります。

#define OFF 0
#define ON  OFF+1

#define START_BIT 1
#define SIN_BIT   2
#define LOAD_BIT  3
#define XRST_BIT  8
#define XCK_BIT   9
#define READ_BIT  10

void put_start(int x)
{
  if ( x ) { LPC_GPIO0->DATA |=  (1 << START_BIT) ; }
  else     { LPC_GPIO0->DATA &= ~(1 << START_BIT) ; }
}

void put_sin(int x)
{
  if ( x ) { LPC_GPIO0->DATA |=  (1 << SIN_BIT) ; }
  else     { LPC_GPIO0->DATA &= ~(1 << SIN_BIT) ; }
}

void put_load(int x)
{
  if ( x ) { LPC_GPIO0->DATA |=  (1 << LOAD_BIT) ; }
  else     { LPC_GPIO0->DATA &= ~(1 << LOAD_BIT) ; }
}

void put_xrst(int x)
{
  if ( x ) { LPC_GPIO0->DATA |=  (1 << XRST_BIT) ; }
  else     { LPC_GPIO0->DATA &= ~(1 << XRST_BIT) ; }
}

void put_xck(int x)
{
  if ( x ) { LPC_GPIO0->DATA |=  (1 << XCK_BIT) ; }
  else     { LPC_GPIO0->DATA &= ~(1 << XCK_BIT) ; }
}

int get_read(void)
{
  int result ;

  result = OFF ;
  if ( LPC_GPIO0->DATA & (1 << READ_BIT) ) { result = ON ; }
}

 ARMは、32ビットのプロセッサなので32ビットが最も
 扱いデータ幅なので、レジスタは32ビットで扱います。

 動作テストにC/C++を持ち出すのは、面倒なのでForthの
 インタプリタを載せます。

 LPC1114に載せるForthは、mecrips-stellarisのtarボールを
 ダウンロードし、含まれているLPC1114用のHEXファイルを
 焼きこんでインストール。

 端末接続して、動作を確認しておきます。



 操作サンプル例は、以下。(¥は全角ですが、本来は半角です)

¥ Blink a LED on P1.8

$40044014 constant IOCON_PIO1_8
$50013FFC constant GPIO1_DATA
$50018000 constant GPIO1_DIR

: blinky ( -- )
  $C0 IOCON_PIO1_8 ! ¥ Set P1.8 as GPIO without Pullup/Pulldown. $C0 are reserved bits that must be set.
  256 GPIO1_DIR    ! ¥ Set P1.8 as Output

  begin
    256 GPIO1_DATA !
    1000000 0 do loop
      0 GPIO1_DATA !
    1000000 0 do loop
  key? until
;

 Forthは、ワードを定義して、それを呼び出すというのが基本。
 上のサンプルでは、P1.8(17ピン)にLEDを接続して、1と0
 を交互に出力するとなります。

 特定ピンに、ビット単位で1か0を出力するのは
 予め組み込まれているワードのbis!、bic!を利用
 しても、等価な処理を実現可能。

 もうひとつサンプル例を見ます。(¥は全角ですが、本来は半角です)

¥ Read voltage on P1.0 = AD1

$40048080 constant SYSAHBCLKCTRL
$40048238 constant PDRUNCFG ¥ Power-down configuration register
$40044078 constant IOCON_PIO1_0

$4001C000 constant AD0CR
$4001C004 constant AD0GDR

¥ $4001C00C constant AD0INTEN
¥ $4001C010 constant AD0DR0
¥ $4001C014 constant AD0DR1
¥ $4001C018 constant AD0DR2
¥ $4001C01C constant AD0DR3
¥ $4001C020 constant AD0DR4
¥ $4001C024 constant AD0DR5
¥ $4001C028 constant AD0DR6
¥ $4001C02C constant AD0DR7
¥ $4001C030 constant AD0STAT

: analog-init ( -- )
  1 13 lshift SYSAHBCLKCTRL bis! ¥ Enable Clock for ADC
  1  4 lshift PDRUNCFG bic!      ¥ Clear Power-down for ADC
  $42 IOCON_PIO1_0 !             ¥ Select Analog input mode for P1.0
;

: analog ( -- measurement )
  1  1 lshift   ¥ AD1 Channel
  4  8 lshift or ¥ CLKDIV = 4 --> 12 Mhz / 4 = 3 MHz < 4.5 MHz maximum.
  0 16 lshift or  ¥ Burst off
  0 17 lshift or   ¥ 11 clock cycles - 10 Bit accuraccy
  1 24 lshift or    ¥ Start conversion now.
  AD0CR !

  begin 1 31 lshift AD0GDR bit@ until ¥ Wait for done flag.
  AD0GDR @ 6 rshift $3FF and
;

: scan ( -- )
  analog-init
  begin
    analog u. cr
  key? until
;

 このサンプルでは、ワードlshiftが多用されています。
 C言語と対比させて見れば、簡単に意味がわかります。

  1 13 lshift => (1 << 13)

 日本語では、そのまま読めば意味はすぐにわかります。

  1を13ビット左にシフトし、スタックに積む

 このカラクリで見ると、次のステートメントの意味がわかります。

  1 13 lshift SYSAHBCLKCTRL bis! ¥ Enable Clock for ADC

  1を13ビット左にシフトし、スタックに積む
  スタックにおいた値をSYSAHBCLKCTRLに格納
  ただし、1がセットされているビットだけ

 組込みワードがどれだけあるのかと見てみます。

2dup 2drop 2swap 2nip 2over 2tuck 2rot 2-rot 2>r 2r> 2r@ 2rdrop d2/ d2*
dshr dshl dabs dnegate d- d+ s>d um* m* ud* udm* */ */mod u*/ u*/mod um/mod
m/mod ud/mod d/mod d/ f* f/ 2!  2@ du< du> d< d> d0< d0= d<> d= sp@ sp!
rp@ rp!  dup drop ?dup swap nip over tuck rot -rot pick depth rdepth >r r>
r@ rdrop rpick true false and bic or xor not clz shr shl ror rol rshift
arshift lshift 0= 0<> 0< >= <= < > u>= u<= u< u> <> = min max umax umin
move fill @ !  +!  h@ h!  h+!  c@ c!  c+!  bis!  bic!  xor!  bit@ hbis!
hbic!  hxor!  hbit@ cbis!  cbic!  cxor!  cbit@ cell+ cells flash-khz
16flash!  eraseflash initflash hflash!  flushflash + - 1- 1+ 2- 2+ negate
abs u/mod /mod mod / * 2* 2/ even base binary decimal hex hook-emit
hook-key hook-emit?  hook-key?  hook-pause emit key emit?  key?  pause
serial-emit serial-key serial-emit?  serial-key?  cexpect accept tib >in
current-source setsource source query compare cr bl space spaces [char]
char ( \ ." c" s" count ctype type hex.  h.s u.s .s words registerliteral,
call, literal, create does> <builds ['] ' postpone inline, ret, exit
recurse state ] [ : ; execute immediate inline compileonly 0-foldable
1-foldable 2-foldable 3-foldable 4-foldable 5-foldable 6-foldable
7-foldable constant 2constant smudge setflags align aligned align4,
align16, h, , ><, string, allot compiletoram?  compiletoram compiletoflash
(create) variable 2variable nvariable buffer: dictionarystart
dictionarynext skipstring find cjump, jump, here flashvar-here then else if
repeat while until again begin k j i leave unloop +loop loop do ?do case
?of of endof endcase token parse digit number .digit hold hold< sign #> f#S
f# #S # <# f.  f.n ud.  d.  u.  .  evaluate interpret hook-quit quit eint?
eint dint ipsr nop unhandled reset irq-systick irq-fault irq-collection
irq-adc irq-i2c irq-uart

 ワードは300ほどあります。
 全ワードの利用はないでしょうが、ハードウエアテスト
 には、必要かつ充分と言えるでしょう。

 Forthは、プロセッサのもっている特性が不明だと
 うまく使いこなせず、スクリプトを作成するのが
 面倒になることがあります。

 裏を返すと、プロセッサ内部にあるSFR(Special Function Register)の
 アドレスやビット構成等をすべてを理解して使いこなしたい場合に利用
 する言語がForthかも知れません。

 Forthの言語仕様は、逆ポーランド記法なので、日本語の文章を
 書くようにコードを入力していくと、ほぼプログラムになります。

 MCRマシンでは、モータを動かすので、タイマー/カウンタに
 関係する内容を理解して、試してみることが必要。

 LPC1114には、タイマー/カウンタは16ビット、32ビットが各2チャネル
 あります。合計4個のタイマー/カウンタを利用できます。

 16ビットのタイマー/カウンタに関係するレジスタは、以下。





 レジスタのエントリーアドレスは、チャネル0、1で次のように
 固定されています。

    Timer 0 (16bit) 0x4000 C000
    Timer 1 (16bit) 0x4001 0000

 タイマー/カウンタのユニットには、プリスケーラが用意されて
 レジスタとカウンタがあり、プリスケーラが出力するクロックを
 入れてタイマー/カウンタを動かすためのクロックにします。




 システムクロックをPCに入力し、PCとPRの値が一致すると
 PCはリセットされ、タイマー/カウンタに1クロック出力
 されます。

 PC、PRともに4バイト=32ビットのアドレスを占有。

 LPC1114がAMRプロセッサで、32ビットを一度に扱える
 ため、アドレスも4バイトを扱えるようにメモリに
 配置されています。

 プリスケーラから出力されたクロックは、タイマー/カウンタに
 入力され、マッチレジスタの値によりゼロクリアされるように
 できます。




 マッチレジスタの値でタイマー/カウンタをリセットするかや
 割込みをどうするのかを設定で決めます。

 タイマー/カウンタのリセット、割込みを発生させるか、停止
 するか等をMCRレジスタで指定できます。



 マッチレジスタ0の値で、タイマー/カウンタをリセットし
 割込みを利用するとすれば、レジスタへの設定は、以下。

¥ set LABEL
$4000C000 constant TMR16B0IR
$4000C004 constant TMR16B0TCR
$4000C008 constant TMR16B0TC
$4000C00C constant TMR16B0PR
$4000C010 constant TMR16B0PC
$4000C014 constant TMR16B0MCR
$4000C018 constant TMR16B0MR0
$4000C01C constant TMR16B0MR1
$4000C020 constant TMR16B0MR2
$4000C024 constant TMR16B0MR3

¥ set prescaler (generate 1MHz)
0 TMR16B0PC !
47999 TMR16B0PR !

¥ set MCR (generate 10Hz)
1 TMR16B0IR !
3 TMR16B0MCR !
49999 TMR16B0MR0 !

¥ enable TMR16B0
3 TMR16B0TCR !

 割込みに関しては、レジスタIRを利用します。



 タイマー/カウンタを動かす場合は、レジスタTCRを使います。




 マッチレジスタが4チャネルあるので、DCモータ、サーボモータを
 合計で4個利用できるとなります。タイマー/カウンタを1チャネル
 利用すると、モータを合計で4個使うことが可能と言えます。

 16ビットのタイマー/カウンタでは、扱えない周波数に対応するには
 32ビットのタイマー/カウンタを使います。
 使い方は、16ビットのタイマー/カウンタと同じです。
 それは、レジスタを見れば、わかります。



 レジスタのエントリーアドレスは、チャネル0、1で次のように
 固定されています。

    Timer 0 (32bit) 0x4001 4000
    Timer 1 (32bit) 0x4001 8000


 モータのドライバとしては、次のように制御パルスを出力する
 ピンと考えればよいでしょう。



 センサーとして、Game Boy Cameraを接続するとした場合
 GPIOの処理が必要となります。

 LPC1114は、ポート0、1にそれぞれ12ビットを持つので
 GPIO_0、GPIO_1の使い方を見てみます。

 SFRのエントリーアドレスは、以下。

    GPIO_0 0x5000 0000
    GPIO_1 0x5001 0000

 用意されているレジスタ類は、次のようになっています。



 入出力設定は、GPIO0DIR、GPIO1DIRで指定。

 ピンの論理値は、GPIO0DATAですが、GPIO0_0から
 GPIO0_11とGPIO1_0からGPIO1_11を使い、細かい
 扱いができるように配慮されています。

 GPIOと16ビットタイマーを利用して、ハードウエアの動作
 チェックを考えます。

 LEDの点滅が最も簡単なので、IchigoJamのハードウエアを
 利用して、14ピンに接続しているLEDを点滅します。



 14ピンはPIO1_5となっているので、GPIO1に関係するレジスタを
 利用して入出力をきめます。

$50010800 constant P1_5
$50018000 constant GPIO1_DIR

1 5 lshift GPIO1_DIR bis!
$fff P1_5 ! ¥ turn on LED
$000 P1_5 ! ¥ turn off LED

 Forthを載せたLPC1114基板は、以下。



 左下にある凹ソケットヘッダにLEDを入れて、点灯
 消灯、点滅をチェック。

 次の制御基板に接続するため、10ピンケーブルと
 ブレッドボードで使うワイヤーを用意します。




目次

inserted by FC2 system