LPC4357 with external USB Phy

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

LPC4357 with external USB Phy

1,808 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by chris.bayley on Thu Jan 29 16:32:59 MST 2015
Has anyone had success using an external USB Phy with the 4357 ?

I have been working on this for a while, and following Application Note AN11309 I have configured the micro for an external transceiver on the ULPI bus.
Communication over the ULPI bus is established but the transceiver is not getting configured correctly.

In this thread royg describes a problem having the same symptoms on the 4350. His problems were addressed when the 4350 went from RevA to RevC although no acknowledgment of the problem was made in the errata.

I'll summarize the problem here but link to the full description and obseravtions as a PDF in my dropbox (also attached to this post) as the tabularized information seems diffcult to present here.

Background:
The LPC43xx Microcontrollers from NXP mostly all feature 2 High-Speed USB Controller logic units, however the these 2 controllers are furnished with 1 High-Speed on-chip Phy and 1 Full- Speed on-chip Phy. If the user wishes to employ 2 high-speed Phys then a second High-Speed Phy can be attached to selected MCUs in the family line via an industry standard ULPI bus. When appropriately configured the MCU will direct all USB traffic across the bus to the external Phy. Such configuration is detailed in the Application note AN11309 from NXP.
I am developing with a LPC4357-Xplorer++ kit from NGX Technologies complimented by a breakout board designed in house fitted with a USB3343 USB transceiver.
The LPC4357 MCU has been configured as per the application note and communication with the transceiver has been established, however normal USB communications are NOT yet working.
I am fairly confident that the MCU is properly configured for ULPI communications as we are able to read and write the internal registers of the attached Phy and the contents of those registers are as we expect from the data-sheet.

Observations:
The most immediate problem with the commencement of a USB connection is the the proper configuration of the USB bus pull-up/pull-down and termination resistors is not taking place and hence the USB device (the LPC dev board) is not being detected by the host.
I have been able to monitor the ULPI bus between the MCU and transceiver and log the transactions that occur there while the transceiver is configured for operation. A transaction log in the linked report shows that the transceiver is misconfigured for the desired operating mode.
The MCU has been configured to operate USB1 in High-Speed Device mode in which the pre-connection state requires D+ to be pulled up but we can see from the logs that D+ is in fact configured for Pull-Down, additionally we note that in fact the configuration of Pull-Up Pull-down and termination resistors meets the criteria of an invalid configuration as defined by the USB3343 data sheet and the behavior of the transceiver in that state is undefined.

Further Work:
Pending advice from NXP or other parties I will manually configure the ULPI registers in the Phy setting the pull-ups and termination resistors into valid state and hope that the LPC's USB controller can be coaxed into life.

Feedback:
I can be contacted via my contact page or via the email given in the report
Labels (1)
0 Kudos
6 Replies

1,193 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mc on Thu Mar 19 08:43:00 MST 2015
Hi Chris,
That's really a good news.
0 Kudos

1,193 Views
jean-marcrouxel
Contributor I

Hello,

I’m Jean-Marc and I’m working as firmware engineer for an optical transport company. I’m working on a board with a LPC4337 and an external PHY USB USB3300  connected to the USB1 port. For the moment, I’m using the USB1 as a device port connected to my computer. The computer just detects the new device but can’t identify it.

I succeed to read/write PHY registers with the ULPI interface so I suppose my ULPI configuration is good. I’m trying to adapt my firmware with your recommendations, but without success.

Did you have some informations to this issue by NXP since 2016 ? Could you exactly send me your sequences of commands to the PHY registers, please ? Sorry to bother you with these old issues. Jean-Marc

0 Kudos

1,193 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by chris_bayley_trimble on Tue Mar 17 15:20:11 MST 2015
SOLVED:

Well a bit of an anti climax really but a thing of great relief:

In our case it all came down to the resistor on the VBus line between the connector and the Phy. The application note shows it to be a 1K fitted for USB device and open for Host. In our case we had a 20k fitted for an OTG situation.
I have changed it to 1K and Device is now working. I haven't yet tested the other modes.

Thanks to everyone who helped

BR
Chris.
0 Kudos

1,193 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by chris_bayley_trimble on Mon Feb 09 17:20:48 MST 2015
* It would be very helpful to see the register contents of your phy once  USBD_API->hw->Init() has run.

The code below makes that easy:
#define _BIT(n) (1 << (n))
#define ULPIWU _BIT(31)
#define ULPIRW _BIT(29)
#define ULPIRUN _BIT(30)
#define ULPISS _BIT(27)
#define ULPIADDR(x) (uint32_t)((x) << 16 )
#define ULPIDATRD(x) (uint8_t)((x) >> 8 & 0xff)

