显卡的最新进展

2009年09月04日 18:39    发布者:wangkj
一会上贴图,下午搞好了,基本能出效果了,没带手机数据线,无法上传。
弄个qq邮箱,stmp又出问题了。
该文章有附件资料,如需下载请访问 电脑版

网友评论

f.luo 2009年09月04日
恭喜会计,又有了新的进展!!!
原野之狼 2009年09月04日
恭喜恭喜呀,赶紧传来看看。。。
wangkj 2009年09月04日
缺点是逻辑单元占用较多,1024*768本来点频是65M,需要两倍的频率,
如果是1280*1024需要160M,1920*1200需要400M,器件跑不动。
这是epm570做通了,测试用的。

这个是7.16完成的,没有贴出来,测试硬件功能和actel cpld(fpga)方案可行性的。
wangkj 2009年09月04日
本帖最后由 wangkj 于 2009-9-4 19:25 编辑

验证了一个问题:刷屏没错,错在数据写入。多亏了以前的那个测试程序。
这个是2009,9,04上午的测试图。(就是今天!!!)
只有1/4的出现花屏,其他3/4数据不动!没有写入。
wangkj 2009年09月04日
正式下午修正之后的图片,为了找这个错误的字母,折腾了我3周。
最下面的几行是:数据输入、数据输出,刷屏指针,3原色测试。这些是cpld逻辑做出来的,上面的才是mcu输入的数据。
wangkj 2009年09月04日
本帖最后由 wangkj 于 2009-9-4 19:21 编辑

pdf 格式
wangkj 2009年09月04日
/*******************************************
单片机显卡测试程序
硬件规格:
stc51单片机主控,cpld+sdram实现显卡硬件,
这是stc51的主控程序。

by
wangkj@yahoo.com
qq:1248780
群:630571
create 2009-07-10
version 0.1
STC5205AD
*******************************************/


//#include "REG51F.H"
//#include
#include
#include
#include

sbit MCU_IR_PWM    = P3^7;
sbit _CS = P1^4;            // SPI总线的片选信号线
sbit SPCK= P1^7;            // SPI总线的钟信号线
sbit MOSI= P1^5;            // SPI总线的串行数据输出线
sbit EA0 = P1^6;            // 地址/数据选择

#define        TRUE        1
#define        FALSE        0
#define     WIDTH       1024
#define     HIGH        768
//#define     nop()  _nop_

volatile unsigned  int data TimerCounter=0;

/********************************************/
/*          定时器 0 中断服务               */
/* 说明:  100us 中断一次, 优先级最高        */
/********************************************/

void  Timer0_Int(void) interrupt 1 using 1 //自动reload方式,10us
{
   
    TimerCounter++;
}

//延时1ms

void nop()
{
   unsigned char data i;
   for (i=0;i<1;i++)
   {
   }
//   _nop_ ;
}

void udelay(void)
{
   unsigned char data i;
   for (i=0;i<10;i++);
}

