FC2カウンター FPGAの部屋 SMM
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

The Simple MicroBlaze Microcontroller 15 (デバック)

The Simple MicroBlaze Microcontroller 13 (16KB RAMのSMMでもう一度)”でソフトウェアをSDKでコンパイルできたので、今度はデバックを試みた。
デバックのやり方は”The Simple MicroBlaze Microcontroller 5(デバック機能)”を参照のこと。
デバックモードにすると、Consoleに”Could not find the frame base for "main".”と表示され、Variablesウインドウに変数値が表示されない。
SMM_58_101220.png

解決策を例によってXilinxのアンサーデータベースで検索したら、”12.1 EDK - SDK could not find the frame base for "main" in debugging”が引っかかった。
解決策としては、何のことはない、関数のプロトタイプ宣言をして、main関数を一番最初にしろとのことだった。

int func1(. . . ); //func1 prototype defined here

int main(void) //main defined here
{
:
:
}

int func1(. . . ) //func1 defined here
{
:
:
}


ソフトウェアを修正することにする。

int main(void)をCソースの一番上にして、下のインクルード・ファイルをインクルードした。

// lcd_rot_cont.h

void Timer_Wait (Xuint32 delay);
void lcd_init (void);
void lcd_print (Xuint32 Line, Xuint8 *Str);
void lcd_clear (void);
void timer_int_handler(void * arg);
void SCCB_reg_init(void);
char *ntoxn(char *str, unsigned short int x, int n);
char *strcpyc(char *s1, char *s2);
void SCCB_reg_status_disp(Xuint8 *Str);
void SCCB_cur_reg_disp(Xuint8 *Str);
void gain_level_reg_set(void);
void aec_level_h_reg_set(void);
void aec_level_l_reg_set(void);
int main(void);


すると、エラーが無くなって、変数が表示されるようになった。
SMM_60_101220.png
  1. 2010年12月20日 05:50 |
  2. SMM
  3. | トラックバック:0
  4. | コメント:0

The Simple MicroBlaze Microcontroller 13 (16KB RAMのSMMでもう一度)

The Simple MicroBlaze Microcontroller 12 (XPSでSMMをカスタマイズ)”でRAMを16KBに拡張したはずなので、生成したsmm.ngcとsmm.bmmをISE12.3のプロジェクトに入れてインプリメントし、SDKでコンパイルしてみた。

前回のプロジェクトにsmm.ngcとsmm_sutb.bmmからリネームしたsmm.bmmを入れて、もう一度インプリメントした。すると、Translateでエラー発生。よく見たら、bmmファイルのインスタンスパスが違っていた。一階層深くなっているので、bmmファイルを編集して、lcd_rot_cont_inst/ を追加した(前回同じことをやっていたのに懲りない。smm.ngcを置く階層に応じてsmm.bmmファイル階層表示を書き換える必要がある)。
こうしたらインプリメントが通った。FPGA Editorで見ても、SMMのRAMのインスタンスは8個あった。

次に、sdk3フォルダを新規に作成して、smm.xmlを置く。”The Simple MicroBlaze Microcontroller 4(リファレンスデザイン2)”の手順でSDKの設定をした。lcd_rot_cont.c をSDKのsrc フォルダにドラック&ドロップする。ビルドが始まり正常終了した。やったー。。。0x23c8番地まで使っているようなので、やはり8KBでは足りなかったようだ。下にビルド・メッセージを示す。

**** Build of configuration Debug for project empty_application_0 ****

make all 
Building file: ../src/lcd_rot_cont.c
Invoking: MicroBlaze gcc compiler
mb-gcc -Wall -O0 -g3 -c -fmessage-length=0 -I../../empty_application_bsp_0/microblaze_0/include -mcpu=v7.30.a -mno-xl-soft-mul -MMD -MP -MF"src/lcd_rot_cont.d" -MT"src/lcd_rot_cont.d" -o"src/lcd_rot_cont.o" "../src/lcd_rot_cont.c"
Finished building: ../src/lcd_rot_cont.c
 
Building target: empty_application_0.elf
Invoking: MicroBlaze gcc linker
mb-gcc -Wl,-T -Wl,../src/lscript.ld -L../../empty_application_bsp_0/microblaze_0/lib -mcpu=v7.30.a -mno-xl-soft-mul -o"empty_application_0.elf"  ./src/lcd_rot_cont.o   
Finished building target: empty_application_0.elf
 
Invoking: MicroBlaze Print Size
mb-size empty_application_0.elf  |tee "empty_application_0.elf.size"
   text       data        bss        dec        hex    filename
   6730        312       2118       9160       23c8    empty_application_0.elf
Finished building: empty_application_0.elf.size
 
Invoking: Xilinx ELF Check
elfcheck empty_application_0.elf -hw ../../SMM_DBG_noUART_hw_platform/system.xml -pe microblaze_0  |tee "empty_application_0.elf.elfcheck"
elfcheck
Xilinx EDK 12.3 Build EDK_MS3.70d
Copyright (c) 1995-2010 Xilinx, Inc.  All rights reserved.

Command Line: elfcheck -hw ../../SMM_DBG_noUART_hw_platform/system.xml -pe
microblaze_0 empty_application_0.elf 

ELF file    : empty_application_0.elf
elfcheck passed.
Finished building: empty_application_0.elf.elfcheck


SDKのXilinx ToolsメニューからProgram FPGAを選択して、ダウンロードしてみたが、動作がおかしい。デバックする必要がある。やっと、ソフトウェアのデバックの段階まで来た。
  1. 2010年12月18日 18:51 |
  2. SMM
  3. | トラックバック:0
  4. | コメント:0

The Simple MicroBlaze Microcontroller 12 (XPSでSMMをカスタマイズ)

前回、SMMのRAM容量が足りないなそう?ということがわかったので、XPSでSMMをカスタマイズし、RAMを8KBから16KBへ倍増させてみることにした。(最初は12.3でやったのだがワーニングが出ていて良いかどうかわからなくなったので、12.1でやり直した)

1. 最初にSMMのフォルダのうちで、SMM_Srcにソースが入っているので、そのうちのS3 (Spartan-3A) フォルダの下のSMM_DBG_noUARTフォルダを適当なフォルダの下にコピーする。ここでは、SMM_S3_BRAM_16Kフォルダの下にコピーする。

2. StartメニューからISE12.3のXilinx Platform Studio(XPS)を立ち上げ、Xilinx Platform StudioのダイアログでOpen recset project を選択し、OKボタンをクリックする。
SMM_43_101217.png

3. Open Existing Projectダイアログで1.のSMM_DBG_noUARTフォルダの下のsmm.xmpを選択して、Openボタンをクリックする。
SMM_44_101217.png

4. プロジェクトを作ったバーションと違うので、プロジェクトを変換するというダイアログが出たので、OKボタンをクリックした。プロジェクトが変換するために、Version Management Wizard が立ち上げる。Next ->ボタンをクリックする。(結構先が長いのかな?やりながらブログを書いています)
SMM_45_101217.png

5. bram_blockがアップデートしたけどfully backward compatible だそうだ。(それなら自動的にアップデートしても良さそう。。。)
SMM_47_101217.png

6. 次はplb_v46。1.04.aから1.05aに変更になったようだ。これは、ピンとパラメターはbackward compatible だが、他の機能が変更されているそうなので、Updata?のチェックを外した。(選べるのも便利そうだ。。。)
SMM_48_101217.png

7. 次はnot backward compatibleで、manually upgrade とのことだ。どうしよう?
SMM_49_101217.png

8. Apply Changes to your Project で終了。不安が残るが、Finishをクリックする。(だめならばやり直す)
SMM_50_101217.png

9. XPSが立ち上げる。やはり、ところどころ黄色い!が付いている。
SMM_51_101217.png

