硬件准备
ADSP-EDU-BF533:BF533开发板
AD-HP530ICE:ADI DSP仿真器
软件准备
Visual DSP++软件
硬件链接
CVBS OUT 视频输出
硬件实现原理
CVBS_OUT 子卡板连接在 ADSP-EDU-BF53x 开发板的扩展端口 PORT3 和 PORT4 上,板卡插入时,应将扩展子卡板上标注的“圆圈”符号与板卡上的“圆圈”对准插入,避免子卡板反向接入板卡。正确插入子卡板后,CVBS
输出的接口是朝向板外。
CVBS_OUT BOARD 子卡板采用了功能强大的视频编码芯片 CH7024B,该芯片支持尺寸拉伸功能,可以将非D1 尺寸的图像数据拉伸到 D1 的尺寸(即 720576 或 720480),不需要再对非 D1 的数据格式作处理,并且支持
RGB,YUV 等多种数据格式输入,方便视频开发。
CVBS_OUT BOARD 子卡板接口说明:
下图为 CVBS_OUT BOARD 子卡板顶视示意图,板卡上有白、红、黄三个接口,分别代表的接口功能是C/CVBS、Y、CVBS。该接口支持 CVBS、S-Video、YPrPb 模式的视频输出。例子程序仅使用了 CVBS 视频输出的功能。
CH7024B 采用 IIC 总线配置初始化,其 IIC 地址为:
CH7024B IIC 器件地址: Slave address W 为 0xEC,Slave address R 为 0xED
CH7024B 和 LCD 公用一个 PPI 接口,其 PPI 时钟由 CPLD 提供,通过配置 CPLD 来切换 PPI 时钟。
DEVICE_OE 寄存器(读/写):
DEVICE_OE 寄存器地址:0x20320000
DEVICE_OE 寄存器设置硬件设备上一些控制管脚的电平状态。
DEVICE_OE 寄存器位功能:
PPI_SET1~0:PPI 选择位
00:选通 CMOS PPI 时钟,使能 CMOS
01:选通 TFT PPI 时钟
选通 板卡为扩展接口的 PPICLK 提供时钟
1x:选通 PPI 时钟由扩展接口输入
选通 CVBS OUT 子卡板 PPI 接口,需将 PPI_SET0 位设置为 1,PPI_SET1 位设置为 0。
硬件连接示意图
代码实现功能
代码实现了通过文件系统读取一张 320240 RGB888 格式的图片,将图像数据送给 CH7024B,CH7024B 将图片拉伸到 720576 尺寸,通过 CVBS 接口输出。通过莲花头视频线,将输出的信号连接电视机,可以在电视上看到
输出的图像。
测试步骤
1. 将仿真器(ICE)与 ADSP-EDU-BF53x 开发板和计算机连接好,将 CVBS_OUT 子卡板插入扩展板接口 PORT3和 PORT4,正确接入后,视频输出接口朝板外。
2. 将莲花头视频线接入 CVBS_OUT 子卡板黄色接口,另一端连接电视机 AV 输入的视频接口,将电视机调到AV 模式。
3. 先给 ADSP-EDU-BF53x 开发板上电,再为仿真器(ICE)上电。
4. 运行 VisualDSP++ 5.0 软件,选择合适的 BF53x 的 session 将仿真器与软件连接。
5. 加载 VisualDSP++ 5.0 工程文件 BF53x_CVBSOUT_320_240.dpj 文件,编译并全速运行。
测试结果
在电视机上可以看到测试图像输出。
程序源码
ch7024.c
#include <cdefBF533.h>
#include"i2c.h"
#define CH7024_ADDRESS 0xec
static i2c_device mcu_i2c;
void init_OV9653(void);
int ch7024_write(unsigned char addr, unsigned char dat);
int ch7024_read(unsigned char addr, unsigned char * buf);
/****************************************************************************
- 名称 :ch7024_write
- 功能 : 写ov9653寄存器函数
- 入口参数 :addr:寄存器偏移地址
dat:寄存器配置值 - 出口参数 :返回0
/
int ch7024_write(unsigned char addr, unsigned char dat)
{
int ret = -1;
i2c_start(&mcu_i2c);
//send slave address
if(i2c_write(&mcu_i2c, CH7024_ADDRESS, 1)){
i2c_stop(&mcu_i2c);
return ret;
}
//send sub-address to device
if(i2c_write(&mcu_i2c, addr, 1)){
i2c_stop(&mcu_i2c);
return ret;
}
//send data to device
i2c_write(&mcu_i2c, dat, 1);
i2c_stop(&mcu_i2c);
return 0;
}
/ - 名称 :ov9653_read
- 功能 : 读ov9653寄存器函数寄存器偏移地址
- 入口参数 :addr:
buf:寄存器读取数据缓存 - 出口参数 :返回0
****************************************************************************/
int ch7024_read(unsigned char addr, unsigned char * buf)
{
unsigned char *p = buf;
int ret = -1;
i2c_start(&mcu_i2c);
//send slave address
if(i2c_write(&mcu_i2c, CH7024_ADDRESS, 1)){
i2c_stop(&mcu_i2c);
return ret;
}
//send sub-address of slave
if(i2c_write(&mcu_i2c, addr, 1)){
i2c_stop(&mcu_i2c);
return ret;
}
i2c_stop(&mcu_i2c);
i2c_start(&mcu_i2c);
// send slave address (+1 read mode)
if(i2c_write(&mcu_i2c, CH7024_ADDRESS+1, 1)){
i2c_stop(&mcu_i2c);
return ret;
}
if(i2c_wait_slave(&mcu_i2c, 1000)){
i2c_stop(&mcu_i2c);
return ret;
}
i2c_read(&mcu_i2c, p++, 1); // send ack
i2c_stop(&mcu_i2c);
return 0;
}
/****************************************************************************
-
名称 :Init_OV9653
-
功能 : CMOS 130万 内部寄存器配置信息
-
入口参数 :无
-
出口参数 :无
****************************************************************************/
void init_ch7024(void)
{
mcu_i2c.sclk = PF0; //时钟PF脚
mcu_i2c.sdata = PF1; //数据PF脚
mcu_i2c.low_ns = 7000; //低电平延时 ns
mcu_i2c.high_ns = 6000; //高电平延时 ns
i2c_init(&mcu_i2c);ch7024_write(0x04,0x00);
ch7024_write(0x0A,0x13);
ch7024_write(0x0B,0x0c);
ch7024_write(0x0C,0x00);
ch7024_write(0x0D,0x28);
ch7024_write(0x0E,0x0c);
ch7024_write(0x0F,0x00);
ch7024_write(0x11,0x19);
ch7024_write(0x12,0x40);
ch7024_write(0x13,0xe8);
ch7024_write(0x17,0x00);
ch7024_write(0x18,0xf0);
ch7024_write(0x19,0xfa);
ch7024_write(0x1C,0x90);
ch7024_write(0x28,0x08);
ch7024_write(0x29,0x8b);
ch7024_write(0x2A,0x80);
ch7024_write(0x2B,0x20);
ch7024_write(0x2C,0xf5);
ch7024_write(0x2D,0x80);
ch7024_write(0x2E,0x3b);
ch7024_write(0x30,0x12);
ch7024_write(0x31,0x13);
ch7024_write(0x34,0x00);
ch7024_write(0x35,0xa8);
ch7024_write(0x36,0x87);
ch7024_write(0x37,0x42);
ch7024_write(0x63,0xc2);
/*
ch7024_write(0x02,0x01); //test
ch7024_write(0x04,0x64); //配置测试模式
ch7024_write(0x02,0x00);
*/
}
cpu.c
#include <cdefBF533.h>
void Set_PLL(int pmsel,int pssel)
{
int new_PLL_CTL;
*pPLL_DIV = pssel;
asm(“ssync;”);
new_PLL_CTL = (pmsel & 0x3f) << 9;
*pSIC_IWR |= 0xffffffff;
if (new_PLL_CTL != *pPLL_CTL)
{
*pPLL_CTL = new_PLL_CTL;
asm(“ssync;”);
asm(“idle;”);
}
}
void Init_SDRAM(void)
{
*pEBIU_SDRRC = 0x00000817;
*pEBIU_SDBCTL = 0x00000013;
*pEBIU_SDGCTL = 0x0091998d;
ssync();
}
void Init_EBIU(void)
{
*pEBIU_AMBCTL0 = 0x7bb07bb0;
*pEBIU_AMBCTL1 = 0x7bb07bb0;
*pEBIU_AMGCTL = 0x000f;
}
void Init_Timers0(int dat)
{
*pTIMER0_CONFIG = 0x0019;
*pTIMER0_WIDTH = dat;
*pTIMER0_PERIOD = 2000;
}
void Enable_Timers0(void)
{
*pTIMER_ENABLE|= 0x0001;
asm(“ssync;”);
}
void Stop_Timers0(void)
{
*pTIMER_ENABLE &= ~0x0001;
asm(“ssync;”);
}
i2c.c
#include <cdefBF533.h>
#include “i2c.h”
#define CORE_CLK_IN 25 * 1000 * 1000
#define SET_PF(pf)
do{
*pFIO_FLAG_S = (pf);
ssync();
}while(0)
#define CLR_PF(pf)
do{
*pFIO_FLAG_C = (pf);
ssync();
}while(0)
#define SET_PF_OUTPUT(pf)
do{
*pFIO_INEN &= ~(pf);
*pFIO_DIR |= (pf);
ssync();
}while(0)
#define SET_PF_INPUT(pf)
do{
*pFIO_DIR &= ~(pf);
*pFIO_INEN |= (pf);
ssync();
}while(0)
int get_core_clk(void)
{
int tempPLLCTL;
int _DF;
int VCO;
int MSEL1;
tempPLLCTL = *pPLL_CTL;
MSEL1 = ((tempPLLCTL & 0x7E00) >> 9);
_DF = tempPLLCTL & 0x0001;
VCO = MSEL1 * __CORE_CLK_IN__;
if(_DF == 1)
VCO /= 2;
return VCO;
}
void delay_ns(unsigned int core_clock, unsigned long long count)
{
count *= core_clock;
count /= 1000000000;
while(count–);
}
int _get_sdata(i2c_device * dev)
{
return ((*pFIO_FLAG_D & dev->sdata) ? 1 : 0);
}
void i2c_init(i2c_device * dev)
{
dev->core_clock = get_core_clk();
dev->delay_ns = delay_ns;
*pFIO_DIR |= dev->sclk | dev->sdata;
ssync();
}
void i2c_deinit(i2c_device * dev)
{
dev->sclk = 0;
dev->sdata = 0;
*pFIO_DIR &= ~(dev->sclk | dev->sdata);
ssync();
}
void i2c_start(i2c_device * dev)
{
SET_PF_OUTPUT(dev->sdata);
SET_PF_OUTPUT(dev->sclk);
SET_PF(dev->sdata);
SET_PF(dev->sclk);
delay_ns(dev->core_clock, dev->high_ns);
CLR_PF(dev->sdata);
delay_ns(dev->core_clock, dev->low_ns);
CLR_PF(dev->sclk);
delay_ns(dev->core_clock, dev->low_ns);
}
void i2c_stop(i2c_device * dev)
{
CLR_PF(dev->sclk);
delay_ns(dev->core_clock, dev->low_ns);
SET_PF_OUTPUT(dev->sdata);
CLR_PF(dev->sdata);
delay_ns(dev->core_clock, dev->low_ns);
SET_PF_INPUT(dev->sclk);
delay_ns(dev->core_clock, dev->high_ns);
SET_PF_INPUT(dev->sdata);
delay_ns(dev->core_clock, dev->high_ns);
}
int i2c_read_ack(i2c_device * dev)
{
int ret = 0;
SET_PF_INPUT(dev->sdata);
delay_ns(dev->core_clock, dev->high_ns/3);
SET_PF(dev->sclk);
delay_ns(dev->core_clock, dev->high_ns/3);
ret = _get_sdata(dev);
delay_ns(dev->core_clock, dev->high_ns/3);
CLR_PF(dev->sclk);
delay_ns(dev->core_clock, dev->low_ns);
SET_PF_OUTPUT(dev->sdata);
return ret;
}
int i2c_wait_slave(i2c_device * dev, unsigned int time_out)
{
int ret;
int count = time_out * 2 / dev->high_ns;
SET_PF_INPUT(dev->sclk);
delay_ns(dev->core_clock, dev->high_ns/2);
do{
ret = *pFIO_FLAG_D & dev->sclk;
if(ret)
break;
delay_ns(dev->core_clock, dev->high_ns/2);
}while(count--);
SET_PF_OUTPUT(dev->sclk);
return !ret;
}
void i2c_write_ack(i2c_device * dev)
{
SET_PF_OUTPUT(dev->sdata);
CLR_PF(dev->sdata);
delay_ns(dev->core_clock, dev->high_ns/2);
SET_PF(dev->sclk);
delay_ns(dev->core_clock, dev->high_ns);
CLR_PF(dev->sclk);
delay_ns(dev->core_clock, dev->low_ns);
}
int i2c_write(i2c_device * dev, unsigned char value, int need_ack)
{
int ret = -1;
unsigned char index;
SET_PF_OUTPUT(dev->sdata);
//send 8 bits to slave
for(index = 0; index < 8; index++){
//send one bit to the i2c bus
if((value<<index) & 0x80){
SET_PF(dev->sdata);
} else {
CLR_PF(dev->sdata);
}
delay_ns(dev->core_clock, dev->low_ns/2);
SET_PF(dev->sclk);
delay_ns(dev->core_clock, dev->high_ns);
CLR_PF(dev->sclk);
delay_ns(dev->core_clock, dev->low_ns/2);
}
if(need_ack){
ret = i2c_read_ack(dev);
}
return ret;
}
int i2c_read(i2c_device * dev, unsigned char * value, int send_ack)
{
unsigned char index;
*value = 0x00;
SET_PF_INPUT(dev->sdata);
delay_ns(dev->core_clock, dev->high_ns/2);
//get 8 bits from the device
for(index = 0; index < 8; index++){
SET_PF(dev->sclk);
delay_ns(dev->core_clock, dev->high_ns/2);
*value <<= 1;
*value |= _get_sdata(dev);
delay_ns(dev->core_clock, dev->high_ns/2);
CLR_PF(dev->sclk);
delay_ns(dev->core_clock, dev->low_ns);
}
// send ack to slave
if(send_ack){
i2c_write_ack(dev);
}
return *value;
}
main.c
#include <cdefBF533.h>
#include <stdio.h>
extern unsigned char DisplayBuffer[][];
extern unsigned char DisplayBuffer_565[][];
extern unsigned char Inputdata[];
void main(void)
{
FILE *fp;
int lenth;
Set_PLL(16,4);
Init_EBIU();
Init_SDRAM();
LCDBK_Disable();
fp = fopen("../RGB888_320_240.bmp", "rb");
lenth = fread(Inputdata, 1, 230454, fp);
fclose(fp);
IIC_Enable();
init_ch7024();
bgrtorgb24();
RGB888_RGB565(&DisplayBuffer,230400,&DisplayBuffer_565);
PCLK_OUT_Enable();
InitDMA();
InitPPI();
InitTimer();
PPI_TMR_DMA_Enable();
while(1);
}
#include <cdefBF533.h>
section(“sdram0_bank1”) unsigned char DisplayBuffer[240][960] ;
section(“sdram0_bank1”) unsigned char DisplayBuffer_565[240][640] ;
section(“sdram0_bank1”) unsigned char TempBuffer_img[240][960] ;
section(“sdram0_bank1”) unsigned char Inputdata[230454];
void InitDMA(void)
{
int addr;
addr = &DisplayBuffer_565;
addr -= 640*10;
*pDMA0_START_ADDR = addr;
*pDMA0_X_COUNT = 640/2;
*pDMA0_X_MODIFY = 2;
*pDMA0_Y_COUNT = 250;
*pDMA0_Y_MODIFY = 2;
*pDMA0_CONFIG = 0x1034;
}
void InitPPI(void)
{
*pPPI_CONTROL = 0xb81e;
*pPPI_DELAY = 0;
*pPPI_COUNT = 319;
*pPPI_FRAME = 250;
}
void InitTimer(void)
{
*pTIMER1_PERIOD = 1000;
*pTIMER1_WIDTH = 336;
*pTIMER1_CONFIG = 0x00a9;
*pTIMER2_PERIOD = 250000;
*pTIMER2_WIDTH = 5760;
*pTIMER2_CONFIG = 0x00a9;
}
void PPI_TMR_DMA_Enable(void)
{
*pDMA0_CONFIG |= 0x1;
asm(“ssync;”);
InitTimer();
*pPPI_CONTROL |= 0x1;
asm(“ssync;”);
*pTIMER_ENABLE|= 0x0006;
asm(“ssync;”);
}
void PPI_TMR_DMAR_Disable(void)
{
*pDMA0_CONFIG &= (~0x1);
*pPPI_CONTROL &= (~0x1);
}
void bgrtorgb24(void)
{
int i,j;
int a,b;
for(i=0;i<240;i++)
{
for(j=0;j<960;j++)
{
TempBuffer_img[i][j] = Inputdata[i*960+j+54];
}
}
for(i=0;i<240;i++)
{
for(j=0;j<320;j++)
{
a = TempBuffer_img[i][j*3];
b = TempBuffer_img[i][j*3+2];
TempBuffer_img[i][j*3] = b;
TempBuffer_img[i][j*3+2] = a;
}
}
for(i=0;i<240;i++)
{
for(j=0;j<960;j++)
{
DisplayBuffer[i][j] = (TempBuffer_img[239-i][j]);
}
}
}
void RGB888_RGB565(unsigned char *src, int src_len, unsigned char *dst)
{
int i = 0;
int j = 0;
if (src_len % 3 != 0)
{
return;
}
for (i = 0; i < src_len; i += 3)
{
dst[j+1] = src[i+2] &0xf8; //B
dst[j+1] |= ((src[i+1]>>5) & 0x07); //GH
dst[j] = ((src[i+1]<<3) & 0xe0); //GL
dst[j] |= ((src[i]>>3) &0x1f); //R
j += 2;
}
}