EVE-3 驱动

同SPI Flash一样,对于MCU端来说,EVE芯片也仅仅是一个SPI外设,对EVE芯片的操作可以简化为SPI写地址,然后读写数据。因此,先定义2个API函数ft8xxWriteBuf和ft8xxReadBuf作为SPI通信的接口函数:

ft8xxWriteBuf的步骤是:首先FT8xx的CS脚拉低,然后写入3字节的地址,接着写入数据,最后将CS脚拉高结束此次传输。

bool_t ft8xxWriteBuf(uint32_t addr, uint8_t *pbuf, uint32_t len)

{

              uint8_t addrBuf[3];

              ft8xxCSEn();

              addrBuf[0] = ((uint8_t)(addr >> 16));

              addrBuf[1] = ((uint8_t)(addr >> 8));

              addrBuf[2] = ((uint8_t)(addr));

              spiWriteBytes(addrBuf, 3);

              spiWriteBytes(pbuf, len);

              ft8xxCSDis();

              return TRUE;

}

ft8xxReadBuf的步骤与ft8xxWriteBuf类似,区别是写入3字节地址后需要多写入一个dummy byte才能开始读数据。

bool_t ft8xxReadBuf(uint32_t addr, uint8_t *pbuf, uint32_t len)

{

              uint8_t addrBuf[4];

              ft8xxCSEn();

              addrBuf[0] = ((uint8_t)(addr >> 16));

              addrBuf[1] = ((uint8_t)(addr >> 8));

              addrBuf[2] = ((uint8_t)(addr));

              addrBuf[3] = 0xff; //dummy read, ft8xx require

              spiWriteBytes(addrBuf, 4);

              spiReadBytes(pbuf, len);

              ft8xxCSDis();

              return TRUE;

}

参数addr表示需要写入或读出数据的地址,pbuf是读写的数据buffer,len表示读写的长度。

其中addr地址对应EVE芯片内部Memory地址空间(BT81x的地址空间与FT81x的相同)如下图,即对EVE芯片的读写地址对应RAM_G/RAM_PAL(只有FT80x)/RAM_DL/RAM_REG/RAM_CMD,这些名字都在头文件FT_Gpu.h(该文件在FTDI官网例程里面均有)里面有定义。

 

SPI数据协议:

1. Host Command

Host Command需要写入3字节命令,因为FT8xx的地址也是3字节,所以可以把Host Command理解为一组特殊的地址。

另外,第二个字节可以默认为0,因为我们一般不会设置这个参数(这个参数目前只有FT81x有,FT80x是默认为0的)。

注意第一个自己的bit7、bit6,这里为01表示该地址是Command。FT8xx就是通过这2个bit来确认当前的操作是属于什么类型。

用宏定义实现:

#define ft8xxWrCmd(cmd)        ft8xxWriteBuf(((uint32_t)cmd) << 16, 0, 0)

这里采用右移16bit的原因是FTDI官网的例程中的头文件FT_Gpu_Hal.h定义的cmd都是字节表示,所以需要移位。

比如选择内部晶振还是外部晶振的命令,datasheet上描述是:

FT_Gpu_Hal.h中的定义是

typedef enum {

    FT_GPU_INTERNAL_OSC = 0x48,

    FT_GPU_EXTERNAL_OSC = 0x44,

}FT_GPU_PLL_SOURCE_T;

写入命令的方式是;

ft8xxWrCmd(FT_GPU_INTERNAL_OSC);

ft8xxWrCmd(FT_GPU_EXTERNAL_OSC);

2. Host Memory Read

读操作的数据格式如下:

注意第一个字节的bit7、bit6为00,表示当前操作为Host Memory Read,写入30字节的地址,写完地址后需要发送一个Dummy byte,后面的数据才是真正的有用数据。

同样可以用宏定义实现:

#define ft8xxRdMemBuf(addr, buf, len)   ft8xxReadBuf(addr, buf, len)

举例从RAMG地址0x00000000中读取10字节数据,数据放在数组buf[10]中:

