SiLabs Pearl: Support for clocking via RC oscillators

Allows clocking the device from RC oscillators (HFRCO, LFRCO).
Note that we can not use the em_cmu.h enums directly as the
preprocessor can not do comparisons on them.

Related changes in serial_api, so that LEUART clock is within
acceptable limits on Pearl.

Contains quite a bit of indentation changes to make the preprocessor
logic more readable so recommend viewing the diff in ignore whitespace
mode.
pull/1501/head
Mikko Polojarvi 2015-12-22 16:01:01 +02:00 committed by Steven Cooreman
parent 73cf96369d
commit efadf47be6
4 changed files with 193 additions and 106 deletions

View File

@ -56,7 +56,7 @@
* * LFRCO: internal RC oscillator (32.768kHz)
* * ULFRCO: internal ultra-low power RC oscillator (available down to EM3) (1kHz)
*/
#define LOW_ENERGY_CLOCK_SOURCE LFXO
#define LOW_ENERGY_CLOCK_SOURCE LFXO
/** Core clock source.
* Options:
@ -65,16 +65,19 @@
*/
#define CORE_CLOCK_SOURCE HFXO
/** HFRCO frequency band
* Options:
* * CMU_HFRCOCTRL_BAND_28MHZ
* * CMU_HFRCOCTRL_BAND_21MHZ
* * CMU_HFRCOCTRL_BAND_14MHZ
* * CMU_HFRCOCTRL_BAND_11MHZ
* * CMU_HFRCOCTRL_BAND_7MHZ
* * CMU_HFRCOCTRL_BAND_1MHZ
*/
#define HFRCO_FREQUENCY CMU_HFRCOCTRL_BAND_14MHZ
/** Select HFRCO frequency */
#define PER_CMU_HFRCO_FREQ_1MHZ 1
#define PER_CMU_HFRCO_FREQ_2MHZ 2
#define PER_CMU_HFRCO_FREQ_4MHZ 3
#define PER_CMU_HFRCO_FREQ_7MHZ 4
#define PER_CMU_HFRCO_FREQ_13MHZ 5
#define PER_CMU_HFRCO_FREQ_16MHZ 6
#define PER_CMU_HFRCO_FREQ_19MHZ 7
#define PER_CMU_HFRCO_FREQ_26MHZ 8
#define PER_CMU_HFRCO_FREQ_32MHZ 9
#define PER_CMU_HFRCO_FREQ_38MHZ 10
#define HFRCO_FREQUENCY PER_CMU_HFRCO_FREQ_38MHZ
#define LFXO_FREQUENCY 32768
#define HFXO_FREQUENCY 40000000

View File

