Skip to content

Commit cee9a71

Browse files
committed
Merge pull request #144 from 0xc0170/dev_k20d5m_testing
K20D50M target - pwm and clocks in HAL
2 parents f1904ba + 937430a commit cee9a71

File tree

8 files changed

+229
-62
lines changed

8 files changed

+229
-62
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: 6 additions & 7 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_I2C_SDA[] = {
2324
{PTB1, I2C_0, 2},
@@ -165,10 +166,11 @@ static int i2c_do_write(i2c_t *obj, int value) {
165166
}
166167

167168
static int i2c_do_read(i2c_t *obj, char * data, int last) {
168-
if (last)
169+
if (last) {
169170
i2c_send_nack(obj);
170-
else
171+
} else {
171172
i2c_send_ack(obj);
173+
}
172174

173175
*data = (obj->i2c->D & 0xFF);
174176

@@ -184,7 +186,7 @@ void i2c_frequency(i2c_t *obj, int hz) {
184186
uint32_t ref = 0;
185187
uint8_t i, j;
186188
// bus clk
187-
uint32_t PCLK = 24000000u;
189+
uint32_t PCLK = bus_frequency();
188190
uint32_t pulse = PCLK / (hz * 2);
189191

190192
// we look for the values that minimize the error
@@ -237,9 +239,8 @@ int i2c_read(i2c_t *obj, int address, char *data, int length, int stop) {
237239
}
238240

239241
// If not repeated start, send stop.
240-
if (stop) {
242+
if (stop)
241243
i2c_stop(obj);
242-
}
243244

244245
// last read
245246
data[count-1] = obj->i2c->D;
@@ -326,11 +327,9 @@ int i2c_slave_receive(i2c_t *obj) {
326327
// read addressed
327328
case 0xE6:
328329
return 1;
329-
330330
// write addressed
331331
case 0xE2:
332332
return 3;
333-
334333
default:
335334
return 0;
336335
}

libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/objects.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ struct pwmout_s {
4343
__IO uint32_t *MOD;
4444
__IO uint32_t *CNT;
4545
__IO uint32_t *CnV;
46-
__IO uint32_t *SYNC;
4746
};
4847

4948
struct serial_s {

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

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -21,28 +21,52 @@
2121

2222
static const PinMap PinMap_PWM[] = {
2323
// LEDs
24-
{LED_RED , PWM_3 , 3}, // PTC3, FTM0 CH2
25-
{LED_GREEN, PWM_5, 3}, // PTD4, FTM0 CH4
26-
{LED_BLUE , PWM_9 , 3}, // PTA2 , FTM0 CH7
24+
{LED_RED , PWM_3 , 4}, // PTC3, FTM0 CH2
25+
{LED_GREEN, PWM_5, 4}, // PTD4, FTM0 CH4
26+
{LED_BLUE , PWM_8 , 3}, // PTA2, FTM0 CH7
2727

2828
// Arduino digital pinout
29-
{D3, PWM_5 , 3}, // PTD4, FTM0 CH4
30-
{D5, PWM_7 , 3}, // PTA1 , FTM0 CH6
31-
{D6, PWM_3 , 3}, // PTC3 , FTM0 CH2
32-
{D9, PWM_8 , 4}, // PTD2 , FTM0 CH7
33-
{D10, PWM_2 , 4}, // PTC2 , FTM0 CH1
29+
{D3, PWM_5 , 4}, // PTD4, FTM0 CH4
30+
{D5, PWM_7 , 3}, // PTA1, FTM0 CH6
31+
{D6, PWM_3 , 4}, // PTC3, FTM0 CH2
32+
{D9, PWM_6 , 4}, // PTD5, FTM0 CH6
33+
{D10, PWM_2 , 4}, // PTC2, FTM0 CH1
34+
35+
{PTA0, PWM_6 , 3}, // PTA0, FTM0 CH5
36+
{PTA3, PWM_1 , 3}, // PTA3, FTM0 CH0
37+
{PTA4, PWM_2 , 3}, // PTA4, FTM0 CH1
38+
{PTA5, PWM_3 , 3}, // PTA5, FTM0 CH2
39+
{PTA12, PWM_9 , 3}, // PTA12, FTM1 CH0
40+
{PTA13, PWM_10, 3}, // PTA13, FTM1 CH1
41+
{PTB0, PWM_9 , 3}, // PTB0, FTM1 CH0
42+
{PTB1, PWM_10, 3}, // PTB1, FTM1 CH1
43+
{PTC1, PWM_1 , 4}, // PTC1, FTM0 CH0
44+
{PTD4, PWM_4 , 4}, // PTD4, FTM0 CH3
45+
{PTD6, PWM_7 , 4}, // PTD6, FTM0 CH6
46+
{PTD7, PWM_8 , 4}, // PTD7, FTM0 CH7
3447

3548
{NC , NC , 0}
3649
};
3750

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

4053
void pwmout_init(pwmout_t* obj, PinName pin) {
4154
// determine the channel
4255
PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM);
4356
if (pwm == (PWMName)NC)
4457
error("PwmOut pin mapping failed");
4558

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;
4670
unsigned int port = (unsigned int)pin >> PORT_SHIFT;
4771
unsigned int ftm_n = (pwm >> TPM_SHIFT);
4872
unsigned int ch_n = (pwm & 0xFF);
@@ -51,22 +75,17 @@ void pwmout_init(pwmout_t* obj, PinName pin) {
5175
SIM->SCGC6 |= 1 << (SIM_SCGC6_FTM0_SHIFT + ftm_n);
5276

5377
FTM_Type *ftm = (FTM_Type *)(FTM0_BASE + 0x1000 * ftm_n);
54-
ftm->MODE |= FTM_MODE_WPDIS_MASK; //write protection disabled
5578
ftm->CONF |= FTM_CONF_BDMMODE(3);
56-
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
5780
ftm->CONTROLS[ch_n].CnSC = (FTM_CnSC_MSB_MASK | FTM_CnSC_ELSB_MASK); /* No Interrupts; High True pulses on Edge Aligned PWM */
58-
ftm->PWMLOAD |= FTM_PWMLOAD_LDOK_MASK; //loading updated values enabled
59-
//ftm->SYNCONF |= FTM_SYNCONF_SWRSTCNT_MASK;
60-
ftm->MODE |= FTM_MODE_INIT_MASK;
6181

6282
obj->CnV = &ftm->CONTROLS[ch_n].CnV;
6383
obj->MOD = &ftm->MOD;
6484
obj->CNT = &ftm->CNT;
65-
obj->SYNC = &ftm->SYNC;
6685

6786
// default to 20ms: standard for servos, and fine for e.g. brightness control
6887
pwmout_period_ms(obj, 20);
69-
pwmout_write (obj, 0);
88+
pwmout_write(obj, 0);
7089

7190
// Wire pinout
7291
pinmap_pinout(pin, PinMap_PWM);
@@ -82,8 +101,6 @@ void pwmout_write(pwmout_t* obj, float value) {
82101
}
83102

84103
*obj->CnV = (uint32_t)((float)(*obj->MOD) * value);
85-
*obj->CNT = 0;
86-
//*obj->SYNC |= FTM_SYNC_SWSYNC_MASK;
87104
}
88105

89106
float pwmout_read(pwmout_t* obj) {
@@ -102,7 +119,7 @@ void pwmout_period_ms(pwmout_t* obj, int ms) {
102119
// Set the PWM period, keeping the duty cycle the same.
103120
void pwmout_period_us(pwmout_t* obj, int us) {
104121
float dc = pwmout_read(obj);
105-
*obj->MOD = PWM_CLOCK_MHZ * us;
122+
*obj->MOD = (uint32_t)(pwm_clock * (float)us);
106123
pwmout_write(obj, dc);
107124
}
108125

@@ -115,5 +132,5 @@ void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) {
115132
}
116133

117134
void pwmout_pulsewidth_us(pwmout_t* obj, int us) {
118-
*obj->CnV = PWM_CLOCK_MHZ * us;
135+
*obj->CnV = (uint32_t)(pwm_clock * (float)us);
119136
}

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

Lines changed: 2 additions & 3 deletions
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;
@@ -98,8 +98,7 @@ void serial_baud(serial_t *obj, int baudrate) {
9898
// Disable UART before changing registers
9999
obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK);
100100

101-
// [TODO] not hardcode this value
102-
uint32_t PCLK = (obj->uart == UART0) ? 48000000u : 24000000u;
101+
uint32_t PCLK = (obj->uart == UART0) ? SystemCoreClock : SystemCoreClock/2;
103102

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

0 commit comments

Comments
 (0)