ft8xxRdMemBuf(RAMG + 0x00000000, buf, 10);

3. Host Memory Write

写操作的数据格式如下:

注意第一个字节的bit7、bit6为10,表示当前操作为Host Memory Write,另外同Read不同的是地址后无需Dummy Byte写入。

其宏定义为:

#define ft8xxWrMemBuf(addr, buf, len) ft8xxWriteBuf(((uint32_t)addr) | ((uint32_t)0x80 << 16), buf, len)

这里地址或上((uint32_t)0x80 << 16)是为了设置第一个字节的bit7、bit6为10。

举例从RAMG地址0x00000000中写入10字节数据,数据放在数组buf[10]中:

ft8xxWrMemBuf (RAMG + 0x00000000, buf, 10);

 

读写EVE芯片的Memory常用的API函数:

void ft8xxWrMem32(uint32_t addr, uint32_t dat)

{

              uint8_t buf[4];

              buf[0] = (uint8_t)dat;

              buf[1] = (uint8_t)(dat >> 8);

              buf[2] = (uint8_t)(dat >> 16);

              buf[3] = (uint8_t)(dat >> 24);

              ft8xxWriteBuf(addr | ((uint32_t)0x80 << 16), buf, 4);

}

uint32_t ft8xxRdMem32(uint32_t addr)

{

              uint8_t buf[4];

              uint32_t value;

              ft8xxReadBuf(addr, buf, 4);

              value = ((uint32_t)buf[0]|((uint32_t)buf[1]<<8)|((uint32_t)buf[2]<<16)|((uint32_t)buf[3]<<24));

              return value;

}

类似函数ft8xxWrMem16,ft8xxWrMem8,ft8xxRdMem16,ft8xxRdMem8,分别对应读写2字节数据,1字节数据。

 

EVE芯片的指令都是32字节的,例如调整alpha值的命令(在文件FT_Gpu.h中有定义)是:

#define COLOR_A(alpha) ((16UL<<24)|(((alpha)&255UL)<<0))

而EVE芯片的指令有2种类型,一种是DL指令,另一种是CMD类型,分别对应Memory空间RAM_DL和RAM_CMD。不过DL指令也可以写入到RAM_CMD执行,而CMD指令不能写入到RAM_DL,所以为了驱动更为简洁,这里设计为所有指令都写入到RAM_CMD,即只使用RAM_CMD空间,不使用RAM_DL,缺点是RAM_CMD只能支持最大1K条指令,而RAM_DL是2K条指令。

 

另外,当需要写多条指令时,如果采用Addr + Data的方式写每一条指令,那么SPI的通信效率太低,比如写3条指令,SPI上的数据就是3B+4B+3B+4B+3B+4B。所以采用buffer方式存储指令,当buffer满或者写指令结束时才将buffer中的指令写入EVE芯片,这样同样3条指令,SPI上的数据就是3B+4B+4B+4B。

因此,定义3个全局变量记录buffer和地址的变化。

static uint16_t gDispAddrStart = 0;

static uint8_t gCmdBuffer[CMD_BUF_SIZE];

static uint16_t gCmdBufferPoint = 0;

gDispAddrStart记录写入RAM_CMD中的偏移地址,gCmdBuffer保存写入的指令,而gCmdBufferPoint记录写入到gCmdBuffer中的位置。

这样当buffer满时,需将buffer中数据一次写入到RAM_CMD,所以增加API函数ftUpdateBufToCmd:

void ftUpdateBufToCmd(void)

{

              if(gCmdBufferPoint > 0)

              {

                            ftWrCoBuf(gCmdBuffer, gCmdBufferPoint, FALSE);

                            gCmdBufferPoint = 0;

              }

}

 

RAM_CMD有一个特别的特性,即它是Circular Buffer,如下图所示,其中REG_CMD_READ、REG_CMD_WRITE分别记录当前读写RAM_CMD的位置,当相等时表示执行结束。

