收藏官网,优惠快人一步
您可以尝试通过快捷键 CTRL + D 加入收藏夹
“盛思锐传感器”第九届立创电子设计开源大赛火热报名中,现在点击报名立创电赛赢2万现金大奖,报名后全阶段可触发福利!
大赛网址:DIY.SZLCSC.COM
为了给大家些创作灵感,今天带来第八届立创电赛优胜奖项目-《双机USB文件互传工具》案例分享!本文作者:瑞萨MCU杯第八届立创电子设计开源大赛选手@Arduino爱好者,禁止商用,未经许可禁止转载。
在工作中,我经常需要在 UEFI Shell 环境下测试编写的 UEFI Application 。通常情况下都是先编译,然后将生成的文件拷贝到U盘,然后再将这个U盘插入到测试机上。显而易见,这样非常繁琐,影响工作效率。因此使用 CH567 这一款来自 WCH 的双USB接口芯片制作一个双机互联工具。在无需插拔的情况下即可进行文件传输。
这个工具的使用说明如下:
主要部件如图所示 ① 供电指示灯 ② 工作指示灯,当有数据传输时会闪烁 ③ ⑦供电跳线,默认情况下通过USB1 供电,换句话说:默认情况下只插入USB0端口设备不工作 ④PSRAM 需要传输的数据会放在这里,这个芯片的容量是8M Bytes ,目前的限制是一次最大只能传输8MB 的文件 ⑤ SPINOR芯片,用于存放工具 ⑥ 主控芯片,CH567 , 这是南京 WCH 出品的ARM主控,支持高速双USB接口。
双机互联工具
设备上电后(推荐USB1端口,就是带有两个LED的那端),在 Windows下可以看到下面的目录:
这里有传输所需的软件以及一些其他方便调试的工具。内置软件介绍:
1. EFI 目录下:
a. Boot\BootX64.efi: 一个 Shell;
b. crd32.efi: 根据DiskImage.bin 创建一个虚拟磁盘;
运行之后再使用 map -r 命令可以看到当前系统会多出一个RAMDISK;
c. GetFile.efi: 从设备收取文件的工具。直接运行即可;
d. SendFile.efi:对设备发送文件的工具,后面接文件名即可发送指定文件;
e. memtest86\bootx64.efi: Memtest86 工具;
f. CrScreenshotDxe.efi: 截屏工具。 Load CrScreenshotDxe.efi 加载,之后ctrl+alt+F12 触发截屏;
2. Win 目录下:
a.7z2300-x64.exe: 7Z 安装包;
b.ntf.8.4.6.Installer.x64.exe: notepadfree安装包;
c.Getfile.exe: 从设备收取文件的命令行工具。需要在管理员权限下运行;
d.Sendfile.exe:对设备发送文件的命令行工具。需要在管理员权限下运行;
e.HE_v1.22.10.19_Portable.zip: 硬件访问工具。
针对传输工具说明如下:
1.使用sendfile.exe 发送文件(需要管理员权限),后面跟着要发送的文件名称。
2.使用 getfile.exe 接收文件。会使用当前设备中的文件名为保存的文件名,如果当前目录下有同名文件,那么会在后面增加”_1”再保存。
3.UEFI 下面工具使用方法相同
首次公开
注:请说明项目是否首次公开;项目是否为原创;项目是否曾经在其他比赛中获奖,若有获奖则叙述获奖详情;项目是否在学校参加过答辩。
Public Domain
注:利他即利己,请认真阅读下述内容。
本项目基于 WCH 的CH567 实现。CH567是一款高性能32位精简指令集微控制器,系统主频可达120MHZ。芯片带有丰富的外设资源。这次用到的是其中的两组独立的高速USB2.0 设备控制器。
CH567控制器
可以看到,设备内部有三个主要芯片,分别是CH567 / PSRAM 和 SPINOR。
其中的 CH567 是这次设计的核心,这次的作品就是通过它模拟出了2个U盘,能够分别在两台电脑上同时工作。
然后为了实现数据交换,板子上放置了一个PSRAM,这种芯片可以理解为 SPI 接口的 SRAM,用户可以方便的使用 SPI 接口实现数据的存储,同时不用担心FLASH磨损这种问题。设备收到的文件会存放在这个芯片中,等待有人访问。这个芯片的大小为 8MB ,就是说每次不能传输大于8MB 的文件。当然,如果有这样的需求,也可以通过改写上位机软件的方式克服这个限制。
最后一个芯片是 GigaDevice 的32MB SPI NOR,我们将UEFI Shell 和文件传输用到的资料都放在其中,这样用户插上即可使用这个工具无需再使用U盘之类的存放工具。
软件设计包括:CH567 的固件代码、传输工具的应用程序(具体又分为 Windows 工具和 UEFI Shell 工具)
这部分介绍CH567芯片代码的设计。
I. 描述符部分。具体定义在 USBShare.c 文件中,其中的 MyManuInfo 定义了厂家信息为 “LAB-Z.COM”,MyProdInfo定义了产品信息为 “DUMT”,此外还有MySerial定义了序列号“012345”,如果有需要可以自行修改;特别的,我们在 BIOS Setup 界面中看到的设备名称之类的信息,是定义在InquiryReply 中的,在启动过程中X86会USB接口通过发送 USB MSD Inquiry Command获取这个字符串,并且显示为启动设备名称;
II. 分布结构。芯片代码部分最主要的是一个 USB Mass Storage(U盘)的框架,所有的功能都是在访问内容部分进行扩展的。
对于上述区域进一步解说。从图中可以看到设备中存在着2个区域:SPINOR 的区域,以及 PSRAM 区域。对于处于这两个区域之外的位置(中间部分),设备会返回空操作。对于读操作,直接返回全0 ;对于写操作,直接返回写入完成。
1. SPI NOR 区域操作。对于这个区域的处理,分成三个 Topic: 0x1800 位置的读取写入、SPINOR 的读取和写入、PSRAM 的读取和写入。
a. 这个区域有一个 0x1800 的位置需要特别处理。这个存放着TranHeader结构体,它是一个用来存储传输状态的结构体,它的大小是512Bytes(刚好一个扇区),具体定义如下:
struct _ TranHeader {
// Offset 0,状态标志,目前用到的有 Busy标志。比如,一个 USB 端口在写入的时候
会将这个位置设置起来,另外一端在访问的时候看到了就知道对面正在使用; 另外
一个是只读标志,默认情况下模拟出来的U盘是只读无法写入的。这样做是为了节省
SPI NOR 的寿命,另外,放置意外篡改内容。
UINT32 Flag; //Bit0: 0 - Busy
// 1 – Not Busy
//Bit1: 0 - ReadOnly Enable
// 1 – ReadOnly Disable
// Offset 4 ,这是一个单调递增的标志,目前没有使用
UINT32 Monot;//单调递增
// Offset 8,传输数据时,写入文件的长度(目前一次传输最高支持8MB 的文件)
UINT32 Size; //本次传输的全部长度(头文件和内容) 1Bytes ---- 8Mbytes
// Offset 12,预留的长文件传输,目前没有使用
UINT32 Counter; //本次传输为第 Counter 段。例如,要传输一个64MB文件,
//需要分割成8段,第一次传输的 Counter 为7,最后一个为0;
// Offset 16
UINT16 FilenameLength; //文件名长度
// Offset 18
UINT8 Filename[494]; // ASCII 的文件名称(不包括路径)
};
目前使用到的相关应用程序有三个:发送文件,接收文件和写入镜像。
上面三个应用程序有部分内容有一些公头的代码。在使用的时候,为了确定系PhysicalDiskX 为我们的设备,需要检查下面2个标志。
第一处标志在注册表中,例如,下图中编号为“1”的设备就是我们的设备,因此,这里对应该 PhysicalDeisk1 是我们的设备。
对应的代码示例如下:
// 当前硬盘信息在
// Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\disk\Enum
RegistryKey myreg = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Services\disk\Enum");
// 如果当前系统只有1个硬盘,那么直接退出
if (myreg.GetValue("Count").ToString() == "1")
{
myreg.Close();
Console.WriteLine("No transfer disk, pressing anykey to exit");
Console.ReadKey();
Environment.Exit(0);
}
string[] subkeyNames = myreg.GetValueNames();
int DiskNo = 0;
foreach (string keyName in subkeyNames)
{
if (myreg.GetValue(keyName).ToString().StartsWith(@"USBSTOR\Disk&Ven_DUMT"))
{
Console.WriteLine(keyName);
Console.WriteLine(myreg.GetValue(keyName).ToString());
DiskNo = int.Parse(keyName);
}
}
myreg.Close();
第二处在磁盘镜像中(写入SPINOR中的内容),如下,可以看到存在一个Signature:
对应的代码如下:
// 检查第5个扇区,判断是否为设备
disk1.Seek(0x800, SeekOrigin.Begin);
disk1.Read(Sector, 0, ONESECTORSIZE);
Console.WriteLine("Checking PHYSICALDRIVE" + DiskNo.ToString()+" Signature:");
string arr = "DATTRANSFTERDISKWWW.LAB-Z.COM";
byte[] bytearr = System.Text.Encoding.Default.GetBytes(arr);
// 如果签名不符合,说明不是我们需要的设备
if (Program.EqualsBytes(ref Sector, ref bytearr) != true)
{
//不是UDT设备,输出错误然后退出
Console.WriteLine("PHYSICALDRIVE"+DiskNo.ToString() + " is NOT a DATATRANFER! ");
disk1.Close();
Console.ReadLine();
Environment.Exit(0);
}
else
{
Console.WriteLine("PHYSICALDRIVE" + DiskNo.ToString() + " signature tests pass! ");
}
除了上面的检查确认设备的代码,还有Busy位的检测,无论是读取还是写入都要进行Busy位的检测,这样避免一端正在写入时另外一端在读取,这样会导致读取出来的数据可能不完整。检查的方式就是读取 0x1800处的TranHeader结构体,确认另外一端没有 Busy才会进行其他操作。
// 检查 Busy 位
disk1.Seek(0x1800, SeekOrigin.Begin);
disk1.Read(Sector, 0, 4096);
if (DEBUGMODE)
{
Console.WriteLine("Busy check:");
for (int i = 0; i < 32; i++)
{
Console.Write("{0:x} ", Sector[i]);
}
Console.WriteLine(" ");
}
//检查 Busy位
if ((Sector[0] & 1) == 0)
{
Console.WriteLine("Device busy, please try again later!");
Console.ReadLine();
Environment.Exit(0);
}
发送文件的操作就是从本地读取文件,然后将文件的大小和名称整理后写入TranHeader结构体中。特别注意,有时候收到的命令行参数的文件名可能带有路径信息,而发送的文件信息中只应该包含文件名信息。例如:sendfile c:\test\foo.bin ,我们读取c:\test\foo.bin文件作为发送内容,但是只应该把 foo.bin 写入TranHeader;
接收文件的操作就是首先获得文件基本信息,然后再读取设备的PSRAM。将内容保存为文件。需要特别注意的是可能遇到存在同名文件的问题。对于 Windows下会对收到的文件重命名,UEFI App 的处理方法是直接删除之前的文件,这样设计的原因是为了避免后续的误操作。
首先,对0x1800处设置ReadOnly标志为 False;这样 CH567的代码会将对 0-32MB范围内的写入操作真正写入 SPINOR中。
byte[] bt = new byte[ONEDATA];
bt[0] = 0x02; // Readonly== False
// 发送命令,Write Enable
disk.Seek(0x1800, SeekOrigin.Begin);
disk.Write(bt, 0, 512);
disk.Flush();
接下来要对前面的扇区是否为空进行检测。Windows会阻止我们对一个带有分区表的硬盘写入,因此我们需要先擦除分区表。如果为 0xFF,后面开始写入操作;否则,先发送擦除然后再进行下一步:
// 检查最前面的扇区是否为全 0xFF
disk.Seek(0, SeekOrigin.Begin);
最后就可以进行硬盘的写入操作了,写入是从硬盘末尾先前进行的。因为实验发现,如果从前开始写入,那么写入分区之后,Windows 会“发现新增加的硬盘”,然后后面内容的写入
for (int i = 0; i < MAXSPIADDRESS / ONEDATA; i++)
项目使用立创 EDA 设计,BOM 如下:
注:项目涉及的BOM清单。这个位置请上传BOM的截图。清单详情请以PDF的格式上传到附件中。建议包括型号、品牌、名称、封装、采购渠道、用途等内容。具体内容和形式应以表达清楚项目构成为准。
USB双击互传工具
视频要求:请横屏拍摄,分辨率不低于1280×720,格式Mp4/Mov,单个视频大小限100M内;
视频标题:立创电赛:{项目名称}-{视频模块名称};如立创电赛:《自动驾驶》-团队介绍。
更多详情:https://diy.szlcsc.com/posts/15a52db9fd7d40c492eb505280278e45
TPS5430DDAR/DC-DC电源芯片 | 1.17 | |
DS18B20+/温度传感器 | 4.54 | |
AD623ARZ-R7/仪表放大器 | 13.54 | |
STM32F030F4P6TR/单片机(MCU/MPU/SOC) | 2.21 | |
ULN2003ADR/达林顿晶体管阵列 | 0.3762 | |
STM32F103C8T6/单片机(MCU/MPU/SOC) | 4.24 | |
STM32F103VCT6/单片机(MCU/MPU/SOC) | 7.8 | |
STM32F103CBT6/单片机(MCU/MPU/SOC) | 6.27 | |
OP07CDR/精密运放 | 0.4075 | |
STM8S003F3P6TR/单片机(MCU/MPU/SOC) | 1.0396 |
56万现货SKU
品类不断扩充中
科技智能大仓储
最快4小时发货
正品有保障
物料可追溯
明码标价节省时间
一站式采购元器件
您确定要删除此收货地址的吗?
您确定删除此收货地址吗?
content
content