Skip to content

Commit aa0f7a7

Browse files
committed
Added clk_freqs.h for clock related functions
Serial now also works when PLL/FLL is disabled and extosc is available. us_ticker tries to divide extosc to 1MHz, otherwise use fast internal oscillator
1 parent ebdbf53 commit aa0f7a7

File tree

6 files changed

+135
-10
lines changed

6 files changed

+135
-10
lines changed

libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/analogin_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
#define MAX_FADC 6000000
2324

@@ -58,7 +59,7 @@ void analogin_init(analogin_t *obj, PinName pin) {
5859
}
5960

6061
// bus clk
61-
uint32_t PCLK = SystemCoreClock / (((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT) + 1);
62+
uint32_t PCLK = bus_frequency();
6263
uint32_t clkdiv;
6364
for (clkdiv = 0; clkdiv < 4; clkdiv++) {
6465
if ((PCLK >> clkdiv) <= MAX_FADC)
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
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 MBED_CLK_FREQS_H
17+
#define MBED_CLK_FREQS_H
18+
19+
#ifdef __cplusplus
20+
extern "C" {
21+
#endif
22+
23+
//Get the peripheral bus clock frequency
24+
static inline uint32_t bus_frequency(void) {
25+
return SystemCoreClock / (((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT) + 1);
26+
}
27+
28+
//Get external oscillator (crystal) frequency
29+
static uint32_t extosc_frequency(void) {
30+
uint32_t MCGClock = SystemCoreClock * (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT));
31+
32+
if ((MCG->C1 & MCG_C1_CLKS_MASK) == MCG_C1_CLKS(2)) //MCG clock = external reference clock
33+
return MCGClock;
34+
35+
if ((MCG->C1 & MCG_C1_CLKS_MASK) == MCG_C1_CLKS(0)) { //PLL/FLL is selected
36+
uint32_t divider, multiplier;
37+
if ((MCG->C6 & MCG_C6_PLLS_MASK) == 0x0u) { //FLL is selected
38+
if ((MCG->S & MCG_S_IREFST_MASK) == 0x0u) { //FLL uses external reference
39+
divider = (uint8_t)(1u << ((MCG->C1 & MCG_C1_FRDIV_MASK) >> MCG_C1_FRDIV_SHIFT));
40+
if ((MCG->C2 & MCG_C2_RANGE0_MASK) != 0x0u)
41+
divider <<= 5u;
42+
/* Select correct multiplier to calculate the MCG output clock */
43+
switch (MCG->C4 & (MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) {
44+
case 0x0u:
45+
multiplier = 640u;
46+
break;
47+
case 0x20u:
48+
multiplier = 1280u;
49+
break;
50+
case 0x40u:
51+
multiplier = 1920u;
52+
break;
53+
case 0x60u:
54+
multiplier = 2560u;
55+
break;
56+
case 0x80u:
57+
multiplier = 732u;
58+
break;
59+
case 0xA0u:
60+
multiplier = 1464u;
61+
break;
62+
case 0xC0u:
63+
multiplier = 2197u;
64+
break;
65+
case 0xE0u:
66+
default:
67+
multiplier = 2929u;
68+
break;
69+
}
70+
71+
return MCGClock * divider / multiplier;
72+
}
73+
} else { //PLL is selected
74+
divider = (1u + (MCG->C5 & MCG_C5_PRDIV0_MASK));
75+
multiplier = ((MCG->C6 & MCG_C6_VDIV0_MASK) + 24u);
76+
return MCGClock * divider / multiplier;
77+
}
78+
}
79+
80+
//In all other cases either there is no crystal or we cannot determine it
81+
//For example when the FLL is running on the internal reference, and there is also an
82+
//external crystal. However these are unlikely situations
83+
return 0;
84+
}
85+
86+
87+
#ifdef __cplusplus
88+
}
89+
#endif
90+
91+
#endif

libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/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
{PTE25, I2C_0, 5},
@@ -206,7 +207,7 @@ void i2c_frequency(i2c_t *obj, int hz) {
206207
uint32_t ref = 0;
207208
uint8_t i, j;
208209
// bus clk
209-
uint32_t PCLK = SystemCoreClock / (((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT) + 1);
210+
uint32_t PCLK = bus_frequency();
210211
uint32_t pulse = PCLK / (hz * 2);
211212

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

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

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "cmsis.h"
2424
#include "pinmap.h"
2525
#include "error.h"
26+
#include "clk_freqs.h"
2627

2728
/******************************************************************************
2829
* INITIALIZATION
@@ -70,7 +71,10 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) {
7071
obj->uart = (UARTLP_Type *)uart;
7172
// enable clk
7273
switch (uart) {
73-
case UART_0: SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK | (1<<SIM_SOPT2_UART0SRC_SHIFT);
74+
case UART_0: if ((MCG->C1 & MCG_C1_CLKS_MASK) == MCG_C1_CLKS(0)) //PLL/FLL is selected
75+
SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK | (1<<SIM_SOPT2_UART0SRC_SHIFT);
76+
else
77+
SIM->SOPT2 |= (2<<SIM_SOPT2_UART0SRC_SHIFT);
7478
SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK; SIM->SCGC4 |= SIM_SCGC4_UART0_MASK; break;
7579
case UART_1: SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK; SIM->SCGC4 |= SIM_SCGC4_UART1_MASK; break;
7680
case UART_2: SIM->SCGC5 |= SIM_SCGC5_PORTD_MASK; SIM->SCGC4 |= SIM_SCGC4_UART2_MASK; break;
@@ -119,8 +123,7 @@ void serial_baud(serial_t *obj, int baudrate) {
119123
// Disable UART before changing registers
120124
obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
121125

122-
// [TODO] not hardcode this value
123-
uint32_t PCLK = (obj->uart == UART0) ? SystemCoreClock : SystemCoreClock / (((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT) + 1);
126+
uint32_t PCLK = (obj->uart == UART0) ? SystemCoreClock : bus_frequency();
124127

125128
// First we check to see if the basic divide with no DivAddVal/MulVal
126129
// ratio gives us an integer result. If it does, we set DivAddVal = 0,

libraries/mbed/targets/hal/TARGET_Freescale/TARGET_KL25Z/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
{PTA15, SPI_0, 2},
@@ -145,7 +146,7 @@ void spi_frequency(spi_t *obj, int hz) {
145146
uint8_t ref_prescaler = 0;
146147

147148
// bus clk
148-
uint32_t PCLK = SystemCoreClock / (((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT) + 1);
149+
uint32_t PCLK = bus_frequency();
149150
uint8_t prescaler = 1;
150151
uint8_t divisor = 2;
151152

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

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
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);
@@ -43,8 +44,7 @@ static void pit_init(void) {
4344
PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_TEN_MASK; // Start timer 1
4445

4546
// Use channel 0 as a prescaler for channel 1
46-
uint32_t PCLK = SystemCoreClock / (((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT) + 1);
47-
PIT->CHANNEL[0].LDVAL = PCLK / 1000000 - 1;
47+
PIT->CHANNEL[0].LDVAL = bus_frequency() / 1000000 - 1;
4848
PIT->CHANNEL[0].TCTRL = PIT_TCTRL_TEN_MASK; // Start timer 0, disable interrupts
4949
}
5050

@@ -77,8 +77,36 @@ static void lptmr_init(void) {
7777
NVIC_EnableIRQ(LPTimer_IRQn);
7878

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

84112
void us_ticker_disable_interrupt(void) {

0 commit comments

Comments
 (0)