Circular Buffer的好处在于每次写入数据时不需要考虑越界问题。比如当前写入地址为0x3FB,4KB空间只剩4字节,然后需要写入2个指令8字节,可以一次写入8字节,buffer满后剩下的4字节数据会自动写入到地址0开始。根据此特性增加API函数:

void ftWrCoBuf(uint8_t *buf, uint32_t len, bool_t wait)

{

              uint16_t retval;

              //FT8xx CMD buffer is circular buffer, FT81X automatically wraps continuous writes from the top address (RAM_CMD + 4095)

              //back to the bottom address (RAM_CMD + 0) if the starting address of a write transfer is within RAM_CMD.

              while(len > 0)

              {

                            uint16_t wrLen;

                            retval = (CMDBUF_SIZE - 4);

                            wrLen = (retval < len) ? retval : len;

                            ft8xxWrMemBuf(RAM_CMD + (uint32_t)gDispAddrStart, buf, wrLen);

                            gDispAddrStart += wrLen;

                            if(wait == TRUE)

                                          ftWaitCoFifoEmpty();

                            else

                            {

                                          gDispAddrStart = (gDispAddrStart + 3) & 0xffc;

                                          gDispAddrStart &= (CMDBUF_SIZE - 1);

                                          ft8xxWrMem16(REG_CMD_WRITE, gDispAddrStart);

                            }

                            buf += wrLen;

                            len -= wrLen;

              }

}

这里while循环的作用是RAM_CMD最大只能写入4KB,当数据大于4KB时,每写入4KB数据一般需要等待寄存器REG_CMD_READ、REG_CMD_WRITE是否相等(即等待EVE芯片处理完所有数据)再写入下一笔数据。

函数ftWaitCoFifoEmpty的实现如下:

void ftWaitCoFifoEmpty(void)

{

              gDispAddrStart &= (CMDBUF_SIZE - 1);

              gDispAddrStart = (gDispAddrStart + 3) & 0xffc;

              ft8xxWrMem16(REG_CMD_WRITE, gDispAddrStart);

              ftWaitPtrEqu(ft8xxRdMem16(REG_CMD_WRITE), REG_CMD_READ);

              gDispAddrStart = ft8xxRdMem16(REG_CMD_READ);

}

函数ftWaitPtrEqu就是等待寄存器REG_CMD_READ、REG_CMD_WRITE相等,如果超时或者是非法值则重启系统。下面的代码请根据实际的需求更改,其中函数SystemReset()是根据MCU系统自行修改,函数ft8xxSleep()是delay函数,也是和平台有关。

void ftWaitPtrEqu(uint16_t wrPtr, uint32_t reg)

{

              uint16_t timeout = 0;

              uint16_t rdPtr = 0;

              do{

                            rdPtr = ft8xxRdMem16(reg);

                            if(rdPtr >= CMDBUF_SIZE || timeout > 30000)

                            {//FT8xx is overrun,RESET SYSTEM

                                          gDispAddrStart = 0;

                                          #ifdef SystemReset

                                          SystemReset();

                                          #endif

                                          break;

                            }

                            timeout++;

                            if(timeout % 100 == 0)

                            {

                                          ft8xxSleep(1);

                            }

              }while (rdPtr != wrPtr);

}

 

写入一条显示指令的API函数:

void ftWrDispCmd(uint32_t dispCmd)

{

              if(gCmdBufferPoint > (CMD_BUF_SIZE - 4))

              {

                            ftUpdateBufToCmd();

              }

              gCmdBuffer[gCmdBufferPoint] = (uint8_t)(dispCmd & 0xff);

              gCmdBuffer[gCmdBufferPoint+1] = (uint8_t)(dispCmd  >> 8);

              gCmdBuffer[gCmdBufferPoint+2] = (uint8_t)(dispCmd  >> 16);

              gCmdBuffer[gCmdBufferPoint+3] = (uint8_t)(dispCmd  >> 24);

              gCmdBufferPoint += FT_BUF_ALIGN;

}

写入多条显示指令的API函数:

