MT9V034攝像頭學習筆記(三)

看完攝像頭的寄存器之後,就開始配置攝像頭的DMA採集。這裏寫圖片描述
還是看網上的大神截圖,攝像頭的時序。
從中我們可以看出,在行信號之後開始採集PCLK的圖像信息。所以我們用PCLK的上升沿觸發DMA進行圖像採集,DMA目的地址默認加一這樣就能實現圖像的自動採集,每次行中斷過來進行DMA目的地址的修正,具體下面的代碼。
// MT9V034 Port Init
void MT_Init(void)
{
uint16_t data = 0;
EXTI_Init(GPIOD,13,rising_up); //行中斷
EXTI_Init(GPIOD,14,falling_up); //場中斷
GPIO_Init(GPIOD,0,GPI,0); //八位數據輸入口
GPIO_Init(GPIOD,1,GPI,0);
GPIO_Init(GPIOD,2,GPI,0);
GPIO_Init(GPIOD,3,GPI,0);
GPIO_Init(GPIOD,4,GPI,0);
GPIO_Init(GPIOD,5,GPI,0);
GPIO_Init(GPIOD,6,GPI,0);
GPIO_Init(GPIOD,7,GPI,0);
SCCB_Init(); //初始化IIC IO口
if(SCB_RegRead(0x5C,MT_VERSION,&data) == 0)//讀取攝像頭版本寄存器
{
if(data != VERSION) //版本號不對說明出錯
{
while(1);
}
}
else
{
while(1);
}

SCB_RegWrite(MT_I2C_ADDR,MT_Mode,0x30a);          //設置攝像頭圖像4*4分頻輸出PCLK 27/4 = 6.75M 
/*下面的三個配置可以提高圖像的穩定性*/
SCB_RegWrite(MT_I2C_ADDR,0x20,0x3C7);           
SCB_RegWrite(MT_I2C_ADDR,0x2B,0x003);          
SCB_RegWrite(MT_I2C_ADDR,0x2F,0x003);          
DMACaptureInit(DMA_CH1,(void*)&PTD_BYTE0_IN,(void*)Image_Data1,PTD12,DMA_BYTE1,Image_Width,DMA_rising_down);//初始化DMA採集
Image_Data1_Status = Captrueing;
Image_Data2_Status = INIT;

}
volatile u8 Image_Data1[Height][Width];
volatile u8 Image_Data2[Height][Width];

u16 Image_Width = Width;//窗口寬度
u16 Image_Height= Height;//窗口高度