void delay1ms(void)
{
   unsigned  int data OldTimerCounter;
   OldTimerCounter = TimerCounter;
   while((TimerCounter-OldTimerCounter)<100)//
   { //如果调试,请把1换成不同到值,1是延时1ms,误差很小
    MCU_IR_PWM=~MCU_IR_PWM;
   }
   
}
/*从SPI总线上读入一个字节
unsigned int spi_read16(void)
{
    unsigned int data inData;
    unsigned char data i;
    for(i=0; i<8; i++)    // 移8次
    {   
        SCK = 0;        // 拉低时钟线
        inData <<= 1;   
        inData |= MO;    // 从SPI总线的数据输出线SO上读入一位
        SCK = 1;        // 拉高时钟线
    }
    return(inData);
} */    // python:  for i in range(1,15): hex(i*1024+i)
/*输出一个字节到SPI总线上*/
void spi_write8(unsigned char data outData)
{
   char i,j;
   for(i=0; i<8; i++)
   {
        
        SPCK = 0;        
        if ((outData & 0x80)==0)
          MOSI=0;
        else
          MOSI=1;
        //delay1ms();  
        for(j=0;j<3;j++);   
        SPCK = 1;
        for(j=0;j<3;j++);
        //delay1ms();
           outData <<= 1;
        
/*        outData <<= 1;        
        SPCK = 1;  
        MOSI = CY;
        SPCK = 0;     */  
   }
   SPCK = 0;
/*  for(i=0; i<8; i++)        // 移8次
    {
//        outData <<= 1;
//        MOSI = CY;        
        SPCK = 1;        
        if ((outData & (0x80>>i))==0)
          MOSI=0;
        else
          MOSI=1;         
   
            // 移出一位,送出至SPI总线的数据输出MOSI上
        SPCK = 0;   
    } */
}/*读SPI器件的状态*/
void spi_write16(unsigned int  outData)
{
   union
   {
      unsigned int  Data16;
      unsigned char Data8;
   } spi8;
   spi8.Data16=outData;
   spi_write8(spi8.Data8);     //high
   spi_write8(spi8.Data8);   //low
}
void cursor(unsigned int x,y)  //设置显存地址 8M 寻址空间。
{
   //int i;
   union
   {
      unsigned long int addr;
      unsigned int addr_HL;
   } addr_union;
   addr_union.addr=1L*(long)y*WIDTH+(long)x;
   EA0=1;//set cmd status
   //addr=272*y+x;
   spi_write16(addr_union.addr_HL);    //high
   spi_write16(addr_union.addr_HL);    //low

   EA0=0;//set data status        PutCmd(0);//reset display ram pointer to 0
}
void clr_scr(void)
{
   unsigned char i,j,k;  

   cursor(0,0);   
   //addr= 1L*WIDTH*HIGH*8*2;  
   MOSI=0;
   for(i=0;i<97*2;i++)
     for(j=0;j<255;j++)
       for(k=0;k<255;k++)   
         {SPCK=1;SPCK=0;}
}
//主程序
void main(void)
{
                  
unsigned  int  i,j,k;//OldTimerCounter;
unsigned long int x,y;
// unsigned char ch;//    cmd,
// unsigned int j;

P1M0=0x00;       //准双向口
P1M1=0x00;      
// AUXR = 0x40;  //可能不能位寻址以及OR,AND 操作,待验证
//AUXR=0x20;//6x UART  速度
AUXR=0x40|0x80; //T0,T1 12X
// AUXR=0x40;
//T0 正常 T1/1 12倍速, UART正常 ,禁用ADC,SPI,低压中断。
/***********************************************
AUXR 地址8EH 复位值=xxxx xx00B

7     6     5         4     3    2     1      0
T0x12 T1x12 UART_M0x6 EADCI ESPI ELVDI            - - 0000,00xx
定时器0 和定时器1:
STC12C5410AD 和STC12C2052AD 系列是 1T 的8051 单片机,为了兼容传统8051,定时器0 和定时器1 复
位后是传统8051 的速度,即12 分频,这是为了兼容传统8051。但也可不进行12 分频,实现真正的1T。
T0x12: 0, 定时器0 是传统8051 速度,12 分频;1, 定时器0 的速度是传统8051 的12 倍,不分频
T1x12: 0, 定时器1 是传统8051 速度,12 分频;1, 定时器1 的速度是传统8051 的12 倍,不分频
如果UART 串口用定时器1 做波特率发生器,T1x12 位就可以控制UART 串口是12T 还是1T 了。
UART 串口的模式0:
STC12C5410AD 和STC12C2052AD 系列是 1T 的8051 单片机,为了兼容传统8051,UART 串口复位后是兼容
传统8051 的。
UART_M0x6: 0, UART 串口的模式0 是传统12T 的8051 速度,12 分频;
1, UART 串口的模式0 的速度是传统12T 的8051 的6 倍,2 分频
如果用定时器T1做波特率发生器时,UART串口的速度由T1的溢出率决定
EADCI: 0, 禁止A/D 中断; 1,允许A/D 中断
ESPI: 0, 禁止SPI 中断; 1,允许SPI 中断
ELVDI: 0, 禁止低压中断; 1,允许低压中断
5V 单片机,3.7V 以下为低压,3V 单片机,2.4V 以下为低压,
如ELVDI=1(允许低压中断),则会产生低压中断,现版本无低压检测中断,是低压复位。
STC12C5410AD 系列无低压检测中断,只有STC12C2052AD 系列单片机才有低压检测中断。
*************************************************/
// 28.636晶振,bps 2400 误差 0.21% STC5410可以12倍速T1,
// T0 标准51方式,做 1ms 基准时间用

  PCON=0x80;  //12倍T1 *  2 倍 bps 2400*12*2=57600
//  PCON=0x00; //正常操作,没有倍速
/***********************************************
7    6     5    4   3   2   1  0
SMOD SMOD0 LVDF POF GF1 GF0 PD IDL
POF:上电复位标志位,单片机停电后,上电复位标志位为1 ,可由软件清0 。
    实际应用:要判断是上电复位(冷启动),还是外部复位脚输入复位信号产生的复位,还是内部看门狗复位
P D: 将其置1 时,进入Power Down 模式,可由外部中断低电平触发或下降沿触发中断模式唤醒。
    进入掉电模式时,外部时钟停振,CPU、定时器、串行口全部停止工作,只有外部中断继续工作。
IDL:将其置1,进入IDLE 模式(空闲),除CPU 不工作外,其余仍继续工作,可由任何一个中断唤醒。
    现C 版本开始大量供货,C 版本IDLE 模式可正常使用(原A 版本和B 版本建议不要用IDLE 模式)。
GF1,GF0: 两个通用工作标志位,用户可以任意使用。
SMOD: 波特率倍速位,置1,串口通讯波特率快一倍
***********************************************/
// SMOD=1;
  IE=0x00;  //disable all interrupt   
/************************************************
IE(0A8H)
7  6   5  4  3   2   1   0
EA EC ET2 ES ET1 EX1 ET0 EX0
使能位=1 使能中断
使能位=0 禁止中断
位标号功能
IE.7 EA 全局禁止位如果EA=0 禁止所有中断如果EA=1 通过置
位或清除使能位对应的每个中断被使能或禁止
IE.6 EC PCA中断使能位
IE.5 ET2 定时器2 中断使能位
IE.4 ES 串行口中断使能位
IE.3 ET1 定时器1 中断使能位
IE.2 EX1 外部中断1 使能位
IE.1 ET0 定时器0 中断使能位
IE.0 EX0 外部中断0 使能位
*************************************************/
  IP=0x02;  //Timer0 is first level of interrupt
/**********************************************  
IP(0B8H) 7 6 5 4 3 2 1 0
PT2 PS PT1 PX1 PT0 PX0
中断优先级控制位=1 定义为高优先级中断
中断优先级控制位=0 定义为低优先级中断
IP.6 PPC PCA中断优先级控制位
IP.5 PT2 定时器2 中断优先级控制位
IP.4 PS 串行口中断优先级控制位
IP.3 PT1 定时器1 中断优先级控制位
IP.2 PX1 外部中断1 中断优先级控制位
IP.1 PT0 定时器0 中断优先级控制位
IP.0 PX0 外部中断0 中断优先级控制位
************************************************/
  TMOD=0x22; //T0,T1 8 bit Reload
            
/***********************************************
TMOD 地址:89H 不可位寻址 复位值:00H
7    6   5  4  3    2   1  0
GATE C/T M1 M0 GATE C/T M1 M0
定时器1 定时器0
位符号 功能
TMOD.7/ GATE TMOD.7 控制定时器1,置1 时只有在INT1 脚为高及TR1 控制位置1 时才可打开定时器/ 计数器1。
TMOD.3/ GATE TMOD.3 控制定时器0,置1 时只有在INT0 脚为高及TR0 控制位置1 时才可打开定时器/ 计数器0。
TMOD.6/ C/T TMOD.6  控制定时器1 用作定时器或计数器,清零则用作定时器(从内部系统时钟输入),
                    置1 用作计数器(从T1/P3.5 脚输入)
TMOD.2/ C/T TMOD.2  控制定时器0 用作定时器或计数器,清零则用作定时器(从内部系统时钟输入),置1
                    用作计数器(从T0/P3.4 脚输入)
                    
TMOD.5/TMOD.4 M1、M0 定时器定时器/计数器1模式选择
0 0   13位定时器/ 计数器,兼容8048 定时器模式,TL1 只用低5 位参与分频,TH1 整个8 位全用。
0 1   16位定时器/ 计数器,TL1、TH1 全用
1 0   8 位自动重装载定时器,当溢出时将TH1 存放的值自动重装入TL1。
1 1   定时器/ 计数器1 此时无效(停止计数)。
TMOD.1/TMOD.0 M1、M0 定时器/ 计数器0 模式选择
0 0   13位定时器/ 计数器,兼容8048 定时器模式,TL0 只用低5 位参与分频,TH0 整个8 位全用。
0 1   16位定时器/ 计数器,TL0、TH0 全用
1 0   8位自动重装载定时器,当溢出时将TH0 存放的值自动重装入TL0。
1 1   定时器0 此时作为双8 位定时器/ 计数器。TL0 作为一个8 位定时器/ 计数器,通过标准定时器0
      的控制位控制。TH0 仅作为一个8 位定时器,由定时器1 的控制位控制。


***********************************************/
  TH1=BAUD_2400;                 //设置串口的波特率为2400 for OSC 28.636Mhz//19200 for 29.08M
  TL1=BAUD_2400;                 //It Will be 2400*12*2 = 57600              //19200*6-115200 6x UART模式
/**********************************************
  串行口在方式1和方式3的波特率可变,与定时器T1或T2的溢出速率有关。51子系列
’常用定时器T1作为波待率发生器,这时方式1和方式3的波特率由定时器Tl的溢出率
确定
***********************************************/

  SCON=0x42;  //8bit variable,无多机通讯,REN=0,disable receive and set TI to generate serial send interupt
              //else the serial interupt will not work.
/**********************************************
  sc0N是一个可位寻址的专用寄存器,用来设定串行口的工作方式、控制串行口的接收
’发送以及状态标志。SCON的字节地址为98H,位地址为98H一9FH。其格式如下:
    D7  D6  D5  D4  D3  D2  Dl  D9
    SM0 SM1 SM2 REN TB8 RB8 TI  RI
各位的定义说明如下
SMO SCON.7  Serial Port mode specifier.(NOTE 1).
SM1 SCON.6  Serial Port mode specifier.(NOTE 1).
SMO SM1 Mode Description baud Rate
0   0   0    SHIFT REGISTER FOSC/12
0   1   1    8-BitUART      Variable
1   0   2    9-BitUART      Fosc/64 or Fosc/32
1   1   3    9-BitUART      Variable
SM2 SCON.5  
  在工作方式2和方式3中允许多机通信控制位。若SM 2置1,则允许多机通
信。当串行口以方式2或方式3接收时,若SM2=1,且接收到的第9位数据(RB8)为l,则
接收到的前8位数据送入SBUF,并置位RI产生中断请求;否则,RI=o,接收到的前8位数
据丢失。而当sM2=o时,则不管RB8是o还是1,都将前8位数据装入SBUF中,并产生中
断请求。
  在方式1中,若SM2=1,则只有接收到有效的停止位时,RI才置1,否则RI 0
在方式o中,SM2必须为o。
REN SCON.4  允许串行接收位。该位由软件置位或清除。REN=1时,允许接收;REN=o时,禁止接收
TB8 SCON.3  
在工作方式2或方式3时,该位为发送的第9位数据,可按需要由软件置位或
清零。在许多通信协议中,该位常作为奇偶校验位。在Mc5—5l多机通信中,TB8的状态用
来表示发送的是地址帧还是数据帧,TB8=o时,为地址帧,TB8=1时,为数据帧。
RB8 SCON.2
在工作方式2或方式3时,存放接收到的第9位数据,代表着接收效据的某种
特征。例如,可能是奇偶位,或为多机通信中的地址/数据标识位。在方式o中,RB8未用;在
方式1中,若SM2=o,RB8是已接收到的停止位。
TI SCON.1     
发送中断标志。方式0中,串行发送完第8位数据后,由硬件置位;在其它方
式中,在发送停止位开始时,由硬件置位。TI=1时,表示帧发送结束,其状态既可供软件查
询使用,也可申请中断。在任何方式中,TI都必须由软件清0。
RI SCON.O
接收中断标志。在方式o中,接收完第8位数据后,由硬件置位;在其它方式中,
在接收到停止位的中间时由硬件置位。RI=1时,表示帧接收结束,其状态既可供软件查询
使用,也可申请中断。RI也必须靠软件清o。
when reset ,SCON=0;
***********************************************/
  REN=1;      //enable serial receive

  TH0=256-111; //1000000/(11.0592*1000*1000/111)=10.04 us
  TL0=256-111;                 
  TR0=1;
  TR1=1; //TCON=0x50;//0B01010000;  //Timer1 enable    Timer0 enable,No external INT
  ET0=1; //enable Timer0 interupt
//  ET1=1; //enable Timer1 interupt
  ES=1;  //enable serial interupt
  EA=1;  //enable  interupt
/*************************************************
    TCON作为定时器/汁数器的技制寄存器,其功能是控制定时器T0或T1的运行或停
止,标志定时器的溢出和中断情况。
TCON: TIMER/COUNTER CONTROL REGISTER. BIT ADDRESSABLE.
        TFl TR1  TFO  TRO  IE1  IT1  IEO  ITO
位地址  8FH  8xH  8DH  8CH  8BH  8AH  89H  88H
    (1)TF1(TCON.7):定时器T1溢出标志。TI溢出时,由硬件自动使置1,并向
CPU申请中断。当进入个断服务程序时,硬件自动将TFl清0。TFl也可以用软件清0。
    (2)TR1(TCON.6);定时器T1运行控制1位。由软件来置1或清0。 1启动工作,0停止。
    (3)TF0(TCON.5):定时器T0溢出标志。
    (4)TR0(TCON.4):定时器T0控制位
    (5)IE1(TCON.3):外部中断1(INT1)请求标志。
    (6)IT1(TCON.2):外部中断1触发方式选择位。
    (7)1E0(TCON .l):外部中断0(INT0)请求标志。
    (8)IT0(TCON.0):外部中断0触发方式选择位。当ITo=o时,为电平触发方式当ITo=1时,为边沿触发方式
       检测到由高到低的负跳变,,则置IEo标志为1,表示外部中断o正在向CPU申请中断必须保证外部中断源输人的高电平
       和低电平的持续时间在12个时钟周期以上
    TCON中的低四位(1E1、ITl、IE0,IT0)与中断有关
TCON.7 Timer 1 overflow flag. Set by hardware when the Timer/Counter 1 overlows.Cleared by hardware
processer vectors to the interrupt service routine.
TCON.6 Timer 1 run control bit. Set/cleared by software to turn Timer/Counter 1 ON/OFF.
TCON.5 Timer O overflow flag. Set by hardware when the Timer/CounterO overflows.Cleared by hsrdware
proceaser vectors to the service routine.
TCON.4 Timer O run control bit. Set/cleared by software to turn Timer/Counter O ON/OFF.
TCON.3 External Interrupt 1 edge flag. Set by hardware when External Interrupt edge is detected.
Cleared by hardware when interrupt is processed.
TCON.2 Interrupt 1 type control bit. Set/cleared by sotlwsre to specify falling edge flow level triggered
External Interrupt.
TCON. 1 External Interrupt O edge flag.Setby hardware when External Interrupt edge deteeted.Cleared
by hardware when interrupt is proeeased.
TCGN.O Interrupt O type control bit. Set/cleared by sotlwsre to specify fsfling edge/low level triggered
External Interrupt.
**************************************************/
  char_init();
/*  i=0;
    for(i=0;i<100;i++)//延时1s,等待所有的机器都启动
{       send_char(i);
       Delay1ms();
}
*/

  SPCK=0;
  while(1)
  {
//   if ((char_can_read()>=1))
   if ((1))
         {
//      cmd=get_char();
//        if (cmd==0x0a) //pc发送不同的命令字,可以执行不同的操作
//        if (cmd=='a') //pc发送不同的命令字,可以执行不同的操作
        //for(j=0;j<10000;j++)  delay1ms();
        //EA0=0;
        //delay1ms();
        //EA0=1;   
        //spi_write16(0);
        for(j=0;j<1000;j++)   //delay
           delay1ms();         
        EA0=1;
        spi_write16(0);
        spi_write16(0xffff);spi_write16(0xffff);spi_write16(0xffff);spi_write16(0xffff);//reset command
        spi_write16(0);
        EA0=0;        
        delay1ms();
        //去掉这行,verilog 接收会出错,开始部分正常(<3000)
/*        for(j=0;j<15000;j++)   //delay
           delay1ms();

        clr_scr();
        for (x=0;x<1024L*1024L;x++)
        {
          //EA0=1; //
          //EA0=!EA0;
          if ((x %5 )==0)
            spi_write16(0x07e0);//green//spi_write16(j);   
          else if  ((x % 5)==1)
            spi_write16(0xf800);//blue//spi_write16(j);   
          else if  ((x % 5)==2)
            spi_write16(0x001f);//red//spi_write16(j);   
          else if  ((x % 5)==3)
            spi_write16(0x0000);//black//spi_write16(j);   
          else if  ((x % 5)==4)
            spi_write16(0xffff);//white//spi_write16(j);  
          if (x<160*1024L)
            spi_write16(0x07e0);//green
          else
          if (x<2*160*1024L)
            spi_write16(0xf800); //blue/
          else
          if (x<3*160*1024L)
            spi_write16(0);
          else
          if (x<4*160*1024L)
            spi_write16(0xffff);
          else
            spi_write16(0x001f); //red/        
          //spi_write16(x>>16);
          for(y=0;y<1;y++)
          {
  
             // delay1ms();     
          }   
          //send_char('.');//    send_char(0xd);send_char(0xa);
          //clr_scr();
        }
        spi_write16(0xffff);
           for(j=0;j<20000;j++)  
          delay1ms();
        //////////////////////////////////   
        //for(i=0;i<1024;i++)
        while (1)
        {
         for(i=0;i<768;i++)
          {
            cursor(i,i);
            delay1ms();
            spi_write16(0xffff);         
          }
          cursor(0,750);
          for (j=0;j<5000;j++) {delay1ms();    spi_write16(0xff);}
          cursor(0,0);
          for(i=0;i<768;i++)
             for (j=0;j<1024;j++)
                if (i==j)
                  spi_write16(0);   //for(n=0;n<1;n++);清屏 延时用2足够了,如果硬件规格高,可以省略。
                else
                  spi_write16(0xffff);  //delay1ms();
          cursor(0,760);
          for (j=0;j<5000;j++) {delay1ms();    spi_write16(0xff00);}
        }
        for(i=0;i<768;i++)
          {
            cursor(i,0);
            spi_write16(0xffff);
          }
        for(i=0;i<768;i++)
          {
            cursor(i,767);
            spi_write16(0xffff);
          }
        for(i=0;i<768;i++)
          {
            cursor(0,i);
            spi_write16(0xffff);
          }
        for(i=0;i<768;i++)
          {
            cursor(767,i);   
            spi_write16(0xffff);
          }     
        for(i=0;i<768;i++)
          {
            cursor(797,i);
            spi_write16(0xffff);
          }         */
        clr_scr();
        for(k=5;k<20;k++)
        {
          cursor(0,0);//clear screen
          for(i=0;i<768;i++)
             for (j=0;j<1024;j++)
                if ((i==j)||(i==j+k*5)||(i%k==0)||(j%k==0)||(i==0)||(j==0)||(j==1023)||(i==767))
                  spi_write16(0xffff);   //for(n=0;n<1;n++);清屏 延时用2足够了,如果硬件规格高,可以省略。
                else
                  //spi_write16(0x0);  //delay1ms();
                {
                  if (i<150)
                    spi_write16(0x07e0);//green
                  else
                  if (i<2*150)
                    spi_write16(0xf800); //blue/
                  else
                  if (i<3*150)
                    spi_write16(0);
                  else
                  if (i<4*150)
                    spi_write16(0xf800|0x07e0);
                  else
                    spi_write16(0x001f); //red/        

                }
          send_char('*');send_char(0xd);send_char(0xa);
        }  

      }
  }
//  for(i=0;i<1000;i++)//延时1s,等待所有的机器都启动
//    Delay1ms();
//   OldTimerCounter = TimerCounter;
//   while((TimerCounter-OldTimerCounter)<=20000)//无符号数减法
//   {
//   }
  
}
wangkj 2009年09月04日
那个压缩文件是工程文件,可以直接烧程序。
f.luo 2009年09月04日
这个是不是该加个精啊?
@︻$▅▆▇◤ 2009年09月05日
果然是大师级人物。我顶!
wangkj 2009年09月09日
for(i=0;i<768;i++)
                  {
                    cursor(i,i);
                        //for(j=0;j<5000;j++)
                         //  delay1ms();
                        spi_write16(0xffff);                
                        //for(j=0;j<5000;j++)
                        //   delay1ms();
                  }

        for(j=600;j<768;j++)
                 for(i=0;i<1024;i++)
                  {
                    cursor(i,j);
                        //for(j=0;j<5000;j++)
                         //  delay1ms();
                        spi_write16(0);                
                        //for(j=0;j<5000;j++)
                        //   delay1ms();
                  }
