OV7670カラー識別トラッキング
24.11.11 ピン配表 訂正:ST7735SのA0ピン
画面の中の、赤い紙がある場所を特定し、緑丸を表示させています。
カラーキャプチャー構成概略
ポートEの8ビットパラレルのピクセルデータをDMA1で受信して、RAMのエリアに転送します。RAMエリアは、1画面分、160×120×2バイトを確保しています。
カメラからのトリガーパルスPCLKに同期して、この8ビットパラレルデータはPORTEを介して、DMA1が自動的にRAMに転送し、用意した配列に格納されます。
データが160×120×2バイトに達すると、DMA2割込みが発生し、そのDMA1割込み処理関数内で、カラーキャプチャー処理を行い、直後に、DMA2によるSPI転送で、液晶にキャプチャーの結果とカメラ画像を表示させています。
一画面全部を一気にRAMに展開し、かつカラーキャプチャー処理を行ったので、FPSは低下しています。
PIC32MX ピン割り付け表
コード DMAの初期化
転送元、転送先の指定。その大きさ。転送するサイズ。DMA転送のトリガーとなる割込みイベントの指定。
転送完了時の割込み処理関数での処理の記述がポイント。
マスターしてしまえば、とても高速で便利。
//DMA2-------------------------------------------------
//sprite1(RAM配列)からSPI2へ転送
void DMA2Init(void)
{
IEC2bits.DMA2IE = 0; // 設定のためDMA2を一時停止させる
DCH2CON = 0;
DCH2ECON = 0;
DCH2INT = 0;
DCH2CONbits.CHPRI = 3; // DMAチャネルの優先度(3)
DCH2ECONbits.CHSIRQ = _TIMER_2_IRQ; // DMAを開始する割り込み番号
DCH2ECONbits.SIRQEN = 1; // 割り込みによる転送を有効にする
DCH2INTbits.CHBCIE = 1; // Channel Block Transfer Complete Interrupt Flag bit
DCH2SSA = KVA_TO_PA(&sprite1);
//DCH2SSIZ = 128*160*3;
DCH2SSIZ = 160*120*2;
DCH2DSA = KVA_TO_PA(&SPI2BUF);
DCH2DSIZ = 1;
DCH2CSIZ = 1;
IFS2bits.DMA2IF = 0; // 割り込みフラグのクリア
IPC11bits.DMA2IP = 7; // 割り込み優先度
IPC11bits.DMA2IS = 3; // 副割り込み優先度
IEC2bits.DMA2IE = 1; // DMA2割り込みを有効にする
DCH2CONbits.CHEN = 1; // DMA1を使用する
DMACONbits.ON = 0; // DMAモジュールを有効にする
}
//DMA1-------------------------------------------------
//PORTEからsprite1(RAM配列)へ転送
void DMA1Init(void)
{
IEC2bits.DMA1IE = 0; // 設定のためDMA2を一時停止させる
DCH1CON = 0;
DCH1ECON = 0;
DCH1INT = 0;
DCH1CONbits.CHPRI = 3; // DMAチャネルの優先度(3)
DCH1ECONbits.CHSIRQ = _EXTERNAL_1_IRQ; // DMAを開始する割り込み番号
DCH1ECONbits.SIRQEN = 1; // 割り込みによる転送を有効にする
DCH1INTbits.CHDDIE = 1; // Channel Block Transfer Complete Interrupt Flag bit
DCH1SSA = KVA_TO_PA(&PORTE);
DCH1SSIZ = 1;
DCH1DSA = KVA_TO_PA(&sprite1);
DCH1DSIZ = 160*120*2;
DCH1CSIZ = 1;
IFS2bits.DMA1IF = 0; // 割り込みフラグのクリア
IPC10bits.DMA1IP = 7; // 割り込み優先度
IPC10bits.DMA1IS = 3; // 副割り込み優先度
IEC2bits.DMA1IE = 1; // DMA2割り込みを有効にする
DCH1CONbits.CHEN = 1; // DMA1を使用する
DMACONbits.ON = 0; // DMAモジュールを有効にする
}
DMA割込み処理
//DMA2
//トリガー:Timer2
//from sprite1 to SPI2BUF
//sprite1 size:160*2
//SPI2BUF size:1
void __ISR(_DMA2_VECTOR, IPL7AUTO) ISR_Dma2(void)
{
IFS2bits.DMA2IF = 0; // DMA2割り込みフラグのクリア
if(DCH2INTbits.CHBCIF == 1)
{
SPI2_Stop();
T2CONbits.ON=0;
//LATBbits.LATB1=~LATBbits.LATB1;
DCH2SSA = KVA_TO_PA(&sprite1);
DCH2CONbits.CHEN = 1; // DMA2を有効にする
DCH2INTbits.CHBCIF = 0; // ブロック終了割り込みフラグのクリア
DCH2ECONbits.SIRQEN = 1;
}
}
//DMA1
//トリガー:外部割込み1 INT1
//from PORTE(size 1)
//to sprite1(size160*2)
void __ISR(_DMA1_VECTOR, IPL7AUTO) ISR_Dma1(void)
{
static int i;
IFS2bits.DMA1IF=0;
if(DCH1INTbits.CHDDIF==1)
{
DCH1INTbits.CHDDIF=0;
DMACONbits.ON = 0;
colorCap();//カラーキャプチャー検索、位置表示。
pushSprite();//この関数の中で、Timer2を起動。連動してDMA2が起動。
DCH1DSA = KVA_TO_PA(&sprite1);
DCH1CONbits.CHEN=1;
//IEC2bits.DMA1IE = 0;
//IEC2bits.DMA2IE = 0;
}
}
カラーキャプチャー
1画面全体の中から、しきい値条件に当てはまったピクセル位置(行と列)を検索。しきい値条件を超えた点が5個になったら、検索終了します。1画面全体を一回で検索すると、次のカメラデータのページに間に合わないので、10行ずつ調べています。120行あるので、12フレーム画面更新で、全体から位置を特定しています。
なので、高速で移動した場合、追尾できません。対象物をゆっくり動かすと、なんとか、トレースしてくれます。
画面上に対象物がない場合、緑の丸の表示は消えます。
やはり、システムクロックは200Mhzぐらいほしいところです。
void colorCap(void)
{
int col,row,pix,err;
static uint8_t xmin, xmax, length;
uint8_t color,red,green;
static int row1=20;
bool exit;
static bool exist;
static int no_exist=0;
int counter;
exit = false;
counter=0;
for(row=row1; row<row1+10; row++)
{
for(pix=10; pix<300; pix++)
{
color = sprite1[(row*320)+pix];
if(pix%2==0)
{
red = color>>3;
green = (color&0x07)<<3;
if(red>20 & green<10)
{
col = pix/2;
OV7670.cCap.x.min = col;
OV7670.cCap.y.min = row;
counter++;
if(counter>5)
{
exit=true;
exist = true;
break;
}
}
}
if(exit)break;
}
}
if((row==row1+10) && (pix==300))
no_exist++;
if(no_exist>=10)
{
no_exist=0;
exist=false;
}
row1+=10;
if(row1>=110)
{
row1=20;
}
if(exist && OV7670.cCap.x.min!=0 && OV7670.cCap.y.min!=0)
{
bresenham_circle(OV7670.cCap.x.min, OV7670.cCap.y.min, 10, 0x0f, 0x3F, 0x00);
bresenham_circle(OV7670.cCap.x.min, OV7670.cCap.y.min, 9, 0x0f, 0x3F, 0x00);
}
}