FPGAと2つのADCを用いたNTSC(S-Video)デコーダの製作

Y信号とChroma信号からなるS-Video 信号を各々、A/Dコンバータ(14bit)に入力し、FPGAで14.318MHzでサンプリング、色復調するシステムを作ってみました。

色復調の方式は、2軸復調方式を用いています。2軸復調方式では、R-Y,B-Yをそれぞれ、色副搬送波を-90°,180°移相したものと色搬送波から求め、G-Yを
G-Y=-0.51(R-Y)-0.19(B-Y) で求めています。

通常、色副搬送波は局部発振した3.58MHzをカラーバースト信号で色同期させていますが、今回は、カラーバースト信号自体をサンプリング・増幅して色副搬送波の代わりにしています。

以下に、1フレーム分のY信号、C信号をA/D変換したバイナリファイルを色復調し R,G,B画像として表示させるPython(2.7)プログラムを示します。



from PIL import Image, ImageDraw
im = Image.new( 'RGB', (1024,720), (0, 0, 0))
draw = ImageDraw.Draw(im)

infile = open(“a_YC_datafile”, "rb")

def syncC( c):
c1 = []
amp = 4
prev_c = -1
j = 0
for i in range(3):
if prev_c < 0 and c[i] >= 0 :
j = i
break
prev_c = c[i]

if j == 0 :
if c[3] < 0:
c1.append(c[0]*amp)
c1.append(c[1]*amp)
c1.append(c[2]*amp)
c1.append(c[3]*amp)
c1.append(0)
else:
c1.append(c[3]*amp)
c1.append(c[0]*amp)
c1.append(c[1]*amp)
c1.append(c[2]*amp)
c1.append(3)
if j == 1 :
c1.append(c[1]*amp)
c1.append(c[2]*amp)
c1.append(c[3]*amp)
c1.append(c[0]*amp)
c1.append(1)
if j == 2 :
c1.append(c[2]*amp)
c1.append(c[3]*amp)
c1.append(c[0]*amp)
c1.append(c[1]*amp)
c1.append(2)
if j == 3 :
c1.append(c[3]*amp)
c1.append(c[0]*amp)
c1.append(c[1]*amp)
c1.append(c[2]*amp)
c1.append(3)

return c1


for yy in range(700): #00):
data = infile.read((1088-16+0)*4+0)
c = []
y = []

cb_sample = 48+3

for xx in range(64, 1024):
ii = xx*4

a1 = (ord(data[ii+1+0]))
a2 = (ord(data[ii+2+0]))
a3 = (ord(data[ii+3+0]))

i = xx - 64

c.append( ((a1 << 8) +(a2 & 0b11111100)) >> 2) #C信号
c[i] = c[i] - 0b10000000000000 #オフセットバイナリの処理

if c[i] < -7000 :
c[i] = 0

y.append( ((a2 & 0b11) << 8) + a3 ) #Y信号
y8 = (y[i] >> 1)


if i == cb_sample :
draw.point( (xx-3, yy), (0, 255, 0))
draw.point( (xx-2, yy), (0, 255, 0))
draw.point( (xx-1, yy), (0, 255, 0))
draw.point( (xx-0, yy), (0, 255, 0))
c0 = c[i-3]
c1 = c[i-2]
c2 = c[i-1]
c3 = c[i-0]

for i in range(1024-64):
if i == cb_sample :

   #カラーバーストのサンプリング
c0 = c[i-3]
c1 = c[i-2]
c2 = c[i-1]
c3 = c[i-0]
cs = syncC( [c0, c1, c2, c3])

if i > cb_sample :
n4 = (i >> 2)<<2

#R-Y計算
RY = cs[3]*c[n4+cs[4]] + cs[0]*c[n4+(cs[4]+1)%4] + cs[1]*c[n4+(cs[4]+2)%4] + cs[2]*c[n4+(cs[4]+3)%4]

   #B−Y計算
BY = cs[2]*c[n4+cs[4]] + cs[3]*c[n4+(cs[4]+1)%4] + cs[0]*c[n4+(cs[4]+2)%4] + cs[1]*c[n4+(cs[4]+3)%4]

RY = RY >> 15
BY = BY >> 14

   #G-Y 計算
GY = (-510*RY)/1024 - (190*BY)/1024

R = (RY + y[i])/2
B = (BY + y[i])/2
G = (GY + y[i])/2

draw.point( (i+64, yy), (R, G, B))

im.show()




このプログラムを動かした結果:

Screen Shot

基本的にこのアルゴリズムで動作するVerilog HDL を記述し、Terasic 社製の C5G FPGAボード及びTHDB-ADA(A/D,D/A) ボードを用いてインプリメントしてみました。

C5G

実際に動作している様子:




参考にした本:日本放送出版協会刊 NHKカラーテレビ受信技術[増補版]

DE1-SoCにLCD(800x480)をつなげてX11を動かしてみた