wangkj 2009年09月09日
wangkj 2009年09月09日
本帖最后由 wangkj 于 2009-9-10 16:47 编辑

本来想显示白线,成彩色的了。写成数据0,也是彩线。但是,如果连续写0,能完成清屏。
可能fifo的数据输入控制还是有点问题呀。
wangkj 2009年09月09日
拍照效果在室内不好,来一张室外的对比一下。
同样的手机拍的。转换到640*480,原图太大,
上不来。
wangkj 2009年09月09日
颜色也全花了,本来是各种颜色的,结果,全白了。(底部的指示行)
wangkj 2009年09月10日
这个效果较好,拍不同位置,有不同的曝光量。向下一点,不是外界光线影响就成。
@︻$▅▆▇◤ 2009年09月10日
什么时候开卖?价格是多少?
wangkj 2009年09月10日
还没计划,不过,我肯定是必须完成的。这版本,有两个布线设计错误,得改版。
原计划,本来包括一个actel的烧写器,但不好用,只好去掉了。原来可以半成品就可以出,
到时候,自己升级就行。现在看来,只能我自己烧程序了。我是买的现成的烧写器,500多,
每个人买一个不现实。所以,只能调试的没有bug了,就可以出了。

另外,如果那位兄弟着急,想玩硬件,可以帮我用protel重新设计一下硬件,
就是一个单片机+a3p060,我原来用allegro做的。设计基本照抄这个原理图就行。

