CY22393 Programmable Clock
Warning
Playing around with the clock chip on the Ethernut 3 Board is fun, but also bears the risk of destroying your hardware due to overclocking.
Overview
The CY22393 is a very versatile part. It can create three completely different frequencies from a single clock source like a simple crystal or a fixed clock oscillator. The different output frequencies are generated in three independant PLL circuits, each of which is configured by a programmable 11-bit multiplier and an 8-bit divider. This gives a really large variety of available output frequencies.
The PLL outputs are routed via a programmable cross point switch to additional programmable output dividers. As a special feature the chip offers three input pins, S0, S1 and S2, which can be used to select seven different configurations of PLL1 as well as two different values for the Clock A and B output dividers. S0 and S1 are sampled during powerr-up, while S2 can be used to change the settings while the clocks are running. Using S2 to change the output dividers of Clock A and B is guaranteed to be glitch free.
The latest data sheet should be available at www.cypress.com. It is essential to study this document before writing applications, which will modify the default clock settings.
Initial Programming
All clock settings can be programmed into the chip's internal Flash Memory. During power-up, the Flash is transfered to an on-chip RAM, which can be modified via I2C.
The chip is distributed with an empty Flash memory, which, when transfered into RAM during power-up, disables all clocks and puts all clock outputs to three-state mode. For the Ethernut Board this results in a special problem: No clock means no running CPU. No running CPU means, no possibility to modify the clock settings via I2C.
To initially program the Flash memory, a specific programming hardware is required:
- CY3672 Programmer Module
- CY3698 Socket Adapter
It is important to note, that the Flash memory on the chips must be programmed before mounting them on the target board. The Flash is not in-system-programmable.
egnite GmbH offers ready-to-run Ethernut 3 boards with pre-programmed clock chips, using these Jedec files:
-
ethernut3.0-rev-e.jed
for Ethernut 3.0 Rev-E -
ethernut3v3.jed
for Ethernut 3.0 Rev-D
The clock setting for the earlier Rev-D Boards is shown below.
On the Ethernut 3 Board the chip is driven by a 25 MHz crystal to generate the reference clock. Four clock outputs are used by default:
Clock Output | Ethernut 3.0 E | Ethernut 3.0 D |
---|---|---|
Clock A | To CPLD GCK1, initially disabled. The Nut/OS NPLMMC driver will re-program this output for MMC SPI clocking. | 25MHz to Ethernet Controller, independent of S2 settings. |
Clock B | 73.7272MHz to CPU, if S2 is driven high (default). Driving S2 low will change the frequency to 14.7455MHz without any glitches. | To CPLD GCK1, initially disabled. The Nut/OS NPLMMC driver will re-program this output for MMC SPI clocking. |
Clock C | 25MHz to Ethernet Controller, independent of S2 settings. | 73.7272MHz to CPU, if S2 is driven high (default). Setting S2 to low will change the output to 29.4912 MHz. Note that this switching is not guaranteed to be glitch free. |
Clock D | To CPLD GCK3, initially disabled. It can be activated by reconfiguring the clock chip via its I2C interface. |
The two remaining outputs, XBUF and Clock E, will available on Ethernut 3.0 Rev-D, when mounting R103 and R104 resp. However, in this case at least R3 must be removed and Clock E and D should never be both enabled. On newer Rev-E boards these outputs are not connected.
Clock wiring of Ethernut 3.0 Rev-E:
Clock wiring of Ethernut 3.0 Rev-D:
I2C Access
As stated earlier, the chip will copy its Flash memory into internal RAM during power-up. An I2C Interface is available to examine and even modify the RAM contents.
The I2C address of the CY22393 is 0x69 and the following code fragment can be used to query the number of the PLL that is connected to a specified clock.
#include <sys/event.h> #include <dev/twif.h> int Cy2239xGetPll(int clk) { int rc = -1; u_char loc = 0x0E; u_char reg; if (clk == 4) { rc = 1; } else if (TwMasterTransact(0x69, &loc, 1, ®, 1, NUT_WAIT_INFINITE) == 1) { rc = (reg >> (2 * clk)) & 0x03; } return rc; }
printf("Clock B on 3.0E uses PLL%d\n", Cy2239xGetPll(2));
CY2239X API
An application programming interface is provided for easy access to the clock configuration. Applications using this API must add the following header file include:
#include <dev/cy2239x.h>
u_long fref; fref = Cy2239xPllGetFreq(CY2239X_REF, 7);
The following sample displays all relevant settings.
/*! * Copyright (C) 2005-2006 by egnite Software GmbH. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the copyright holders nor the names of * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * For additional information see http://www.ethernut.de/ */ /*! * $Log$ */ #include <dev/board.h> #include <dev/debug.h> #include <dev/cy2239x.h> #include <stdio.h> #include <io.h> #include <sys/version.h> /* Determine the compiler. */ #if defined(__IMAGECRAFT__) #if defined(__AVR__) #define CC_STRING "ICCAVR" #else #define CC_STRING "ICC" #endif #elif defined(__GNUC__) #if defined(__AVR__) #define CC_STRING "AVRGCC" #elif defined(__arm__) #define CC_STRING "YAGARTO" #else #define CC_STRING "GCC" #endif #else #define CC_STRING "Compiler unknown" #endif #if !defined(ETHERNUT3) #warning Requires Ethernut 3 int main(void) { for (;;); } #else /* Formatting macros. */ #define MEGA(f) ((f) / 1000000UL) #define MFRACT(f) ((f) - (MEGA(f) * 1000000UL)) /* * Display frequency and status of a specified PLL. */ void DumpPll(char *name, int pll, int fctrl) { u_long f = Cy2239xPllGetFreq(pll, fctrl); printf("%-6.6s = %3lu.%06lu Mhz ", name, MEGA(f), MFRACT(f)); if (Cy2239xPllEnable(pll, fctrl, -1)) { puts("running"); } else { puts("disabled"); } } /* * Display frequency and status of a specified clock output. */ void DumpClk(char *name, int clk, int fctrl) { u_long f; int pll; int dv; f = Cy2239xGetFreq(clk, fctrl); printf("%-6.6s = %3lu.%06lu Mhz ", name, MEGA(f), MFRACT(f)); pll = Cy2239xGetPll(clk); if (pll > 0) { printf("PLL%d", pll); } else if (pll == 0) { printf("Ref"); } dv = Cy2239xGetDivider(clk, fctrl); if (dv) { printf("/%d\n", dv); } else { puts(" off"); } } /* * Main application routine. */ int main(void) { u_long baud = 115200; /* * Register the UART device, open it, assign stdout to it and set * the baudrate. */ NutRegisterDevice(&DEV_DEBUG, 0, 0); freopen(DEV_DEBUG_NAME, "w", stdout); _ioctl(_fileno(stdout), UART_SETSPEED, &baud); printf("\n\nPLL Configuration 1.0.0 - Nut/OS %s - " CC_STRING "\n\n", NutVersionString()); #if 0 /* Shows how to change the associated clock. */ if (Cy2239xSetPll(CY2239X_CLKB, CY2239X_PLL3)) { printf("SetPll failed\n"); } #endif #if 0 /* Shows how to change the divider value. */ if (Cy2239xSetDivider(CY2239X_CLKB, 1, 4)) { printf("SetDiv failed\n"); } #endif /* Dump reference and PLL clocks. */ DumpPll("Ref", CY2239X_REF, 7); DumpPll("PLL1.0", CY2239X_PLL1, 3); DumpPll("PLL1.1", CY2239X_PLL1, 7); DumpPll("PLL2", CY2239X_PLL2, 7); DumpPll("PLL3", CY2239X_PLL3, 7); putchar('\n'); /* Dump clock outputs. */ DumpClk("ClkA.0", CY2239X_CLKA, 3); DumpClk("ClkA.1", CY2239X_CLKA, 7); DumpClk("ClkB.0", CY2239X_CLKB, 3); DumpClk("ClkB.1", CY2239X_CLKB, 7); DumpClk("ClkC", CY2239X_CLKC, 7); DumpClk("ClkD", CY2239X_CLKD, 7); DumpClk("ClkE", CY2239X_CLKE, 7); putchar('\n'); for(;;); } #endif /* ETHERNUT3 */
PLL Configuration 1.0.0 - Nut/OS 4.1.9.7 - YAGARTO Ref = 25.000000 Mhz running PLL1.0 = 368.636319 Mhz running PLL1.1 = 368.636319 Mhz running PLL2 = 75.000001 Mhz disabled PLL3 = 75.000001 Mhz disabled ClkA.0 = 0.000000 Mhz Ref off ClkA.1 = 0.000000 Mhz Ref off ClkB.0 = 14.745452 Mhz PLL1/25 ClkB.1 = 73.727263 Mhz PLL1/5 ClkC = 25.000000 Mhz Ref/1 ClkD = 0.000000 Mhz Ref off ClkE = 0.000000 Mhz PLL1 off
Running on Rev-D boards will produce this output:
PLL Configuration 1.0.0 - Nut/OS 4.1.9.7 - YAGARTO Ref = 25.000000 Mhz running PLL1.0 = 147.457622 Mhz running PLL1.1 = 368.636319 Mhz running PLL2 = 100.000001 Mhz running PLL3 = 75.000001 Mhz running ClkA.0 = 25.000000 Mhz PLL2/4 ClkA.1 = 25.000000 Mhz PLL2/4 ClkB.0 = 0.000000 Mhz PLL2 off ClkB.1 = 0.000000 Mhz PLL2 off ClkC = 73.727263 Mhz PLL1/5 ClkD = 0.000000 Mhz PLL1 off ClkE = 0.000000 Mhz PLL1 off
More details about this and all other functions of the CY2239X API are available in the Nut/OS API Documentation.