10. dlmb_cntlrのlmb_bram_if_cntlrをダブルクリックして、ダイアログを表示させる。LMB BRAM High Addressを0x00001fffから0x00003fffに変更する。
SMM_52_101217.png

11. ilmb_cntlrのlmb_bram_if_cntlrもダブルクリックして、ダイアログを表示させる。LMB BRAM High Addressを0x00001fffから0x00003fffに変更する。

12. ProjectメニューからExport Hardware Design to SDK...を選択する。
SMM_53_101217.png

13. Export to SDK/Launch SDKダイアログが開く。Include bitstream and BMM fileにチェックを入れるかどうか迷ったが、チェックを入れないと、smm.xmlは生成されるが、smm.ngcとsmm.bmmは生成されないようだ。Export Onlyボタンをクリックする。
SMM_54_101217.png

14. そうするとエラーが出てしまう。ワーニングが出ているせいかな?といろいろやってみたのだが、おかしくなってしまった。ここで諦めて、バージョン12.1のXPSでやり直した。こっちは、すんなりXPSが開いてワーニングがない。
SMM_56_101217.png

15. 12.3同様にdlmb_cntlrとilmb_cntlrのLMB BRAM High Addressを0x00001fffから0x00003fffに変更して、12.と13.を行う。

16. するとやはり同じようなエラーが出てしまう。

--------------
Number of errors : 87
Number of warnings : 91
ERROR:Xflow - Program map returned error code 2. Aborting flow execution...
Done!


17. しかし、smm.ngc, smm.bmm, smm.xml は出来ているようなので、このまま使うことにする。多分、12.3でも出来ていたので、12.3でも大丈夫だと思う?

smm.ngc : SMM_S3_BRAM_16K\SMM_DBG_noUART\implementation\smm.ngc
smm.bmm : SMM_S3_BRAM_16K\SMM_DBG_noUART\implementation\smm_stub.ngc
smm.xml : SMM_S3_BRAM_16K\SMM_DBG_noUART\SDK\SDK_Export\hw\smm.xml


smm.bmmを開いてみてみたが、以前はBRAMのインスタンスが4個で8KBだったが、8個になっていたので、メモリは16KBになったと思う。
  1. 2010年12月18日 13:30 |
  2. SMM
  3. | トラックバック:0
  4. | コメント:0

The Simple MicroBlaze Microcontroller 11(SDKでエラー発生)

SMMでCMOSカメラのパラメータを設定するために、LCDにパラメータを表示して設定するという計画(長い。。。)のCソースは、だいたい書き終えた。550行くらいあるので、ソースをブログに貼ることができない。長い。
SDKでビルドしようとしたらエラーになってしまった。エラーは下の通り。