原理图和单片机的程序是完全开放的,也希望大家当单片机学习。
我正在考虑是不是开放一部分verilog代码,不包括sdram控制,而是用内置的
wangkj 2009年09月10日
4K ram实现 160×120的显示器显示方案,这样,玩俄罗斯方块之类的游戏是完全没问题的。
这样,这就是一个 单片机和 cpld/fpga的学习板子,如果可能内置basic(arm版本),就是早期的8086 pc机了。

想想,不知道该不该。早期的pc也就是64K内存,640K软驱而已。
@︻$▅▆▇◤ 2009年09月10日
顶一个。
wangkj 2009年09月10日
sdram clk 上升沿之前,数据必须准备好,
而不是上升沿时,同时准备数据。
这个是测试代码,所以,只有1/4的数据是正确的。
        for(j=0;j<768;j++)
         for(i=0;i<1024;i++)
          {
            cursor(i,j);
            delay1ms();
            spi_write16(0);
          }

本来是全黑数据,结果,只有1/4的是全黑的。也就是1/4是正确的。
明天得改变整个程序的结构。
用fifo就是繁琐,为了性能,俺忍了。继续努力。
wangkj 2009年09月10日
for(j=0;j<768;j++)
                  {
                    cursor(j+20,j);
                        delay1ms();
                    spi_write16(0x3f<<5);
                  }
        for(j=0;j<768;j++)
                  {
                    cursor(j+30,j);
                        delay1ms();
                    spi_write16(0xf800);
                  }
        for(j=0;j<768;j++)
                  {
                    cursor(j+40,j);
                        delay1ms();
                    spi_write16(0xffff);
                  }
