# lpc-clk, a clock calculation tool
[LPC2xxx related tools running on the host]

LPCxxxx PLL and UART calculator tool. More...

LPCxxxx PLL and UART calculator tool.

This program can calculate the PLL settings for a given clock source and desired CPU clock frequency. In addition, it can calculate the UART's division parameters (integer and fractional) for a given set of baud rates.

## Usage

`lpc-clk options list_of_baud_rates`
The output of the program is in the format of a valid C header file, so you can incorporate it in your sources and use the generated values without actually typing them from the screen. If you start the program without any command line switches, it will print a usage message that details all options. It will also list all the chips which it knows.
If you supply the required parameters on the command line, then the program calculates the PLL and UART settings, formats them so that they can be included in your C source and prints the result on the standard output, which you can redirect to a file. The requirements and the actual achieved values and deviations are also written as C comments.
The following list tells you what can possibly be defined in the output. Some of these definitions may be omitted, due to not being requested or the given chip not supporting the given feature. The names below all start with `CLOCK_`, but that can be changed with a command line option. All defined values are integers.

    CLOCK_XTAL       is the crystal frequency, in Hz
    CLOCK_CCLK       is the (achieved) CPU frequency, in Hz
    CLOCK_PLL_M      is the 'M' value for the PLL
    CLOCK_PLL_N      is the 'N' value for the PLL
    CLOCK_PLL_P      is the 'P' setting for the PLL
    CLOCK_CPU_DIV    is the CPU clock division value
    CLOCK_USB_DIV    is the USB clock division value
    CLOCK_MAM_TIM    is the minimum MAM time value
    CLOCK_RTC_DIV    is the peripheral clock prescaler code for the RTC
    CLOCK_RTC_CLK    is the actual prepheral clock for the RTC, in Hz
    CLOCK_RTC_INT    is the RTC fractional divider integer value
    CLOCK_RTC_FRA    is the RTC fractional divider remainder value
    CLOCK_SIO_DIV    is the peripheral clock prescaler code for the UART
    CLOCK_SIO_CLK    is the actual prepheral clock for the UART, in Hz

Further definitions are emitted for the UART, their format is explained under the -a option. In case of an error, an error message is sent to `stderr`.
Note that the PLL_M and PLL_N as well as the CPU_DIV and USB_DIV values are the actual numbers (from which you have to subtract 1 before you write them into the relevant register), the PLL_P, RTC_DIV and SIO_DIV values are the actual field values as encoded by the chip. It is because there is no simple mapping between the codes and values for the latter set. For the same reason the chip header files in the package are expecting the values exactly in the format generated by this tool. For example, booting the PLL on an LPC2103 using the values calculated by this tool and the headers from this package looks something like this:

    #include "clock.h"              // The file generated by the tool
    #include <chips/LPC210x/scb.h>  // The header for the SCB module of the chip
        ...

        // Load the PLL divisor values

        lpc_scb->pllcfg  = SCB_PLLCFG_MSEL( CLOCK_PLL_M ) |
                           SCB_PLLCFG_PSEL( CLOCK_PLL_P );
        lpc_scb->pllfeed = SCB_PLLFEED_FOOD1;
        lpc_scb->pllfeed = SCB_PLLFEED_FOOD2;

        // Enable the PLL

        lpc_scb->pllcon  = SCB_PLLCON_PLLE;
        lpc_scb->pllfeed = SCB_PLLFEED_FOOD1;
        lpc_scb->pllfeed = SCB_PLLFEED_FOOD2;

        // Wait for the PLL to stabilise

        while ( ! ( lpc_scb->pllstat & SCB_PLLSTAT_PLOCK ) );

        // Connect the PLL.

        lpc_scb->pllcon  = SCB_PLLCON_PLLE | SCB_PLLCON_PLLC;
        lpc_scb->pllfeed = SCB_PLLFEED_FOOD1;
        lpc_scb->pllfeed = SCB_PLLFEED_FOOD2;

        // Now we're running from our nominal clock, enable memory acceleration.

        lpc_scb->mamtim  = CLOCK_MAM_TIM;
        lpc_scb->mamcr   = SCB_MAMCR_MODE_FULL;

        // Load the peripheral clock divider, as per the UART settings

        lpc_scb->apbdiv  = CLOCK_SIO_DIV;

        ...