@ -32,37 +32,70 @@
#include "device_peripherals.h"
#if( CORE_CLOCK_SOURCE == HFXO)
#define REFERENCE_FREQUENCY HFXO_FREQUENCY
# define REFERENCE_FREQUENCY HFXO_FREQUENCY
#elif( CORE_CLOCK_SOURCE == HFRCO)
#if( HFRCO_FREQUENCY == CMU_HFRCOCTRL_BAND_1MHZ)
#define REFERENCE_FREQUENCY 1000000
#elif(HFRCO_FREQUENCY == CMU_HFRCOCTRL_BAND_7MHZ)
#define REFERENCE_FREQUENCY 7000000
#elif(HFRCO_FREQUENCY == CMU_HFRCOCTRL_BAND_11MHZ)
#define REFERENCE_FREQUENCY 7000000
#elif(HFRCO_FREQUENCY == CMU_HFRCOCTRL_BAND_14MHZ)
#define REFERENCE_FREQUENCY 14000000
#elif(HFRCO_FREQUENCY == CMU_HFRCOCTRL_BAND_21MHZ)
#define REFERENCE_FREQUENCY 21000000
#elif(HFRCO_FREQUENCY == CMU_HFRCOCTRL_BAND_28MHZ)
#define REFERENCE_FREQUENCY 28000000
#else
#define REFERENCE_FREQUENCY 14000000
#endif
# if defined _CMU_HFRCOCTRL_BAND_MASK
# if( HFRCO_FREQUENCY == CMU_HFRCOCTRL_BAND_1MHZ)
# define REFERENCE_FREQUENCY 1000000
# elif(HFRCO_FREQUENCY == CMU_HFRCOCTRL_BAND_7MHZ)
# define REFERENCE_FREQUENCY 7000000
# elif(HFRCO_FREQUENCY == CMU_HFRCOCTRL_BAND_11MHZ)
# define REFERENCE_FREQUENCY 7000000
# elif(HFRCO_FREQUENCY == CMU_HFRCOCTRL_BAND_14MHZ)
# define REFERENCE_FREQUENCY 14000000
# elif(HFRCO_FREQUENCY == CMU_HFRCOCTRL_BAND_21MHZ)
# define REFERENCE_FREQUENCY 21000000
# elif(HFRCO_FREQUENCY == CMU_HFRCOCTRL_BAND_28MHZ)
# define REFERENCE_FREQUENCY 28000000
# else
# define REFERENCE_FREQUENCY 14000000
# endif
# elif defined _CMU_HFRCOCTRL_FREQRANGE_MASK
# ifndef PER_CMU_HFRCO_FREQ_1MHZ
# error "Missing device_peripheral PER_CMU_ defines"
# endif
# if HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_1MHZ
# define REFERENCE_FREQUENCY 1000000
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_2MHZ
# define REFERENCE_FREQUENCY 2000000
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_4MHZ
# define REFERENCE_FREQUENCY 4000000
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_7MHZ
# define REFERENCE_FREQUENCY 7000000
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_13MHZ
# define REFERENCE_FREQUENCY 13000000
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_16MHZ
# define REFERENCE_FREQUENCY 16000000
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_19MHZ
# define REFERENCE_FREQUENCY 19000000
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_26MHZ
# define REFERENCE_FREQUENCY 26000000
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_32MHZ
# define REFERENCE_FREQUENCY 32000000
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_38MHZ
# define REFERENCE_FREQUENCY 38000000
# else
# error "Not a valid HFRCO frequency"
# endif
# else
# error "HFRCO frequency not defined"
# endif
#endif
#if ( LOW_ENERGY_CLOCK_SOURCE == LFXO )
#define LEUART_USING_LFXO
#if ( defined(CMU_CTRL_HFLE) && (REFERENCE_FREQUENCY > 24000000) )
#define LEUART_HF_REF_FREQ (REFERENCE_FREQUENCY / 4)
# define LEUART_USING_LFXO
# if ( (defined(CMU_CTRL_HFLE) || defined(CMU_CTRL_WSHFLE) ) && (REFERENCE_FREQUENCY > 24000000) )
# define LEUART_HF_REF_FREQ (REFERENCE_FREQUENCY / 4)
# else
# define LEUART_HF_REF_FREQ (REFERENCE_FREQUENCY / 2)
# endif
# define LEUART_LF_REF_FREQ LFXO_FREQUENCY
#else
#define LEUART_HF_REF_FREQ (REFERENCE_FREQUENCY / 2)
#endif
#define LEUART_LF_REF_FREQ LFXO_FREQUENCY
#else
#if ( defined(CMU_CTRL_HFLE) && (REFERENCE_FREQUENCY > 24000000) )
#define LEUART_REF_FREQ (REFERENCE_FREQUENCY / 4)
#else
#define LEUART_REF_FREQ (REFERENCE_FREQUENCY / 2)
#endif
# if ( (defined(CMU_CTRL_HFLE) || defined(CMU_CTRL_WSHFLE) ) && (REFERENCE_FREQUENCY > 24000000) )
# define LEUART_REF_FREQ (REFERENCE_FREQUENCY / 4)
# else
# define LEUART_REF_FREQ (REFERENCE_FREQUENCY / 2)
# endif
#endif