/* 狀態機 */
typedef enum
{
INIT,
Captrueing,
Finish,
Using
}MT9V034_Status;
MT9V034_Status Image_Data1_Status;
MT9V034_Status Image_Data2_Status;
//攝像頭圖像採集中斷處理函數
void PORTD_IRQHandler(void)
{
static uint32_t h_counter=0;
//行中斷PTD13
if((PORTD_ISFR & 0x2000))//行中斷 (1<<13)
{
PORTD_ISFR |= 0x2000; //清除中斷標識
if(h_counter > Image_Height)
{
h_counter=0;
}

    if(Image_Data1_Status == Captrueing||Image_Data1_Status == Finish)
    {
        DMA_SetDestAddress(DMA_CH1,(uint32_t)(&Image_Data1[h_counter++][0]));

    }
    else if(Image_Data2_Status == Captrueing||Image_Data2_Status == Finish)
    {
        DMA_SetDestAddress(DMA_CH1,(uint32_t)(&Image_Data2[h_counter++][0]));
    }

    DMA_SetMajorLoopCounter(DMA_CH1,Image_Width);
    DMA_EN(DMA_CH1);    
    return ;
}
//場中斷PTD14
if((PORTD_ISFR & 0x4000))//(1<<14)
{
    PORTD_ISFR |= 0x4000; //清除中斷標識    
      // 用戶程序 
    if(Image_Data1_Status == Captrueing)
    {
        if(Image_Data2_Status != Using)
        {
            Image_Data1_Status = Finish;
            Image_Data2_Status = Captrueing;   
        }
    }
    else if(Image_Data2_Status == Captrueing)
    {
        if(Image_Data1_Status != Using)
        {
            Image_Data2_Status = Finish;
            Image_Data1_Status = Captrueing;
        }
    }
    else
    {

    }
    h_counter = 0;
    return ;
}   

}
/***************************************************************
* 河南科技大學一隊
*
* 函數名稱:void DMACaptureInit(DMA_CHn CHn,void *SADDR, void *DADDR,PTXn_e ptxn,DMA_BYTEn byten,u32 count,DMA_PORTx2BUFF_cfg cfg)
* 功能說明:初始化DMA
* 參數說明:
* 函數返回:讀取字節
* 修改時間:2018年3月5日
* 備 注:
***************************************************************/
void DMACaptureInit(DMA_CHn CHn,void *SADDR, void *DADDR,PTXn_e ptxn,DMA_BYTEn byten,u32 count,DMA_Count_cfg cfg)
{
u8 BYTEs = (byten == DMA_BYTE1 ? 1 : (byten == DMA_BYTE2 ? 2 : (byten == DMA_BYTE4 ? 4 : 16 ) ) ); //計算傳輸字節數

//開啓時鐘 
SIM_SCGC7 |= SIM_SCGC7_DMA_MASK;                        //打開DMA模塊時鐘
SIM_SCGC6 |= SIM_SCGC6_DMAMUX_MASK;                     //打開DMA多路複用器時鐘

// 配置 DMA 通道 的 傳輸控制塊 TCD ( Transfer Control Descriptor ) 
DMA_SADDR(CHn) =    (u32)SADDR;                    // 設置  源地址
DMA_DADDR(CHn) =    (u32)DADDR;                    // 設置目的地址
DMA_SOFF(CHn)  =    0;                                  // 設置源地址不變
DMA_DOFF(CHn)  =    BYTEs;                                  // 每次傳輸後,目的加BYUEs

DMA_ATTR(CHn)  =    (0
                     | DMA_ATTR_SMOD(0x0)                // 源地址模數禁止  Source address modulo feature is disabled
                     | DMA_ATTR_SSIZE(byten)             // 源數據位寬 :DMA_BYTEn  。    SSIZE = 0 -> 8-bit ,SSIZE = 1 -> 16-bit ,SSIZE = 2 -> 32-bit ,SSIZE = 4 -> 16-byte
                     | DMA_ATTR_DMOD(0x0)                // 目標地址模數禁止
                     | DMA_ATTR_DSIZE(byten)             // 目標數據位寬 :DMA_BYTEn  。  設置參考  SSIZE
                    );
DMA_CITER_ELINKNO(CHn)  = DMA_CITER_ELINKNO_CITER(count); //當前主循環次數
DMA_BITER_ELINKNO(CHn)  = DMA_BITER_ELINKYES_BITER(count);//起始主循環次數

DMA_CR &= ~DMA_CR_EMLM_MASK;                            // CR[EMLM] = 0  disable Minor Loop Mapping

DMA_NBYTES_MLNO(CHn) =   DMA_NBYTES_MLNO_NBYTES(BYTEs); // 通道每次傳輸字節數,這裏設置爲BYTEs個字節。注:值爲0表示傳輸4GB 

// 配置 DMA 傳輸結束後的操作 
DMA_SLAST(CHn)      =   0;                              //調整源地址的附加值,主循環結束後恢復源地址
DMA_DLAST_SGA(CHn)  =   0;                              //調整目的地址的附加值,主循環結束後恢復目的地址或者保持地址
DMA_CSR(CHn)        =   (0
                         | DMA_CSR_DREQ_MASK            //主循環結束後停止硬件請求
                         | DMA_CSR_INTMAJOR_MASK        //主循環結束後產生中斷
                        );

// 配置 DMA 觸發源 
DMAMUX_CHCFG_REG(DMAMUX_BASE_PTR, CHn) = (0
        | DMAMUX_CHCFG_ENBL_MASK                        // Enable routing of DMA request 
        | DMAMUX_CHCFG_SOURCE((ptxn >> 5) + DMA_Port_A) // 通道觸發傳輸源:     
                                         );

SIM_SCGC5 |= (SIM_SCGC5_PORTA_MASK << (ptxn>>5));                                                               //開啓PORTx端口
GPIO_PDDR_REG(GPIOX[(ptxn>>5)]) &= ~(1 << (ptxn & 0x1f));                                                       //設置端口方向爲輸入
PORT_PCR_REG(PORTX[(ptxn>>5)], (ptxn & 0x1F)) = ( 0
        | PORT_PCR_MUX(1)               // 複用GPIO
        | PORT_PCR_IRQC(cfg & 0x03 )    // 確定觸發模式
        | ((cfg & 0xc0 ) >> 6)          // 開啓上拉或下拉電阻,或者沒有
                                                );
GPIO_PDDR_REG(GPIOX[(ptxn>>5)]) &= ~(1 << (ptxn && 0x1F));  

//開啓中斷 
DMA_EN(CHn);                                    //使能通道CHn 硬件請求
//DMA_IRQ_EN(CHn);                                //允許DMA通道傳輸

}
/***************************************************************
* 河南科技大學一隊
*
* 函數名稱:void DMA_SetDestAddress(uint8_t ch,uint32_t address)
* 功能說明:設置DMA傳輸的目的地址
* 參數說明:
* 函數返回:讀取字節
* 修改時間:2018年3月5日
* 備 注:
***************************************************************/
void DMA_SetDestAddress(uint8_t CHn,uint32_t address)
{
DMA_DADDR(CHn) = address; // 設置目的地址
}
/***************************************************************
* 河南科技大學一隊
*
* 函數名稱:void DMA_SetMajorLoopCounter(uint8_t CHn,uint32_t Val)
* 功能說明:設置傳輸循環次數
* 參數說明:
* 函數返回:void
* 修改時間:2018年3月5日
* 備 注:
***************************************************************/
void DMA_SetMajorLoopCounter(uint8_t CHn,uint32_t Val)
{
DMA_CITER_ELINKNO(CHn) = DMA_CITER_ELINKNO_CITER(Val); //當前主循環次數
DMA_BITER_ELINKNO(CHn) = DMA_BITER_ELINKYES_BITER(Val);//起始主循環次數
}
這樣就行實現圖像的採集,但是圖像還是有一個黑邊,可能和DMA的頻率有關KV58的DMA最高頻率只有27.5MHZ,雖然我把MT9V034的頻率降低到了6.75MHZ,但是採集的餘量還不是很大,在使能DMA之後就要進行第一個像素點的採集,有對不齊的現象出現。
DMA時鐘配置圖,這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章