Content originally posted in LPCWare by wellsk on Tue Feb 26 10:43:00 MST 2013
>Q1) Is it the case that the only way to change the MDC frequency is thru these control bits and by adjusting the CPU clock?
Yes, the MII clock is based on (only) the M3/M4 ethernet register clock, which is the same as the CPU clock rate (which uses the base clock for BASE_M3/M4_CLK setup in the CGU). Ideally, that MII clock rate should be under 2.5MHz, so a 204MHz CPU clock would require a divider of about 82, but 104 (the closest) would work to give a MII clock rate of about 1.96MHz.
Q2) Adjusting the CPU clk has some limitations (11.2.1.1 in the usr manual) when increasing frequency. Is there further info on exactly the limitations, please? I.e. is this a PLL issue or a clock-tree issue? So, is it always OK to switch CPU clk back and forth, say between PLL1 and IRC? This is an important consideration for us more in low power than MDIO function, of course.
When switching the CPU rate from the oscillator (or IRC) to the PLL, the PLL needs to be setup at 100MHz first and then the maximum rate (above 100MHz). This isn't really a PLL issue, but it allows the internal regulator to ramp up correctly. The code is below.
<code>
/* Switch main system clocking to crystal */
Chip_Clock_EnableCrystal();
Chip_Clock_SetBaseClock(CLK_BASE_MX, CLKIN_CRYSTAL, true, false);
/* Setup PLL for 100MHz and switch main system clocking */
Chip_Clock_SetupMainPLLHz(CLKIN_CRYSTAL, CRYSTAL_MAIN_FREQ_IN, 100 * 1000000, 100 * 1000000);
Chip_Clock_SetBaseClock(CLK_BASE_MX, CLKIN_MAINPLL, true, false);
/* Setup PLL for maximum clock */
Chip_Clock_SetupMainPLLHz(CLKIN_CRYSTAL, CRYSTAL_MAIN_FREQ_IN, MAX_CLOCK_FREQ, MAX_CLOCK_FREQ); // MAX_CLOCK_FREQ = 204000000
</code>
If you cycle the CPU between IRC rate (12MHz) and PLL rate (204MHz) and you want to keep the MII clock as close to 2.5Hhz as possible, you'll need to adjust the MII divider with the clock change (although running at a slower rate should probably be ok).
If you plan on keeping the ethernet interface active (transmit and/or receive) when adjusting CPU clocking, I would avoid adjusting the PLL at run-time when the CPU is using as it can halt the CPU (and buses) waiting for PLL lock. If ethernet is moving data during this lock wait period, the packets could be dropped/lost or you may get ethernet overrun/underrun errors. Instead, you might setup the PLL are 204MHz and keep it there and route the CPU base clock (and ethernet MII clock) via a divider something like this. This will allow clean clock transitiio ns
<code>
Chip_Clock_EnableCrystal();
Chip_Clock_SetBaseClock(CLK_BASE_MX, CLKIN_CRYSTAL, true, false);
/* Setup PLL for maximum clock */
Chip_Clock_SetupMainPLLHz(CLKIN_CRYSTAL, CRYSTAL_MAIN_FREQ_IN, MAX_CLOCK_FREQ, MAX_CLOCK_FREQ); // MAX_CLOCK_FREQ = 204000000
/* Setup a divider for about 100MHz operation (divide by 2 from main PLL) */
Chip_Clock_SetDivider(CLK_IDIV_B, CLKIN_MAINPLL, 2);
/* Route CPU clock from main osc (crystal) to divider B to get 102MHz rate on CPU */
Chip_Clock_SetBaseClock(CLK_BASE_MX, CLKIN_IDIVB, true, true);
for (i = 0; i < 250; i++); // Very small delay to allow power up
/* Setup divider for 1 for CPU rate of 204MHz */
Chip_Clock_SetDivider(CLK_IDIV_B, CLKIN_MAINPLL, 1);
...
...
...
...
/* To switch to a lower CPU rate, do this. Divider B can go up to divide by 16 */
Chip_Clock_SetDivider(CLK_IDIV_B, CLKIN_MAINPLL, 16); // CPU clock rate = 204/16 = 12.75MHz
...
...
...
...
/* When ramping back up to 204Mhz, do this ... */
Chip_Clock_SetDivider(CLK_IDIV_B, CLKIN_MAINPLL, 2);
for (i = 0; i < 250; i++); // Very small delay to allow power up
/* Setup divider for 1 for CPU rate of 204MHz */
Chip_Clock_SetDivider(CLK_IDIV_B, CLKIN_MAINPLL, 1);
</code>