这几条彩线,位置都对,颜色部分对。比昨天好多了,昨天是全错。
一朝成名 2009年09月10日
:L
@︻$▅▆▇◤ 2009年09月11日
狂顶!
wangkj 2009年09月15日
数据没有写入,明天检查,这是090904改版以来,头一次刷新正常。
这次结构做了很大调整。

估计是某个变量没控制好。明天好好检查。
wangkj 2009年09月15日
显示的数据是090904的程序写入的,
sdram其实几分钟不刷新数据都不会丢失。只是可能有几个错误数据,大部分是没问题的。
如果真的想sdram数据消失的话,只能等一天。这时候,读出来的就是混乱数据了。

读取的数据,和读取方式还有关系,不同的读取方式,读取是的乱码非常不同。

但是,如果是正常数据,不同的操作方式,回读的就是正常的了。

估计是sdram中的电荷电压处于临界态,不同读取方式,电压不同,比较结果不同所致。
ecgui.com 2009年09月16日
很不错!加油!:)
wangkj 2009年09月16日
原来的采用epm570的已经完全成功驱动1024*768,无等待状态输入。
epm240没有实际焊接,但支持480*272的编译结果是93%逻辑占用,应该可以用。
如果采用epm240和busy信号,应该支持640*480 25Mhz点频应该没问题,
这应该是最低成本方案,可采用stc1052 3元的单片机,采用25M晶体,从
wangkj 2009年09月16日
单片机的clk_out输出的震荡信号同时驱动8元的epm240,外加2元的sdram,总共成本应该能控制到15-20元。

