LPC2378 Ethernet Initialization

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:

  1. 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);
}