../../empty_application_bsp_0/microblaze_0/lib/libxil.a(write.o): In function `write':
/gnu/mb_gnu/src/gcc/libgloss/microblaze/write.c:36: undefined reference to `outbyte'
/gnu/mb_gnu/src/gcc/libgloss/microblaze/write.c:34: undefined reference to `outbyte'
../../empty_application_bsp_0/microblaze_0/lib/libxil.a(read.o): In function `read':
/gnu/mb_gnu/src/gcc/libgloss/microblaze/read.c:35: undefined reference to `inbyte'


SMM_41_101215.png

早速、おなじみのXilinxのアンサーをあさると、”32968 - 11.1 EDK - GCC コンパイラで undefined reference to "outbyte" エラーが発生する”が見つかった。ソリューションを下に引用する。

このエラーは、[Software Platform Settings] で stdout が None に設定されているのに print 関数で有効な stdout が必要になるために発生します。
[Software] > [Software Platform Settings] > [OS and Libraries] で有効な stdout を設定してライブラリを生成し直すとこの問題を解決できます。


あれ?これはよくみるとXPSでの解決策だった。SDKはSoftwareメニューがない。。。どうしたら良いのか?
stdio.hをインクルードして、sprintfを使っているのが多分まずいんだろうと思う?

    switch (setting_item) {
        case AGC_SET :
            if (agc_reg)
                i = sprintf((char *)Str, "AGC ON");
            else
                i = sprintf((char *)Str, "AGC OFF");
            break;
        case GAIN_LEVEL_SET :
            i = sprintf((char *)Str, "AGC GAIN %03x", gain_level);
            break;


UG643 OS and Libraries Document Collectionの76ページのTable16: Configuration Parameterの stdin, stdoutをnoneから何か選べれば大丈夫だと思うのだが、その方法がわからない?やはりXPSを使う必要があるのかな?

あれ?もしかしたら、現在はSMM_DEG_noUART_hw_platformを使っているが、これではstdin, stdoutを使うにしてもどこにつないだら良いのだろう?となってしまうのではないか?使わないまでもUARTがあるのを選べば、stdin, stdoutがUARTになっているということはないだろうか?

SMM_Fullつまり、DEBUGもUARTも入ってる物をSDKで読み込んだら、Board Supprot Package Settings のところでstdin, stdout がUART になっていた。これでやればCソースをコンパイルできるかな?
SMM_42_101215.png

やってみたところ、今度は undefined reference to `outbyte'などのエラーは出なくなったので、stdin, stdoutの問題はクリアされているようだが、どうやら8KBのRAMが一杯になってしまったのかな?