inline bool UlpiIsReady()
{
return ( LPC_USB1->ULPIVIEWPORT & ULPISS );
}
inline void UlpiWakeUp()
{
LPC_USB1->ULPIVIEWPORT = 0x0 | ULPIWU;
while ( (LPC_USB1->ULPIVIEWPORT & ULPIWU) ) {}; // wait for wake up
}
inline uint8_t UlpiRegRead(uint8_t regAddr )
{
uint32_t tmp = ULPIADDR(regAddr) | ULPIRUN;
LPC_USB1->ULPIVIEWPORT = tmp;
while ( LPC_USB1->ULPIVIEWPORT & ULPIRUN ) {}; //wait for completion
return ULPIDATRD(LPC_USB1->ULPIVIEWPORT);
}
inline void UlpiRegWrite(uint8_t regAddr, uint8_t data)
{
LPC_USB1->ULPIVIEWPORT = ULPIADDR(regAddr) | data | ULPIRW | ULPIRUN;
while ( LPC_USB1->ULPIVIEWPORT & ULPIRUN ) {}; //wait for completion
return ULPIDATRD(LPC_USB1->ULPIVIEWPORT);
}

uint8_t ulpiRegs[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x07, 0x0A, 0x0D, 0x10, 0x13, 0x14, 0x15, 0x16, 0x19, 0x1D, 0x20, 0x21, 0x31, 0x32, 0x33, 0x36, 0x39 };
uint8_t regVals[sizeof(ulpiRegs)];
unsigned inti;

if ( ! UlpiIsReady() )
UlpiWakeUp();

for (i=0;i < sizeof(ulpiRegs);i++)
{
regVals = UlpiRegRead(ulpiRegs);
}
for (i=0;i < sizeof(ulpiRegs);i++)
{
printf("UlpiReg[0x%02X]=0x%02X\n",ulpiRegs,regVals);
}




-----
BR
Chris
0 Kudos

1,193 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by chris_bayley_trimble on Mon Feb 09 17:16:43 MST 2015
Hi Mahesh, thank you for your support.

As you say there is the chance that it is a layout issue and I hope that that is so since after software that is the next easiest thing to fix.

* We have the ULPI configured on slightly different pins to your board but here is the pin mux config and the ULPI setup we are using:

STATIC const PINMUX_GRP_T usb1pinmuxing[] = {
/* USB1-ULPI pin group */
{0x8, 5, (SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_FUNC1)}, // ULPI_D0
{0x8, 4, (SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_FUNC1)}, // ULPI_D1
{0x8, 3, (SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_FUNC1)}, // ULPI_D2
{0xB, 6, (SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_FUNC1)}, // ULPI_D3
{0xB, 5, (SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_FUNC1)}, // ULPI_D4
{0xB, 4, (SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_FUNC1)}, // ULPI_D5
{0xB, 3, (SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_FUNC1)}, // ULPI_D6
{0xB, 2, (SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_FUNC1)}, // ULPI_D7

{0x8, 6, (SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_FUNC1)}, // ULPI_NXT
{0xB, 1, (SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_FUNC1)}, // ULPI_DIR
{0x8, 7, (SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_FUNC1)}, // ULPI_STP
{0x8, 8, (SCU_MODE_HIGHSPEEDSLEW_EN | SCU_MODE_INACT | SCU_MODE_INBUFF_EN | SCU_MODE_ZIF_DIS | SCU_MODE_FUNC1)}, // ULPI_CLK
};

void Ulpi_USB1_Init(void)
{
    uint32_t  portsc;

    /* Setup and enable the PLL else we cant't access the USB Clock registers !! */
    Chip_Clock_EnableBaseClock(CLK_BASE_USB1);

    /* disable USB1_CLOCK, it's clock will be provided by the PHY */
    LPC_CCU1->CLKCCU[CLK_USB1].CFG &= ~1;
   
    /* ULPI pin setup is done prior to setting up clocking */
    Chip_SCU_SetPinMuxing(usb1pinmuxing, sizeof(usb1pinmuxing) / sizeof(PINMUX_GRP_T));

    /* switch to ulpi phy and turn on the power to phy*/
    // Clear PFSC (bit24) to prevent the port from forcing a high speed connection
    portsc = LPC_USB1->PORTSC1_D & 0x00FFFFFF;
    //portsc |= _BIT(24); // force full speed connection OR
    portsc &= ~_BIT(24); // clear PFSC to allow any speed connect
    portsc |= 0x80000000; // PTS select, bit 31:30, 0x2 = ULPI
    LPC_USB1->PORTSC1_D = portsc;

    /* reset the controller */
    LPC_USB1->USBCMD_D = _BIT(1);

    /* wait for reset to complete */
    while (LPC_USB1->USBCMD_D & _BIT(1));

    /* Program the controller to be the USB device mode */
    LPC_USB1->USBMODE_D =   0x02 | _BIT(3);
}

