Zephyr OS新增USB接口字符串描述符索引配置问题咨询
Zephyr OS USB自定义字符串描述符索引异常解决方案
问题根因
Zephyr USB设备栈按字符串描述符在链接段中的排布顺序,从0开始依次分配索引:
- 索引0固定为语言ID描述符
- 索引1、2、3分别对应内置的厂商、产品、序列号字符串描述符
- 以上内置描述符全部注册在
usbd_str_descr_primary段,栈初始化时优先遍历该段分配索引
使用USBD_STRING_DESCR_DEFINE(primary)将自定义描述符加入primary段时,若自定义描述符所在源文件的链接顺序早于内置usb_descriptor.c,就会被排到段前部,抢占低索引值(返回索引0就是抢占了语言ID描述符的位置),直接破坏描述符结构导致枚举异常。
可落地解决方案
方案1:使用非primary段注册(官方推荐,无兼容性问题)
不要将自定义字符串描述符注册到预留的primary段,改用自定义段名即可。栈会在遍历完所有primary段内置描述符后,再遍历其他自定义段的描述符分配索引,天然保证自定义描述符索引从4开始。
修改后的代码示例:
// 仅需将宏参数的primary替换为自定义段名,例如webusb、user均可 USBD_STRING_DESCR_DEFINE(webusb) struct webusb_iface_descriptor webusb_string_descr = { /* webusb iface String Descriptor */ .bLength = sizeof(struct webusb_iface_descriptor), .bDescriptorType = USB_DESC_STRING, .bString = WEBUSB_IFNAME, }; void webusb_init() { int idx = usb_get_str_descriptor_idx(&webusb_string_descr); if (idx > 0) { webusb_desc.if0.iInterface = idx; } }
该方案不需要修改任何链接器配置、CMake规则,适配所有Zephyr 3.0及以上版本,不会随版本迭代出现排序异常。
方案2:调整primary段链接顺序(不推荐)
如果必须将自定义描述符放到primary段,需要通过链接规则保证内置usb_descriptor.c的目标文件排在自定义目标文件之前:
- 可以在应用的CMakeLists.txt中,将包含自定义描述符的源文件添加到链接列表的末尾
- 也可以修改链接脚本,对
usbd_str_descr_primary段添加SORT_BY_NAME规则,通过给自定义描述符的符号名加后缀的方式调整排序
该方法依赖版本内置文件的链接、命名规则,版本升级后容易失效,非特殊场景不建议使用。
注意事项
- 禁止手动硬编码字符串索引值,现有通过
usb_get_str_descriptor_idx()动态获取索引的写法完全正确,描述符排序正常后会自动返回符合预期的索引值 - 自定义字符串描述符不要使用
primary作为段名,避免和内置描述符抢占排序位置
内容的提问来源于stack exchange,提问作者Dmitry Kr
相关产品推荐
相关产品推荐

