カメラ動作確認
FIFO付カメラで撮影した画像を、カラー液晶で
表示し、動作確認します。
カラー液晶は、Nokiaの128x128(6100)を使います。
コネクタは10ピンですが、非常に小さいので
専用コネクタを使い、外部に引き出します。
コネクタ上の各ピンは、以下。
- Vcc
- nRESET
- DATA
- CLK
- nCS
- Vcc
- (no connect)
- GND
- VLED-
- VLED+
外部から見ると、カラー液晶は、メモリに見える
仕様です。
SPI相当のインタフェースで、アドレス、データを
外部電子回路から与えて対応します。
SPIは、8ビットのデータ転送ですが、この液晶の
インタフェースは、9ビット転送です。
さらに、受信ピンのみがあるだけ。
バックライト用に、VLED-/VLED+を使います。
(5V以上の電圧がかかるようにします。)
この2本は、電源電圧とは異なるので、別ワイヤーで
接続できるようにします。
このカメラをFPGAに接続できるようにします。
SCCBによるカメラの初期設定はマイコンに任せ
画像データ受信は、FPGAに担当させます。
テストに利用した基板は、ARMのADuC7026、FPGAは
Spartan3の50kゲートを使います。
FIFOなしカメラを利用し、FPGAで画像データを
取得するためのVHDLコードは、以下。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity camtst is
generic (
TOPX : integer := 4 ;
XMAX : integer := 12 ;
TOPY : integer := 17 ;
YMAX : integer := 80000 ;
TOPZ : integer := 9 ;
ZMAX : integer := 499 ;
LCNT_MAX : integer := 120 ;
PCNT_MAX : integer := 160 --;
);
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- camera
PCLK : in std_logic ;
VSYNC : in std_logic ;
HREF : in std_logic ;
GDAT : in std_logic_vector( 7 downto 0) ;
-- monitor
MFINDEX : out std_logic_vector( 9 downto 0) ;
MOUT : out std_logic_vector( 1 downto 0) ;
MGDAT : out std_logic_vector(15 downto 0) --;
);
end camtst ;
architecture Behavioral of camtst is
-- component clock generator
component clkgenx is
generic (
TOPX : integer ;
RMAX : integer --;
);
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- output
CLKOUT : out std_logic -- ;
);
end component ;
-- clock
signal iSCLK : std_logic ;
-- camera state machine
signal iVS_SFT : std_logic_vector(2 downto 0) ;
signal iVSTRG : std_logic ;
signal iPCLK_SFT : std_logic_vector(2 downto 0) ;
signal iPTRG : std_logic ;
signal iHREF : std_logic ;
signal iLCNT : integer range 0 to LCNT_MAX ;
signal iPCNT : integer range 0 to PCNT_MAX ;
signal iCSTATE : std_logic_vector(3 downto 0) ;
signal iFINDEX : integer range 0 to 924 ;
signal iGDAT : std_logic_vector(15 downto 0) ;
signal iMOUT : std_logic_vector(1 downto 0) ;
begin
-- component clock generator (48MHz/80000 = 600Hz)
CLKY : clkgenx generic map (TOPY,YMAX) port map (nRESET,CLOCK,iSCLK);
-- input
iHREF <= HREF ;
-- output
MOUT <= not iMOUT ;
MGDAT <= not iGDAT ;
MFINDEX <= not conv_std_logic_vector(iFINDEX,10);
-- trigger
process (nRESET,iSCLK)
begin
if ( nRESET = '0' ) then
iVS_SFT <= "000" ;
elsif rising_edge(iSCLK) then
iVS_SFT <= iVS_SFT(1 downto 0) & VSYNC ;
end if ;
end process ;
iVSTRG <= '1' when ( iVS_SFT = "011" or iVS_SFT = "001" ) else '0' ;
--PCLK
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iPCLK_SFT <= "000" ;
elsif rising_edge(CLOCK) then
iPCLK_SFT <= iPCLK_SFT(1 downto 0) & PCLK ;
end if ;
end process ;
iPTRG <= '1' when ( iPCLK_SFT = "011" or iPCLK_SFT = "001" ) else '0' ;
-- camera sequencer
process (nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iCSTATE <= "0000" ;
iLCNT <= 0 ;
iPCNT <= 0 ;
iFINDEX <= 0 ;
elsif rising_edge(CLOCK) then
case conv_integer(iCSTATE) is
-- wait trigger
when 0 => if ( iVSTRG = '1' ) then
iCSTATE <= "0001" ;
iLCNT <= 0 ;
iPCNT <= 0 ;
iFINDEX <= 0 ;
else
iCSTATE <= "0000" ;
end if ;
-- judge line max
when 1 => if ( iLCNT = LCNT_MAX ) then
iCSTATE <= "1000" ;
iLCNT <= 0 ;
else
iCSTATE <= "0011" ;
end if ;
-- judge pixel max
when 3 => if ( iPCNT = PCNT_MAX ) then
iCSTATE <= "1100" ;
iPCNT <= 0 ;
iLCNT <= iLCNT + 1 ;
else
iCSTATE <= "0111" ;
end if ;
-- get upper data
when 7 => if ( iPTRG = '1' and iHREF = '1' ) then
iCSTATE <= "1111" ;
iGDAT(15 downto 8) <= GDAT ;
else
iCSTATE <= "0111" ;
end if ;
-- get lower data
when 15 => if ( iPTRG = '1' and iHREF = '1' ) then
iCSTATE <= "1110" ;
iGDAT(7 downto 0) <= GDAT ;
else
iCSTATE <= "1111" ;
end if ;
-- store
when 14 => iCSTATE <= "0011" ;
if ( 13 < iPCNT and iPCNT < 147 ) then
if ( iLCNT = 8 or iLCNT = 16 or iLCNT = 24 or iLCNT = 32 or
iLCNT = 40 or iLCNT = 48 or iLCNT = 56 ) then
--
iFINDEX <= iFINDEX + 1 ;
end if ;
end if ;
iPCNT <= iPCNT + 1 ;
-- pixel loop
when 12 => iCSTATE <= "0001" ;
-- return first state
when 8 => iCSTATE <= "0000" ;
-- default
when others =>
iCSTATE <= "0000" ;
end case ;
end if ;
end process ;
iMOUT(0) <= '1' when ( iCSTATE(2 downto 0) = "111" ) else '0' ;
iMOUT(1) <= '1' when ( iCSTATE = "1110" or iCSTATE = "1100" ) else '0' ;
end Behavioral;
VSYNC、PCLKの立上がりエッジをつかまえて
シーケンサを動かします。
シーケンサから、フレームメモリ、LCDにデータ転送します。
1ライン=160ピクセル分を132ピクセルにし、フレーム
バッファには、0〜59のうちの7ライン分を格納します。
QQVGA(160x120)でカメラ動作を確認するため
ARMのADuC7026用ファームウエアは、以下です。
#include <ADuC7026.h>
#define OFF 0
#define ON OFF+1
/* data definitions */
typedef unsigned char UBYTE ;
typedef signed char SBYTE ;
typedef unsigned short UWORD ;
typedef signed short SWORD ;
typedef unsigned long ULONG ;
typedef signed long SLONG ;
void IRQ_Handler(void) __irq;
void init_usr(void);
#define MASKFF 0xFF
#define MASK0F 0x0F
#define MASK80 0x80
#define MASK40 0x40
#define MASK20 0x20
#define MASK10 0x10
#define MASK08 0x08
#define MASK04 0x04
#define MASK02 0x02
#define MASK01 0x01
#define MASKF0 0xF0
#define SCCB_ID_WR 0x42
#define SCCB_ID_RD 0x43
#define S_SCL 23
#define S_SDA 22
#define S_WEN 21
#define S_RRST 20
#define S_OE 18
#define S_RCLK 17
#define S_VS 2
ULONG timcnt ;
UBYTE lcnt ;
UBYTE pcnt ;
UWORD gtmp ;
#define MAX_LCNT 120
#define MAX_PCNT 160
#define PCNT_FIRST 13
#define PCNT_LAST 147
void rs_putchar(UBYTE x);
void crlf(void);
void rs_puts(UBYTE *x);
void show_help(void);
void init_cam(void);
void put_sccb_start(void);
void put_sccb_stop(void);
void put_sccb_data(UBYTE x);
UBYTE get_sccb_data(void);
UBYTE load_cam(UBYTE adr);
void send_cam(UBYTE adr,UBYTE dat);
void delay_ms(UWORD x);
void delay_100us(UWORD x);
UBYTE gdat(void);
void set_rclk(UBYTE x);
void set_oe(UBYTE x);
void set_rrst(UBYTE x);
void out_gdat(UBYTE col,UBYTE lin,UWORD x);
void init_pla(void);
void ca_handler(void);
UBYTE is_valid_line(UBYTE x);
/* global variables */
volatile UBYTE uflag ;
volatile UBYTE sbuf[8] ;
volatile UBYTE sindex ;
volatile UBYTE cmd ;
volatile UBYTE asc_hex[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
volatile UBYTE state ;
volatile UBYTE cstate ;
volatile UWORD vscnt ;
volatile UBYTE strg ;
volatile UBYTE vtrg ;
volatile UBYTE ptrg ;
volatile UWORD fbuf[924] ;
volatile UBYTE findex ;
#define REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */
#define REG_BLUE 0x01 /* blue gain */
#define REG_RED 0x02 /* red gain */
#define REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */
#define REG_COM1 0x04 /* Control 1 */
#define COM1_CCIR656 0x40 /* CCIR656 enable */
#define REG_BAVE 0x05 /* U/B Average level */
#define REG_GbAVE 0x06 /* Y/Gb Average level */
#define REG_AECHH 0x07 /* AEC MS 5 bits */
#define REG_RAVE 0x08 /* V/R Average level */
#define REG_COM2 0x09 /* Control 2 */
#define COM2_SSLEEP 0x10 /* Soft sleep mode */
#define REG_PID 0x0a /* Product ID MSB */
#define REG_VER 0x0b /* Product ID LSB */
#define REG_COM3 0x0c /* Control 3 */
#define COM3_SWAP 0x40 /* Byte swap */
#define COM3_SCALEEN 0x08 /* Enable scaling */
#define COM3_DCWEN 0x04 /* Enable downsamp/crop/window */
#define REG_COM4 0x0d /* Control 4 */
#define REG_COM5 0x0e /* All "reserved" */
#define REG_COM6 0x0f /* Control 6 */
#define REG_AECH 0x10 /* More bits of AEC value */
#define REG_CLKRC 0x11 /* Clocl control */
#define CLK_EXT 0x40 /* Use external clock directly */
#define CLK_SCALE 0x3f /* Mask for internal clock scale */
#define REG_COM7 0x12 /* Control 7 */
#define COM7_RESET 0x80 /* Register reset */
#define COM7_FMT_MASK 0x38
#define COM7_FMT_VGA 0x00
#define COM7_FMT_CIF 0x20 /* CIF format */
#define COM7_FMT_QVGA 0x10 /* QVGA format */
#define COM7_FMT_QCIF 0x08 /* QCIF format */
#define COM7_RGB 0x04 /* bits 0 and 2 - RGB format */
#define COM7_YUV 0x00 /* YUV */
#define COM7_BAYER 0x01 /* Bayer format */
#define COM7_PBAYER 0x05 /* "Processed bayer" */
#define REG_COM8 0x13 /* Control 8 */
#define COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */
#define COM8_AECSTEP 0x40 /* Unlimited AEC step size */
#define COM8_BFILT 0x20 /* Band filter enable */
#define COM8_AGC 0x04 /* Auto gain enable */
#define COM8_AWB 0x02 /* White balance enable */
#define COM8_AEC 0x01 /* Auto exposure enable */
#define REG_COM9 0x14 /* Control 9 - gain ceiling */
#define REG_COM10 0x15 /* Control 10 */
#define COM10_HSYNC 0x40 /* HSYNC instead of HREF */
#define COM10_PCLK_HB 0x20 /* Suppress PCLK on horiz blank */
#define COM10_HREF_REV 0x08 /* Reverse HREF */
#define COM10_VS_LEAD 0x04 /* VSYNC on clock leading edge */
#define COM10_VS_NEG 0x02 /* VSYNC negative */
#define COM10_HS_NEG 0x01 /* HSYNC negative */
#define REG_HSTART 0x17 /* Horiz start high bits */
#define REG_HSTOP 0x18 /* Horiz stop high bits */
#define REG_VSTART 0x19 /* Vert start high bits */
#define REG_VSTOP 0x1a /* Vert stop high bits */
#define REG_PSHFT 0x1b /* Pixel delay after HREF */
#define REG_MIDH 0x1c /* Manuf. ID high */
#define REG_MIDL 0x1d /* Manuf. ID low */
#define REG_MVFP 0x1e /* Mirror / vflip */
#define MVFP_MIRROR 0x20 /* Mirror image */
#define MVFP_FLIP 0x10 /* Vertical flip */
#define REG_AEW 0x24 /* AGC upper limit */
#define REG_AEB 0x25 /* AGC lower limit */
#define REG_VPT 0x26 /* AGC/AEC fast mode op region */
#define REG_HSYST 0x30 /* HSYNC rising edge delay */
#define REG_HSYEN 0x31 /* HSYNC falling edge delay */
#define REG_HREF 0x32 /* HREF pieces */
#define REG_TSLB 0x3a /* lots of stuff */
#define TSLB_YLAST 0x04 /* UYVY or VYUY - see com13 */
#define REG_COM11 0x3b /* Control 11 */
#define COM11_NIGHT 0x80 /* NIght mode enable */
#define COM11_NMFR 0x60 /* Two bit NM frame rate */
#define COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */
#define COM11_50HZ 0x08 /* Manual 50Hz select */
#define COM11_EXP 0x02
#define REG_COM12 0x3c /* Control 12 */
#define COM12_HREF 0x80 /* HREF always */
#define REG_COM13 0x3d /* Control 13 */
#define COM13_GAMMA 0x80 /* Gamma enable */
#define COM13_UVSAT 0x40 /* UV saturation auto adjustment */
#define COM13_UVSWAP 0x01 /* V before U - w/TSLB */
#define REG_COM14 0x3e /* Control 14 */
#define COM14_DCWEN 0x10 /* DCW/PCLK-scale enable */
#define REG_EDGE 0x3f /* Edge enhancement factor */
#define REG_COM15 0x40 /* Control 15 */
#define COM15_R10F0 0x00 /* Data range 10 to F0 */
#define COM15_R01FE 0x80 /* 01 to FE */
#define COM15_R00FF 0xc0 /* 00 to FF */
#define COM15_RGB565 0x10 /* RGB565 output */
#define COM15_RGB555 0x30 /* RGB555 output */
#define REG_COM16 0x41 /* Control 16 */
#define COM16_AWBGAIN 0x08 /* AWB gain enable */
#define REG_COM17 0x42 /* Control 17 */
#define COM17_AECWIN 0xc0 /* AEC window - must match COM4 */
#define COM17_CBAR 0x08 /* DSP Color bar */
#define REG_RGB444 0x8c /* RGB 444 control */
#define R444_ENABLE 0x02 /* Turn on RGB444, overrides 5x5 */
#define R444_RGBX 0x01 /* Empty nibble at end */
#define REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */
#define REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */
#define REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */
int main(void)
{
/* initialize user */
init_usr();
/* show message */
rs_puts("Hello"); crlf();
/* endless loop */
while(ON)
{
/* command interrpreter */
if ( uflag == ON ) {
/* clear flag */
uflag = OFF ;
/* judge */
cmd = *(sbuf+0) ;
if ( cmd == '?' ) { show_help(); }
/* initialize CAMERA */
if ( cmd == 'I' ) { crlf(); init_cam() ; }
/* take shot */
if ( cmd == 'S' ) { strg = ON ; }
}
/* get graphic data from camera */
ca_handler();
}
/* dummy return */
return (0);
}
void IRQ_Handler(void) __irq
{
volatile UBYTE ch ;
/* judge UART receive interruption */
if ( (IRQSTA & UART_BIT) == UART_BIT ) {
/* judge */
if ( COMSTA0 & 1 ) {
/* clear flag */
ch = COMRX ;
*(sbuf+sindex) = ch ;
sindex++ ;
if ( ch == '\r' ) {
sindex = 0 ;
uflag = ON ;
}
}
}
/* judge timer0 interruption (100us) */
if ( (IRQSTA & RTOS_TIMER_BIT) == RTOS_TIMER_BIT ) {
/* clear timer0 interrupt flag */
T0CLRI = 0xff ;
/* increment */
timcnt++ ;
/* judge */
if ( (timcnt & 0x3ff) == 0 ) {
GP4DAT ^= (1 << 23);
}
}
/* judge timer1 interruption (100Hz) */
if ( (IRQSTA & GP_TIMER_BIT) == GP_TIMER_BIT ) {
/* clear timer0 interrupt flag */
T1CLRI = 0xff ;
/* increment */
vscnt++ ;
/* 600Hz handling */
if ( vscnt == 600 ) {
vscnt = 0 ;
/* get vsync signal */
GP3DAT ^= (1 << 23) ;
}
}
/* judge PLA0 interruption (exteranl interruption) */
if ( (IRQSTA & PLA_IRQ0_BIT) == PLA_IRQ0_BIT ) {
vtrg = OFF ;
/* enable */
if ( strg == ON ) {
/* set flag */
vtrg = ON ;
}
/* get vsync signal Debug */
GP3DAT ^= (1 << 22) ;
}
/* judge PLA1 interruption (exteranl interruption) */
if ( (IRQSTA & PLA_IRQ1_BIT) == PLA_IRQ1_BIT ) {
ptrg = OFF ;
/* enable */
if ( strg == ON ) {
/* set flag */
ptrg = ON ;
}
/* get PCLK signal Debug */
GP3DAT ^= (1 << 21) ;
}
}
void init_usr(void)
{
/* select clock 41.78MHz
initialized in start up routine
*/
PLLKEY1 = 0xaa ;
PLLCON = 0x01 ;
PLLKEY2 = 0x55 ;
/* power control
initialized in start up routine
*/
/* clear flag */
uflag = OFF ;
strg = OFF ;
vtrg = OFF ;
ptrg = OFF ;
/* clear counter */
timcnt = 0 ;
sindex = 0 ;
state = 0 ;
cstate = 0 ;
vscnt = 0 ;
/* initialize UART */
{
/* set baud rate 38400 bps CD = 0 DL = 0x11 */
COMCON0 = 0x80 ; /* select COMDIV1 and COMDIV0 */
COMDIV0 = 0x22 ;
//COMDIV0 = 0x44 ;
COMDIV1 = 0x00 ;
/* set conditions */
COMCON0 = 0x03 ; /* select COMRX and COMTX , 8bit data , 1 stop bit , no parity */
/* enable interrupt */
COMIEN0 = 0x01 ; /* ERBFI */
}
/* P0 */
{
/* */
GP0DAT = 0xFF3C0000 ;
}
/* P1 */
{
/* GP1.4 (PLA IN) use UART */
GP1CON = 0x03030011 ;
/* */
GP1DAT = 0x2E000000 ;
}
/* P2 */
{
/* all bits input */
GP2DAT = 0x00000000 ;
}
/* P3 */
{
GP3DAT = 0xffff0000 ;
}
/* P4 */
{
GP4DAT = 0xff000000 ;
}
/* initialize timer 0 (100us) */
{
T0LD = 4178 ; /* (41.78MHz / 1) / 10kHz */
T0CON = 0xc0 ; /* enable , cyclic , 1/1 */
}
/* initialize timer 1 (600Hz) */
{
T1LD = 4352 ; /* (41.78MHz / 16) / 600Hz */
T1CON = 0xc4 ; /* enable , cyclic , 1/16 */
}
/* initialize PLA */
init_pla();
/* enable timer 0 interrupt , timer 1 interrupt and UART interrupt */
IRQEN = RTOS_TIMER_BIT | GP_TIMER_BIT | UART_BIT | PLA_IRQ0_BIT ;
}
/* UART putchar */
void rs_putchar(UBYTE x)
{
/* ? transmmit buffer empty */
while( (COMSTA0 & 0x40) == 0 ) ;
/* set value */
COMTX = x ;
}
/* carriage return and line feed */
void crlf(void)
{
rs_putchar('\r');
rs_putchar('\n');
}
/* UART puts */
void rs_puts(UBYTE *x)
{
while ( *x != '\0' ) {
rs_putchar( *x ) ;
x++ ;
}
}
/* show help */
void show_help(void)
{
rs_puts("? help") ; crlf();
rs_puts("I initialize camera"); crlf();
rs_puts("S shot picture") ; crlf();
}
void put_sccb_start(void)
{
/* both high level */
GP0DAT |= ((1 << S_SCL) | (1 << S_SDA)) ; /* SCL = ON ; SDA = ON */
delay_100us(3);
/* 0 -> SDA */
GP0DAT &= ~(1 << S_SDA) ; /* SCL = ON ; SDA = OFF */
delay_100us(3);
/* 0 -> SCL */
GP0DAT &= ~(1 << S_SCL) ; /* SCL = OFF ; SDA = OFF */
delay_100us(3);
}
void put_sccb_stop(void)
{
/* both high level */
GP0DAT |= (1 << S_SCL) ; /* SCL = ON ; SDA = ? */
delay_100us(3);
/* 0 -> SDA */
GP0DAT &= ~(1 << S_SDA) ; /* SCL = ON ; SDA = OFF */
delay_100us(3);
/* both high level */
GP0DAT |= (1 << S_SDA) ; /* SCL = ON ; SDA = ON */
delay_100us(3);
}
void put_sccb_data(UBYTE x)
{
UBYTE tmp ;
UBYTE i ;
/* load raw data */
tmp = x ;
/* transfer data with write code */
for ( i = 0 ; i < 8 ; i++ ) {
/* send bit datum */
GP0DAT &= ~(1 << S_SDA) ;
if ( tmp & MASK80 ) { GP0DAT |= (1 << S_SDA) ; }
delay_ms(1) ;
/* 1 -> SCL */
GP0DAT |= (1 << S_SCL) ; delay_100us(5) ;
/* shift */
tmp <<= 1 ;
/* 0 -> SCL */
GP0DAT &= ~(1 << S_SCL) ; delay_100us(5) ;
}
/* data low */
GP0DAT &= ~(1 << S_SDA) ; delay_100us(5) ;
/* change input */
GP0DAT &= ~(1 << 30) ; delay_100us(5) ;
/* 1 -> SCL */
GP0DAT |= (1 << S_SCL) ; delay_100us(5) ;
/* get acknowledge */
tmp = OFF ;
if ( (GP0DAT & MASK40) == MASK40 ) { tmp = ON ; }
/* 0 -> SCL */
GP0DAT &= ~(1 << S_SCL) ; delay_100us(5) ;
/* change output */
GP0DAT |= (1 << 30) ;
}
UBYTE get_sccb_data(void)
{
UBYTE result ;
UBYTE i ;
UBYTE tmp ;
/* change inupt */
GP0DAT &= ~(1 << 30) ;
/* default */
result = 0 ;
/* loop */
for ( i = 0 ; i < 8 ; i++ ) {
/* shift */
result <<= 1 ;
/* 1 -> SCL */
GP0DAT |= (1 << S_SCL) ; delay_100us(5) ;
/* get bit datum */
if ( (GP0DAT & MASK40) == MASK40 ) { result |= ON ; }
/* 0 -> SCL */
GP0DAT &= ~(1 << S_SCL) ; delay_100us(5) ;
}
/* 1 -> SCL */
GP0DAT |= (1 << S_SCL) ; delay_100us(5) ;
/* get acknowledge */
tmp = OFF ;
if ( (GP0DAT & MASK40) == MASK40 ) { tmp = ON ; }
/* 0 -> SCL */
GP0DAT &= ~(1 << S_SCL) ; delay_100us(5) ;
/* change output */
GP0DAT |= (1 << 30) ;
return result ;
}
void send_cam(UBYTE adr,UBYTE dat)
{
/* start conditon */
put_sccb_start() ;
/* send ID */
put_sccb_data(SCCB_ID_WR);
/* send address */
put_sccb_data(adr);
/* send parameter */
put_sccb_data(dat);
/* stop condition */
put_sccb_stop();
/* delay */
delay_100us(5);
}
UBYTE load_cam(UBYTE adr)
{
UBYTE result ;
/* start conditon */
put_sccb_start() ;
/* send ID (write) */
put_sccb_data(SCCB_ID_WR);
/* send address */
put_sccb_data(adr);
/* stop condition */
put_sccb_stop();
/* start conditon */
put_sccb_start() ;
/* send ID (read) */
put_sccb_data(SCCB_ID_RD);
/* get parameter */
result = get_sccb_data();
/* stop condition */
put_sccb_stop();
return result ;
}
void delay_100us(UWORD x)
{
ULONG last ;
/* calculate */
last = timcnt + x ;
/* wait */
while ( timcnt < last ) ;
}
void delay_ms(UWORD x)
{
ULONG last ;
/* calculate */
last = timcnt + 10 * x ;
/* wait */
while ( timcnt < last ) ;
}
void init_cam(void)
{
send_cam(REG_COM7,COM7_RESET); //0x12:COM7(Reset,QCIF,Cbar,RGBformat)
delay_ms(200); //200ms
rs_puts("Complete reset"); crlf();
send_cam(REG_COM7,COM7_RGB | COM7_RGB); //0x12:COM7 , 0x0C) //RGB
send_cam(REG_RGB444,R444_ENABLE | R444_RGBX); //0x8c:RGB 444 control
send_cam(REG_COM1,0x40); //0x04:COM1(CCIR656,AEC) //0) //0x40)
send_cam(REG_COM15,COM15_R01FE|COM15_RGB565); //0x40:COM15
send_cam(REG_COM9, 0x38); //0x14:COM9=max AGC gain ceiling, Freeze AGC/AEC
//c(0x3d,0xc3) //(REG_COM13, COM13_GAMMA|COM13_UVSAT|0x2) //0x3d:COM13
send_cam(REG_HAECC7,0x94); //0xaa:Hist AEC/AGC control 7 c(0xAA,0x94) //AEC algorithm
send_cam(REG_TSLB,0x04); //0x3a:Neg,UVval,YUYV,window TSLB_YLAST) //0x04) //0x0C) //0x80) //0x00) //0x04)
send_cam(0x20,0x0f); //ADCCTR0, A/D range&ref, mu0102
send_cam(REG_COM8,0x9a); //mu0103
send_cam(0x10,0x01); //mu0103
/* CLKRC */
send_cam(0x11,0x80);
/* COM1 */
send_cam(0x3b,0x0a); /* disable night mode */
/* TSLB */
send_cam(0x3a,0x04);
/* COM7 */
send_cam(0x12,0x04);
/* RGB444 */
send_cam(0x8c,0x02);
/* COM15 */
send_cam(0x40,0xd0);
/* HSTART */
send_cam(0x17,0x16);
/* HSTOP */
send_cam(0x18,0x04);
/* HREF */
send_cam(0x32,0x24);
/* VSTRT */
send_cam(0x19,0x02);
/* VSTOP */
send_cam(0x1a,0x7a);
/* VREF */
send_cam(0x03,0x0a);
/* COM10 */
//send_cam(0x15,0x02);
/* COM3 */
send_cam(0x0c,0x04);
/* COM4 */
send_cam(0x3e,0x1a);
/* SCALING_DCWCTR */
send_cam(0x72,0x22);
/* SCALING_PCLK_DIV */
send_cam(0x73,0xf2);
rs_puts("Exit initialize"); crlf();
}
UBYTE gdat(void)
{
UBYTE result ;
/* get graphic data */
result = GP2DAT & MASKFF ;
return result ;
}
void set_rclk(UBYTE x)
{
if ( x ) { GP0DAT |= (1 << S_RCLK) ; }
else { GP0DAT &= ~(1 << S_RCLK) ; }
}
void set_oe(UBYTE x)
{
if ( x ) { GP0DAT &= ~(1 << S_OE) ; }
else { GP0DAT |= (1 << S_OE) ; }
}
void set_rrst(UBYTE x)
{
if ( x ) { GP0DAT &= ~(1 << S_RRST) ; }
else { GP0DAT |= (1 << S_RRST) ; }
}
void out_gdat(UBYTE col,UBYTE lin,UWORD x)
{
UWORD tmp ;
/* clear upper nibble */
tmp = x & 0x0fff ;
/* judge */
if ( col > 131 ) return ;
if ( lin > 120 ) return ;
/* send data to LCD*/
}
void init_pla(void)
{
/* VSYNC */
/* initialize element block #0 */
PLAELM0 = 0x549 ; /* NOT B and A */
PLAELM4 = 0x34 ; /* select GP1.4 , B */
PLAELM5 = 0x458 ; /* select E4 , A */
/* initialize element block #1 */
PLAELM6 = 0x035 ; /* P1.6 toss */
PLAELM7 = 0x659 ; /* E6 toss */
PLAELM8 = 0x058 ; /* get E6 and regist */
PLAELM9 = 0x034 ; /* get E9 and regist */
PLAELM15 = 0x025 ; /* not E8 and E9 */
/* select clock */
PLACLK = 0x35 ; /* HCLK , Timer1 overflow */
/* interrupt enable */
PLAIRQ = 0x1f10 ; /* element 15 H , element 1 H element 0 H */
}
void ca_handler(void)
{
UBYTE res ;
UBYTE href ;
/* get HREF */
res = GP1DAT & MASKFF ;
href = OFF ;
if ( (res & MASK40) == MASK40 ) { href = ON ; }
/* state machine */
switch (cstate) {
/* wait trigger */
case 0 : cstate = 0 ; /* stay */
if ( vtrg == ON ) {
vtrg = OFF ;
lcnt = 0 ; /* clear line counter */
pcnt = 0 ; /* clear pixel counter */
findex = 0 ; /* clear frame index */
/* next state */
cstate = 1 ;
}
break ;
/* judge end of line */
case 1 : cstate = 2 ; /* stay */
if ( lcnt == MAX_LCNT ) {
lcnt = 0 ; /* clear line counter */
/* next */
cstate = 7 ;
}
break ;
/* judge end of pixel */
case 2 : cstate = 3 ; /* next */
if ( pcnt == MAX_PCNT ) {
/* next state */
cstate = 6 ;
}
break ;
/* get upper byte */
case 3 : cstate = 3 ; /* stay */
if ( (ptrg & href) == ON ) {
/* clear trigger flag */
ptrg = OFF ;
/* get data and shift */
gtmp = gdat() ;
gtmp <<= 8 ;
/* next state */
cstate = 4 ;
}
break ;
/* get lower byte */
case 4 : cstate = 4 ; /* stay */
if ( (ptrg & href) == ON ) {
/* clear trigger flag */
ptrg = OFF ;
/* get data */
gtmp |= gdat() ;
/* next */
cstate = 5 ;
}
break ;
/* store data */
case 5 : cstate = 2 ; /* next */
/* judge range */
if ( pcnt > PCNT_FIRST && pcnt < PCNT_LAST ) {
/* juge valid line */
if ( is_valid_line(lcnt) == ON ) {
*(fbuf+findex) = gtmp ;
/* frame buffer index increment */
findex++ ;
}
}
/* pixel counter increment */
pcnt++ ;
break ;
/* return line judgement */
case 6 : cstate = 1 ; /* next */
/* line counter increment */
lcnt++ ;
/* clear pixel counter */
pcnt = 0 ;
break ;
/* return first state */
case 7 : cstate = 0 ; /* next */
strg = OFF ;
break ;
/* */
default : cstate = 0 ;
break ;
}
}
UBYTE is_valid_line(UBYTE x)
{
UBYTE result ;
/* judge */
switch ( x ) {
case 8 :
case 16 :
case 24 :
case 32 :
case 40 :
case 48 :
case 56 : result = ON ; break ;
default : result = OFF ; break ;
}
return result ;
}
(under construction)
目次
前
次