如果谁有大量需要,咱可以考虑,这个低成本方案,我实在想不出来必要性。
否则,还是考虑新能更好的a3p060方案吧,这个更通用。性价比更好。这个得等一段时间。我正在努力调试中。
有时候,成本不是最主要的,主要的是有钱赚。
wangkj 2009年09月16日
我放弃epm570是因为只想支持一种cpld,不想同时支持几种,1024×768性能没有差异。
但更高分辨率,或者做更复杂的事情,epm570就不够了。
现在,同样价格的a3p060我才用到了50%的资源,哪怕支持到1920*1200也不会增加几个单元。
剩下的单元,可以做更多的事情。
@︻$▅▆▇◤ 2009年09月17日
:)
wangkj 2009年09月18日
这是最新结果,写数据不闪屏了,写入的第二个数据是对的。第一个可能是色彩数据可能和光标位置相同。写的数据好像少了几个。
快速刷屏,屏幕非常稳定,上午是狂闪。刚刚修正的这个bug.
希望下周能完成调试。
wangkj 2009年09月21日
斜线如果成白色,如果单色色块不多那么几个像素,就完全正常了。
继续调试,周末虽然没干活,但一直再思考。今天这是刚刚改进的控制程序。
wangkj 2009年09月21日
有些糊,但是大致还算正确。
wangkj 2009年09月23日
这次,写入位置和颜色完全正确了,只是多了些拖尾,这是sdram写入信号没处理好。
wangkj 2009年09月23日
更进一步的改进,效果更好了。继续改进中。
wangkj 2009年09月23日
for(y=500;y<768;y+=24)
           for(i=0;i<24;i++)
           {
             cursor(100+y,y+i);
                for (j=0;j<88/8;j++)  
           for (k=0;k<8;k++)
            {
              if (((pic<<(k)&0x80)==0x80))
                 spi_write16(0xffff);//0xffff;
              else
                 spi_write16(0x0);               
            }
            }                   
        for (j=0;j<768;j++)
                {
                                  cursor(514,j);
                                  spi_write16(0x1f);   //for(n=0;n<1;n++);清屏 延时用2足够了,如果硬件规格高,可以省略。
                                }
        for (j=0;j<768;j++)
                {
                                  cursor(1,j);
                                  spi_write16(0x1f);   //for(n=0;n<1;n++);清屏 延时用2足够了,如果硬件规格高,可以省略。
                                }
        for (j=0;j<768;j++)
                {
                                  cursor(1018,j);
                                  spi_write16(0x1f);   //for(n=0;n<1;n++);清屏 延时用2足够了,如果硬件规格高,可以省略。
                                }

                for(k=0;k<100;k+=5)
                {
                  for (j=0;j<768;j++)
                {
                                  cursor(j,j+k);       
                                  if (k<5)
                                        spi_write16(0x07e0);//green
                                  else
                                  if (k<5*2)
                                        {
                                          spi_write16(0xf800); //blue
                                          spi_write16(0xf800); //blue
                                          spi_write16(0xf800); //blue
                                        }
                                  else
                                  if (k<5*3)
                                        spi_write16(0x1f); //red
                                  else
                                  if (k<5*4)
                                        spi_write16(0x0821); //灰
                                  else
                                  if (k<5*5)
                                        spi_write16(0xffff);//白               
                                  else
                                        spi_write16(0xff);//黄色               
                                }
                }


            cursor(0,645);       
        for (j=0;j<1024;j++)
                {
                                  spi_write16(0x1f);   //for(n=0;n<1;n++);清屏 延时用2足够了,如果硬件规格高,可以省略。
                                }
            cursor(0,648);       
        for (j=0;j<1024;j++)
                {
                                  spi_write16(0x821);   //for(n=0;n<1;n++);清屏 延时用2足够了,如果硬件规格高,可以省略。
                                }
        for (i=0;i<100;i++)
            {
                 cursor(462,334+i);       
         for (j=0;j<100;j++)
                {
                                  spi_write16(0x0ffff);   //for(n=0;n<1;n++);清屏 延时用2足够了,如果硬件规格高,可以省略。
                                }
                }
                for (j=0;j<25000;j++) {delay1ms();}
                for (j=0;j<25000;j++) {delay1ms();}
                cursor(0,0);
                for(i=0;i<768;i++)
                for (j=0;j<1024;j++)
                   spi_write16(0);   //for(n=0;n<1;n++);清屏 延时用2足够了,如果硬件规格高,可以省略。

                for (j=0;j<25000;j++) {delay1ms();}
   
                       
                for(k=5;k<6;k++)
                {
                  cursor(0,0);//clear screen
                  for(i=0;i<768;i++)
                for (j=0;j<1024;j++)
                if ((i==j)||(i==j+k*5)||(i%k==0)||(j%k==0)||(i==0)||(j==0)||(j==1023)||(i==767))
                  spi_write16(0xffff);   //for(n=0;n<1;n++);清屏 延时用2足够了,如果硬件规格高,可以省略。
                else
/*                  spi_write16(0x0);  //delay1ms(); */
                                {
                                  if (i<150)
                                        spi_write16(0x07e0);//green
                                  else
                                  if (i<2*150)
                                        spi_write16(0xf800); //blue/
                                  else
                                  if (i<3*150)
                                        spi_write16(0);
                                  else
                                  if (i<4*150)
                                        spi_write16(0xf800|0x07e0);
                                  else
                                        spi_write16(0x001f); //red/               

                                }
  
                  send_char('*');send_char(0xd);send_char(0xa);
        }  

      }
  }
wangkj 2009年09月23日
这是测试源码。
wangkj 2009年09月24日
又一点进展
一朝成名 2009年09月24日
我有个屏保程序,老王应该弄上去,你这个走的太难看了~~
wangkj 2009年09月25日
兄弟,把你的屏保程序给我,我试试看,不过,不能超过5K,我的单片机,只有5k空间。

这次,还差一点点,左边多了2个像素,偶尔会写错数据。本来是很正规的方格,多来些线条干扰。估计是那个条件没控制好。不过,数据fifo的输入数量,和读取数量已经正确了。
wangkj 2009年09月25日
那些多余的小横线,就是bug,查找中。
一朝成名 2009年09月25日
一段时间想在机顶盒里加一个简单的屏保程序,想起来win下有一个小球在画面上弹来弹去的屏保……
于是就想些一个这样的屏保程序,在网上搜了一把也没找到,就自己写了,开始的思路是写一个通用的y=k*x的函数,这个小logo就按照函数弹,但是那一个麻烦阿,后来的思路转变写成了下面的模样…事实证明开始的时候是自己把问题复杂化。
函数不包含图片的刷新函数,这个可以根据自己的环境写,修改x,y的步进调整线的斜率,修改初始坐标,也可以随即化,主要是写的屏保的小算法……

俺小虾米班门弄斧了哈哈…………
很多电视机也有这样的屏保,因为是盒子里面的程序不能模拟就不能传图片了……

大家有什么好的算法上传俩,这玩意这费了我N多脑细胞…………晕


目标:实现一个logo在桌面内随机直线行走碰见边缘反弹

