Skip to main content
Visitor II
Sep 25, 2026 1:39 PM UTC
Question

External ULPI PHY extended register read

On STM32F7 OTG_HS with an external ULPI PHY, is there a supported way for firmware to issue an ULPI Extended Register Read/Write transaction?

The required ULPI sequences are:

Extended read:

  •     TX CMD 0xEF
  •     extended address byte
  •     read returned data

Extended write:

  •     TX CMD 0xAF
  •     extended address byte
  •     data byte

The undocumented PHYCR viewport at USB_OTG_HS + 0x34 used by STM32CubeF7 only appears to support ordinary single register accesses. Can PHYCR issue an extended ULPI transaction?

Thanks,

Alex

2 replies

ST Technical Moderator
Oct 26, 2026 5:05 PM UTC

Hi ​@alexfryer1 

I agree that this register was not documented. To investigate this further, an internal ticket has been opened with the dedicated team: CDM0066815 (internal access only).

To give better visibility on the answered topics, please click on "Best answer" on the reply which solved your issue or answered your question.Best regards,FBL
ST Technical Moderator
Oct 30, 2026 4:45 PM UTC

Hi ​@alexfryer1 again,

 

You can try the following example to test extended ULPI register access through the USB_OTG_HS PHYCR . The address and data below are examples; use an extended register supported by your PHY.

#define EXT_REG_ADDR 0x16 /* as example extended scratch*/
#define USB3320_TEST_PATTERN 0x5AU

/* Extended ULPI register access.
Replace these example placeholders with the target register address
and expected data from the PHY datasheet. */
if (USB_ULPI_ExtWrite(EXT_REG_ADDR, USB3320_TEST_PATTERN) == 0U)
{
Error_Handler(); /* Access timed out or did not complete */
}

regval = USB_ULPI_ExtRead(EXT_REG_ADDR);

if (regval != USB3320_TEST_PATTERN)
{
Error_Handler();
}

The helper functions below use the PHYCR to request the access. The bit definitions of extended register address is at position 8 :

/******************/

#define USBULPI_REGADDR_Pos 16U
#define USBULPI_EXTADDR_Pos 8U
#define USBULPI_EXTADDR_Msk (0x3FU << USBULPI_EXTADDR_Pos)
#define USBULPI_EXT_ACCESS (0x2FU << USBULPI_REGADDR_Pos)


uint32_t USB_ULPI_ExtRead(uint32_t ext_addr);
uint32_t USB_ULPI_ExtWrite(uint32_t ext_addr, uint32_t data);

uint32_t USB_ULPI_ExtRead(uint32_t ext_addr)
{
uint32_t val;
uint32_t timeout = 100U;

USB_OTG_WRITE_REG32(
USBULPI_PHYCR,
USBULPI_New |
USBULPI_EXT_ACCESS |
((ext_addr & 0x3FU) << USBULPI_EXTADDR_Pos));

do {
val = USB_OTG_READ_REG32(USBULPI_PHYCR);
} while (((val & USBULPI_S_DONE) == 0U) && (timeout-- != 0U));

return val & USBULPI_D07;
}

uint32_t USB_ULPI_ExtWrite(uint32_t ext_addr, uint32_t data)
{
uint32_t val;
uint32_t timeout = 100U;

USB_OTG_WRITE_REG32(
USBULPI_PHYCR,
USBULPI_New |
USBULPI_RW |
USBULPI_EXT_ACCESS |
((ext_addr & 0x3FU) << USBULPI_EXTADDR_Pos) |
(data & USBULPI_D07));

do {
val = USB_OTG_READ_REG32(USBULPI_PHYCR);
} while (((val & USBULPI_S_DONE) == 0U) && (timeout-- != 0U));

return (val & USBULPI_S_DONE) != 0U;
}

/******************/

 

To give better visibility on the answered topics, please click on "Best answer" on the reply which solved your issue or answered your question.Best regards,FBL