View File

@ -53,51 +53,85 @@ void mbed_sdk_init()
SystemHFXOClockSet(HFXO_FREQUENCY);
#elif( CORE_CLOCK_SOURCE == HFRCO)
CMU_ClockSelectSet(cmuClock_HF, cmuSelect_HFRCO);
# if defined _CMU_HFRCOCTRL_BAND_MASK
CMU_HFRCOBandSet(HFRCO_FREQUENCY);
# elif defined _CMU_HFRCOCTRL_FREQRANGE_MASK
# ifndef PER_CMU_HFRCO_FREQ_1MHZ
# error "Need PER_CMU_ definitions"
# endif
# if HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_1MHZ
CMU_HFRCOFreqSet(cmuHFRCOFreq_1M0Hz);
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_2MHZ
CMU_HFRCOFreqSet(cmuHFRCOFreq_2M0Hz);
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_4MHZ
CMU_HFRCOFreqSet(cmuHFRCOFreq_4M0Hz);
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_7MHZ
CMU_HFRCOFreqSet(cmuHFRCOFreq_7M0Hz);
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_13MHZ
CMU_HFRCOFreqSet(cmuHFRCOFreq_13M0Hz);
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_16MHZ
CMU_HFRCOFreqSet(cmuHFRCOFreq_16M0Hz);
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_19MHZ
CMU_HFRCOFreqSet(cmuHFRCOFreq_19M0Hz);
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_26MHZ
CMU_HFRCOFreqSet(cmuHFRCOFreq_26M0Hz);
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_32MHZ
CMU_HFRCOFreqSet(cmuHFRCOFreq_32M0Hz);
# elif HFRCO_FREQUENCY == PER_CMU_HFRCO_FREQ_38MHZ
CMU_HFRCOFreqSet(cmuHFRCOFreq_38M0Hz);
# else
# error "Invalid HFRCO clock selection"
# endif
# else
# error "Can't set HFRCO frequency"
# endif
#else
#error "Core clock selection not valid (mbed_overrides.c)"
# error "Core clock selection not valid (mbed_overrides.c)"
#endif
CMU_ClockEnable(cmuClock_CORELE, true);
#if( LOW_ENERGY_CLOCK_SOURCE == LFXO )
#ifdef CMU_LFACLKSEL_REG
# ifdef CMU_LFACLKSEL_REG
CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO);
#endif
#ifdef CMU_LFBCLKSEL_REG
# endif
# ifdef CMU_LFBCLKSEL_REG
/* cmuClock_LFB (to date) only has LEUART peripherals.
* This gets set automatically whenever you create serial objects using LEUART
*/
#endif
#ifdef _CMU_LFECLKEN0_MASK
# endif
# ifdef _CMU_LFECLKEN0_MASK
CMU_ClockSelectSet(cmuClock_LFE, cmuSelect_LFXO);
#endif
# endif
SystemLFXOClockSet(LFXO_FREQUENCY);
#elif( LOW_ENERGY_CLOCK_SOURCE == LFRCO )
#ifdef CMU_LFACLKSEL_REG
# ifdef CMU_LFACLKSEL_REG
CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);
#endif
#ifdef CMU_LFBCLKSEL_REG
# endif
# ifdef CMU_LFBCLKSEL_REG
//CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFRCO);
#endif
#ifdef CMU_LFECLKSEL_REG
# endif
# ifdef _CMU_LFECLKEN0_MASK
CMU_ClockSelectSet(cmuClock_LFE, cmuSelect_LFRCO);
#endif
# endif
# if defined _CMU_HFRCOCTRL_BAND_MASK
CMU_HFRCOBandSet(HFRCO_FREQUENCY);
# endif
#elif( LOW_ENERGY_CLOCK_SOURCE == ULFRCO)
#ifdef CMU_LFACLKSEL_REG
# ifdef CMU_LFACLKSEL_REG
CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_ULFRCO);
#endif
#ifdef CMU_LFBCLKSEL_REG
# endif
# ifdef CMU_LFBCLKSEL_REG
CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_ULFRCO);
#endif
#ifdef CMU_LFECLKSEL_REG
# endif
# ifdef CMU_LFECLKSEL_REG
CMU_ClockSelectSet(cmuClock_LFE, cmuSelect_ULFRCO);
#endif
# endif
#else
#error "Low energy clock selection not valid"
# error "Low energy clock selection not valid"
#endif
/* Enable BC line driver to avoid garbage on CDC port */