#define     LOGO_DIAPLMENT                     64      //每次位移的像素
#define     SCREENSAVE_WIDTH                640    //大屏幕的宽、高
#define     SCREENSAVE_HIGH                   480
#define     LOGO_WIDTH                           190     //logo的宽、高
#define     LOGO_HIGH                              80

void screensave (){

       static  int pos_count_x = pos_count_y = 0;

       static  int x_last_state = y_last_state = 1;//初始状态      

         if (pos_count_x < LOGO_DIAPLMENT)
                x_last_state = 1;
         else if (pos_count_x >= SCREENSAVE_WIDTH - LOGO_WIDTH - LOGO_DIAPLMENT)
                x_last_state = 2;

        if (pos_count_y < LOGO_DIAPLMENT)
                y_last_state = 1;
         else if (pos_count_y >= SCREENSAVE_HIGH - LOGO_HIGH - LOGO_DIAPLMENT)
                y_last_state = 2;
      


            if (y_last_state == 1)
                pos_count_y += LOGO_DIAPLMENT;
            else
                pos_count_y -= LOGO_DIAPLMENT;

           if (x_last_state == 1)
                pos_count_x += LOGO_DIAPLMENT;
            else
                pos_count_x -= LOGO_DIAPLMENT;

}
一朝成名 2009年09月25日
一共才几行程序把你那个“中文测试”模块镶嵌进去。只要把写图片和擦图片的函数加进去就行
就会出现一个弹来弹去的程序。。。。肯定比较好看

主要算法,4行:shutup:
wangkj 2009年09月25日
你这里好多中文字符,咋搞的?
直接贴过来就乱码了。
wangkj 2009年09月25日
void screensave(void){

       static  int pos_count_x =0 , pos_count_y=0;

       static  int x_last_state =1,  y_last_state = 1;//初始状态      

         if (pos_count_x < LOGO_DIAPLMENT)
                x_last_state = 1;
         else if (pos_count_x >= SCREENSAVE_WIDTH - LOGO_WIDTH - LOGO_DIAPLMENT)
                x_last_state = 2;

        if (pos_count_y < LOGO_DIAPLMENT)
                y_last_state = 1;
         else if (pos_count_y >= SCREENSAVE_HIGH - LOGO_HIGH - LOGO_DIAPLMENT)
                y_last_state = 2;
      


            if (y_last_state == 1)
                pos_count_y += LOGO_DIAPLMENT;
            else
                pos_count_y -= LOGO_DIAPLMENT;

           if (x_last_state == 1)
                pos_count_x += LOGO_DIAPLMENT;
            else
                pos_count_x -= LOGO_DIAPLMENT;


                      for(y=500;y<768;y+=24)
           for(i=0;i<24;i++)                 //显示图片,汉字测试
           {
             cursor(100+y,y+i);                 //光标移动一次,连续输入数据,速度较快
                for (j=0;j<88/8;j++)  
           for (k=0;k<8;k++)
            {
              if (((pic<<(k)&0x80)==0x80))
                 { spi_write16(0xffff); }
              else
                 { spi_write16(0x0);    }            
            }
            }


}
wangkj 2009年09月25日
改了一半,算了,不想了,还是找俺自己的bug吧。
一朝成名 2009年09月25日
你就用个坐标就完事~
先把旧图片擦掉,新坐标画图~~~~
wangkj 2009年09月25日
等俺有空了,改改试试看。
wangkj 2009年09月25日
今天调整的不错,剩下很少的错误了。这是调整后的真实拍摄图片,只有少量几个错误的小点。横线方向貌似不连续的线,是数码相机和电脑分辨率差造成的。实际上是非常连续的。只有偶尔出现的几个红色点上错误的,照片上几乎看不出来。另外一个问题,就是写图像时,屏幕抖动。
wangkj 2009年10月12日
最新的现实效果,还是有些花点,屏基本不闪,算法改动很大。
wangkj 2009年10月12日
红色数字的含义:一行红色,表示的是像素位置,对齐的黄色竖线距离50点,蓝色20点,红色10点。右下的数字,表示方格线的间距,单位是像素数。这个是间距23的方格。
Netjob 2009年10月12日
其实这个项目就是个RAM DAC,  没有2D/3D/SSE,OPGL等功能
也就是最简单的显卡了。区别是RGB与VGA输出的不同。
显卡的缓存至少有2M,4M的SDRAM/DDRAM上真彩的基本条件。

没有好的,宽带硬件RAM DAC,失真应该比较严重,估计。

最后 还是很佩服楼主的精神的。从无到有,从设计的意念。。。。
wangkj 2009年10月12日
我这个是8M的显存,才2-3元的sdram,难度也就是因为这个。
fifo模式读写,无等待周期,只用很少的宏单元,这就是难度。
有难度,不容易被仿制才是好产品。
sdram搞定了,fifo搞定了,vga搞定。
加起来,就是这个结果,还差一点,但基本能用了。如果谁想参与,可以帮我设计pcb先。
俺相信也能搞定。
其实,%1电阻,用RGB 565格式,误差是6%,3%,6%完全在精度范围内,就是这几个电阻的选值
一直不知道该选多少,目前是:0.5k,1k,2k,4k,8k。
Netjob 2009年10月13日
其实网上介绍这个CPLD VGA的资料也很多的~~
wangkj 2009年10月14日
现在有个非常犹豫的事情,这可能是我自己决策错误,
本来以为,换actel的这个cpld用两个月就能搞定,现在三个月过去了,
事情还不圆满,有些问题还是不是很清楚,部分代码还得重新写。
不知道何时能完成,或许一周,或许2-3个月。最多肯定不会到年底。

如果用epm240,也可以搞定640*480 真彩模式,用
wangkj 2009年10月14日
STC的单片机,本身可以产生晶振信号,VGA 640x480@60 Hz Industry standard (pixel clock 25.175 MHz),用这个频点的两腿晶振,就很容易,低成本做出来,但缺点是需要等待,必须用busy信号在回扫区写入数据。优点是及其便宜。
本身stc单片机就几块钱,epm240都是烂大街的片子,非好便宜也非常好买。这个应该很快可以做出来。这种带等待周期的模式,对于我而言,非常容易。

