通过mplab添加harmony框架提供的sam9x60的usb驱动,总比自己适配tinyUSB之类的要快嘛
然后就发现遇到第一个坑。仅添加usb host layer 驱动后编译就报错了
volatile uint32_t * interruptList = hDriver->hcHCCA->hccaInterruptTable;
说它
drv_usb_ohci.c:142:41: error: taking address of packed member of 'struct USB_OHCI_HCCA' may result in an unaligned pointer value
以及后面凡是对这个hcHCCA->hccaInterruptTable 进行32位指针化都会报这个错。
原因是它的结构体定义USB_OHCI_HCCA ,是添加了__attribute__((packed)) 修饰符的。
导致结构体成员可能没有按照自然对齐要求排列,直接获取 hccaInterruptTable 成员的地址会产生未对齐指针。
typedef struct __attribute__((packed)) USB_OHCI_HCCA
{volatile uint32_t hccaInterruptTable[32];volatile uint16_t hccaFrameNumber;volatile uint16_t hccaPad1;volatile uint32_t hccaDoneHead;volatile uint8_t reserved[116];} USB_OHCI_HCCA;
这是因为大多数CPU要求特定类型的数据必须存储在特定地址上(例如32位数据必须存储在4字节对齐的地址上),而USB OHCI控制器的硬件通信区域定义,它们的内存布局必须与硬件规范完全一致。
这些结构体是硬件寄存器的直接映射,任何内存布局的变化都可能导致与硬件通信失败。使用 attribute((packed)) 修饰的结构体,编译器会压缩存储,不考虑自然对齐要求。
于是进行32位指针化时错误就发生了。
解决方案有多种,反正都是ai给的,我只说说能编译的。
第一个,获取的时候计算成员地址。
volatile uint32_t * interruptList = (volatile uint32_t *)((uint32_t)hDriver->hcHCCA + offsetof(USB_OHCI_HCCA, hccaInterruptTable));
方案特点:
- 保持了结构体的 packed 布局(与硬件兼容)
- 使用 offsetof 宏安全计算成员地址,避免未对齐访问
- 不改变硬件通信区域的内存布局,确保系统稳定性
- 是处理packed结构体成员访问的标准做法
第二种修改结构体成员 hccaInterruptTable 的对齐属性,给它单独添加修饰符
typedef struct __attribute__((packed)) USB_OHCI_HCCA
{volatile uint32_t hccaInterruptTable[32] __attribute__((aligned(4)));volatile uint16_t hccaFrameNumber;volatile uint16_t hccaPad1;volatile uint32_t hccaDoneHead;volatile uint8_t reserved[116];} USB_OHCI_HCCA;
既能保留结构体其他成员的紧凑排列(packed 作用),又能强制该成员 4 字节对齐,彻底消除警告。
此外还有些需要特定编译器(gcc等,但我这是microchip的xc32编译器,我就不试了)
目前我选择第二个方案,单独给数组成员hccaInterruptTable添加修饰符使其对齐4k。能编译就行。
吐槽,这个是芯片官方框架提供的usb驱动的最新版本,当然我看了下前几个版本也是这个样子的。也不知道他们是怎么编译通过然后上传的。
如果是因为他们内部开发人员用的付费版编译器,那我真是无语了。
还有这个驱动能编译了也不代表能用,目前压根初始化不了,调试发现就是卡死在这个host layer 的初始化阶段。慢慢再继续给阿三擦屁股吧。