void ftWrDispBuf(char *buf, uint16_t len)

{

              ftUpdateBufToCmd();

              ftWrCoBuf((uint8_t *)buf, len, FALSE);

}

 

例如要在屏幕坐标(100,200)显示字符串”Hello World!”,写入命令的代码如下:

ftWrDispCmd(CMD_DLSTART);

ftWrDispCmd(CLEAR_COLOR_RGB(0, 0, 0));

ftWrDispCmd(CLEAR(1, 1, 1));

ftWrDispCmd(CMD_TEXT);

ftWrDispCmd((100 << 16) | (200 & 0xffff));

ftWrDispCmd(((0 << 16) | 31));

ftWrDispBuf(“Hello World!”, strlen((char *)”Hello World!”) + 1);

ftWrDispCmd(DISPLAY());

ftWrDispCmd(CMD_SWAP);

 

注意:显示指令必须在红色部分指令之间。因此增加2个API函数:

void ftStartDisp(void)

{

              ftWaitPtrEqu(ft8xxRdMem16(REG_CMD_WRITE), REG_CMD_READ);

              ftWrDispCmd(CMD_DLSTART);

}

void ftEnDisp(bool_t wait)

{

              ftWrDispCmd(FTDISPLAY());

              ftWrDispCmd(CMD_SWAP);

              ftUpdateBufToCmd();

              if(wait == TRUE)

                            ftWaitCoFifoEmpty();

              else

              {

                            gDispAddrStart = (gDispAddrStart + 3) & 0xffc;

                            gDispAddrStart &= (CMDBUF_SIZE - 1);

                            ft8xxWrMem16(REG_CMD_WRITE, gDispAddrStart);

              }

}

 

### 关于 Eve-NG 的 WinXP 镜像下载 Eve-NG 是一种网络仿真平台,允许用户创建复杂的虚拟化环境来测试和学习各种网络技术。对于需要在 Eve-NG 中运行 Windows XP 虚拟机的情况,可以按照以下方法获取适用的镜像文件。 #### 获取合法授权 需要注意的是,在使用任何操作系统镜像之前,必须确保拥有该操作系统的合法许可证[^4]。未经授权分发或使用的操作系统可能违反版权法。 #### 下载途径 1. **官方渠道** Microsoft 已停止支持 Windows XP,因此无法通过其官方网站直接获得安装介质。然而,可以通过某些存档站点找到 ISO 文件,这些站点通常提供历史版本的操作系统供教育用途下载。例如,一些大学或研究机构可能会托管旧版软件资源以用于教学目的[^5]。 2. **社区分享** 许多 IT 社区成员会上传经过预配置的 Eve-NG 兼容镜像到公开存储库中。以下是几个常见的来源: - GitHub 或 GitLab 上的相关项目仓库。 - EVE Community Forum (https://community.eve-ng.net/) 用户贡献区域。 3. **自定义准备** 如果找不到现成的镜像,也可以自行制作适合 Eve-NG 使用的 Windows XP VM。具体步骤如下: - 安装 VirtualBox 或 VMware Workstation Pro 创建基础虚拟机。 - 将所需驱动程序集成至 Guest OS 内部以便更好地适配 KVM/QEMU 平台特性[^6]。 - 导出 OVA/OVF 格式的压缩包再转换为目标格式导入目标设备上完成迁移过程。 #### 性能优化建议 为了使老化的 Windows XP 在现代硬件环境下流畅运作,可采取下列措施提升效率: - 设置定时延迟脚本以模拟真实世界中的等待时间场景[^7]: ```batch @echo off echo wscript.sleep 5000>sleep.vbs start /wait sleep.vbs start gdh.txt del /f /s /q sleep.vbs ``` - 启用图形渲染增强功能改善用户体验效果[^8]: 开启 DirectX 加速选项能够显著提高应用程序界面响应速度以及视觉表现力: 进入“开始 -> 运行”,输入命令`dxdiag`启动调试窗口;切换至“显示”标签页勾选对应开关项即可生效。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值