## Options

- `-d device`
  Specifies the device. It is an integer, which is the chip's type with the leading LPC part omitted. The list of known chips can be obtained by starting the tool without any arguments.
  For backward compatibility reasons this option defaults to 2378.

- `-x xtal`
  The reference clock frequency (float)
  If the number is less than 100, it is taken as MHz, otherwise as Hz. Values between 32.768kHz and 40MHz are accepted.
  This option is mandatory.

- `-c cclk`
  The required CPU clock (float).
  If the number is less than 100, it is taken as MHz, otherwise as Hz.
  This option is mandatory.

- `-s stem`
  The name stem for all definitions. It defaults to `CLOCK`. The program does not check if the stem is a valid C identifier or not.

- `-h max_clock`
  Maximum CPU clock (float).
  If the number is less than 100, it is taken as MHz, otherwise as Hz. The default is 60MHz or the specified clock (whichever is larger). If you specify a value that is less than the requested clock frequency the the requested clock frequency will be used instead. This value is only used if the required CPU clock can not be exactly achieved. A value close to the requested frequency will be accepted if it is not higher than this value.

- `-l min_clock`
  Minimum CPU clock (float).
  If the number is less than 100, it is taken as MHz, otherwise as Hz. The default is 0. If you specify a value that is more than the requested clock frequency then the requested clock frequency will be used instead. This value is only used if the required CPU clock can not be exactly achieved. A value close to the requested frequency will be accepted if it is not lower than this value.

- `-u max_error`
  Maximum USB error (float).
  Indicates that USB is needed. In that case the VCO frequency must be set to an exact multiple of 96MHz. The parameter indicates the maximum frequency error, in ppm. Specifying 0 or a negative value disables the USB calculations. The default is 0. Suggested value is 500ppm.

- `-p n`
  The peripheral clock divider for the UART's clock (1, 2, 4 or 8).
  For chips with only one peripheral divider, if this option is specified and the -r option is also specified, the two values must be the same. If this option is omitted but the -r option is used, then the value specified there will be used. If neither -p nor -r are used, then the default value of 4 will be used.

- `-r n`
  The peripheral clock divider for the RTC's clock (1, 2, 4 or 8).
  If the value is specified, then RTC calculations will be performed. For chips with only one peripheral divider, if this option is specified and the `-p` option is also specified, the two values must be the same.

- `-i string`
  The identifier to be used for the #ifndef directive protecting the header file from multiple inclusions. It must be a valid C identifier. The program does *not* check the validity of the string, it uses it verbatim. The default is `_LPC_CLOCK_TOOL`.

- `-a`
  Selects the alternate format for UART calculations.
  The default is to create three definitions for each baudrate:
  `CLOCK_SIO_I_XXXX` is the UART's integer divider for baud rate XXXX
  `CLOCK_SIO_M_XXXX` is the UART's fractional divider's 'M' value
  `CLOCK_SIO_A_XXXX` is the UART's fractional divider's 'A' value
  The alternative format is that an initialiser is defined for an array of structures. The structure has to have 4 members, the first one is the baud rate, the next one is the integer divider value, then the fractional divider's M value and finally the fractional divider's A value. The suggested member sizes are int, short, char and char, all unsigned. The initialiser is called `CLOCK_SIO_TABLE` and can be used like this:

          // Structure to store the baud rate parameters

          typedef struct {
              unsigned int    b;  // Baud rate
              unsigned short  i;  // Integer divisor
              unsigned char   m;  // Fractional divider M value
              unsigned char   a;  // Fractional divider A value
          } BAUDS;

          // Table holding the baud rates

          static const BAUDS brate_table[] = { CLOCK_SIO_TABLE };

## List of baud rates

It is an optional list of integers, separated by space. Each number is a baud rate for which the divisor values should be calculated. For example, the list
`9600 38400 115200`
will make the tool calculate the divisor values for three common baud rates.

## Exit code

0 : success
1 : command line format error or illegal parameter value
2 : the requirements could not be satisfied