1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

PIC32MX + OV7670カメラ カラーキャプチャー

Last updated at Posted at 2024-11-08

OV7670カラー識別トラッキング

24.11.11 ピン配表 訂正:ST7735SのA0ピン

IMG_5076.JPG

画面の中の、赤い紙がある場所を特定し、緑丸を表示させています。

カラーキャプチャー構成概略

概略図.jpg
ポートEの8ビットパラレルのピクセルデータをDMA1で受信して、RAMのエリアに転送します。RAMエリアは、1画面分、160×120×2バイトを確保しています。

カメラからのトリガーパルスPCLKに同期して、この8ビットパラレルデータはPORTEを介して、DMA1が自動的にRAMに転送し、用意した配列に格納されます。

データが160×120×2バイトに達すると、DMA2割込みが発生し、そのDMA1割込み処理関数内で、カラーキャプチャー処理を行い、直後に、DMA2によるSPI転送で、液晶にキャプチャーの結果とカメラ画像を表示させています。

一画面全部を一気にRAMに展開し、かつカラーキャプチャー処理を行ったので、FPSは低下しています。

PIC32MX ピン割り付け表

ピン配改2.png

コード DMAの初期化

転送元、転送先の指定。その大きさ。転送するサイズ。DMA転送のトリガーとなる割込みイベントの指定。
転送完了時の割込み処理関数での処理の記述がポイント。
マスターしてしまえば、とても高速で便利。

DMA1,2初期化
//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割込み処理

DMA ISR.c
//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);
    }
    
    
}
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?