DMA, Direct Memory Access. 设定后,无需CPU干预即可将外设数据读到RAM中去。
摄像头组需要不断读取图像到内存,DMA可以分担图像读取的操作,大大减少了CPU的负担,于是我们可以有更多资源处理其他事情。
DMA另一个好处是可以跟着摄像头的PCLK读取数据,图像不会有噪点。
坏消息是,XS128不带DMA功能,呵呵。
通过DMA读取图像的方法:
1. 初始化摄像头管脚输入方向,初始化DMA;
2. 场中断到来,允许行中断;
3. 行中断到来,开启DMA,让DMA读取一行的数据;
4. 关闭DMA,等待下一次行中断。
1. 初始化管脚输入方向
gpio_init(CCD_PORT,CCD0,GPI,0);
gpio_init(CCD_PORT,CCD1,GPI,0);
gpio_init(CCD_PORT,CCD2,GPI,0);
gpio_init(CCD_PORT,CCD3,GPI,0);
gpio_init(CCD_PORT,CCD4,GPI,0);
gpio_init(CCD_PORT,CCD5,GPI,0);
gpio_init(CCD_PORT,CCD6,GPI,0);
gpio_init(CCD_PORT,CCD7,GPI,0);
gpio_init(CCD_PORT,CCD1,GPI,0);
gpio_init(CCD_PORT,CCD2,GPI,0);
gpio_init(CCD_PORT,CCD3,GPI,0);
gpio_init(CCD_PORT,CCD4,GPI,0);
gpio_init(CCD_PORT,CCD5,GPI,0);
gpio_init(CCD_PORT,CCD6,GPI,0);
gpio_init(CCD_PORT,CCD7,GPI,0);
2. 初始化行场中断(外部中断)
//行中断
FTM_Input_init(CCD_FTM,CCD_HR_CH,Rising); //初始化FTM输入捕捉模式,上升沿触发
//场中断
FTM_Input_init(CCD_FTM,CCD_VS_CH,Falling); //初始化FTM输入捕捉模式,下降沿触发
FTM_Input_init(CCD_FTM,CCD_HR_CH,Rising); //初始化FTM输入捕捉模式,上升沿触发
//场中断
FTM_Input_init(CCD_FTM,CCD_VS_CH,Falling); //初始化FTM输入捕捉模式,下降沿触发
3. 初始化DMA
具体方法请参考野火手册。
DMA_PORTx2BUFF_Init (CCD_DMA_CH,(void *)&CCD_DATA,&Pic_Buffer[0][0],PLCK_CH,DMA_BYTE1,COLUMN,DMA_rising);//DMA_falling DMA_rising
//DMA通道4初始化,PTA27上升沿触发DMA传输,源地址为PTD_BYTE0_IN,目的地址为:BUFF ,每次传输1Byte,传输3次后停止传输,恢复目的地址
/* 开启中断 */
//DMA_EN(CCD_DMA_CH); //使能通道CHn 硬件请求
//DMA_IRQ_EN(CCD_DMA_CH); //允许DMA通道传输
DMA_IRQ_CLEAN(CCD_DMA_CH);
//DMA通道4初始化,PTA27上升沿触发DMA传输,源地址为PTD_BYTE0_IN,目的地址为:BUFF ,每次传输1Byte,传输3次后停止传输,恢复目的地址
/* 开启中断 */
//DMA_EN(CCD_DMA_CH); //使能通道CHn 硬件请求
//DMA_IRQ_EN(CCD_DMA_CH); //允许DMA通道传输
DMA_IRQ_CLEAN(CCD_DMA_CH);
4. 行场中断处理
/*************************************************************************
* 函数名称:PORTB_IRQHandler
* 功能说明:摄像头行场中断服务函数
* 参数说明:无
* 函数返回:无
* 修改时间:2014-3-29 modified by feichashao
* 备 注:
< 使用了往届学长的代码 >
原本杨向军的摄像头例程使用的是FTM模块完成行场中断任务,
这里由于直立车的测速模块已经占用了FTM模块的两个子模块通道,
因此这里我改用外部中断EXTI模块完成行场中断任务,
当然也有人说建议使用FTM进行摄像头终端,但原因我也不太明白
*************************************************************************/
u32 tmpline = 0;//行号
u32 error_row = 0;//发生错误行号
u32 tmprow = 0; //列号
u32 tmpnum = 0; //场号
u32 picLineSum = 0;//总行数
void PORTB_IRQHandler()
{
u32 tmpISFR = 0;
tmpISFR=PORTB_ISFR;
PORTB_ISFR |= 0xFFFFFFFF;
// DisableInterrupts; //注释掉,以允许其他中断进入
//========================== n = CAM_HR_CHn ========================================
if((tmpISFR & (1<<CAM_HR_CHn))) //PB1 触发中断 行中断
{
tmpline++;
if(0 == (tmpline % 2))//对tmpline取余,当tmpline为偶数行时进入(进行数据传输)
{
if(DMA_CITER_ELINKNO(CAM_DMA_CH) != COLUMN)
{
//uartPrintf("DMA末传输结束 %d \n",DMA_CITER_ELINKNO(CCD_DMA_CH));
Error = 1;
error_row = tmprow ;
}
DMA_SETDAADDR(CAM_DMA_CH,&Pic_Buffer[tmprow][0]);//Pic_Buffer的大小为120(row)*160(column) 这里是指从第row行的第0列(个像素点)开始传输
DMA_EN(CAM_DMA_CH);//使能通道硬件DMA请求
tmprow++;
if(tmprow >= ROW)
{
photeCompleteFlag = 1;
}
}
}
//========================== n = CAM_VS_CHn ========================================
if((tmpISFR & (1<<CAM_VS_CHn))) //PTB2 触发中断 场中断;
{
tmpnum++;
picLineSum = tmpline;
tmpline = 0;//行号清零
tmprow = 0; //列号清零
DMA_IRQ_CLEAN(CAM_DMA_CH);//清除通道传输中断标志位
En_HREF; //打开行中断
}
if(!(tmpISFR & (1<<CAM_HR_CHn)) && !(tmpISFR & (1<<CAM_VS_CHn)))
{
uartPrintf("Unexpected Interrapt 0x%X",tmpISFR);
}
// EnableInterrupts; //注释掉,以允许其他中断进入
}
* 函数名称:PORTB_IRQHandler
* 功能说明:摄像头行场中断服务函数
* 参数说明:无
* 函数返回:无
* 修改时间:2014-3-29 modified by feichashao
* 备 注:
< 使用了往届学长的代码 >
原本杨向军的摄像头例程使用的是FTM模块完成行场中断任务,
这里由于直立车的测速模块已经占用了FTM模块的两个子模块通道,
因此这里我改用外部中断EXTI模块完成行场中断任务,
当然也有人说建议使用FTM进行摄像头终端,但原因我也不太明白
*************************************************************************/
u32 tmpline = 0;//行号
u32 error_row = 0;//发生错误行号
u32 tmprow = 0; //列号
u32 tmpnum = 0; //场号
u32 picLineSum = 0;//总行数
void PORTB_IRQHandler()
{
u32 tmpISFR = 0;
tmpISFR=PORTB_ISFR;
PORTB_ISFR |= 0xFFFFFFFF;
// DisableInterrupts; //注释掉,以允许其他中断进入
//========================== n = CAM_HR_CHn ========================================
if((tmpISFR & (1<<CAM_HR_CHn))) //PB1 触发中断 行中断
{
tmpline++;
if(0 == (tmpline % 2))//对tmpline取余,当tmpline为偶数行时进入(进行数据传输)
{
if(DMA_CITER_ELINKNO(CAM_DMA_CH) != COLUMN)
{
//uartPrintf("DMA末传输结束 %d \n",DMA_CITER_ELINKNO(CCD_DMA_CH));
Error = 1;
error_row = tmprow ;
}
DMA_SETDAADDR(CAM_DMA_CH,&Pic_Buffer[tmprow][0]);//Pic_Buffer的大小为120(row)*160(column) 这里是指从第row行的第0列(个像素点)开始传输
DMA_EN(CAM_DMA_CH);//使能通道硬件DMA请求
tmprow++;
if(tmprow >= ROW)
{
photeCompleteFlag = 1;
}
}
}
//========================== n = CAM_VS_CHn ========================================
if((tmpISFR & (1<<CAM_VS_CHn))) //PTB2 触发中断 场中断;
{
tmpnum++;
picLineSum = tmpline;
tmpline = 0;//行号清零
tmprow = 0; //列号清零
DMA_IRQ_CLEAN(CAM_DMA_CH);//清除通道传输中断标志位
En_HREF; //打开行中断
}
if(!(tmpISFR & (1<<CAM_HR_CHn)) && !(tmpISFR & (1<<CAM_VS_CHn)))
{
uartPrintf("Unexpected Interrapt 0x%X",tmpISFR);
}
// EnableInterrupts; //注释掉,以允许其他中断进入
}