This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TMS320F28P650DK:USB 外设本身进入器件模式

Guru**** 2325120 points
Other Parts Discussed in Thread: SYSCONFIG, C2000WARE, TMS320F28069
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1501544/tms320f28p650dk-usb-peripheral-enters-device-mode-by-itself

器件型号:TMS320F28P650DK
Thread 中讨论的其他器件:SysConfigC2000WARETMS320F28069

工具/软件:

我尝试让 USB MSC 主机应用程序运行原型硬件。
我在硬件上成功运行了"usb_msc_host_ex7"示例、只做了少量修改(时钟设置、引脚分配等)。 我可以连接闪存驱动器、程序会枚举它并装载 FAT 文件系统。
当我尝试从 CPU2而不是 CPU1与 USB 进行交互时、问题就会开始。 USB 外设看起来自发退出主机模式并进入设备模式、然后一直保持该状态。

我尝试对示例代码进行少量更改。 在 SysConfig 中为 CPU2设置了 USB 外设+库。

CPU1伪代码:
-运行 device_init ()、board_init ()等来设置时钟和其他硬件。
-运行"SysCtl_selectCPUForPeripheralInstance(SysCtl_CPUSEL_USBA, SysCtl_CPUSEL_CPU2 );"将 USB 外设控制传输至 CPU2。
-引导 CPU 2并要求它开始初始化(通过 IPC 标志)。
-等待 CPU 2完成初始化(通过 IPC 标志)。
-启用中断并启动主循环。

CPU2伪代码:
-等待 CPU 1指示我们开始初始化。
-运行 device_init ()、board_init ()等
-运行 C2000ware_libraries_init ()。 值得注意的是、这也称为"USBStackModeSet (0、eUSBModeForceHost、ModeCallback);"、因为 SYSCTL 知道我们要在主机模式下运行。
-告诉 CPU1我们完成了初始化(通过 IPC 标志)。
-启用中断并启动主循环。 主循环调用 USBHCDMain ()(从 usbhost.h )并监控状态。

具体情况如下:
1.系统启动成功。 此时、USBDEVCTL 寄存器包含 DEV=0、HOST=0且 FSDEV=0。
2.一旦启用中断、USB_INTCTRL_MODE_DETECT 中断就会熄灭。 除了 USBIDVISC=1之外、没有任何变化。 主循环开始运行。
3.插入闪存盘。 USB_INTCTRL_CONNECT 中断会关闭。 此时、USBDEVCTL 寄存器包含 DEV=0、HOST=1、FSDEV=1。
4.主循环调用 USBHCDMain (),可以看到设备已连接。 USBHCDMAIN()调用 USBHCDReset()以复位器件。
5. USB_INTCTRL_RESET 中断发出。 此时、USBDEVCTL 寄存器包含 DEV=1、HOST=0、FSDEV。 USB 控制器已确定它不再是主机、现在是设备。
     ——请注意,在 ISR 启动时 USBDEVCTL 已经发生了变化,所以 ISR 不能引起这个问题。
     ——请注意,这种情况发生在主上下文甚至从 USBHCDReset ()返回之前。
6.同时,USBHCDMain ()继续通过其状态机运行。 它启动控制传输以检索设备描述符、但控制传输会一直挂起、因为 USB 控制器认为它处于设备模式。 断开并连接闪存驱动器不再触发中断。

通读本文档后、我很难理解 USB 控制器如何决定处于哪种模式。 这似乎是一个动态过程、具体取决于 D+和 D-引脚的状态、以及(不存在) ID 和 Vbus 检测引脚的状态。 是否有人知道总线复位后为什么外设可能自行设置为器件模式? 另一张海报 过去似乎也有同样的问题、采用了 TMS320F28069。

