Hey All -
I’ve been having issues getting ethernet initialized on my Olimex LPC2378-STK REV C dev board, which uses a Micrel KS8721BT PHY. I’m not even to the point of worrying about rx/tx descriptors or sending packets. I can’t read the PHY ID, though I have in the past, sporadically. My code is just taken directly from the uIP webserver demo at http://sourceforge.net/projects/freertos/files/ and fixed up for differing #define names.
I’m hoping someone could look over the ethernet_setup function and tell me if they spot something wrong.
Some other things I would like to know:
-
I am running at 72Mhz. Any reason this wouldn’t work (something about phy_ref_clk)?
Does the PHY clock divider (MCFG register) scale down the core clock, or the on-board 12-Mhz clock? I think the scaled clock is supposed to be under 2.5 Mhz.
There seems to be 3 logical blocks (MAC, MAC block configuration) on the micro-controller, and the PHY which must be configured via RMII. The configuration order is unclear to me. Decent documentation?
uint16_t read_phy(uint32_t register_number)
{
unsigned int tout;
*(MADR) = PHY_ADDRESS | register_number;
*(MCMD) = MCMD_READ;
/* Wait until operation completed */
tout = 0;
for (tout = 0; tout < MII_WRITE_TIMEOUT_COUNT; tout++) {
if ((*(MIND) & MIND_BUSY) == 0) {
uint16_t result = *(MRDD);
*(MCMD) = 0;
return result;
}
}
assert(false);
}
void write_phy(uint32_t register_number, uint16_t value)
{
unsigned int tout;
*(MADR) = PHY_ADDRESS | register_number;
*(MWTD) = value;
/* Wait until operation completed */
tout = 0;
for (tout = 0; tout < MII_WRITE_TIMEOUT_COUNT; tout++) {
if ((*(MIND) & MIND_BUSY) == 0) {
return;
}
}
assert(false);
}
void ethernet_setup()
{
// Power the ethernet block and clock
*(PCONP) |= PCONP_PCENET;
sleep(7200000);
// Select the pin input/output sources
// ...
// Here I set PINSEL2 = 0x50150105, PINSEL3 = 0x00000005
// ...
// I disable pull-up/down resistors on all the ethernet ports
// I have a newer chip revision, so I don't worry about OLD_EMAC_MODULE
// and P1.6
/* Reset all EMAC internal modules. */
*MAC1 = MAC1_RESET_TX | MAC1_RESET_MCS_TX | MAC1_RESET_RX | MAC1_RESET_MCS_RX | MAC1_SIMULATION_RESET | MAC1_SOFT_RESET;
*Command = Command_RegReset | Command_TxReset | Command_RxReset;
/* A short delay after reset. */
sleep( 7200000 );
/* Initialize MAC control registers. */
*MAC1 = MAC1_PASS_ALL_RECEIVE_FRAMES;
*MAC2 = MAC2_CRC_ENABLE | MAC2_PAD_CRC_ENABLE;
*MAXF = MAXF_MAXIMUM_FRAME_LENGTH;
*CLRT = CLRT_DEFAULT;
*IPGR = IPGR_DEFAULT;
// Original comment: /* Enable Reduced MII interface. */
// Doesn't make sense. Wrong register.
*Command = Command_PassRuntFrame;
/* Reset Reduced MII Logic. */
*SUPP = SUPP_SPEED_BIT;
*SUPP = 0;
/* Put the DP83848C in reset mode */
write_phy (PHY_BASIC_CONTROL, 0x8000);
write_phy (PHY_BASIC_CONTROL, 0x8000);
/* Wait for hardware reset to end. */
int tout = 0;
int regv;
for (tout = 0; tout < 100; tout++) {
sleep( 7200000 );
regv = read_phy (PHY_BASIC_CONTROL);
if (!(regv & 0x8000)) {
assert(regv != 0xffff);
/* Reset complete */
break;
}
}
int id1 = read_phy(PHY_ID1);
int id2 = read_phy(PHY_ID2);
while(1);
}