ADSP5.0中 video input(c) 例程拍摄得出的图片是两层的图片,效果如下图
上面的图片只是一部分,原图还要更高一点,但是我现在只能找到这张了。有时候上下两部分中间还有20~30像素高的黑条。
出现这个情况的原因,是该例程视频输入采用ITU-656模式,在这种模式下视频输入数据分为filed1和filed2两个场,filed1中放的是奇数行的数据,filed2中放的是偶数行的数据。比较简单的办法是另外申请一块内存,将奇数行数据和偶数行数据交叉放置就可以了。但是一方面这样花费了额外的处理时间,另一方面当出现上面说的黑条时,这样处理后的图片也会出现黑条,这个我也不清楚为什么会出现。
ITU-656 输入模式
在该例程中,使用的是active video only sent模式,即输入数据完全是图像数据,没有任何描述信息和冗余信息。如果将数据一次读进来,结果就是上面的样子,我希望可以将图像用两次读进来,第一次读field1,第二次读field2,并且在读入数据时就将它们存入正确的位置。解决方案是采用交叉传送(好像是叫这个名字)。
在例程里面拍照是通过调用Init_DMA();和Init_PPI();两个函数实现的,前者是配置DMA,主要是数据宽度、偏移量、数据量等信息,后者配置数据的行数并且启动传输。实现交叉传送的关键就在于配置DMA的偏移量,具体来说是设置行偏移寄存器DMA0_Y_MODIFY。它的功能是设置当传输完一行数据一行,数据目的指针增加的字节数,在例程里面是0x2,因为图像数据是16位的,占两个字节。比如用下面的数组存储图像
Short datas[100][300];
那么图像的宽度是300,高度是100,datas[0][299]是第一行的最后一个像素,datas[1][0]是第二行的第一个像素,这两个元素的地址相差一个short的大小,即0x2 。
现在我要达到的效果是,第一行数据传输完以后,下一行数据从datas[2][0]开始存储,跳过datas[1],那么只需要将DMA0_Y_MODIFY加上一行数据的字节数,即300*2,则DMA0_Y_MODIFY的值为2+300*2=602 。
同时由于一张图片传送两次,那么每次的数据量减半,DMA0_Y_COUNT的值变为原来的一半。两次传送的起始地址是不一样的,为了不改变接口,添加了一个全局变量来标识。
char frame_1=1;
在Init_DMA()函数中判断frame_1的值来决定是否偏移数据首地址。
修改后的代码如下
#define Line_Length 720
#define Frame_Length 576
char frame_1=1;
void Init_DMA(unsigned char *pAdd)
{
//Target address of the DMA
if(frame_1)
*pDMA0_START_ADDR = pAdd;
else
*pDMA0_START_ADDR = pAdd+ Line_Length*2;
//Line_Length 16bit transfers will be executed
*pDMA0_X_COUNT = Line_Length;
//The modifier is set to 2 because of the 16bit transfers
*pDMA0_X_MODIFY = 0x2;
//Frame_Length 16bit transfers will be executed
//*pDMA0_Y_COUNT = Frame_Length;
*pDMA0_Y_COUNT = Frame_Length/2;
//The modifier is set to 2 because of the 16bit transfers
//*pDMA0_Y_MODIFY = 0x2;
*pDMA0_Y_MODIFY = Line_Length+2;
//PPI Peripheral is used
*pDMA0_PERIPHERAL_MAP = 0x0;
//DMA Config: Enable DMA | Memory write DMA | 2-D DMA | Discard DMA FIFO before start | enable assertation of interrupt | NDSIZE for stop mode | Enable STOP DMA
*pDMA0_CONFIG = DMAEN | DI_EN | WNR | WDSIZE_16| DMA2D | RESTART | DI_EN;
}//end Init_DMA
void Init_PPI(void)
{
//The PPI is set to receive 525 lines for each frame
//*pPPI_FRAME = 576;
*pPPI_FRAME = 288;
//PPI enabled, input mode, active video only, receive field 1&2,
//packing enabled, skipping disabled, 8bit data bus, nothing inverted
*pPPI_CONTROL = PORT_EN | FLD_SEL | PACK_EN | DLEN_8 ;
}//end Init_PPI
注释掉的代码是例程中原来的代码。
在主函数中连续采集图像,即相当于拍摄视频的代码如下
frame_1=1;
n=-1;
while(n==-1)
{
camera=1;
Init_DMA((void *) VideoFrame);
Init_PPI();
while(camera);
frame_1=!frame_1;
if(frame_1)
send_packet((char*)VideoFrame+80,614400,1,1440); //这个+80是什么我不记得了
}
其中camera变量在DMA0_PPI_ISR中断中被复位,表明DMA传送完成。