如果回到3个月之前,我肯定会选择后面放方法,但是,研发就是这样,很多问题,只有做了才能发现,这种现象也很正常。

现在做的这个方案,是给mini2440配套用的,当然,也可以支持任意的其他arm(硬件略微修改),分辨率可以做到1920*1200,当然,verilog程序也非常精巧,因为精巧,时序也非常不好安排,总是出现一些小问题。而且epm240的方案,非常简单,程序复杂程度比这个小很多很多。用a3p060的方案,这么难搞,是当初无法估计的--这个片子从来没用过。
李冬发 2009年10月16日
帮你顶一个,不错的东西。
wangkj 2009年10月20日
基本好啦,左边多一条线。
没有花点,不闪屏,非常好。有的汉字是写图片,有的汉字是写点。所以有的汉字上面多点东西,那是以前写屏留下的痕迹。
另外,显示器不太干净,看这挺好,拍出来多了几个白点。
wangkj 2009年10月20日
清理代码,检查多余的那条线。进展不错。另外,股票大涨俺的股票+1100多啦。
老郭 2009年10月20日
不错。搞完了是不是应该庆祝一下?
wangkj 2009年10月20日
还没最终完成,还得修正最后那条多余的线,另外,得重新做一版pcb,考虑一下推广问题。
wangkj 2009年10月20日
原理图/程序/pcb图,bom表。verilog这个不能公开,不要给我要。更多资料在qq群:630571
terrysun 2009年10月20日
欣赏一下!
wangkj 2009年10月20日
把测试语句去掉,有些点错位了。明天把所有的调试语句去掉,然后再修正。
基本就是sdram和fifo的读写时机问题。挨个测试没办法,不好仿真啊。
wangkj 2009年10月22日
显示不错位了,nnd,原来是a3p060的fifo使用和手册不一致。
手册说是10ns出数据,实际上,错后来两个周期(65M时钟)。

另外发现一个问题,写入第一个数据,不显示,写入第二个数据第一才出来。
也就是,cpld保持这一个数据,这可能和第一个一个问题。
我是按照手册编程的,这个可能得修正。
wangkj 2009年10月22日
图片
原野之狼 2009年10月22日
王会计做的东西不错。
话说找出了数据手册的错误是否可以向原厂申请奖励呢,呵呵~
wangkj 2009年10月22日
另外,就是其fifo的clk,手册上说可以输入输出不同步,实际上,这样会出错。
只能用同样的时钟。 这个肯定是bug。
上面提到的那个,也可能是我的布线时间过长,
但也不至于用两个周期啊。懒得检查了。
好用就行。
wangkj 2009年10月22日
for (j=0;j<40;j++)                    //recentage
         for (i=1024/2-20;i<1024/2+20;i++)            
          {
            cursor(i,768/2-20+j);
            spi_write16(0xffff);
          }
        for (i=1024/2-20;i<1024/2+20;i++) //mid line
          {
            cursor(i,768/2);
            spi_write16(0);
          }
应该是一个白色的填充方框,被中间的黑线完全隔开,少了一个点。
如果增加一个spi_write指令或者cursor指令,这个点就出现了。
不是少刷新了一个数据,就是fifo有个数据没写入sdram。
这是用那的手机拍摄的,效果自我感觉不错。也算是对这个DIY项目的一个投入吧。
很多眼睛看不清的,就用这个手机的微距功能拍摄,放大来看。
一朝成名 2009年10月22日
把数据算好了写死,虽说cpu很快,但是一直计算,也是浪费时间的
特别对你这个要求性能的东西~
wangkj 2009年10月22日
那些数据会自动优化掉的。这个放心。
wangkj 2009年10月23日
今天去cypress展会,没调试,不过,一直再考虑,
基本考虑明白了,就是数据从fifo读取写入sdram的时候,少了一个周期!
按照actel的手册,一个周期足够,实际上必须两个周期,下周试试看。
改起来,比较麻烦,数据流有点乱了。得重新规划。
一朝成名 2009年10月23日
恭喜会计收工了。。。。。
wangkj 2009年10月27日
离收工远的呢,得重新做pcb,增加硬件2d/3d能力,还得调试mini2440兼容部分。
不知道后面咋运作。商业化俺确实不懂。
wangkj 2009年10月27日
这回完全正常了,多的那一个点也搞定了。跟我的猜测相同,改起来花了不少功夫。
新的芯片,不要相信他的手册和宣传,只能作为参考,一切,还得自己去验证。
所以,在新的项目中,不到不得已,不要采用新元件。
也就是说,新的元件,必须有一组人马做小白鼠,做一些可有可无,甚至验证性的项目。
@︻$▅▆▇◤ 2009年10月27日
:loveliness::):lol;P:$:P
一朝成名 2009年10月27日
商家一般不会承认自己的芯片有bug的。。。。。。。。。。。
wangkj 2009年11月06日
DIY显存8M的单片机显卡(基于stm32,allegro)专区
http://bbs.eeworld.com.cn/forum-97-1.html

自己一个人干非常累,好在几个群友帮我弄了个专区。大家一起做

rp老弟,帮我们搞定allegro16.2安装吧,确定用allegro了。我现在用的15.5

这里可以同步转播 :lol ,或者 rp 弄个allegro专区。
alpha321 2009年11月12日
楼主好精神,终于做出来了!
wangkj 2009年12月02日
http://bbs.eeworld.com.cn/thread-90402-1-1.html
这是原始链接,
感谢小天同学的努力,原理图差不多完成了,应该开始布线了。
wangkj 2010年01月05日
冒雪周一取得板子,去的时候,打车。
回来的时候,只能做地铁倒347,根本没空车。
2010年02月06日
太好了
长话短说 2010年06月01日
漂过。
lfy129977 2010年06月02日
不错!
amender 2010年06月17日
很需要这个,先留个印子再看
yespiao 2010年06月24日
看看
Findlife 2010年08月08日
牛人!!!膜拜然后树立榜样
center123 2010年08月14日
现在的显卡技术开始使用GPGPU
yespiao 2010年08月26日
看看
dong_abc 2010年08月29日
瞧瞧
noescape 2010年09月17日
效果怎么样....
wangkj 2010年11月05日
成品
wangkj.taobao.com
wbsh 2010年12月08日
:)
arnoldlai 2013年08月12日
真是太棒了。