DE1-SoCにHUMANDATA製 UTL-021(Terasic LTM 4.3'LCD コンパチブル)をつなげてX11のXserverを動かしてみました。



使用OSは
Linux linaro-ubuntu-desktop 3.12.0-00307-g507abb4-dirty #8 SMP Mon Jan 20 13:42:47 CST 2014 armv7larmv7l
armv7l GNU/Linux

Terasic のサイトで公開しているものです。

LCDのフレームバッファにはSDRAM(32Mx16/150MHz)を使っています。そしてHPS-to-FPGA Bridge 経由でARM側からSDRAMにアクセスしています。

Qsysの構成は以下の通り:
Qsys


LCD_FrameBufferというコンポーネントを新たに作成しています。このコンポーネントの中で、HPS-to-FPGA Bridge のAXIバスからSDRAMコントローラへの制御信号の生成を行っています。

SDRAMは、またLCDのフレームバッファになっており800x480xRGB-24bitのフルカラーの情報を保持しています。

一方、Linux側では、xorg-server-1.12.2(現時点での最新版)をダウンロードしてきてXfbdev が作成される様に configure しておきます。make; sudo make install しますが
その際、xorg-server-1.12.2/hw/kdrive/fbdev/fbdev.c のfbdevInitialize関数内でpriv->fb_base 変数にAXIバス空間がmmapされる様に変更しています:

 if( (fd_LCD=open( "/dev/mem", (O_RDWR | O_SYNC)))
   == -1){
    ErrorF( "ERROR: /dev/mem\n");
   return(FALSE);
 }

 priv->fb_base = (char *) mmap( NULL,
        priv->fix.smem_len,
        (PROT_READ|PROT_WRITE),
        MAP_SHARED, fd_LCD,
        ALT_AXI_FPGASLVS_OFST);

/dev/fb0のようなデバイスドライバを作らずに済むように、少し特殊な事をしています。

最後に、SDRAMは150MHzで駆動していますが、x16bit構成のためフルカラー24bitRGBを表示するためにメモリの帯域の6割くらいを消費しています。そのためAXIバスからのSDRAMのアクセスに時間がかかり、結果的にxengineのスコアがかなり低くなっています。

参考:FPGAマガジン No.5 pp116-127,
   http://www.altera.com/literature/hb/cyclone-v/cv_54005.pdf

Beagle Bone Black に4.3'LCDをつなげる

秋月電子で3000円で販売されている 4.3inch(480x272)液晶ディスプレイATM0430D5 をBBBにつなげてみたので、その手順を簡単にまとめてみました。

先ず、BBBの心臓部AM3358は HDMI出力とLCDコントロール用の信号を同一のピンで共有しているので、HDMI出力機能をdisableする必要があります。disableするには、以下のサイトを参考にして、uEnv.txtファイルを書き換えます。

http://www.logicsupply.com/blog/2013/07/18/disabling-the-beaglebone-black-hdmi-cape/

次に、ssh でBBBにlogonして、

# cd /sys/devices/bone_capemgr.*
# echo BB-BONE-LCD4-01 > slots

と入力します。

以上の操作で、LCD上に以下のような画面が現れます。

BBB LCD


※配線について。

BBB側            LCD側
LCD_PCLK(P8.28) <--> CLK
LCD_AC_BIAS_E(P8.30) <--> DE
LCD_DATA <--> R,G,B
(RGB565信号を適宜RGB24bitにつなげてください。写真ではRGBの各MSBのみつなげてます。)

MacPlusToo のSpartan-3 Starter Boardへの移植

old Mac(Mac plus)のレプリカをFPGA(DE1)でインプリメントした、MacPlusToo( http://www.bigmessowires.com/plus-too/ )※1 というものを先日見つけたので、DIGILENT社製Spartan-3 Starter Board(XC3S1000版、以下S3-Boardと略します)に移植してみました。

MacPlusToo 1



移植にあたってのポイントは、メモリ(RAM,ROM)、ファイルシステム(OS)関連をどうするかにあります。
オリジナルのDE1版では、オンボード4MBのフラッシュメモリ上に128KBのROMとOS(1.6MB)を載せていますが、S3-Boardには4Mbit(512KB)のPlatform Flash(XCF04)と1MBのSRAMしか載ってません。
そこで、Mac側の128KBROMはPlatform Flash に置いて、OSは自作の外付けSDカードに置く事にしてみました。
(Platform Flashのイメージ(.mcs)作成と読み込みには、XAPP694を使用させて頂きました。)

.bitファイルと.mcsファイルを公開しますので、ご興味のある方は自己責任でお試しください。

zipファイル(.bit .mcs)

(.mcs ファイルはPlatform Flashの方に書き込みますのでご注意ください。また、Platform Flashの内容をSRAMにロードするために、JP1をFlash Read側にセットしてください。)

SDカードI/Fの結線図は以下の通りです。

[A2 connector]

A2-Pin4 -- SD_DAT3(CS)
A2-Pin6 -- SD_CMD(DI)
A2-Pin10 -- SD_CLK(SCLK)
A2-Pin14 -- SD_DAT0(DO)

MacPlusToo 2


SDカードへのOSイメージ書き込みは、ubuntuなどの上で、※1リンク先のDisk608-800K.binというファイルを

# dd if=Disk608-800K.bin of=/dev/sdc

のように書き込みます。(/dev/sdc は環境により異なりますので適宜SDカードのデバイスノード名に変更ください)

PS2マウスをつなげて、S3-BoardのBTN1を押すことでブートが始まるはずです。

Qsysを使ってDE0でVGA表示

Quartus II (12.0sp2) で使えるQsysの勉強をしてみました。
例題は、NiosII にVGA(640x480)表示機能を持たせるというものです。
FPGAボードにはDE0を使いました。

Qsysの構成は以下の通り:
Qsys構成

SDRAMはフレームバッファ用、onchip_memoryにNiosIIのプログラムを置きます。
一番下のVGA_CLKというモジュールはVGA用自作クロックジェネレータです。


sgdma_0の設定は以下の通り:
sgdma_0

Read burstcount signal widthが8ビットになってますが6ビットで充分かも。

vga_sync_generator_0の設定は以下の通り:
vga_sync_generator_0

フロントポーチなどの数値は、適当なので、モニタによっては表示がズレるかもしれません。



で、VGA表示させるためには、NiosIIからsgdmaへDMA転送命令を送る必要があるわけですが
そのプログラムは以下の通り:

NiosII側プログラム

IRQを使ってDMA命令を発行しています。



参考にさせていただいたサイト:
https://sites.google.com/site/fpgaandco/de0-nano-niosii-lcd-driver