FC2カウンター FPGAの部屋 2013年02月16日
FC2ブログ

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

FPGAの部屋

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

ZedBoard Linux のフレームバッファにカメラ画像を表示12(SDカードのイメージ変更)

前回、SDKのリモートデバック機能を使用して、Windows 上で動作するSDKからZedBoard上に、ELFファイルをSSH接続でアップロードして動作させ、カメラのレジスタ設定を行った
今回は、SDカードのイメージにカメラレジスタ設定プログラムを追加して、Linuxのブート時に自動的に起動するように設定する。

まずは、Linuxの起動について勉強した。”第10回 Linux起動の仕組みを理解しよう[init/inittab編]”を参考にした。
/etc/inittab に処理が定義してあった。inittab に下に示すようにsysinit が定義されていた。

::sysinit:/etc/init.d/rcS


よって、/etc/init.d/rcS が初期化時に起動することがわかった。rcSの記述に

echo "++ Configure static IP 192.168.1.10"
ifconfig eth0 down
ifconfig eth0 192.168.1.10 up


があったので、自分のIPアドレスに変更した。

echo "++ Configure static IP 192.168.3.130"
ifconfig eth0 down
ifconfig eth0 192.168.3.130 netmask 255.255.255.0 up


そして、最後の”rcs Complete"と表示する前に、

/Apps/cam_disp3_linux.elf


を記述した。

これで、rcS の書き換えは終了したが、これをSDカードのramdisk8M.image に書き込む必要がある。そのやり方は、”Modify your boot image on your ZedBoard”を真似させて頂いた。

・ルート・ディレクトリに行って、sdcard ディレクトリを作製した。


zynq> cd /
zynq> mkdir sdcard
zynq> ls
Apps        etc         linuxrc     opt         sbin        tmp
bin         lib         lost+found  proc        sdcard      usr
dev         licenses    mnt         root        sys         var


・/dev/mmcblk0p1 を /sdcard にマウントして、ls コマンドで見ると、SDカードの内容が見えた。

zynq> mount /dev/mmcblk0p1 /sdcard
zynq> ls sdcard
BOOT.bin                README                  ramdisk8M.image.gz
BOOT_org.BINo           devicetree_ramdisk.dtb  zImage


・/sdcard/ramdisk8M.image.gz を /tmp ディレクトリにコピーして、展開し、/mnt にマウントする。

zynq> cp /sdcard/ramdisk8M.image.gz /tmp/
zynq> gunzip /tmp/ramdisk8M.image.gz
zynq> mount -o loop /tmp/ramdisk8M.image /mnt/
[22221.420000] EXT4-fs (loop0): couldn't mount as ext3 due to feature incompatibilities
[22221.470000] EXT4-fs (loop0): mounting ext2 file system using the ext4 subsystem
[22221.470000] EXT4-fs (loop0): warning: mounting unchecked fs, running e2fsck is recommended
[22221.480000] EXT4-fs (loop0): mounted filesystem without journal. Opts: (null)
zynq> ls /mnt
bin         lib         lost+found  proc        sys         var
dev         licenses    mnt         root        tmp
etc         linuxrc     opt         sbin        usr


・/Apps/cam_disp3_linux.elf と /etc/init.d/rcS を /mnt ディレクトリにコピーする。

zynq> cp -r Apps /mnt/
zynq> cp /etc/init.d/rcS /mnt/etc/init.d/rcS


・ramdisk8M.image.gz を生成して、SDカードに書き込んだ。(umount のオプションは、-L(小文字)です)

zynq> umount -l /mnt
zynq> gzip -9 /tmp/ramdisk8M.image
zynq> mv /tmp/ramdisk8M.image.gz /sdcard/
zynq> umount -l /sdcard/


これで、Linuxの初期化時にカメラの設定ソフトウェアを起動することが出来た。
ZedBoard を電源ONして、Linuxが起動した時にカメラ画像がVGAディスプレイに表示された。おまけに、正しいIPアドレスも設定できた。
参照させて頂いた2つのサイトにお礼を申し上げる。
  1. 2013年02月16日 12:01 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0

ZedBoard Linux のフレームバッファにカメラ画像を表示11(SDKリモートデバック3)

前回は、GPIOの出力ポートを1に出来て、Camera Controller とBitmap Display Controller のリセットを解除することが出来た。そこまでは出来たのだが、カメラのレジスタ設定が出来なかった。今回はなぜ、カメラのレジスタ設定が出来ないかとその回避策を探ってみた。

SDKリモートデバックでステップ実行を行うと、カメラ設定用のI2CのステータスレジスタRead でReadしたデータが0で止まっていた。ステータスレジスタのRead はI2Cの動作がすべて完了したことを確認しているので、その代わりにusleep(1000); を入れてみたところ、カメラの設定がうまく行って、画像が表示できた。
ZedBoard_Linux_94_130216.jpg

なぜRead出来ないかは分からないが、とりあえず、画像が表示できたので、良かった。これで、カメラの画像をLinuxから読める可能性が出てきた。(今のところRead がおかしいと思っているので、控えめな表現にしましたw)
ソフトウェアのコードは、”RPi Low-level peripherals”の void setup_io(); を使わせていただいていた。前回、ZC702ボードでLinuxからaxi_gpio やMIO のGPIO をアクセスした際にも、 void setup_io(); はブログに載せていなかったが、、”RPi Low-level peripherals”の void setup_io(); のコードが変わっていたので、以前のコードを参照させていただいたことにして、全ソースコードを載せておこうと思う。free() や munmap() もしていない。(注:バグ有りコードです。Readできません)

