基于具有USB功能的STM32微控制器

该设计是一个物理开关,它确定每次打开计算机时要启动的操作系统。它使用stm32微控制器充当usb大容量存储设备,并提供一个动态文件。该文件可以由系统的引导配置加载,以根据物理输入来更改其引导行为:
组件:
拨动开关
具有usb功能的stm32微控制器
st-link编程器
该项目的解决方案是通过代码编写的,因此需要一个拨动开关,一个具有usb功能的stm32微控制器和一个st-link编程器。
代码:点击查看
设计过程:
启动linux,只需按电源按钮;另一方面,要引导到windows,则需要在grub短暂显示自己时进行战术,精确定时的敲击,以更改选择:
引导加载程序中的脚本
gnu grub是一种流行的linux启动加载程序-在加载任何操作系统之前运行的程序,它决定启动什么以及如何启动它。通常,将与上图所示的菜单进行交互,但实际上,grub是由简化的脚本语言配置的。在它的下面是用c语言编写的模块系统。
grub必须在操作系统外部运行,因此必须提供所有自己的工具,因此可用功能相当简单。
在grub中可以任意访问usb设备吗?
创建一个具有自定义(“特定于供应商”)接口的usb设备,以读出开关位置,就非usb而言,它就像是裸露的串行连接。可以从操作系统访问,但是不确定grub是否可以处理它。
grub实现在其原生支持usb ehci、uhci、ohci模块,但有一个问题-加载任何这些禁用用于访问磁盘上的常态机制通过bios来避免冲突,让你有无人接盘。有一个nativedisk模块可以独立于bios访问磁盘,但是除了速度慢之外,严重地使用该模块意味着grub无法链式加载windows(说明),从而使这种方法成为注销。
伪装成usb大容量存储设备
可以利用bios已经为grub提供对所有连接的存储设备的访问的事实,而不是创建自定义usb接口。需要做的就是将设备显示为存储设备,其中包含一个文件,其内容指示开关位置。
从概念上讲这很简单,但是有几层:
提供大容量存储类描述符,指示要使用的几种存储协议之一(scsi,ata)。
实现所选的存储协议。除了用于读取和写入扇区的标准请求外,这是一组用于询问存储设备的功能,容量,布局和其他元数据的命令。
读取时模拟有效的文件系统,而实际上没有任何存储介质。
使用usb状态指示灯中已有的支持usb的stm32板卡和代码,将供应商类设备更改为大容量存储类设备只需更改现有usb描述符中的几个字节即可。
对于存储协议层,发现它libopencm3具有内置的scsi大容量存储实现,具有简单read_block(address)和write_block(address)回调功能,隐藏了存储协议的复杂性:
由于这个原因,即使在这个阶段它只能读出无尽的0x00字节流,仍然可以使用可识别的存储设备快速启动并运行。
熟悉fat
模拟grub可以理解的文件系统。格式化存储设备,选择fat12,因为它的文档非常齐全,而且布局简单:
引导扇区:描述卷名称和几何形状的固定结构
文件分配表:一个索引,用于说明磁盘的哪些部分被使用以及分配/碎片化了多大的文件
根目录条目:文件元数据。指向实际文件内容所在的位置
[其余磁盘上没有固定的结构]
经过阅读和修改之后,进行了一个设置,可以定义虚拟文件列表,并在毫不怀疑的主机要求下即时生成目录条目和文件内容:
struct virtualfile {
char* longname;
struct fatdirentry dir;
void (*read) (uint8_t* output);
};
static void readswtich(uint8_t* output) { // output is a zeroed-out 512 byte buffer (one block)
output[0] = gpio_get(gpioa, gpio6) ? ‘1’ : ‘0’;
}
static struct virtualfile _virtualfiles[] = {
{
.longname = “switch_position”,
.dir = { .name = “switch~1”, .ext = “ ”, .size = 1 },
.read = readswtich
},
// 。..
};
转储块设备看起来像这样:
0000h是引导扇区,0200h是fat的第一个副本,0400h是fat的第二个副本,0600h是根目录条目。一共有三个32字节的目录条目-两个长文件名条目,然后是在640h该文件的实际目录条目。虚拟文件内容在4800h读出。
在grub中读取文件
grub没有将文件内容加载到变量中的任何内置支持,也不像典型的linux shell那样支持命令替换:
# this is bash and what i wanted to do
# grub script unfortunately doesn‘t support this kind of substitution
pos=$(cat /path/to/switch_position)
echo $pos
使用grub的“源” 命令从虚拟文件中加载其他配置。这种方法是开箱即用的,并且理论上适用于任何版本的grub:
根据开关位置启动
使用grub外壳中的switch位置了,然后修改系统启动配置,以根据此信息进行启动选择。
在 /etc/grub.d/00_header中, 将此添加到了 生成的输出中(删除了转义符以使其更易于阅读):
# look for hardware switch device by its hard-coded filesystem id
search --no-floppy --fs-uuid --set hdswitch 55aa-6922
# if found, read dynamic config file and select appropriate entry for each position
if [ “${hdswitch}” ] ; then
source ($hdswitch)/switch_position_grub.cfg
if [ “${os_hw_switch}” == 0 ] ; then
# boot linux
set default=“0”
elif [ “${os_hw_switch}” == 1 ] ; then
# boot windows
set default=“2”
else
# fallback to default
set default=“${grub_default}”
fi
else
set default=“${grub_default}”
fi
运行update-grub生成新的启动配置后,
硬件安装
小的铝制扁杆,几个螺丝和一些钻孔。


全球32项最新创新技术发明:牙齿传感器
TLK3132工作原理 CPRI接口应用(二)
5G会有真假之说的源头在于网络存在两种制式
使用Nsight Compute进行高级内核评测
锤子T3/T3X真机图爆出:这完全就是小米iPhone的合体
基于具有USB功能的STM32微控制器
基于RT9119 的家庭版高效能音效放大器设计
雷曼巨幕满足消费升级下高净值人群的家居需求
数据中心供配电系统主备用电源自动切换探究
我们正处于下一代控制台正式发布的边缘
华为云桌面,如何为办公而生
Xbox Series X实机游戏测试,在局部光照和积云效果上更胜一筹
按键式时控开关每天定时一样该如何去设置
光纤放大器/EDFA,光纤放大器/EDFA的原理和分类
PS VR眼镜模糊、起雾戴起来晕眩怎么办 小编教你如下几招
Pasternack将其射频同轴探针产品线扩展至40GHz工作频率范围
物联网设备在家庭虐待和隐私安全如何做到平衡?
北京电信面向垂直行业细分场景定制方案,打造新型网络基础设施
新型智能腕带:一个手势便能控制智能家电
单片机电子时钟程序设计