View File

@ -70,6 +70,9 @@
#ifdef _SILICON_LABS_32B_PLATFORM_2
#define SERIAL_LEUART_MAX_BAUDRATE 9600
#ifndef LEUART_USING_LFXO
# define SERIAL_LEUART_MIN_BAUDRATE (LEUART_REF_FREQ>>10)
#endif
static void serial_switch_to_usart(serial_t *obj, int baudrate);
@ -101,6 +104,7 @@ static void serial_rx_abort_asynch_intern(serial_t *obj, int unblock_sleep);
static void serial_tx_abort_asynch_intern(serial_t *obj, int unblock_sleep);
static void serial_block_sleep(serial_t *obj);
static void serial_unblock_sleep(serial_t *obj);
static void serial_leuart_baud(serial_t *obj, int baudrate);
/* ISRs for RX and TX events */
#ifdef UART0
@ -186,7 +190,7 @@ static void uart_init(serial_t *obj, uint32_t baudrate, SerialParity parity, int
#ifdef LEUART_USING_LFXO
init.refFreq = LEUART_LF_REF_FREQ;
#else
init.refFreq = LEUART_REF_FREQ;
init.refFreq = 0;
#endif
LEUART_Init(obj->serial.periph.leuart, &init);
@ -564,7 +568,12 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
CMU_ClockEnable(cmuClock_CORELE, true);
#else
//set to use high-speed clock
#ifdef _SILICON_LABS_32B_PLATFORM_2
CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_HFCLKLE);
CMU_ClockDivSet(serial_get_clock(obj), 8);
#else
CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_CORELEDIV2);
#endif
#endif
}
@ -662,56 +671,17 @@ void serial_baud(serial_t *obj, int baudrate)
{
if(LEUART_REF_VALID(obj->serial.periph.leuart)) {
#ifndef _SILICON_LABS_32B_PLATFORM_2
#ifdef LEUART_USING_LFXO
/* check if baudrate is within allowed range */
MBED_ASSERT(baudrate >= (LEUART_LF_REF_FREQ >> 7));
if(baudrate > (LEUART_LF_REF_FREQ >> 1)){
/* check if baudrate is within allowed range */
MBED_ASSERT((baudrate <= (LEUART_HF_REF_FREQ >> 1)) && (baudrate > (LEUART_HF_REF_FREQ >> 10)));
CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_CORELEDIV2);
uint8_t divisor = 1;
if(baudrate > (LEUART_HF_REF_FREQ >> 7)){
divisor = 1;
}else if(baudrate > (LEUART_HF_REF_FREQ >> 8)){
divisor = 2;
}else if(baudrate > (LEUART_HF_REF_FREQ >> 9)){
divisor = 4;
}else{
divisor = 8;
}
CMU_ClockDivSet(serial_get_clock(obj), divisor);
LEUART_BaudrateSet(obj->serial.periph.leuart, LEUART_HF_REF_FREQ/divisor, (uint32_t)baudrate);
}else{
CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO);
CMU_ClockDivSet(serial_get_clock(obj), 1);
LEUART_BaudrateSet(obj->serial.periph.leuart, LEUART_LF_REF_FREQ, (uint32_t)baudrate);
}
#else
/* check if baudrate is within allowed range */
MBED_ASSERT((baudrate > (LEUART_REF_FREQ >> 10)) && (baudrate <= (LEUART_REF_FREQ >> 1)));
uint8_t divisor = 1;
if(baudrate > (LEUART_REF_FREQ >> 7)){
divisor = 1;
}else if(baudrate > (LEUART_REF_FREQ >> 8)){
divisor = 2;
}else if(baudrate > (LEUART_REF_FREQ >> 9)){
divisor = 4;
}else{
divisor = 8;
}
CMU_ClockDivSet(serial_get_clock(obj), divisor);
LEUART_BaudrateSet(obj->serial.periph.leuart, LEUART_REF_FREQ/divisor, (uint32_t)baudrate);
#endif
serial_leuart_baud(obj, baudrate);
#else
/* For Pearl, we must check if we need to upgrade to using a standard USART */
if( baudrate > SERIAL_LEUART_MAX_BAUDRATE ) {
if( (baudrate > SERIAL_LEUART_MAX_BAUDRATE)
#ifndef LEUART_USING_LFXO
|| (baudrate < SERIAL_LEUART_MIN_BAUDRATE)
#endif
) {
serial_switch_to_usart(obj, baudrate);
} else {
LEUART_BaudrateSet(obj->serial.periph.leuart, LEUART_LF_REF_FREQ, (uint32_t)baudrate);
serial_leuart_baud(obj, baudrate);
}
#endif
} else {
@ -719,6 +689,53 @@ void serial_baud(serial_t *obj, int baudrate)
}
}
static void serial_leuart_baud(serial_t *obj, int baudrate)
{
#ifdef LEUART_USING_LFXO
/* check if baudrate is within allowed range */
MBED_ASSERT(baudrate >= (LEUART_LF_REF_FREQ >> 7));
if(baudrate > (LEUART_LF_REF_FREQ >> 1)){
/* check if baudrate is within allowed range */
MBED_ASSERT((baudrate <= (LEUART_HF_REF_FREQ >> 1)) && (baudrate > (LEUART_HF_REF_FREQ >> 10)));
CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_CORELEDIV2);
uint8_t divisor = 1;
if(baudrate > (LEUART_HF_REF_FREQ >> 7)){
divisor = 1;
}else if(baudrate > (LEUART_HF_REF_FREQ >> 8)){
divisor = 2;
}else if(baudrate > (LEUART_HF_REF_FREQ >> 9)){
divisor = 4;
}else{
divisor = 8;
}
CMU_ClockDivSet(serial_get_clock(obj), divisor);
LEUART_BaudrateSet(obj->serial.periph.leuart, LEUART_HF_REF_FREQ/divisor, (uint32_t)baudrate);
}else{
CMU_ClockSelectSet(cmuClock_LFB, cmuSelect_LFXO);
CMU_ClockDivSet(serial_get_clock(obj), 1);
LEUART_BaudrateSet(obj->serial.periph.leuart, LEUART_LF_REF_FREQ, (uint32_t)baudrate);
}
#else
/* check if baudrate is within allowed range */
MBED_ASSERT((baudrate > (LEUART_REF_FREQ >> 10)) && (baudrate <= (LEUART_REF_FREQ >> 1)));
uint8_t divisor = 1;
if(baudrate > (LEUART_REF_FREQ >> 7)){
divisor = 1;
}else if(baudrate > (LEUART_REF_FREQ >> 8)){
divisor = 2;
}else if(baudrate > (LEUART_REF_FREQ >> 9)){
divisor = 4;
}else{
divisor = 8;
}
CMU_ClockDivSet(serial_get_clock(obj), divisor);
LEUART_BaudrateSet(obj->serial.periph.leuart, LEUART_REF_FREQ/divisor, (uint32_t)baudrate);
#endif
}
#ifdef _SILICON_LABS_32B_PLATFORM_2
/**
* Deinit LEUART, and allocate and init an USART on the same pins with