/cygdrive/k/HDL/Xilinx/12.3/ISE_DS/EDK/gnu/microblaze/nt/bin/../lib/gcc/microblaze-xilinx-elf/4.1.2/../../../../microblaze-xilinx-elf/bin/ld: region ilmb_cntlr_dlmb_cntlr is full (empty_application_0.elf section .text)
/cygdrive/k/HDL/Xilinx/12.3/ISE_DS/EDK/gnu/microblaze/nt/bin/../lib/gcc/microblaze-xilinx-elf/4.1.2/../../../../microblaze-xilinx-elf/bin/ld: empty_application_0.elf: section .text lma 0x50 overlaps previous sections
/cygdrive/k/HDL/Xilinx/12.3/ISE_DS/EDK/gnu/microblaze/nt/bin/../lib/gcc/microblaze-xilinx-elf/4.1.2/../../../../microblaze-xilinx-elf/bin/ld: empty_application_0.elf: section .fini lma 0x78 overlaps previous sections
/cygdrive/k/HDL/Xilinx/12.3/ISE_DS/EDK/gnu/microblaze/nt/bin/../lib/gcc/microblaze-xilinx-elf/4.1.2/../../../../microblaze-xilinx-elf/bin/ld: empty_application_0.elf: section .rodata lma 0x98 overlaps previous sections
/cygdrive/k/HDL/Xilinx/12.3/ISE_DS/EDK/gnu/microblaze/nt/bin/../lib/gcc/microblaze-xilinx-elf/4.1.2/m/crtend.o:(.init+0x0): relocation truncated to fit: R_MICROBLAZE_32_PCREL_LO against `.text'
collect2: ld returned 1 exit status
make: *** [empty_application_0.elf] Error 1


メモリの量が足りないとしたら、やはり、stdioのライブラリを呼んでしまったので、ライブラリ分だけ増えちゃったんだろうな?
どうしようか?sprintfを使わないで、独自に関数を書いちゃおうか?そうしてみます。

(2010/12/16:追加)
sprintfを独自関数で書きなおしても

/cygdrive/k/HDL/Xilinx/12.3/ISE_DS/EDK/gnu/microblaze/nt/bin/../lib/gcc/microblaze-xilinx-elf/4.1.2/../../../../microblaze-xilinx-elf/bin/ld: region ilmb_cntlr_dlmb_cntlr is full (empty_application_0.elf section .heap)


になってしまった。
こうなったら、SMMをXPSで、リコンフィグして、メモリを8Kから16Kに変更しようと思う。
  1. 2010年12月15日 05:04 |
  2. SMM
  3. | トラックバック:0
  4. | コメント:0

The Simple MicroBlaze Microcontroller 10 (Cソフトウェアを書いているところ)

前回、SCCBレジスタの設定回路(SCCBインターフェース回路)をSMMから制御できるようにハードウェアを変更と、LCDに表示して設定するSCCBレジスタを決定したので、今度はSDKのソフトウェアを変更中だ。
今のところ、SCCB設定用レジスタの設定用のdefineを書いている。まだ全部書けていないが、下のような感じで書いている。

#define    SCCB_REG_00        0x00    // SCCB Register Address 0x00 (GAIN[7:0])
#define SCCB_REG_01        0x40    // SCCB Register Address 0x01 (AWB RED)
#define SCCB_REG_02        0x60    // SCCB Register Address 0x02 (AWB BLUE)
#define SCCB_REG_03        0x0A    // SCCB Register Address 0x03 ([7:6] - GAIN LEVEL[9:8])
#define SCCB_REG_04        0x00    // SCCB Register Address 0x04 ([1:0] - AEC LEVEL L[1:0])
#define SCCB_REG_07        0x00    // SCCB Register Address 0x07 ([5:0] - AEC LVEVL H[7:2])
#define    SCCB_REG_10        0x00    // SCCB Register Address 0x10 ([5:0] - AEC LEVEL L[7:2])
#define SCCB_REG_13        0xEF    // SCCB Register Address 0x13 ([2] - AGC, [1] - AWB, [0] - AEC)
#define SCCB_REG_1E        0x27    // SCCB Register Address 0x1E ([5] - MIRROR)

#define awb_red            reg01
#define    awb_blue        reg02

#define SCCB_2_AGC            ((reg13 & 0x04)>>2)
#define AGC_2_SCCB            ((agc_reg & 0x01)<<2)
#define SCCB_2_AWB            ((reg13 & 0x02)>>1)
#define AWB_2_SCCB            ((awb_reg & 0x01)<<1)
#define SCCB_2_AEC            (reg13 & 0x1)
#define AEC_2_SCCB            (aec_reg & 0x01)
#define    SCCB_2_GAIN_LEVEL    (((reg03 & 0xC0)<<2) | reg00)
#define GAIN_LEVEL_2_SCCB03    ((gain_level & 0x300)>>2)
#define GAIN_LEVEL_2_SCCB00    (gain_level & 0xFF)


/* Global Variable */
// SCCB Register Variable
unsigned char reg00 = SCCB_REG_00;
unsigned char reg01 = SCCB_REG_01;
unsigned char reg02 = SCCB_REG_02;
unsigned char reg03 = SCCB_REG_03;
unsigned char reg04 = SCCB_REG_04;
unsigned char reg07 = SCCB_REG_07;
unsigned char reg10 = SCCB_REG_10;
unsigned char reg13 = SCCB_REG_13;
unsigned char reg1E = SCCB_REG_1E;

unsigned char agc_reg;
unsigned short int gain_level;
unsigned char awb_reg;
unsigned char aec_reg;
unsigned char aec_level_h;
unsigned char aec_level_l;
unsigned char mirror_reg;


作っているが、書いていると飽きてくる。。。が、取り敢えず、マクロを作りきる。

#C++本格的に書いたことが無いので、よくわからないが、C++だったらSCCBレジスタを設定するクラスとかを作って、それを継承して個別のレジスタを設定するメソッドを書けば良いのだろうか?
  1. 2010年12月10日 05:39 |
  2. SMM
  3. | トラックバック:0
  4. | コメント:2

The Simple MicroBlaze Microcontroller 9 (SCCB回路の変更、設定SCCBレジスタ)

さて、前回でロータリーエンコーダを使用することができた
今度は、SCCBレジスタの設定回路(SCCBインターフェース回路)をSMMから制御できるようにハードウェアを変更することと、LCDに表示して設定するSCCBレジスタを決定した。設定するSCCBレジスタの決定には、特殊電子回路株式会社の”OV7670で作るUSBカメラ”のページを参考にさせて頂いた。
最初に設定するレジスタの仕様を下に示す。
SMM_40_101209.png

AGC、AWB、AECのON, OFFと値、MIRRORのON, OFFを設定できるようにした。LCDの1桁目は設定する項目 (AGC, AWBなど)の値を表示する。ロータリーエンコーダのセンタースイッチを押すと編集モードに入って、1行目の後ろにEを表示する。編集モードでは、表示されている項目のON, OFFまたは値をロータリーエンコーダの右、または左回転で変更することができる。もう一度ロータリーエンコーダのセンタースイッチを押すと、編集モードから抜けて表示モードに戻る。この時に、ロータリーエンコーダの右、または左回転すると、表示する項目を移動できる。
LCDの2桁目は、全体を上図のように表示する。GはAGCがONであることを示し、BはAWBがONであること、EはAECがONであること、MはMIRRORがONであることを示す。OFFの時には表示は消える。

次に、SCCBインターフェース回路の変更点だ。
SCCBインターフェース回路の説明は、”SCCBインターフェース回路の説明1(SCCB_Reg_Controller.vhd)”、”SCCBインターフェース回路の説明2(freqdiv.vhd、SCCB_reg_values_ROM.vhd)”、”SCCBインターフェース回路の説明3(One_Transaction_SCCB.vhd)”を参照してください。
この中のSCCB_Reg_Controller.vhd にaddr_data、ad_enable、SCCB_busy の3つのポートを追加した。addr_dataは全体で16ビットで、上位8ビットがアドレス、下位8ビットがデータとなる。ad_enableはaddr_dataの値が有効でSCCBレジスタへの書き込みを示す1パルスの信号だ。SCCB_busyは、現在ステートマシンがSCCBレジスタに書き込み中を示す。これは、ステータス信号として、SMM (The Simple MicroBlaze Microcontroller) からReadすることができるようにする。

entity SCCB_Reg_Controller is
    port(
        clk : in std_logic; -- クロック
        reset  : in std_logic; -- リセット
        addr_data : in std_logic_vector(15 downto 0); -- SMMから設定されるSCCB設定レジスタのアドレスとデータ
        ad_enable : in std_logic; -- addr_data信号のイネーブルパルス
        SCCB_busy : out std_logic; -- SCCBレジスタを設定中を表すbusyフラグ
        SCL : out std_logic; -- SCCBのクロック
        SDA : out std_logic -- SCCBのデータ
    );
end SCCB_Reg_Controller;


初期化時に、SCCBインターフェース回路は、SCCB_reg_values.data の設定値を全て設定するが、その後はSMMの要求で、SCCBレジスタに設定値を書きこむように変更した。初期化設定時には、SCCB_busyを1にしておいて、SMMにSCCBインターフェース回路がbusyであることを知らせる。初期化後はaddr_data、ad_enableによるSMMからのレジスタ書き込みを行うことができるが、SMMはその前にSCCB_busyフラグを読んで、SCCBインターフェース回路がbusyでないことを確かめてから、レジスタの設定を行う。
下にSCCB_Reg_Controller.vhd の変更箇所を示す。

    -- One_Transaction_SCCB のインスタンス
    One_Transaction_SCCB_inst : One_Transaction_SCCB port map(
        clk => clk,
        reset => reset,
        SCCB_address => SCCB_address,
        SCCB_data => SCCB_data,
        op_enable => op_enable,
        start_pulse => SCCB_start_pulse,
        end_pulse => end_pulse,
        SCL => SCL,
        SDA => SDA
    );
    -- セレクタ、初期化が終了するまではROMのデータを選択して、終了した後ではSMMからの設定を選択する
    SCCB_address <= ROM_data(15 downto 8) when cs_reg_set/=end_state else addr_data(15 downto 8);
    SCCB_data <= ROM_data(7 downto 0) when cs_reg_set/=end_state else addr_data(7 downto 0);
    SCCB_start_pulse <= start_pulse when cs_reg_set/=end_state else ad_enable;
    
    -- SCCB_busyの制御
    process(clk) begin
        if clk'event and clk='1' then
            if reset='1' then
                cs_SCCB_busy <= idle_SCCB_busy;
                SCCB_busy_node <= '1';
            else
                case cs_SCCB_busy is
                    when idle_SCCB_busy =>
                        if cs_reg_set=end_state then -- 初期設定が終了
                            cs_SCCB_busy <= initialize_end;
                            SCCB_busy_node <= '0';
                        end if;
                    when initialize_end =>
                        if ad_enable='1' then -- SMMのSCCBレジスタ設定開始
                            cs_SCCB_busy <= SCCB_setting;
                            SCCB_busy_node <= '1';
                        end if;
                    when SCCB_setting =>
                        if end_pulse='1' then -- SMMのSCCBレジスタ設定終了
                            cs_SCCB_busy <= initialize_end;
                            SCCB_busy_node <= '0';
                        end if;
                end case;
            end if;
        end if;
    end process;
    SCCB_busy <= SCCB_busy_node;


ここで、cs_reg_setはステートマシンのステートを示す信号で、end_stateに遷移していると初期化が終了したことを示している。

次に、SMMとのインターフェース回路lcd_rot_cont.vhdだが、ここにSCCB_addr_data、SCCB_ad_enable、SCCB_busyポートを追加した。

entity lcd_rot_cont is
    Port (     clk : in  STD_LOGIC;
                Reset : in  STD_LOGIC;
                rot_a : in std_logic;
                rot_b : in std_logic;
                rot_center : in std_logic;
                Button_S : in STD_LOGIC;
                LCD_DB : out STD_LOGIC_VECTOR (7 downto 0);
                LCD_RS : out STD_LOGIC;
                LCD_RW : out STD_LOGIC;
                LCD_E : out STD_LOGIC;
                SCCB_addr_data : out std_logic_vector(15 downto 0); -- SMMから設定されるSCCB設定レジスタのアドレスとデータ
                SCCB_ad_enable : out std_logic; -- addr_data信号のイネーブルパルス
                SCCB_busy : in std_logic -- SCCBレジスタを設定中を表すbusyフラグ
    );
end lcd_rot_cont;


0040番地にSCCBインターフェース回路へのアドレス、データを書き込む回路を追加した。

CS_SCCB_wr <= '1' when ((ADDR = X"0040") and CS = '1' and RNW = '0') else '0' ;


SCCB_ad_enableを生成する回路を追加して、アドレス、データの16ビットは下位16ビットに割り当てた。

    -- SCCB_ad_enable の生成
    process(clk) begin
        if clk'event and clk='1' then
            if Reset='1' then
                SCCB_ad_enable <= '0';
            else
                if CS_SCCB_wr='1' and CS_SCCB_wr_1d='0' then
                    SCCB_ad_enable <= '1';
                else
                    SCCB_ad_enable <= '0';
                end if;
            end if;
        end if;
    end process;
    
    SCCB_addr_data <= DOUT(0 to 15);  -- 上位16ビット


(修正)
SCCB_addr_data <= DOUT(0 to 15); -- 上位16ビット に修正しました。元は下位16ビットでした。アドレスが面倒になるので上位16ビットに変更です。
  1. 2010年12月09日 05:12 |
  2. SMM
  3. | トラックバック:0
  4. | コメント:0

The Simple MicroBlaze Microcontroller 8 (ロータリーエンコーダの実装)

前回の”The Simple MicroBlaze Microcontroller 7 (50MHzから25MHzへクロックを変更)”でクロック周波数を50MHzから25MHzに変更してみたが、今度は目的の”Spartan-3A Starter Kitによる画像演奏装置”にロータリーエンコーダの制御回路と一緒に組み込んだ。だが、まだ、目的のSCCB設定レジスタを制御するように変更してはいない。それは今、修正中だ。

さて、ロータリーエンコーダをled_ref.vhdの中に下のように組み込んだ。ついでに、いつまでもled_ref.vhdではないので、ファイル名もlcd_rot_cont.vhdに変更した。(ついでにCのソフトウェアのファイル名もlcd_rot_cont.cに変更した)

    -- ロータリーエンコーダ
    rot_enc_cont_i : rot_enc_cont port map(
        clk => clk,
        reset => Reset,
        rot_a => rot_a,
        rot_b => rot_b,
        rot_center => rot_center,
        right_pulse => right_pulse,
        left_pulse => left_pulse,
        center_pulse => center_pulse
    );


SMMのDIN入力は下のように変更した。

DIN (0) <= Button_S_int;
DIN (1) <= right_pulse;
DIN (2) <= left_pulse;
DIN (3) <= rot_center;
DIN (4 to 31) <= (others => '0') ; -- Not used


更に、ロータリーエンコーダのセンタースイッチを押すと、LCDにrot_center と表示するように、SMMのソフトウェアを変更した。同様にロータリーエンコーダを右に回すとright_pulse、左に回すとleft_pulseと表示するようにした。そうすると、ロータリーエンコーダのセンタースイッチは反応して、LCDにrot_center と表示されるが、他は表示されない。
そうだ、pulseは1パルスのみ出力するんだった。これではSMMが検知できないということでハンドシェークすることにした。どうしたかというと、right_pulse, left_pulse をホールドするFF (right_hold, left_hold) を付けて、それらをクリアする書き込みアドレスを用意した。

    -- right_pulse, left_pulse をホールドするFF
    process(clk) begin
        if clk'event and clk='1' then
            if Reset='1' then
                right_hold <= '0';
                left_hold <= '0';
            else
                if right_pulse = '1' then
                    right_hold <= '1';
                elsif CS_rot_enc_wr='1' then 
                    right_hold <= '0';
                end if;
                
                if left_pulse='1' then
                    left_hold <= '1';
                elsif CS_rot_enc_wr='1' then
                    left_hold <= '0';
                end if;
            end if;
        end if;
    end process;


CS_rot_enc_wr <= '1' when ((ADDR = X"0030") and CS = '1' and RNW = '0') else '0' ;


DIN (0) <= Button_S_int;
DIN (1) <= right_hold;
DIN (2) <= left_hold;
DIN (3) <= rot_center;
DIN (4 to 31) <= (others => '0') ; -- Not used


lcd_rot_cont.cの関連するソフトウェアは下。

    while (1) {
        while (1){
            button_push = XIo_In8(STATUS_ADDR);
            if (button_push == 0x10break;
            else if (button_push == 0x20break;
            else if (button_push == 0x40break;
        }

        // Clear the LCD
        lcd_clear();

        // Print to the LCD
        if (button_push == 0x10){
            lcd_print(1"rot_center ON");
        } else if (button_push == 0x40){ // right -> left
            XIo_Out32(ROT_ENC_ADDR, 0);
            lcd_print(2"left_pulse");
        } else if (button_push == 0x20){ // left -> right
            XIo_Out32(ROT_ENC_ADDR, 0);
            lcd_print(2"right_pulse");
        }
    }


上のソフトウェアで、leftとrightが逆だが、最初は右に回すとleft_pulseと表示されて、左に回すとright_pulseと表示されてしまったので、どうやら逆のようだったので、ソフトウェアの方で反対にした。
下に表示の様子を示す。
SMM_37_101207.jpg
SMM_38_101207.jpg
SMM_39_101207.jpg

これで、ロータリーエンコーダと組み合わせての表示はOKなので、今度はSCCBレジスタ設定回路を修正して、SMMからのコマンドを受け付けるようにするつもりだ。
  1. 2010年12月07日 04:45 |
  2. SMM
  3. | トラックバック:0
  4. | コメント:0