mbed library with additional peripherals for ST F401 board
Fork of mbed-src by
This mbed LIB has additional peripherals for ST F401 board
- UART2 : PA_3 rx, PA_2 tx
- UART3 : PC_7 rx, PC_6 tx
- I2C2 : PB_3 SDA, PB_10 SCL
- I2C3 : PB_4 SDA, PA_8 SCL
Revision 73:299c67215126, committed 2014-01-14
- Comitter:
- mbed_official
- Date:
- Tue Jan 14 20:45:05 2014 +0000
- Parent:
- 72:248c61396e08
- Child:
- 74:847f030b50ee
- Commit message:
- Synchronized with git revision cee9a71069fc940693df076382e8f182cf1a5919
Full URL: https://github.com/mbedmicro/mbed/commit/cee9a71069fc940693df076382e8f182cf1a5919/
K20D50M target - pwm and clocks in HAL
Changed in this revision
--- a/targets/hal/TARGET_Freescale/TARGET_K20D5M/analogin_api.c Mon Jan 13 10:45:05 2014 +0000 +++ b/targets/hal/TARGET_Freescale/TARGET_K20D5M/analogin_api.c Tue Jan 14 20:45:05 2014 +0000 @@ -18,6 +18,7 @@ #include "cmsis.h" #include "pinmap.h" #include "error.h" +#include "clk_freqs.h" static const PinMap PinMap_ADC[] = { {PTC2, ADC0_SE4b, 0}, @@ -33,6 +34,8 @@ {NC, NC, 0} }; +#define MAX_FADC 6000000 + void analogin_init(analogin_t *obj, PinName pin) { obj->adc = (ADCName)pinmap_peripheral(pin, PinMap_ADC); if (obj->adc == (ADCName)NC) @@ -43,13 +46,23 @@ uint32_t port = (uint32_t)pin >> PORT_SHIFT; SIM->SCGC5 |= 1 << (SIM_SCGC5_PORTA_SHIFT + port); + // bus clk + uint32_t PCLK = bus_frequency(); + uint32_t clkdiv; + for (clkdiv = 0; clkdiv < 4; clkdiv++) { + if ((PCLK >> clkdiv) <= MAX_FADC) + break; + } + if (clkdiv == 4) //Set max div + clkdiv = 0x7; + ADC0->SC1[1] = ADC_SC1_ADCH(obj->adc); ADC0->CFG1 = ADC_CFG1_ADLPC_MASK // Low-Power Configuration - | ADC_CFG1_ADIV(3) // Clock Divide Select: (Input Clock)/8 + | ADC_CFG1_ADIV(clkdiv & 0x3) // Clock Divide Select | ADC_CFG1_ADLSMP_MASK // Long Sample Time | ADC_CFG1_MODE(3) // (16)bits Resolution - | ADC_CFG1_ADICLK(1); // Input Clock: (Bus Clock)/2 + | ADC_CFG1_ADICLK(clkdiv >> 2); // Input Clock ADC0->CFG2 = ADC_CFG2_MUXSEL_MASK // ADxxb or ADxxa channels | ADC_CFG2_ADACKEN_MASK // Asynchronous Clock Output Enable
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/targets/hal/TARGET_Freescale/TARGET_K20D5M/clk_freqs.h Tue Jan 14 20:45:05 2014 +0000 @@ -0,0 +1,97 @@ +/* mbed Microcontroller Library + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef CLK_FREQS_H +#define CLK_FREQS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \brief Get the peripheral bus clock frequency + * \return Bus frequency + */ +static inline uint32_t bus_frequency(void) { + return SystemCoreClock / (((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT) + 1); +} + +/*! + * \brief Get external oscillator (crystal) frequency + * \return External osc frequency + */ +static uint32_t extosc_frequency(void) { + uint32_t MCGClock = SystemCoreClock * (1u + ((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV1_MASK) >> SIM_CLKDIV1_OUTDIV1_SHIFT)); + + if ((MCG->C1 & MCG_C1_CLKS_MASK) == MCG_C1_CLKS(2)) //MCG clock = external reference clock + return MCGClock; + + if ((MCG->C1 & MCG_C1_CLKS_MASK) == MCG_C1_CLKS(0)) { //PLL/FLL is selected + uint32_t divider, multiplier; + if ((MCG->C6 & MCG_C6_PLLS_MASK) == 0x0u) { //FLL is selected + if ((MCG->S & MCG_S_IREFST_MASK) == 0x0u) { //FLL uses external reference + divider = (uint8_t)(1u << ((MCG->C1 & MCG_C1_FRDIV_MASK) >> MCG_C1_FRDIV_SHIFT)); + if ((MCG->C2 & MCG_C2_RANGE0_MASK) != 0x0u) + divider <<= 5u; + /* Select correct multiplier to calculate the MCG output clock */ + switch (MCG->C4 & (MCG_C4_DMX32_MASK | MCG_C4_DRST_DRS_MASK)) { + case 0x0u: + multiplier = 640u; + break; + case 0x20u: + multiplier = 1280u; + break; + case 0x40u: + multiplier = 1920u; + break; + case 0x60u: + multiplier = 2560u; + break; + case 0x80u: + multiplier = 732u; + break; + case 0xA0u: + multiplier = 1464u; + break; + case 0xC0u: + multiplier = 2197u; + break; + case 0xE0u: + default: + multiplier = 2929u; + break; + } + + return MCGClock * divider / multiplier; + } + } else { //PLL is selected + divider = (1u + (MCG->C5 & MCG_C5_PRDIV0_MASK)); + multiplier = ((MCG->C6 & MCG_C6_VDIV0_MASK) + 24u); + return MCGClock * divider / multiplier; + } + } + + //In all other cases either there is no crystal or we cannot determine it + //For example when the FLL is running on the internal reference, and there is also an + //external crystal. However these are unlikely situations + return 0; +} + + +#ifdef __cplusplus +} +#endif + +#endif
--- a/targets/hal/TARGET_Freescale/TARGET_K20D5M/i2c_api.c Mon Jan 13 10:45:05 2014 +0000 +++ b/targets/hal/TARGET_Freescale/TARGET_K20D5M/i2c_api.c Tue Jan 14 20:45:05 2014 +0000 @@ -18,6 +18,7 @@ #include "cmsis.h" #include "pinmap.h" #include "error.h" +#include "clk_freqs.h" static const PinMap PinMap_I2C_SDA[] = { {PTB1, I2C_0, 2}, @@ -165,10 +166,11 @@ } static int i2c_do_read(i2c_t *obj, char * data, int last) { - if (last) + if (last) { i2c_send_nack(obj); - else + } else { i2c_send_ack(obj); + } *data = (obj->i2c->D & 0xFF); @@ -184,7 +186,7 @@ uint32_t ref = 0; uint8_t i, j; // bus clk - uint32_t PCLK = 24000000u; + uint32_t PCLK = bus_frequency(); uint32_t pulse = PCLK / (hz * 2); // we look for the values that minimize the error @@ -237,9 +239,8 @@ } // If not repeated start, send stop. - if (stop) { + if (stop) i2c_stop(obj); - } // last read data[count-1] = obj->i2c->D; @@ -326,11 +327,9 @@ // read addressed case 0xE6: return 1; - // write addressed case 0xE2: return 3; - default: return 0; }
--- a/targets/hal/TARGET_Freescale/TARGET_K20D5M/objects.h Mon Jan 13 10:45:05 2014 +0000 +++ b/targets/hal/TARGET_Freescale/TARGET_K20D5M/objects.h Tue Jan 14 20:45:05 2014 +0000 @@ -43,7 +43,6 @@ __IO uint32_t *MOD; __IO uint32_t *CNT; __IO uint32_t *CnV; - __IO uint32_t *SYNC; }; struct serial_s {
--- a/targets/hal/TARGET_Freescale/TARGET_K20D5M/pwmout_api.c Mon Jan 13 10:45:05 2014 +0000 +++ b/targets/hal/TARGET_Freescale/TARGET_K20D5M/pwmout_api.c Tue Jan 14 20:45:05 2014 +0000 @@ -21,21 +21,34 @@ static const PinMap PinMap_PWM[] = { // LEDs - {LED_RED , PWM_3 , 3}, // PTC3, FTM0 CH2 - {LED_GREEN, PWM_5, 3}, // PTD4, FTM0 CH4 - {LED_BLUE , PWM_9 , 3}, // PTA2 , FTM0 CH7 + {LED_RED , PWM_3 , 4}, // PTC3, FTM0 CH2 + {LED_GREEN, PWM_5, 4}, // PTD4, FTM0 CH4 + {LED_BLUE , PWM_8 , 3}, // PTA2, FTM0 CH7 // Arduino digital pinout - {D3, PWM_5 , 3}, // PTD4, FTM0 CH4 - {D5, PWM_7 , 3}, // PTA1 , FTM0 CH6 - {D6, PWM_3 , 3}, // PTC3 , FTM0 CH2 - {D9, PWM_8 , 4}, // PTD2 , FTM0 CH7 - {D10, PWM_2 , 4}, // PTC2 , FTM0 CH1 + {D3, PWM_5 , 4}, // PTD4, FTM0 CH4 + {D5, PWM_7 , 3}, // PTA1, FTM0 CH6 + {D6, PWM_3 , 4}, // PTC3, FTM0 CH2 + {D9, PWM_6 , 4}, // PTD5, FTM0 CH6 + {D10, PWM_2 , 4}, // PTC2, FTM0 CH1 + + {PTA0, PWM_6 , 3}, // PTA0, FTM0 CH5 + {PTA3, PWM_1 , 3}, // PTA3, FTM0 CH0 + {PTA4, PWM_2 , 3}, // PTA4, FTM0 CH1 + {PTA5, PWM_3 , 3}, // PTA5, FTM0 CH2 + {PTA12, PWM_9 , 3}, // PTA12, FTM1 CH0 + {PTA13, PWM_10, 3}, // PTA13, FTM1 CH1 + {PTB0, PWM_9 , 3}, // PTB0, FTM1 CH0 + {PTB1, PWM_10, 3}, // PTB1, FTM1 CH1 + {PTC1, PWM_1 , 4}, // PTC1, FTM0 CH0 + {PTD4, PWM_4 , 4}, // PTD4, FTM0 CH3 + {PTD6, PWM_7 , 4}, // PTD6, FTM0 CH6 + {PTD7, PWM_8 , 4}, // PTD7, FTM0 CH7 {NC , NC , 0} }; -#define PWM_CLOCK_MHZ (0.75) // (48)MHz / 64 = (0.75)MHz +static float pwm_clock = 0; void pwmout_init(pwmout_t* obj, PinName pin) { // determine the channel @@ -43,6 +56,17 @@ if (pwm == (PWMName)NC) error("PwmOut pin mapping failed"); + uint32_t clkdiv = 0; + float clkval = SystemCoreClock / 1000000.0f; + + while (clkval > 1) { + clkdiv++; + clkval /= 2.0; + if (clkdiv == 7) + break; + } + + pwm_clock = clkval; unsigned int port = (unsigned int)pin >> PORT_SHIFT; unsigned int ftm_n = (pwm >> TPM_SHIFT); unsigned int ch_n = (pwm & 0xFF); @@ -51,22 +75,17 @@ SIM->SCGC6 |= 1 << (SIM_SCGC6_FTM0_SHIFT + ftm_n); FTM_Type *ftm = (FTM_Type *)(FTM0_BASE + 0x1000 * ftm_n); - ftm->MODE |= FTM_MODE_WPDIS_MASK; //write protection disabled ftm->CONF |= FTM_CONF_BDMMODE(3); - ftm->SC = FTM_SC_CLKS(1) | FTM_SC_PS(6); // (48)MHz / 64 = (0.75)MHz + ftm->SC = FTM_SC_CLKS(1) | FTM_SC_PS(clkdiv); // (clock)MHz / clkdiv ~= (0.75)MHz ftm->CONTROLS[ch_n].CnSC = (FTM_CnSC_MSB_MASK | FTM_CnSC_ELSB_MASK); /* No Interrupts; High True pulses on Edge Aligned PWM */ - ftm->PWMLOAD |= FTM_PWMLOAD_LDOK_MASK; //loading updated values enabled - //ftm->SYNCONF |= FTM_SYNCONF_SWRSTCNT_MASK; - ftm->MODE |= FTM_MODE_INIT_MASK; obj->CnV = &ftm->CONTROLS[ch_n].CnV; obj->MOD = &ftm->MOD; obj->CNT = &ftm->CNT; - obj->SYNC = &ftm->SYNC; // default to 20ms: standard for servos, and fine for e.g. brightness control pwmout_period_ms(obj, 20); - pwmout_write (obj, 0); + pwmout_write(obj, 0); // Wire pinout pinmap_pinout(pin, PinMap_PWM); @@ -82,8 +101,6 @@ } *obj->CnV = (uint32_t)((float)(*obj->MOD) * value); - *obj->CNT = 0; - //*obj->SYNC |= FTM_SYNC_SWSYNC_MASK; } float pwmout_read(pwmout_t* obj) { @@ -102,7 +119,7 @@ // Set the PWM period, keeping the duty cycle the same. void pwmout_period_us(pwmout_t* obj, int us) { float dc = pwmout_read(obj); - *obj->MOD = PWM_CLOCK_MHZ * us; + *obj->MOD = (uint32_t)(pwm_clock * (float)us); pwmout_write(obj, dc); } @@ -115,5 +132,5 @@ } void pwmout_pulsewidth_us(pwmout_t* obj, int us) { - *obj->CnV = PWM_CLOCK_MHZ * us; + *obj->CnV = (uint32_t)(pwm_clock * (float)us); }
--- a/targets/hal/TARGET_Freescale/TARGET_K20D5M/serial_api.c Mon Jan 13 10:45:05 2014 +0000 +++ b/targets/hal/TARGET_Freescale/TARGET_K20D5M/serial_api.c Tue Jan 14 20:45:05 2014 +0000 @@ -53,7 +53,7 @@ obj->uart = (UART_Type *)uart; // enable clk switch (uart) { - case UART_0: SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK | (1<<SIM_SOPT5_UART0TXSRC_SHIFT); + case UART_0: SIM->SOPT2 |= SIM_SOPT2_PLLFLLSEL_MASK; SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK; SIM->SCGC4 |= SIM_SCGC4_UART0_MASK; break; case UART_1: SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK; SIM->SCGC4 |= SIM_SCGC4_UART1_MASK; break; case UART_2: SIM->SCGC5 |= SIM_SCGC5_PORTD_MASK; SIM->SCGC4 |= SIM_SCGC4_UART2_MASK; break; @@ -98,8 +98,7 @@ // Disable UART before changing registers obj->uart->C2 &= ~(UART_C2_RE_MASK | UART_C2_TE_MASK); - // [TODO] not hardcode this value - uint32_t PCLK = (obj->uart == UART0) ? 48000000u : 24000000u; + uint32_t PCLK = (obj->uart == UART0) ? SystemCoreClock : SystemCoreClock/2; // First we check to see if the basic divide with no DivAddVal/MulVal // ratio gives us an integer result. If it does, we set DivAddVal = 0,
--- a/targets/hal/TARGET_Freescale/TARGET_K20D5M/spi_api.c Mon Jan 13 10:45:05 2014 +0000 +++ b/targets/hal/TARGET_Freescale/TARGET_K20D5M/spi_api.c Tue Jan 14 20:45:05 2014 +0000 @@ -20,6 +20,7 @@ #include "cmsis.h" #include "pinmap.h" #include "error.h" +#include "clk_freqs.h" static const PinMap PinMap_SPI_SCLK[] = { {PTC5, SPI_0, 2}, @@ -59,11 +60,12 @@ error("SPI pinout mapping failed"); } - SIM->SCGC5 |= (1 << 11) | (1 << 12); // PortC & D - SIM->SCGC6 |= 1 << 12; // spi clocks + SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK | SIM_SCGC5_PORTD_MASK; + SIM->SCGC6 |= SIM_SCGC6_SPI0_MASK; // halted state - obj->spi->MCR = SPI_MCR_HALT_MASK; + obj->spi->MCR &= ~SPI_MCR_MDIS_MASK; + obj->spi->MCR |= SPI_MCR_HALT_MASK | SPI_MCR_DIS_RXF_MASK | SPI_MCR_DIS_TXF_MASK; // set default format and frequency if (ssel == NC) { @@ -111,50 +113,60 @@ obj->spi->CTAR[0] |= (polarity << SPI_CTAR_CPOL_SHIFT) | (phase << SPI_CTAR_CPHA_SHIFT); } +static const uint8_t baudrate_prescaler[] = {2,3,5,7}; +static const uint32_t baudrate_scaler[] = {2, 4, 6, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768}; +static const uint8_t delay_prescaler[] = {1, 3, 5, 7}; + void spi_frequency(spi_t *obj, int hz) { uint32_t error = 0; uint32_t p_error = 0xffffffff; uint32_t ref = 0; - uint32_t spr = 0; + uint32_t br = 0; uint32_t ref_spr = 0; uint32_t ref_prescaler = 0; // bus clk - uint32_t PCLK = 48000000u; - uint32_t prescaler = 1; + uint32_t PCLK = bus_frequency(); uint32_t divisor = 2; + uint32_t prescaler; - for (prescaler = 1; prescaler <= 8; prescaler++) { + /* TODO */ + for (uint32_t i = 0; i < 4; i++) { + prescaler = baudrate_prescaler[i]; divisor = 2; - for (spr = 0; spr <= 8; spr++, divisor *= 2) { - ref = PCLK / (prescaler*divisor); - if (ref > (uint32_t)hz) - continue; - error = hz - ref; - if (error < p_error) { - ref_spr = spr; - ref_prescaler = prescaler - 1; - p_error = error; + for (br = 0; br <= 15; br++, divisor *= 2) { + for (uint32_t dr = 0; dr < 2; dr++) { + ref = (PCLK / prescaler) * ((1U + dr) / divisor); + if (ref > (uint32_t)hz) + continue; + error = hz - ref; + if (error < p_error) { + ref_spr = br; + ref_prescaler = i; + p_error = error; + } } } } - // set SPPR and SPR - obj->spi->CTAR[0] = ((ref_prescaler & 0x7) << 4) | (ref_spr & 0xf); + // set PBR and BR + obj->spi->CTAR[0] = ((ref_prescaler & 0x3) << SPI_CTAR_PBR_SHIFT) | (ref_spr & 0xf); } -static inline int spi_writeable(spi_t * obj) { - return (obj->spi->SR & SPI_SR_TCF_MASK) ? 1 : 0; +static inline int spi_writeable(spi_t *obj) { + return (obj->spi->SR & SPI_SR_TFFF_MASK) ? 1 : 0; } -static inline int spi_readable(spi_t * obj) { - return (obj->spi->SR & SPI_SR_TFFF_MASK) ? 1 : 0; +static inline int spi_readable(spi_t *obj) { + return (obj->spi->SR & SPI_SR_RFDF_MASK) ? 0 : 1; } int spi_master_write(spi_t *obj, int value) { // wait tx buffer empty while(!spi_writeable(obj)); - obj->spi->PUSHR = SPI_PUSHR_TXDATA(value & 0xff); + obj->spi->PUSHR = SPI_PUSHR_TXDATA(value & 0xff) /*| SPI_PUSHR_EOQ_MASK*/; + + while (!obj->spi->SR & SPI_SR_TCF_MASK); // wait for transfer to be complete // wait rx buffer full while (!spi_readable(obj));
--- a/targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c Mon Jan 13 10:45:05 2014 +0000 +++ b/targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c Tue Jan 14 20:45:05 2014 +0000 @@ -16,11 +16,14 @@ #include <stddef.h> #include "us_ticker_api.h" #include "PeripheralNames.h" +#include "clk_freqs.h" static void pit_init(void); static void lptmr_init(void); + static int us_ticker_inited = 0; +static uint32_t pit_ldval = 0; void us_ticker_init(void) { if (us_ticker_inited) @@ -35,7 +38,7 @@ void pit0_isr(void) { pit_us_ticker_counter++; - PIT->CHANNEL[0].LDVAL = 48; // 1us + PIT->CHANNEL[0].LDVAL = pit_ldval; // 1us PIT->CHANNEL[0].TFLG = 1; } @@ -46,7 +49,9 @@ SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; // Clock PIT PIT->MCR = 0; // Enable PIT - PIT->CHANNEL[0].LDVAL = 48; // 1us + pit_ldval = bus_frequency() / 1000000; + + PIT->CHANNEL[0].LDVAL = pit_ldval; // 1us PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TIE_MASK; PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN_MASK; // Start timer 1 @@ -82,10 +87,36 @@ NVIC_EnableIRQ(LPTimer_IRQn); /* Clock at (1)MHz -> (1)tick/us */ - OSC0->CR |= OSC_CR_ERCLKEN_MASK; - LPTMR0->PSR = 0; - LPTMR0->PSR |= LPTMR_PSR_PCS(3); // OSCERCLK -> 8MHz - LPTMR0->PSR |= LPTMR_PSR_PRESCALE(2); // divide by 8 + /* Check if the external oscillator can be divided to 1MHz */ + uint32_t extosc = extosc_frequency(); + + if (extosc != 0) { //If external oscillator found + OSC0->CR |= OSC_CR_ERCLKEN_MASK; + if (extosc % 1000000u == 0) { //If it is a multiple if 1MHz + extosc /= 1000000; + if (extosc == 1) { //1MHz, set timerprescaler in bypass mode + LPTMR0->PSR = LPTMR_PSR_PCS(3) | LPTMR_PSR_PBYP_MASK; + return; + } else { //See if we can divide it to 1MHz + uint32_t divider = 0; + extosc >>= 1; + while (1) { + if (extosc == 1) { + LPTMR0->PSR = LPTMR_PSR_PCS(3) | LPTMR_PSR_PRESCALE(divider); + return; + } + if (extosc % 2 != 0) //If we can't divide by two anymore + break; + divider++; + extosc >>= 1; + } + } + } + } + //No suitable external oscillator clock -> Use fast internal oscillator (4MHz) + MCG->C1 |= MCG_C1_IRCLKEN_MASK; + MCG->C2 |= MCG_C2_IRCS_MASK; + LPTMR0->PSR = LPTMR_PSR_PCS(0) | LPTMR_PSR_PRESCALE(1); } void us_ticker_disable_interrupt(void) {