mbed library with additional peripherals for ST F401 board

Fork of mbed-src by mbed official

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

Files at this revision

API Documentation at this revision

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

targets/hal/TARGET_Freescale/TARGET_K20D5M/analogin_api.c Show annotated file Show diff for this revision Revisions of this file
targets/hal/TARGET_Freescale/TARGET_K20D5M/clk_freqs.h Show annotated file Show diff for this revision Revisions of this file
targets/hal/TARGET_Freescale/TARGET_K20D5M/i2c_api.c Show annotated file Show diff for this revision Revisions of this file
targets/hal/TARGET_Freescale/TARGET_K20D5M/objects.h Show annotated file Show diff for this revision Revisions of this file
targets/hal/TARGET_Freescale/TARGET_K20D5M/pwmout_api.c Show annotated file Show diff for this revision Revisions of this file
targets/hal/TARGET_Freescale/TARGET_K20D5M/serial_api.c Show annotated file Show diff for this revision Revisions of this file
targets/hal/TARGET_Freescale/TARGET_K20D5M/spi_api.c Show annotated file Show diff for this revision Revisions of this file
targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c Show annotated file Show diff for this revision Revisions of this file
--- 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) {