// cam_disp3_linux.c
// 
// GPIOを1にして、カメラ表示回路を生かし、MT9D111の設定レジスタにRGB565を設定する
//
// 2013/02/11
//

#define XPAR_AXI_GPIO_0_BASEADDR        0x44000000
#define XPAR_AXI_IIC_MT9D111_BASEADDR    0x45000000

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>

#include <unistd.h>

#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)

// I/O access

volatile unsigned *setup_io(off_t addr);

volatile unsigned *cam_i2c_control_reg;
volatile unsigned *cam_i2c_status_reg;
volatile unsigned *cam_i2c_tx_fifo;
volatile unsigned *cam_i2c_rx_fifo;

void cam_i2c_init(void) {
    *cam_i2c_control_reg = 0x2// reset tx fifo
    *cam_i2c_control_reg = 0x1// enable i2c
}

void cam_i2x_write_sync(void) {
    // unsigned c;

    // c = *cam_i2c_rx_fifo;
    // while ((c & 0x84) != 0x80)
        // c = *cam_i2c_rx_fifo; // No Bus Busy and TX_FIFO_Empty = 1
    usleep(1000);
}

void cam_i2c_write(unsigned int device_addr, unsigned int write_addr, unsigned int write_data){
    *cam_i2c_tx_fifo = 0x100 | (device_addr & 0xfe);    // Slave IIC Write Address
    *cam_i2c_tx_fifo = write_addr;
    *cam_i2c_tx_fifo = (write_data >> 8)|0xff;            // first data
    *cam_i2c_tx_fifo = 0x200 | (write_data & 0xff);        // second data
    cam_i2x_write_sync();
}

int main()
{
    volatile unsigned *cam_i2c, *axi_gpio;
    volatile unsigned *axi_gpio_tri;
    
    cam_i2c = setup_io((off_t)XPAR_AXI_IIC_MT9D111_BASEADDR);
    axi_gpio = setup_io((off_t)XPAR_AXI_GPIO_0_BASEADDR);
    
    cam_i2c_control_reg = cam_i2c + 0x40// 0x100番地
    cam_i2c_status_reg = cam_i2c + 0x41// 0x104番地
    cam_i2c_tx_fifo = cam_i2c + 0x42// 0x108番地
    cam_i2c_rx_fifo = cam_i2c + 0x43// 0x10C番地
    
    axi_gpio_tri = axi_gpio + 0x1// 0x4番地
    
    // GPIOに1を書いて、カメラ表示回路を動作させる
    *axi_gpio_tri = 0;    // set output
    *axi_gpio = 0x1;    // output '1'
    
    // CMOS Camera initialize, MT9D111
    cam_i2c_init();
    
    cam_i2c_write(0xba, 0xf00x1);        // IFP page 1 へレジスタ・マップを切り替える
    cam_i2c_write(0xba, 0x970x20);    // RGB Mode, RGB565
    
    return(0);
}

//
// Set up a memory regions to access GPIO
//
volatile unsigned *setup_io(off_t mapped_addr)
// void setup_io()
{
    int  mem_fd;
    char *gpio_mem, *gpio_map;

   /* open /dev/mem */
   if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
      printf("can't open /dev/mem \n");
      exit (-1);
   }

   /* mmap GPIO */

   // Allocate MAP block
   if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
      printf("allocation error \n");
      exit (-1);
   }

   // Make sure pointer is on 4K boundary
   if ((unsigned long)gpio_mem % PAGE_SIZE)
     gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE);

   // Now map it
   gpio_map = (unsigned char *)mmap(
      (caddr_t)gpio_mem,
      BLOCK_SIZE,
      PROT_READ|PROT_WRITE,
      MAP_SHARED|MAP_FIXED,
      mem_fd,
      mapped_addr
   );

   if ((long)gpio_map < 0) {
      printf("mmap error %d\n", (int)gpio_map);
      exit (-1);
   }

   // Always use volatile pointer!
   // gpio = (volatile unsigned *)gpio_map;
   return((volatile unsigned *)gpio_map);

// setup_io


東北学院大学の熊谷先生の”デバイスドライバに頼らないハードウェア操作”は、とってもためになるページなので、この辺を参照しながら、0x1A000000 からのフレームバッファをARMプロセッサから読んでみたい。

(おまけです)
2頭のペンギンが写っていたHDMI画面は、800 x 600 ピクセルのカメラ画像のフレームバッファとして使用しているので、下の写真の様な画面が表示されています。HDMIの画面は、1920 x 1080 のフルHDです。後ろから日の光が差しているので、私の姿が写っています。
ZedBoard_Linux_95_130216.jpg

(2013/02/18:追記)
Linuxが死なないで、正常動作するのはフレームバッファが0x1A000000 スタートに割り当てられる場合と考えられます。確率的にLinuxが死んだりします。詳しくは、”ZedBoard Linux のフレームバッファにカメラ画像を表示13(未完成)”を御覧ください。
  1. 2013年02月16日 05:12 |
  2. ZedBoard
  3. | トラックバック:0
  4. | コメント:0