谢谢!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、

    如您所述、器件或主机模式检测取决于 USB 信号。  

    您是否知道导致复位中断发生的是什么?  此外、如果仅在 CPU1内核上运行此操作、是否会看到相同的行为?

    此致

    Siddharth  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    "设备或主机模式检测取决于 USB 信号"
    是否有更多关于这方面的具体文档? 我称之为"USBStackModeSet (0、eUSBModeForceHost、ModeCallback)"--所以不管 USB 信号如何、我都希望外围设备保持在主机模式下。 C2000ware USB 库显然也没有期待这种行为、因为它会卡在等待控制事务完成的无限循环中、并且不会重新检查 USBDEVCTL 寄存器。
    外围设备最初设计为使用硬件 ID 和 VBUS 信号、但这些信号在该芯片上不存在--那么它如何决定处于哪种模式? 哪些情况会触发切换到器件模式?

    "您知道什么导致了复位中断发生?"
    中断立即发生在:
    USBHCDMain ()-> ProcessUSBDeviceStateMachine ()-> USBHCDReset ()-> USBHostReset (USB_BASE、1)
    总线复位是正常枚举过程的一部分。 但是、在一个工作示例中、它不会触发 RESET 中断。

    "此外、如果您仅在 CPU1内核上运行此操作、是否会看到相同的行为?"
    编号 如果我在同一硬件上仅使用 CPU1、USB 似乎工作正常。 当我插入闪存驱动器时、程序会成功枚举并装载文件系统。

    感谢您抽出宝贵的时间来了解此内容!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、  

    很抱歉、回复延迟。

     USB 主机通过检测两条 USB 数据线(D+/D-)的状态来检测 USB 从器件。  USB 主机将 D+和 D-数据线拉低、而全速 USB 器件将 D+线路拉高、低速 USB 器件将 D-线路拉高。  一旦其中一条数据线被上拉、它就会假定已连接新器件。 这符合 USB 协议规范。

    USB 库假定 USB 外设在设置后保持在主机模式。 但是、与上面指定的某些条件可能会导致器件在主机之间切换模式。  

    我仍然不知道为什么两个 CPU 之间的行为不同。  是否可以记录 USB 中断标志并比较两个 CPU 之间的序列。  此外,如果您可以共享 USB 配置的代码片段,我将看看它,看看是否缺少任何内容。

    此致

    Siddharth

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    如果我正确理解您、USB 外设和库的架构会让我有点担心。 假设:
    1.一切正常(即,当前问题得到解决),并且在正常情况下,闪存驱动器安装成功。
    2. D+和 D-线路由于某种原因被拉低(水分进入,客户插入不符合要求的设备,EMI 等)。
    在这种情况下、USB 外设似乎会自动切换到设备模式、USB 库会卡住、我们的固件将崩溃。 这是正确的吗? 如果是、这不一定是一个大问题、但我们最好考虑一下。

    "您是否可以记录 USB 中断标志并比较两个 CPU 之间的序列"
    是的。 我运行了一个测试、修改了 USB0HostIntHandler (usbhostenum.c)以记录 USBIntStatus()的输出。
    CPU1 (工作):
    USB_INTCTRL_MODE_DETECT (一旦启用中断、就会发生这种情况)
    USB_INTCTRL_CONNECT (连接闪存驱动器时)
    USB_INTCTRL_SOF (对器件描述符请求控制传输的响应)
    ...然后随着枚举的继续、还有更多 USB_INTCTRL_SOF 中断。

    CPU2 (断开):
    USB_INTCTRL_MODE_DETECT (一旦启用中断、就会发生这种情况)
    USB_INTCTRL_CONNECT (连接闪存驱动器时)
    USB_INTCTRL_RESET (当程序处于对 USBHCDReset ()的调用内部时发生(usbhostenum.c))

    代码片段:
    main_cpu1.c

    void main(void)
    {
        // Initialize device clock and peripherals
        Device_init();
    
        // Initialize GPIO and configure the GPIO pin as a push-pull output
        Device_initGPIO();
        
        // Transfer USB peripheral to CPU2
        SysCtl_selectCPUForPeripheralInstance(SYSCTL_CPUSEL_USBA, SYSCTL_CPUSEL_CPU2);
        GPIO_setControllerCore(42, GPIO_CORE_CPU2);
        GPIO_setControllerCore(43, GPIO_CORE_CPU2);
     
        // Initialize PIE and clear PIE registers. Disables CPU interrupts.
        Interrupt_initModule();
    
        // Initialize the PIE vector table with pointers to the shell Interrupt
        // Service Routines (ISR).
        Interrupt_initVectorTable();
    
        // Initialize settings from SysConfig
        Board_init();
        C2000Ware_libraries_init();
        
        // Boot CPU2 core
        // Sync CPUs before starting the main loop.
        IPC_clearFlagLtoR(IPC_CPU1_L_CPU2_R, IPC_FLAG_ALL);
        Device_bootCPU2(BOOT_MODE_CPU2);
        // Start booting CPU 2
        IPC_sync(IPC_CPU1_L_CPU2_R, IPC_SYNC);
        // Wait for CPU 2 to finish booting
        IPC_sync(IPC_CPU1_L_CPU2_R, IPC_SYNC);
    
        // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
        EINT;
        ERTM;
    
        //
        // Loop Forever
        //
        for(;;)
        {       
        }
    }

    MAIN_CPU2.c
    void main(void)
    {
    
        // Sync CPUs before starting the main loop
        IPC_clearFlagLtoR(IPC_CPU2_L_CPU1_R, IPC_FLAG_ALL);
        IPC_sync(IPC_CPU2_L_CPU1_R, IPC_SYNC);
    
        // Initialize device clock and peripherals
        Device_init();
    
        // Initialize PIE and clear PIE registers. Disables CPU interrupts.
        Interrupt_initModule();
    
        // Initialize the PIE vector table with pointers to the shell Interrupt
        // Service Routines (ISR).
        Interrupt_initVectorTable();
    
        // Initialize settings from SysConfig
        Board_init(); 
    
        C2000Ware_libraries_init();
        USBPostInit();
        
        IPC_sync(IPC_CPU2_L_CPU1_R, IPC_SYNC);
    
        // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
        EINT;
        ERTM;
    
        // Loop Forever
        for(;;)
        {
            USBMain();
        }
    }

    usb_hal.c 在很大程度上合并了 usb_ex7_host_msc 示例中的 main.c 和 usb_hal.c 部分。
    一些相关片段:
    USBMain(void)
    {
        tState eStateCopy;
    
        //
        // See if a mass storage device has been enumerated.
        //
        if(g_eState == STATE_DEVICE_ENUM)
        {
            //
            // Take it easy on the Mass storage device if it is slow to
            // start up after connecting.
            //
            if(USBHMSCDriveReady(g_psMSCInstance) != 0)
            {
                //
                // Wait about 100ms before attempting to check if the
                // device is ready again.
                //
                SysCtl_delay(SysCtl_getClock(DEVICE_OSCSRC_FREQ)/30);
    
                return;
            }
    
            //
            // Reset the working directory to the root.
            //
            g_cCwdBuf[0] = '/';
            g_cCwdBuf[1] = '\0';
    
            //
            // Attempt to open the directory.  Some drives take longer to
            // start up than others, and this may fail (even though the USB
            // device has enumerated) if it is still initializing.
            //
            f_mount(0, &g_sFatFs);
            if(f_opendir(&g_sDirObject, g_cCwdBuf) == FR_OK)
            {
                //
                // The drive is fully ready, so move to that state.
                //
                g_eState = STATE_DEVICE_READY;
            }
        }
    
        //
        // Run the main routine of the Host controller driver.
        //
        USBHCDMain();
    }
    
    void USBPostInit(void)
    {
        // Register the host class drivers.
        USBHCDRegisterDrivers(0, g_ppHostClassDrivers, NUM_CLASS_DRIVERS);
    
        // Open an instance of the mass storage class driver.
        g_psMSCInstance = USBHMSCDriveOpen(0, (tUSBHMSCCallback)MSCCallback);
    
        // Initialize the file system.
        f_mount(0, &g_sFatFs);
    }
    
    __interrupt void
    INT_myUSB0_ISR(void)
    {
        USB0HostIntHandler();
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP9);
    }

    自动生成的 c2000ware_libraries.c 用于 CPU2:
    void C2000Ware_libraries_init()
    {
        USBLib_init();
    }
    
    
    uint8_t g_pui8HCDPool[myUSB0_LIB_HCD_MEMORY_SIZE];
    void USBLib_init(){
        //
        // Initialize the USB stack mode and pass in a mode callback.
        //
        USBStackModeSet(0, eUSBModeForceHost, ModeCallback);
        //
        // Initialize the power configuration.
        //
        USBHCDPowerConfigInit(0,USBHCD_VBUS_AUTO_HIGH | USBHCD_VBUS_FILTER);
        //
        // Initialize the USB controller for OTG operation with a 2ms polling
        // rate.
        //
        USBHCDInit(0,g_pui8HCDPool, myUSB0_LIB_HCD_MEMORY_SIZE);
    }

    如果您愿意、我也可以通过私人消息向您发送整个项目。 如果您需要任何其他信息、请告诉我。 谢谢!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、  

    该检测机制(对于高电平/低电平器件、D+/D-上拉电阻)是 USB 的预期行为。  如果您不希望连接任何器件、可能需要添加一些错误处理。  

    我看了一下您分享的代码。 看起来没关系。  我仍然不知道为什么 CPU 之间存在不同的序列、因为 USB 库/事件不是特定于 CPU 的。  

    此致

    Siddharth  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    好的--
    经过大量实验后、我发现以下内容:
    -这个问题( USB 外设切换到设备模式)实际上发生在 CPU1上,只是少得多。 相反、 CPU2上偶尔未出现问题。
    -使用低质量的 USB 闪存驱动器时,问题发生得更频繁(但不限于)。 即使在运行未修改的 USB 示例的开发套件上、同一闪存驱动器有时也无法枚举、但我无法重现开发套件上切换到设备模式的问题。
    -当我通过 Beagle USB 分析仪将闪存驱动器连接到我们的主板时、问题非常严重-在100多个连接/断开连接后、我只通过这种方式复制了一次。 即使我们的设计中的 D+和 D-线正确地从 MCU 直接到达端口、这也使我想知道我们的电路板和开发套件之间的差异是否只是一些杂散电容或沿着这些线的某个值。

    我想我也许可以通过使用 USBTEST 寄存器中的 FORCEH 位来缓解这个问题--然而、我似乎不能写它。 我可以写和读回低四个(保留)位、但无论我对它们执行什么操作、无论是在 USB 外设初始化之前还是之后写入它们、高四位看起来都读回为0。 我意识到该寄存器可能不是用于生产用途、但是否有任何使用示例(或者确实确认它甚至存在于最终版本硬件中)?

    还有--
    当硬件处于设备模式并且库期望它处于主机模式时、USB 库永远挂起在 USBHCDMain ()内。 鉴于硬件能够自主切换模式、而无需固件发出显式命令、我认为这可能是一种错误。 除了看门狗计时器或自己修改库之外、我无法保证不会发生这种情况并导致系统崩溃。