STATIC INLINE void Chip_SCU_SetPinMuxing(const PINMUX_GRP_T *pinArray, uint32_t arrayLength)
{
uint32_t ix;
for (ix = 0; ix < arrayLength; ix++ ) {
Chip_SCU_PinMuxSet(pinArray[ix].pingrp, pinArray[ix].pinnum, pinArray[ix].modefunc);
}
}
STATIC INLINE void Chip_SCU_PinMuxSet(uint8_t port, uint8_t pin, uint16_t modefunc)
{
LPC_SCU->SFSP[port][pin] = modefunc;
}

We are using LPCOpen in LPCXpresso so the macro definitions and function call names are different to those of the Keil project for AN11309 but the effect should be the same.

I have formed the belief that the pinmuxing is ok because I can read and write the internal registers of the Phy over the ULPI bus.

* I am running the code to the point where USB1 is configured as HS device using the external phy and waiting for a host connection. I then plug in the host cable. At no point is any voltage seen on DP or DM as no pull-ups are configured.

As you say during the second ULPI there is an anomalous dir assertion which may be due to a layout issue, if however that write command had been successful and set TermSelect = 1, the next command is successful and sets TermSelect=0. In the third trace when USBD_API->hw->Init() is called TermSelect=0 is set once more.

* Our parts are marked:

LPC4357FET256
PMB609.00
ESD13130-

* Schematics for our ULPI break out board and the NGX dev kit are attached.



-----------
BR
Chris
0 Kudos

1,193 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by mc on Sun Feb 08 22:11:00 MST 2015
Hi Chris,
Thanks for extensive investigation.
I do not have PHY USB3343, however, I tested both flash and flashless devices with ISP1507BBS PHY without problem. It has been tested successfully on below revision of devices.


LPC4350 RevA
LPC4350 RevC
LPC4357 Rev -

LPC1850 RevA
LPC1850 RevC
LPC1857 Rev -

It could be layout  issue.

Could you please post code here?
Please also post device marking and schematic?

In your ULPI traces the second set is executed when Run bit (bit 0) in the USBCMD_D register is set to 1.

In this trace, LPC4357 is probably trying to set TermSel bit to 1b.
But the anomalous dir assertion is preventing TermSel to be set to 1b.


In my board PHY is placed on same board, where as you are connecting PHY using wires/cables

Please see  pinmux settings below for ULPI clock, control and data signals in my project.

/* for ULPI */

    scu_pinmux(0x8, 8, MD_PLN | MD_EZI | MD_ZI | MD_EHS, FUNC1);   //ULPI_CLK
    scu_pinmux(0x8, 6, MD_PLN | MD_EZI | MD_ZI | MD_EHS, FUNC1);    //ULPI_NXT
    scu_pinmux(0x8, 7, MD_PLN | MD_EZI | MD_ZI | MD_EHS, FUNC1);  //ULPI_STP
    scu_pinmux(0xC, 11, MD_PLN | MD_EZI | MD_ZI | MD_EHS, FUNC1);  //ULPI_DIR
    scu_pinmux(0x8, 5, MD_PLN | MD_EZI | MD_ZI | MD_EHS , FUNC1);  //D0
    scu_pinmux(0x8, 4, MD_PLN | MD_EZI | MD_ZI | MD_EHS , FUNC1);  //D1
    scu_pinmux(0x8, 3, MD_PLN | MD_EZI | MD_ZI | MD_EHS , FUNC1);  //D2
    scu_pinmux(0xC, 5, MD_PLN | MD_EZI | MD_ZI | MD_EHS , FUNC1);  //D3
    scu_pinmux(0xC, 4, MD_PLN | MD_EZI | MD_ZI | MD_EHS , FUNC1);  //D4
    scu_pinmux(0xC, 3, MD_PLN | MD_EZI | MD_ZI | MD_EHS , FUNC0);  //D5
    scu_pinmux(0xC, 2, MD_PLN | MD_EZI | MD_ZI | MD_EHS , FUNC0);  //D6
    scu_pinmux(0xC, 1, MD_PLN | MD_EZI | MD_ZI | MD_EHS , FUNC0);  //D7
0 Kudos