Skip to content

Instantly share code, notes, and snippets.

@jboone
Created June 5, 2012 18:43
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jboone/2876843 to your computer and use it in GitHub Desktop.
Save jboone/2876843 to your computer and use it in GitHub Desktop.
LPC43xx code for configuring Si5351 and internal clock tree.
volatile uint_fast8_t* peripheral_bitband_address(volatile void* const address, const uint_fast8_t bit_number) {
const uint32_t bit_band_base = 0x42000000;
const uint32_t byte_offset = (uint32_t)address - 0x40000000;
const uint32_t bit_word_offset = (byte_offset * 32) + (bit_number * 4);
const uint32_t bit_word_address = bit_band_base + bit_word_offset;
return (volatile uint_fast8_t*)bit_word_address;
}
void peripheral_bitband_set(volatile void* const peripheral_address, const uint_fast8_t bit_number) {
volatile uint_fast8_t* const bitband_address = peripheral_bitband_address(peripheral_address, bit_number);
*bitband_address = 1;
}
void peripheral_bitband_clear(volatile void* const peripheral_address, const uint_fast8_t bit_number) {
volatile uint_fast8_t* const bitband_address = peripheral_bitband_address(peripheral_address, bit_number);
*bitband_address = 0;
}
uint_fast8_t peripheral_bitband_get(volatile void* const peripheral_address, const uint_fast8_t bit_number) {
volatile uint_fast8_t* const bitband_address = peripheral_bitband_address(peripheral_address, bit_number);
return *bitband_address;
}
#define CLOCKGEN_I2C LPC_I2C0
#define CLOCKGEN_SLAVE_ADDRESS 0x60
int clockgen_write(
uint8_t* const data,
const uint_fast8_t data_count) {
I2C_M_SETUP_Type setup;
Status status;
setup.sl_addr7bit = CLOCKGEN_SLAVE_ADDRESS;
setup.tx_data = data;
setup.tx_length = data_count;
setup.rx_data = NULL;
setup.rx_length = 0;
setup.retransmissions_max = 0;
status = I2C_MasterTransferData(CLOCKGEN_I2C, &setup, I2C_TRANSFER_POLLING);
return (status != SUCCESS);
}
int clockgen_disable_all_outputs() {
/* Disable all CLKx outputs. */
uint8_t data[] = { 3, 0xFF };
return clockgen_write(data, sizeof(data));
}
int clockgen_disable_oeb_pin_control() {
/* Turn off OEB pin control for all CLKx */
uint8_t data[] = { 9, 0xFF };
return clockgen_write(data, sizeof(data));
}
int clockgen_power_down_all_clocks() {
/* Power down all CLKx */
uint8_t data[] = { 16, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 };
return clockgen_write(data, sizeof(data));
}
int clockgen_set_crystal_configuration() {
/* Register 183: Crystal Internal Load Capacitance
* Reads as 0xE4 on power-up
* Set to 10pF (until I find out what loading the crystal/PCB likes best)
*/
uint8_t data[] = { 183, 0xE4 };
return clockgen_write(data, sizeof(data));
}
int clockgen_enable_xo_and_ms_fanout() {
/* Register 187: Fanout Enable
* Turn on XO and MultiSynth fanout only.
*/
uint8_t data[] = { 187, 0x50 };
return clockgen_write(data, sizeof(data));
}
int clockgen_configure_pll_sources_for_xtal() {
/* Register 15: PLL Input Source
* CLKIN_DIV=0 (Divide by 1)
* PLLB_SRC=0 (XTAL input)
* PLLA_SRC=0 (XTAL input)
*/
uint8_t data[] = { 15, 0x00 };
return clockgen_write(data, sizeof(data));
}
int clockgen_configure_pll1_multisynth() {
/* MultiSynth NA (PLL1) */
uint8_t data[] = { 26, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00 };
return clockgen_write(data, sizeof(data));
}
int clockgen_configure_multisynth(
const uint_fast8_t ms_number,
const uint32_t p1,
const uint32_t p2,
const uint32_t p3
) {
// TODO: Check for p3 > 0? 0 has no meaning in fractional mode?
// And it makes for more jitter in integer mode.
const uint_fast8_t register_number = 42 + (ms_number * 8);
uint8_t data[] = {
register_number,
(p3 >> 8) & 0xFF,
(p3 >> 0) & 0xFF,
(0 << 4) | (0 << 2) | ((p1 >> 16) & 0x3),
(p1 >> 8) & 0xFF,
(p1 >> 0) & 0xFF,
(((p3 >> 16) & 0xF) << 4) | (((p2 >> 16) & 0xF) << 0),
(p2 >> 8) & 0xFF,
(p2 >> 0) & 0xFF
};
return clockgen_write(data, sizeof(data));
}
int clockgen_configure_clock_control() {
/* Registers 16 through 23: CLKx Control
* CLK0:
* CLK0_PDN=0 (powered up)
* MS0_INT=1 (integer mode)
* MS0_SRC=0 (PLLA as source for MultiSynth 0)
* CLK0_INV=0 (not inverted)
* CLK0_SRC=3 (MS0 as input source)
* CLK0_IDRV=3 (8mA)
* CLK1:
* CLK1_PDN=0 (powered up)
* MS1_INT=1 (integer mode)
* MS1_SRC=0 (PLLA as source for MultiSynth 1)
* CLK1_INV=0 (not inverted)
* CLK1_SRC=3 (MS1 as input source)
* CLK1_IDRV=3 (8mA)
* CLK4:
* CLK4_PDN=0 (powered up)
* MS4_INT=0 (fractional mode -- to support 12MHz to LPC for USB DFU)
* MS4_SRC=0 (PLLA as source for MultiSynth 4)
* CLK4_INV=0 (not inverted)
* CLK4_SRC=3 (MS4 as input source)
* CLK4_IDRV=3 (8mA)
*/
uint8_t data[] = {
16,
0x4F, 0x4F, 0x80, 0x80, 0x0F, 0x80, 0x80, 0x80
};
return clockgen_write(data, sizeof(data));
}
int clockgen_enable_clock_outputs() {
/* Enable CLK outputs 0, 1, 4 only. */
uint8_t data[] = {
3, 0xEC
};
return clockgen_write(data, sizeof(data));
}
void SetupHardware() {
SystemInit();
// Running on internal RC at this point.
// Configure I2C to bring up Si5351C, as clock for the
// LPC.
// Not calling I2C_Init, because it's written to use PLL1, and we're
// not in a position to fuss with PLL1 yet.
//
//I2C_Init(CLOCKGEN_I2C, 400000);
CGU_EntityConnect(CGU_CLKSRC_IRC, CGU_BASE_APB1);
LPC_SCU->SFSI2C0 = (1<<3 | 1<<11);
const uint32_t clockrate = 400000;
const uint32_t tem = CGU_GetPCLKFrequency(CGU_PERIPHERAL_M4CORE) / clockrate;
CLOCKGEN_I2C->SCLH = (uint32_t)(tem / 2);
CLOCKGEN_I2C->SCLL = (uint32_t)(tem - CLOCKGEN_I2C->SCLH);
CLOCKGEN_I2C->CONCLR = (I2C_I2CONCLR_AAC |I2C_I2CONCLR_SIC | I2C_I2CONCLR_STAC | I2C_I2CONCLR_I2ENC);
I2C_Cmd(CLOCKGEN_I2C, ENABLE);
clockgen_disable_all_outputs();
clockgen_disable_oeb_pin_control();
clockgen_power_down_all_clocks();
clockgen_set_crystal_configuration();
clockgen_enable_xo_and_ms_fanout();
clockgen_configure_pll_sources_for_xtal();
clockgen_configure_pll1_multisynth();
// MS0/CLK0 is the source for the MAX2837 clock input.
clockgen_configure_multisynth(0, 2048, 0, 1); // 40MHz
// MS1/CLK1 is the source for the MAX5864 codec.
clockgen_configure_multisynth(1, 4608, 0, 1); // 20MHz
// MS4/CLK4 is the source for the LPC43xx microcontroller.
clockgen_configure_multisynth(4, 8021, 1, 3); // 12MHz
clockgen_configure_clock_control();
clockgen_enable_clock_outputs();
I2C_Cmd(CLOCKGEN_I2C, DISABLE);
I2C_DeInit(CLOCKGEN_I2C);
// 12MHz clock is entering LPC XTAL1/OSC input now.
// Set up PLL1 to run from XTAL1 input.
CGU_SetXTALOSC(12000000);
CGU_EnableEntity(CGU_CLKSRC_XTAL_OSC, ENABLE);
CGU_EntityConnect(CGU_CLKSRC_XTAL_OSC, CGU_BASE_M4);
CGU_EntityConnect(CGU_CLKSRC_XTAL_OSC, CGU_BASE_APB1);
CGU_EntityConnect(CGU_CLKSRC_XTAL_OSC, CGU_CLKSRC_PLL1);
CGU_SetPLL1(1);
CGU_EnableEntity(CGU_CLKSRC_PLL1, ENABLE);
CGU_UpdateClock();
CGU_SetPLL1(9);
CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_BASE_M4);
wait_count(1000000);
CGU_SetPLL1(17);
wait_count(1000000);
CGU_UpdateClock();
CGU_EntityConnect(CGU_CLKSRC_XTAL_OSC, CGU_CLKSRC_PLL0);
CGU_SetPLL0();
CGU_EnableEntity(CGU_CLKSRC_PLL0, ENABLE);
CGU_EntityConnect(CGU_CLKSRC_PLL0, CGU_BASE_USB0);
/*CGU_EnableEntity(CGU_BASE_PERIPH, ENABLE);
CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_BASE_PERIPH);
CGU_EntityConnect(CGU_CLKSRC_PLL1, CGU_BASE_APB1);*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment