STM32H750 + USB3300 | No signals on ULPI
Hi guys, i am at a complete loss; even with describing the problem.
- I have a 6-layer board with the USB3300 directly underneath the H750(100Pin LQFP), so traces are short and basically optimal.
- I use CubeMX to generate an example -> I use MCO2 as 24MHz source for the USB3300, eveything in the H750 is working at 96MHz. The clocks are derived from PLL fed by HSE.
- After enabling MCO2 i wait for several milliseconds in order to let the PLL of the USB3300 stabilize and generate the 60MHz ULPI clock.
- the Reset-pin of the USB3300 is low.
My main problem (initially) was, that the USB-Lines are not becoming active after a call to USB_DevConnect - i would have expected to see the PullUp on the D+ line (using Fullspeed as a start).
Now, everthing with the USB3300 seems touchy as hell. Cant put words to it...
Within the USB_CoreInit function there is a call to USB_CoreReset. Sometimes this locks up the USB3300 completely (the 60MHz clock stops) and sometimes it works. Sometimes if I call USB_CoreReset twice, then it works.. whatever.
Then i try the basics. Reading a register from the USB3300. I found those functions mentioned here in the forum USB_ULPI_Write and USB_ULPI_Read. Disregarding the fact that they are completely undocumented, i cannot get them to work anywhere in the code.
#define USBULPI_PHYCR ((uint32_t)(0x40040000 + 0x034))
#define USBULPI_D07 ((uint32_t)0x000000FF)
#define USBULPI_New ((uint32_t)0x02000000)
#define USBULPI_RW ((uint32_t)0x00400000)
#define USBULPI_S_BUSY ((uint32_t)0x04000000)
#define USBULPI_S_DONE ((uint32_t)0x08000000)
#define USB_OTG_READ_REG32(reg) (*(__IO uint32_t *)(reg))
#define USB_OTG_WRITE_REG32(reg,value) (*(__IO uint32_t *)(reg) = (value))
uint32_t USB_ULPI_Read(uint32_t Addr)
{
__IO uint32_t val = 0;
__IO uint32_t timeout = 1000; /* Can be tuned based on the Clock or etc... */
__IO uint32_t bussy = 0;
USB_OTG_WRITE_REG32(USBULPI_PHYCR, USBULPI_New | (Addr << 16));
val = USB_OTG_READ_REG32(USBULPI_PHYCR);
while (((val & USBULPI_S_DONE) == 0) && (timeout--))
{
val = USB_OTG_READ_REG32(USBULPI_PHYCR);
bussy = val & USBULPI_S_BUSY;
}
val = USB_OTG_READ_REG32(USBULPI_PHYCR);
return (val & 0x000000ff);
}
/**
* @brief Write CR value
* @param Addr the Address of the ULPI Register
* @param Data Data to write
* @retval Returns value of PHY CR register
*/
uint32_t USB_ULPI_Write(uint32_t Addr, uint32_t Data) /* Parameter is the Address of the ULPI Register & Date to write */
{
__IO uint32_t val;
__IO uint32_t timeout = 100; /* Can be tuned based on the Clock or etc... */
__IO uint32_t bussy = 0;
USB_OTG_WRITE_REG32(USBULPI_PHYCR, USBULPI_New | USBULPI_RW | (Addr << 16) | (Data & 0x000000ff));
val = USB_OTG_READ_REG32(USBULPI_PHYCR);
while (((val & USBULPI_S_DONE) == 0) && (timeout--))
{
val = USB_OTG_READ_REG32(USBULPI_PHYCR);
bussy = val & USBULPI_S_BUSY;
}
val = USB_OTG_READ_REG32(USBULPI_PHYCR);
return 0;
}I added a check for the Busy-Bit for the purpose of debugging. Well.. this bit never is cleared once.
The only time i see something on my oscilloscope is when USB_CoreReset is called. (and the signals look fine in my optinion)
However when I use the fact that i see life for a short moment:
//...in USB_CoreInit
ret = USB_CoreReset(USBx);
volatile unsigned read = 0;
while(1)
{
USB_ULPI_Write(0x16, 0x55); //USB3300 scratch register
read = USB_ULPI_Read(0x16);
HAL_Delay(1);
}
//...Exactly NOTHING happens at the ULPI-Pins. Not a single pins toggles.
And yes, for the ULPI-gurus among you, the DIR-signal is LOW, so the USB3300 should be able to handle requests.
I tried the Write-Read-Loop else where in the code, no success either.
As said, i am at a complete loss. This is nothing more than pure CubeMX-Code with an additional delay for USB3300-Clock-Startup and then my debugging stuff in between.
I dont know why the ULPI-Interface is not even trying. I am not even complaining about no enumeration.. it is much more fundamentally broken.
And i also dont understand why the most basic functions, like reading PHY-Registers, arent properly documented. But thats another topic. And yes, i tried reading different registers (like product ID) but it always return busy.
Any ideas what to check next?
