(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365)
YIE001PCIe开发板之跑马灯实验
在等待开发板YIE002焊接的日子里,回到YIE001上继续编程。
本篇准备完成跑马灯的实验,让YIE001上的4个LED灯跑起来。在开篇中,已经大致了解了YIE001上的硬件资源,为方便后续的编程,把这些资源先记录一下。
表1 开发板YIE001上硬件资源
开发板上名称 | 引脚名称 | 所属寄存器 | 地址 | 位址 |
---|---|---|---|---|
LED1 | SW0 | 控制寄存器CTLR | IO基址+0x1 | bit 0 |
LED2 | SW1 | 控制寄存器CTLR | IO基址+0x1 | bit 1 |
LED3 | GPO | 辅助寄存器AUXR | IO基址+0xf8 | bit 0 |
LED4 | RST0 | 辅助寄存器AUXR | IO基址+0xf8 | bit 7 |
KEY1 | GPI1 | 输入寄存器GPIR | IO基址+0x2 | bit 1 |
KEY2 | GPI2 | 输入寄存器GPIR | IO基址+0x2 | bit 2 |
I2C | SDA | 输出寄存器GPOR | IO基址+0x0 | bit 0 |
I2C | SCL | 输出寄存器GPOR | IO基址+0x0 | bit 1 |
需要注意的是,在CH366提供的芯片手册上,对于GPO和RST0所属的寄存器AUXR,给出的地址为IO基址+0x18。在实际使用中,此寄存器无法写入,经过测试发现应该是0xf8才对。
下面介绍下跑马灯的编写以及测试过程。
1 控制LED灯的函数
我是在开发探索71的框架示例上进行改造的,框架代码不用修改,主要将原来的HelloUEFI()函数替换为新的函数就可以了。首先编写控制LED灯的函数,其相关的宏定义如下:
#define CH366CTLR 0x01
#define CH366AUXR 0xf8
#define LED1 1 //SW0 see CH366's manual
#define LED2 2 //SW1
#define LED3 3 //GPO
#define LED4 4 //RST0
#define KEY1 1 //GPI1 -- GPIR(IO基地址+02h) bit 1
#define KEY2 2 //GPI2 -- GPIR(IO基地址+02h) bit 2
#define LEDON 0 //低电平点亮灯
#define LEDOFF 1 //高电平关闭灯
对照芯片手册,很容易将点亮和关闭LED等的函数编写出来,代码如下所示。
/**
点亮或者关闭开发板YIE001上的灯.
@param IoBaseAddress YIE001上PCIE芯片的基地址
@param LedNum 灯的标识,共有四个,从LED1至LED4
@param value LEDON或者LEDOFF,亮灯或者关灯
@retval VOID
**/
VOID SetLed(UINT16 IoBaseAddress,UINT8 LedNum,UINT8 value)
{
UINT8 regValue=0;
if(LedNum==LED1)
{
regValue = IoRead8(MyIoBaseAddr+CH366CTLR); //CTRL
if(value)
regValue |= 0x01;
else
regValue &= 0xFE;
IoWrite8(MyIoBaseAddr+CH366CTLR,regValue);
}
if(LedNum==LED2)
{
regValue = IoRead8(MyIoBaseAddr+CH366CTLR); //CTRL
if(value)
regValue |= 0x02;
else
regValue &= 0xFD;
IoWrite8(MyIoBaseAddr+CH366CTLR,regValue);
}
if(LedNum==LED3)
{
regValue = IoRead8(MyIoBaseAddr + CH366AUXR); //AUXR 0x18? 0xF8!
if(value)
regValue |= 0x01;
else
regValue &= 0xFE;
IoWrite8(MyIoBaseAddr+CH366AUXR,regValue);
}
if(LedNum==LED4)
{
regValue = IoRead8(MyIoBaseAddr + CH366AUXR); //AUXR 0x18? 0xF8!
if(value)
regValue |= 0xF0;
else
regValue &= 0x7F;
IoWrite8(MyIoBaseAddr+CH366AUXR,regValue);
}
}
代码非常简单,就不解释了。
2 实现跑马灯
在嵌入式开发中,一般会使用定时器来实现跑马灯。为了简单起见,我使用了while循环来实现依次点亮-依次熄灭的功能。代码如下:
VOID HelloMyROM(VOID)
{
EFI_INPUT_KEY key={0,0};
gST->ConOut->OutputString(gST->ConOut,L"Hello, I am YIE001!\n\r");
gST->ConOut->OutputString(gST->ConOut,L"Start Horse Race Lamp, ESC key to exit...\n\r");
while(key.ScanCode!=0x17) //ESC键退出循环
{
GetKey(&key);
if(key.UnicodeChar == 0x31) //按’1’退出当前循环
break;
SetLed(MyIoBaseAddr,LED1,LEDON);
Delayms(200);
SetLed(MyIoBaseAddr,LED2,LEDON);
Delayms(200);
SetLed(MyIoBaseAddr,LED3,LEDON);
Delayms(200);
SetLed(MyIoBaseAddr,LED4,LEDON);
Delayms(200);
SetLed(MyIoBaseAddr,LED4,LEDOFF);
Delayms(200);
SetLed(MyIoBaseAddr,LED3,LEDOFF);
Delayms(200);
SetLed(MyIoBaseAddr,LED2,LEDOFF);
Delayms(200);
SetLed(MyIoBaseAddr,LED1,LEDOFF);
Delayms(200);
}
}
以上的代码,能够实现目标功能。不过,在检查键盘按键的过程中,有些滞后感。主要是因为在控制灯的过程中,无法检查键盘输入。可以使用UEFI的Event,重新构建代码,解决上述问题。具体的实现就不写了,有兴趣可以自己试试。
3 编译及测试
所写的示例工程,假设为YIE1LED。可以在编译成ROM生成文件后,写入开发板YIE001,在实际的机器上进行测试。
3.1 编译
编译命令如下:
C:\UEFIWorkspace>build -t VS2015x86 -p RobinPkg\RobinPkg.dsc -m RobinPkg\Drivers\YIE1LED\YIE1LED.inf -a X64
生成的文件,位于C:\vUDK2018\edk2\Build\RobinPkg\DEBUG_VS2015x86\X64下,名称为YIE1LED.rom。
3.2 刷写YIE001的固件
YIE001上使用的PCIe芯片,是沁恒电子的CH366。在其官网上,提供了Windows和DOS下的刷写工具:http://www.wch.cn/search?t=all&q=366。
所提供的刷写工具为CH364PGM.COM(DOS工具)和CH364PGM.EXE(Windows工具),个人比较习惯于使用DOS工具进行刷写。从官方提供的一些资料来看,编写一个UEFI下的刷写工具,也是可以的。不过涉及到商业版权等一些非技术性原因的限制,暂时还是不这么做了。
按照如下步骤刷写固件:
(1) 修改ROM文件
CH366对ROM文件有一定的要求,个人感觉这算是芯片特性吧,其他的PCIE芯片好像没看到这种要求。
也即将ROM文件的第三字节(即偏移0x02)修改为0x40,对照PCI ROM的头结构,可以知道这是指定ROM文件长度为32K。
我一般是使用UltraEdit进行二进制修改,也可以使用VS Code配合hexdump插件进行修改。如图1所示。
图1 修改扩展ROM头结构中的ROM长度
(2) 刷写Flash ROM
用U盘制作DOS启动盘,将ROM文件和DOS刷写工具CH364PGM.COM拷贝在U盘中同一文件夹下。
将YIE001开发板插在带PCIE接口的测试机器上,当然,必须是X86架构的机器。笔者使用的是MSI的机器,使用的处理器为AMD A8-7650K。选择进入U盘的DOS系统,运行如下命令:
C:\FLASH\CH364PGM.COM YIE1LED.ROM
* Program CH364/CH366/CH367/CH368 Flash-ROM, V2.0
...... //其他提示信息
* OK! Written & verified
刷写成功后,重新启动计算机,准备查看ROM代码运行情况。
目前大部分计算机还是支持DOS启动盘的,如果上述方法无法成功,请进入Windows系统,使用Windows刷写工具对YIE001进行刷写。
(3)测试
不需要做特别的动作,启动系统后,BIOS将自动加载YIE001上的Option ROM代码。其运行情况如图2所示。
图2 YIE001的跑马灯
Gitee地址:https://gitee.com/luobing4365/uefi-explorer
项目所用ROM文件位于:/ 75 YIE1LED下