Ethernut Home Hardware Firmware Tools Download Community
 
 
Search | Legals | Deutsch

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.

CY39x Internals

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:

These items can be purchased online from Cypress Semiconductor Corp..

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:

These files have been created by CyClocksRT R3.10.00 utility, which is freely available at www.cypress.com and runs on the Win32 PCs. Here is a screenshot of the CyClocksRT Software after loading the Ethernut 3.0 Rev-E Jedec File.

CyClocksRT Rev-E

The clock setting for the earlier Rev-D Boards is shown below.

CyClocksRT

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:

Ethernut 3.0 Rev-E Clock Schema

Clock wiring of Ethernut 3.0 Rev-D:

Ethernut 3.0 Rev-D Clock Schema

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, &reg, 1, NUT_WAIT_INFINITE) == 1) {
        rc = (reg >> (2 * clk)) & 0x03;
    }
    return rc;
}
Calling this function on Ethernut 3.0 Rev-E for Clock B or on Ethernut 3.0 Rev-D for Clock C (Main CPU Clock) should return the value 1 (PLL1).
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>
To query the reference clock, use
u_long fref;
                  
fref = Cy2239xPllGetFreq(CY2239X_REF, 7);
The expected result on Ethernut 3 is 25,000,000 (or 25 MHz).

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 */
When running this code on Ethernut 3.0 Rev-E, the following output is expected.
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.