Skip to content

Commit 937430a

Browse files
committed
clk freq header file
- HAL clock improvement
1 parent 4e5993e commit 937430a

File tree

7 files changed

+169
-15
lines changed

7 files changed

+169
-15
lines changed

libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/analogin_api.c

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "cmsis.h"
1919
#include "pinmap.h"
2020
#include "error.h"
21+
#include "clk_freqs.h"
2122

2223
static const PinMap PinMap_ADC[] = {
2324
{PTC2, ADC0_SE4b, 0},
@@ -33,6 +34,8 @@ static const PinMap PinMap_ADC[] = {
3334
{NC, NC, 0}
3435
};
3536

37+
#define MAX_FADC 6000000
38+
3639
void analogin_init(analogin_t *obj, PinName pin) {
3740
obj->adc = (ADCName)pinmap_peripheral(pin, PinMap_ADC);
3841
if (obj->adc == (ADCName)NC)
@@ -43,13 +46,23 @@ void analogin_init(analogin_t *obj, PinName pin) {
4346
uint32_t port = (uint32_t)pin >> PORT_SHIFT;
4447
SIM->SCGC5 |= 1 << (SIM_SCGC5_PORTA_SHIFT + port);
4548

49+
// bus clk
50+
uint32_t PCLK = bus_frequency();
51+
uint32_t clkdiv;
52+
for (clkdiv = 0; clkdiv < 4; clkdiv++) {
53+
if ((PCLK >> clkdiv) <= MAX_FADC)
54+
break;
55+
}
56+
if (clkdiv == 4) //Set max div
57+
clkdiv = 0x7;
58+
4659
ADC0->SC1[1] = ADC_SC1_ADCH(obj->adc);
4760

4861
ADC0->CFG1 = ADC_CFG1_ADLPC_MASK // Low-Power Configuration
49-
| ADC_CFG1_ADIV(3) // Clock Divide Select: (Input Clock)/8
62+
| ADC_CFG1_ADIV(clkdiv & 0x3) // Clock Divide Select
5063
| ADC_CFG1_ADLSMP_MASK // Long Sample Time
5164
| ADC_CFG1_MODE(3) // (16)bits Resolution
52-
| ADC_CFG1_ADICLK(1); // Input Clock: (Bus Clock)/2
65+
| ADC_CFG1_ADICLK(clkdiv >> 2); // Input Clock
5366

5467
ADC0->CFG2 = ADC_CFG2_MUXSEL_MASK // ADxxb or ADxxa channels
5568
| ADC_CFG2_ADACKEN_MASK // Asynchronous Clock Output Enable
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2006-2013 ARM Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#ifndef CLK_FREQS_H
17+
#define CLK_FREQS_H
18+
19+
#ifdef __cplusplus
20+
extern "C" {
21+
#endif
22+
23+
/*!
24+
* \brief Get the peripheral bus clock frequency
25+
* \return Bus frequency
26+
*/
27+
static inline uint32_t bus_frequency(void) {
28+
return SystemCoreClock / (((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT) + 1);
29+
}
30+
31+
/*!
32+
* \brief Get external oscillator (crystal) frequency
33+
* \return External osc frequency
34+
*/
35+
static uint32_t extosc_frequency(void) {
36+
uint32_t MCGClock = SystemCoreClock * (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT));
37+
38+
if ((MCG->C1 & MCG_C1_CLKS_MASK) == MCG_C1_CLKS(2)) //MCG clock = external reference clock
39+
return MCGClock;
40+
41+
if ((MCG->C1 & MCG_C1_CLKS_MASK) == MCG_C1_CLKS(0)) { //PLL/FLL is selected
42+
uint32_t divider, multiplier;
43+
if ((MCG->C6 & MCG_C6_PLLS_MASK) == 0x0u) { //FLL is selected
44+
if ((MCG->S & MCG_S_IREFST_MASK) == 0x0u) { //FLL uses external reference
45+
divider = (uint8_t)(1u << ((MCG->C1 & MCG_C1_FRDIV_MASK) >> MCG_C1_FRDIV_SHIFT));
46+
if ((MCG->C2 & MCG_C2_RANGE0_MASK) != 0x0u)
47+
divider <<= 5u;
48+
/* Select correct multiplier to calculate the MCG output clock */
49+
switch (MCG->C4 & (MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) {
50+
case 0x0u:
51+
multiplier = 640u;
52+
break;
53+
case 0x20u:
54+
multiplier = 1280u;
55+
break;
56+
case 0x40u:
57+
multiplier = 1920u;
58+
break;
59+
case 0x60u:
60+
multiplier = 2560u;
61+
break;
62+
case 0x80u:
63+
multiplier = 732u;
64+
break;
65+
case 0xA0u:
66+
multiplier = 1464u;
67+
break;
68+
case 0xC0u:
69+
multiplier = 2197u;
70+
break;
71+
case 0xE0u:
72+
default:
73+
multiplier = 2929u;
74+
break;
75+
}
76+
77+
return MCGClock * divider / multiplier;
78+
}
79+
} else { //PLL is selected
80+
divider = (1u + (MCG->C5 & MCG_C5_PRDIV0_MASK));
81+
multiplier = ((MCG->C6 & MCG_C6_VDIV0_MASK) + 24u);
82+
return MCGClock * divider / multiplier;
83+
}
84+
}
85+
86+
//In all other cases either there is no crystal or we cannot determine it
87+
//For example when the FLL is running on the internal reference, and there is also an
88+
//external crystal. However these are unlikely situations
89+
return 0;
90+
}
91+
92+
93+
#ifdef __cplusplus
94+
}
95+
#endif
96+
97+
#endif

libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/i2c_api.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "cmsis.h"
1919
#include "pinmap.h"
2020
#include "error.h"
21+
#include "clk_freqs.h"
2122

2223
static const PinMap PinMap_I2C_SDA[] = {
2324
{PTB1, I2C_0, 2},
@@ -185,7 +186,7 @@ void i2c_frequency(i2c_t *obj, int hz) {
185186
uint32_t ref = 0;
186187
uint8_t i, j;
187188
// bus clk
188-
uint32_t PCLK = SystemCoreClock/2;
189+
uint32_t PCLK = bus_frequency();
189190
uint32_t pulse = PCLK / (hz * 2);
190191

191192
// we look for the values that minimize the error

libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/pwmout_api.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,25 @@ static const PinMap PinMap_PWM[] = {
4848
{NC , NC , 0}
4949
};
5050

51-
#define PWM_CLOCK_MHZ (0.75) // (48)MHz / 64 = (0.75)MHz
51+
static float pwm_clock = 0;
5252

5353
void pwmout_init(pwmout_t* obj, PinName pin) {
5454
// determine the channel
5555
PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM);
5656
if (pwm == (PWMName)NC)
5757
error("PwmOut pin mapping failed");
5858

59+
uint32_t clkdiv = 0;
60+
float clkval = SystemCoreClock / 1000000.0f;
61+
62+
while (clkval > 1) {
63+
clkdiv++;
64+
clkval /= 2.0;
65+
if (clkdiv == 7)
66+
break;
67+
}
68+
69+
pwm_clock = clkval;
5970
unsigned int port = (unsigned int)pin >> PORT_SHIFT;
6071
unsigned int ftm_n = (pwm >> TPM_SHIFT);
6172
unsigned int ch_n = (pwm & 0xFF);
@@ -65,7 +76,7 @@ void pwmout_init(pwmout_t* obj, PinName pin) {
6576

6677
FTM_Type *ftm = (FTM_Type *)(FTM0_BASE + 0x1000 * ftm_n);
6778
ftm->CONF |= FTM_CONF_BDMMODE(3);
68-
ftm->SC = FTM_SC_CLKS(1) | FTM_SC_PS(6); // (48)MHz / 64 = (0.75)MHz
79+
ftm->SC = FTM_SC_CLKS(1) | FTM_SC_PS(clkdiv); // (clock)MHz / clkdiv ~= (0.75)MHz
6980
ftm->CONTROLS[ch_n].CnSC = (FTM_CnSC_MSB_MASK | FTM_CnSC_ELSB_MASK); /* No Interrupts; High True pulses on Edge Aligned PWM */
7081

7182
obj->CnV = &ftm->CONTROLS[ch_n].CnV;
@@ -108,7 +119,7 @@ void pwmout_period_ms(pwmout_t* obj, int ms) {
108119
// Set the PWM period, keeping the duty cycle the same.
109120
void pwmout_period_us(pwmout_t* obj, int us) {
110121
float dc = pwmout_read(obj);
111-
*obj->MOD = PWM_CLOCK_MHZ * us;
122+
*obj->MOD = (uint32_t)(pwm_clock * (float)us);
112123
pwmout_write(obj, dc);
113124
}
114125

@@ -121,5 +132,5 @@ void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) {
121132
}
122133

123134
void pwmout_pulsewidth_us(pwmout_t* obj, int us) {
124-
*obj->CnV = PWM_CLOCK_MHZ * us;
135+
*obj->CnV = (uint32_t)(pwm_clock * (float)us);
125136
}

libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/serial_api.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) {
5353
obj->uart = (UART_Type *)uart;
5454
// enable clk
5555
switch (uart) {
56-
case UART_0: SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK | (1<<SIM_SOPT5_UART0TXSRC_SHIFT);
56+
case UART_0: SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK;
5757
SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK; SIM->SCGC4 |= SIM_SCGC4_UART0_MASK; break;
5858
case UART_1: SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK; SIM->SCGC4 |= SIM_SCGC4_UART1_MASK; break;
5959
case UART_2: SIM->SCGC5 |= SIM_SCGC5_PORTD_MASK; SIM->SCGC4 |= SIM_SCGC4_UART2_MASK; break;

libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/spi_api.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "cmsis.h"
2121
#include "pinmap.h"
2222
#include "error.h"
23+
#include "clk_freqs.h"
2324

2425
static const PinMap PinMap_SPI_SCLK[] = {
2526
{PTC5, SPI_0, 2},
@@ -125,7 +126,7 @@ void spi_frequency(spi_t *obj, int hz) {
125126
uint32_t ref_prescaler = 0;
126127

127128
// bus clk
128-
uint32_t PCLK = SystemCoreClock;
129+
uint32_t PCLK = bus_frequency();
129130
uint32_t divisor = 2;
130131
uint32_t prescaler;
131132

libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,14 @@
1616
#include <stddef.h>
1717
#include "us_ticker_api.h"
1818
#include "PeripheralNames.h"
19+
#include "clk_freqs.h"
1920

2021
static void pit_init(void);
2122
static void lptmr_init(void);
2223

24+
2325
static int us_ticker_inited = 0;
26+
static uint32_t pit_ldval = 0;
2427

2528
void us_ticker_init(void) {
2629
if (us_ticker_inited)
@@ -35,7 +38,7 @@ static uint32_t pit_us_ticker_counter = 0;
3538

3639
void pit0_isr(void) {
3740
pit_us_ticker_counter++;
38-
PIT->CHANNEL[0].LDVAL = 48; // 1us
41+
PIT->CHANNEL[0].LDVAL = pit_ldval; // 1us
3942
PIT->CHANNEL[0].TFLG = 1;
4043
}
4144

@@ -46,7 +49,9 @@ static void pit_init(void) {
4649
SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; // Clock PIT
4750
PIT->MCR = 0; // Enable PIT
4851

49-
PIT->CHANNEL[0].LDVAL = 48; // 1us
52+
pit_ldval = bus_frequency() / 1000000;
53+
54+
PIT->CHANNEL[0].LDVAL = pit_ldval; // 1us
5055
PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TIE_MASK;
5156
PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN_MASK; // Start timer 1
5257

@@ -82,10 +87,36 @@ static void lptmr_init(void) {
8287
NVIC_EnableIRQ(LPTimer_IRQn);
8388

8489
/* Clock at (1)MHz -> (1)tick/us */
85-
OSC0->CR |= OSC_CR_ERCLKEN_MASK;
86-
LPTMR0->PSR = 0;
87-
LPTMR0->PSR |= LPTMR_PSR_PCS(3); // OSCERCLK -> 8MHz
88-
LPTMR0->PSR |= LPTMR_PSR_PRESCALE(2); // divide by 8
90+
/* Check if the external oscillator can be divided to 1MHz */
91+
uint32_t extosc = extosc_frequency();
92+
93+
if (extosc != 0) { //If external oscillator found
94+
OSC0->CR |= OSC_CR_ERCLKEN_MASK;
95+
if (extosc % 1000000u == 0) { //If it is a multiple if 1MHz
96+
extosc /= 1000000;
97+
if (extosc == 1) { //1MHz, set timerprescaler in bypass mode
98+
LPTMR0->PSR = LPTMR_PSR_PCS(3) | LPTMR_PSR_PBYP_MASK;
99+
return;
100+
} else { //See if we can divide it to 1MHz
101+
uint32_t divider = 0;
102+
extosc >>= 1;
103+
while (1) {
104+
if (extosc == 1) {
105+
LPTMR0->PSR = LPTMR_PSR_PCS(3) | LPTMR_PSR_PRESCALE(divider);
106+
return;
107+
}
108+
if (extosc % 2 != 0) //If we can't divide by two anymore
109+
break;
110+
divider++;
111+
extosc >>= 1;
112+
}
113+
}
114+
}
115+
}
116+
//No suitable external oscillator clock -> Use fast internal oscillator (4MHz)
117+
MCG->C1 |= MCG_C1_IRCLKEN_MASK;
118+
MCG->C2 |= MCG_C2_IRCS_MASK;
119+
LPTMR0->PSR = LPTMR_PSR_PCS(0) | LPTMR_PSR_PRESCALE(1);
89120
}
90121

91122
void us_ticker_disable_interrupt(void) {

0 commit comments

Comments
 (0)