From 19d131973c50213daf355148c27dc8c265d0ae84 Mon Sep 17 00:00:00 2001 From: Sissors Date: Wed, 16 Apr 2014 08:12:31 +0200 Subject: [PATCH 1/5] Initial K20 fixes Added the required gpio-irq enable/disable + fixed bus_frequency --- .../TARGET_K20D5M/clk_freqs.h | 2 +- .../TARGET_K20D5M/gpio_irq_api.c | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/clk_freqs.h b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/clk_freqs.h index a86573ca1b..be7f10aa60 100644 --- a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/clk_freqs.h +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/clk_freqs.h @@ -25,7 +25,7 @@ extern "C" { * \return Bus frequency */ static inline uint32_t bus_frequency(void) { - return SystemCoreClock / (((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV4_MASK) >> SIM_CLKDIV1_OUTDIV4_SHIFT) + 1); + return SystemCoreClock / (((SIM->CLKDIV1 & SIM_CLKDIV1_OUTDIV2_MASK) >> SIM_CLKDIV1_OUTDIV2_SHIFT) + 1); } /*! diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/gpio_irq_api.c b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/gpio_irq_api.c index db4d36b758..3da9bb827a 100644 --- a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/gpio_irq_api.c +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/gpio_irq_api.c @@ -165,3 +165,43 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) { // Interrupt configuration and clear interrupt port->PCR[obj->pin] = (port->PCR[obj->pin] & ~PORT_PCR_IRQC_MASK) | irq_settings | PORT_PCR_ISF_MASK; } + +void gpio_irq_enable(gpio_irq_t *obj) { + switch (obj->port) { + case PortA: + NVIC_EnableIRQ(PORTA_IRQn); + break; + case PortB: + NVIC_EnableIRQ(PORTB_IRQn); + break; + case PortC: + NVIC_EnableIRQ(PORTC_IRQn); + break; + case PortD: + NVIC_EnableIRQ(PORTD_IRQn); + break; + case PortE: + NVIC_EnableIRQ(PORTE_IRQn); + break; + } +} + +void gpio_irq_disable(gpio_irq_t *obj) { + switch (obj->port) { + case PortA: + NVIC_DisableIRQ(PORTA_IRQn); + break; + case PortB: + NVIC_DisableIRQ(PORTB_IRQn); + break; + case PortC: + NVIC_DisableIRQ(PORTC_IRQn); + break; + case PortD: + NVIC_DisableIRQ(PORTD_IRQn); + break; + case PortE: + NVIC_DisableIRQ(PORTE_IRQn); + break; + } +} From 6ff874c0cbf66b21c151813883f39c6cb447b165 Mon Sep 17 00:00:00 2001 From: Sissors Date: Thu, 17 Apr 2014 18:04:36 +0200 Subject: [PATCH 2/5] Modified timer code Timer/Wait timer --- .../TARGET_K20D5M/us_ticker.c | 31 +++++++++++++++---- 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c index 72767601aa..f3885c9ecc 100644 --- a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c @@ -34,22 +34,29 @@ void us_ticker_init(void) { lptmr_init(); } -static uint32_t pit_us_ticker_counter = 0; +static volatile uint32_t pit_msb_counter = 0; +static uint32_t pit_division; //Division used to get LSB bits void pit0_isr(void) { - pit_us_ticker_counter++; - PIT->CHANNEL[0].LDVAL = pit_ldval; // 1us + pit_msb_counter++; + PIT->CHANNEL[0].LDVAL = pit_ldval; PIT->CHANNEL[0].TFLG = 1; } /****************************************************************************** * Timer for us timing. + * + * The K20D5M does not have a prescaler on its PIT timer nor the option + * to chain timers, which is why a software timer is required to get 32-bit + * word length. ******************************************************************************/ static void pit_init(void) { SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; // Clock PIT PIT->MCR = 0; // Enable PIT - - pit_ldval = bus_frequency() / 1000000; + + pit_division = bus_frequency() / 1000000; + //CLZ counts the leading zeros, returning number of bits not used by pit_division + pit_ldval = pit_division << __CLZ(pit_division); PIT->CHANNEL[0].LDVAL = pit_ldval; // 1us PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TIE_MASK; @@ -62,8 +69,20 @@ static void pit_init(void) { uint32_t us_ticker_read() { if (!us_ticker_inited) us_ticker_init(); + + uint32_t retval; + __disable_irq(); + retval = (pit_ldval - PIT->CHANNEL[0].CVAL) / pit_division; //Hardware bits + retval |= pit_msb_counter << __CLZ(pit_division); //Software bits + + if (PIT->CHANNEL[0].TFLG == 1) { //If overflow bit is set, force it to be handled + pit0_isr(); //Handle IRQ, read again to make sure software/hardware bits are synced + NVIC_ClearPendingIRQ(PIT0_IRQn); + return us_ticker_read(); + } - return pit_us_ticker_counter; + __enable_irq(); + return retval; } /****************************************************************************** From ee658aa3e1199ee077fdf58b5acd630abe862105 Mon Sep 17 00:00:00 2001 From: Sissors Date: Thu, 17 Apr 2014 18:08:15 +0200 Subject: [PATCH 3/5] Some tab fixes --- .../hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c index f3885c9ecc..78cdd7a24a 100644 --- a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c @@ -73,11 +73,11 @@ uint32_t us_ticker_read() { uint32_t retval; __disable_irq(); retval = (pit_ldval - PIT->CHANNEL[0].CVAL) / pit_division; //Hardware bits - retval |= pit_msb_counter << __CLZ(pit_division); //Software bits + retval |= pit_msb_counter << __CLZ(pit_division); //Software bits - if (PIT->CHANNEL[0].TFLG == 1) { //If overflow bit is set, force it to be handled - pit0_isr(); //Handle IRQ, read again to make sure software/hardware bits are synced - NVIC_ClearPendingIRQ(PIT0_IRQn); + if (PIT->CHANNEL[0].TFLG == 1) { //If overflow bit is set, force it to be handled + pit0_isr(); //Handle IRQ, read again to make sure software/hardware bits are synced + NVIC_ClearPendingIRQ(PIT0_IRQn); return us_ticker_read(); } From ccdfed52eb7bac069360c64fa87e4213e73e1e5e Mon Sep 17 00:00:00 2001 From: Sissors Date: Thu, 17 Apr 2014 22:36:03 +0200 Subject: [PATCH 4/5] Moved ticker timer to a PIT channel + adjusted namings The timer which creates interrupts is now also done using one of the PIT channels. Since also here no chaining is possible we still need to do some bits in software, but 32-bit without prescaling is still better than 16-bit with. Also some code was moved around and naming conventions changes, since no lptmr is used anymore, and calling both pit-timer would get confusing --- .../TARGET_K20D5M/us_ticker.c | 175 +++++++----------- 1 file changed, 65 insertions(+), 110 deletions(-) diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c index 78cdd7a24a..c0666ccd16 100644 --- a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/us_ticker.c @@ -18,29 +18,30 @@ #include "PeripheralNames.h" #include "clk_freqs.h" -static void pit_init(void); -static void lptmr_init(void); +#define PIT_TIMER PIT->CHANNEL[0] +#define PIT_TIMER_IRQ PIT0_IRQn +#define PIT_TICKER PIT->CHANNEL[1] +#define PIT_TICKER_IRQ PIT1_IRQn + +static void timer_init(void); +static void ticker_init(void); static int us_ticker_inited = 0; -static uint32_t pit_ldval = 0; +static uint32_t clk_mhz; void us_ticker_init(void) { if (us_ticker_inited) return; us_ticker_inited = 1; + + SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; // Clock PIT + PIT->MCR = 0; // Enable PIT + + clk_mhz = bus_frequency() / 1000000; - pit_init(); - lptmr_init(); -} - -static volatile uint32_t pit_msb_counter = 0; -static uint32_t pit_division; //Division used to get LSB bits - -void pit0_isr(void) { - pit_msb_counter++; - PIT->CHANNEL[0].LDVAL = pit_ldval; - PIT->CHANNEL[0].TFLG = 1; + timer_init(); + ticker_init(); } /****************************************************************************** @@ -50,20 +51,24 @@ void pit0_isr(void) { * to chain timers, which is why a software timer is required to get 32-bit * word length. ******************************************************************************/ -static void pit_init(void) { - SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; // Clock PIT - PIT->MCR = 0; // Enable PIT - - pit_division = bus_frequency() / 1000000; - //CLZ counts the leading zeros, returning number of bits not used by pit_division - pit_ldval = pit_division << __CLZ(pit_division); +static volatile uint32_t msb_counter = 0; +static uint32_t timer_ldval = 0; - 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 +static void timer_isr(void) { + msb_counter++; + PIT_TIMER.TFLG = 1; +} - NVIC_SetVector(PIT0_IRQn, (uint32_t)pit0_isr); - NVIC_EnableIRQ(PIT0_IRQn); +static void timer_init(void) { + //CLZ counts the leading zeros, returning number of bits not used by clk_mhz + timer_ldval = clk_mhz << __CLZ(clk_mhz); + + PIT_TIMER.LDVAL = timer_ldval; // 1us + PIT_TIMER.TCTRL |= PIT_TCTRL_TIE_MASK; + PIT_TIMER.TCTRL |= PIT_TCTRL_TEN_MASK; // Start timer 0 + + NVIC_SetVector(PIT_TIMER_IRQ, (uint32_t)timer_isr); + NVIC_EnableIRQ(PIT_TIMER_IRQ); } uint32_t us_ticker_read() { @@ -72,14 +77,14 @@ uint32_t us_ticker_read() { uint32_t retval; __disable_irq(); - retval = (pit_ldval - PIT->CHANNEL[0].CVAL) / pit_division; //Hardware bits - retval |= pit_msb_counter << __CLZ(pit_division); //Software bits + retval = (timer_ldval - PIT_TIMER.CVAL) / clk_mhz; //Hardware bits + retval |= msb_counter << __CLZ(clk_mhz); //Software bits - if (PIT->CHANNEL[0].TFLG == 1) { //If overflow bit is set, force it to be handled - pit0_isr(); //Handle IRQ, read again to make sure software/hardware bits are synced - NVIC_ClearPendingIRQ(PIT0_IRQn); + if (PIT_TIMER.TFLG == 1) { //If overflow bit is set, force it to be handled + timer_isr(); //Handle IRQ, read again to make sure software/hardware bits are synced + NVIC_ClearPendingIRQ(PIT_TIMER_IRQ); return us_ticker_read(); - } + } __enable_irq(); return retval; @@ -89,57 +94,19 @@ uint32_t us_ticker_read() { * Timer Event * * It schedules interrupts at given (32bit)us interval of time. - * It is implemented used the 16bit Low Power Timer that remains powered in all - * power modes. + * It is implemented using PIT channel 1, since no prescaler is available, + * some bits are implemented in software. ******************************************************************************/ -static void lptmr_isr(void); - -static void lptmr_init(void) { - /* Clock the timer */ - SIM->SCGC5 |= SIM_SCGC5_LPTIMER_MASK; - - /* Reset */ - LPTMR0->CSR = 0; +static void ticker_isr(void); +static void ticker_init(void) { /* Set interrupt handler */ - NVIC_SetVector(LPTimer_IRQn, (uint32_t)lptmr_isr); - NVIC_EnableIRQ(LPTimer_IRQn); - - /* Clock at (1)MHz -> (1)tick/us */ - /* 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); + NVIC_SetVector(PIT_TICKER_IRQ, (uint32_t)ticker_isr); + NVIC_EnableIRQ(PIT_TICKER_IRQ); } void us_ticker_disable_interrupt(void) { - LPTMR0->CSR &= ~LPTMR_CSR_TIE_MASK; + PIT_TICKER.TCTRL &= ~PIT_TCTRL_TIE_MASK; } void us_ticker_clear_interrupt(void) { @@ -147,40 +114,24 @@ void us_ticker_clear_interrupt(void) { } static uint32_t us_ticker_int_counter = 0; -static uint16_t us_ticker_int_remainder = 0; -static void lptmr_set(unsigned short count) { - /* Reset */ - LPTMR0->CSR = 0; - - /* Set the compare register */ - LPTMR0->CMR = count; - - /* Enable interrupt */ - LPTMR0->CSR |= LPTMR_CSR_TIE_MASK; - - /* Start the timer */ - LPTMR0->CSR |= LPTMR_CSR_TEN_MASK; +inline static void ticker_set(uint32_t count) { + PIT_TICKER.TCTRL = 0; + PIT_TICKER.LDVAL = count; + PIT_TICKER.TCTRL = PIT_TCTRL_TIE_MASK | PIT_TCTRL_TEN_MASK; } -static void lptmr_isr(void) { - // write 1 to TCF to clear the LPT timer compare flag - LPTMR0->CSR |= LPTMR_CSR_TCF_MASK; +static void ticker_isr(void) { + // Clear IRQ flag + PIT_TICKER.TFLG = 1; if (us_ticker_int_counter > 0) { - lptmr_set(0xFFFF); + ticker_set(0xFFFFFFFF); us_ticker_int_counter--; - } else { - if (us_ticker_int_remainder > 0) { - lptmr_set(us_ticker_int_remainder); - us_ticker_int_remainder = 0; - - } else { - // This function is going to disable the interrupts if there are - // no other events in the queue - us_ticker_irq_handler(); - } + // This function is going to disable the interrupts if there are + // no other events in the queue + us_ticker_irq_handler(); } } @@ -192,13 +143,17 @@ void us_ticker_set_interrupt(unsigned int timestamp) { return; } - us_ticker_int_counter = (uint32_t)(delta >> 16); - us_ticker_int_remainder = (uint16_t)(0xFFFF & delta); - if (us_ticker_int_counter > 0) { - lptmr_set(0xFFFF); + //Calculate how much falls outside the 32-bit after multiplying with clk_mhz + //We shift twice 16-bit to keep everything within the 32-bit variable + us_ticker_int_counter = (uint32_t)(delta >> 16); + us_ticker_int_counter *= clk_mhz; + us_ticker_int_counter >>= 16; + + uint32_t us_ticker_int_remainder = (uint32_t)delta * clk_mhz; + if (us_ticker_int_remainder == 0) { + ticker_set(0xFFFFFFFF); us_ticker_int_counter--; } else { - lptmr_set(us_ticker_int_remainder); - us_ticker_int_remainder = 0; + ticker_set(us_ticker_int_remainder); } } From 62dcd84aa32a2ad1a4cb3a668d2f4f09f5c09e51 Mon Sep 17 00:00:00 2001 From: Sissors Date: Sat, 19 Apr 2014 18:11:16 +0200 Subject: [PATCH 5/5] Added (deep)sleep Pretty much copy pasta of KLxx sleep code with only tiny change --- .../TARGET_Freescale/TARGET_K20D5M/device.h | 2 +- .../TARGET_Freescale/TARGET_K20D5M/sleep.c | 51 +++++++++++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/sleep.c diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/device.h b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/device.h index 962e9ab2be..6a6d5cae5b 100644 --- a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/device.h +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/device.h @@ -45,7 +45,7 @@ #define DEVICE_LOCALFILESYSTEM 0 #define DEVICE_ID_LENGTH 24 -#define DEVICE_SLEEP 0 +#define DEVICE_SLEEP 1 #define DEVICE_DEBUG_AWARENESS 0 diff --git a/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/sleep.c b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/sleep.c new file mode 100644 index 0000000000..3fcffd4fbd --- /dev/null +++ b/libraries/mbed/targets/hal/TARGET_Freescale/TARGET_K20D5M/sleep.c @@ -0,0 +1,51 @@ +/* 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. + */ +#include "sleep_api.h" +#include "cmsis.h" + +//Normal wait mode +void sleep(void) +{ + SMC->PMPROT = SMC_PMPROT_AVLLS_MASK | SMC_PMPROT_ALLS_MASK | SMC_PMPROT_AVLP_MASK; + + //Normal sleep mode for ARM core: + SCB->SCR = 0; + __WFI(); +} + +//Very low-power stop mode +void deepsleep(void) +{ + //Check if PLL/FLL is enabled: + uint32_t PLL_FLL_en = (MCG->C1 & MCG_C1_CLKS_MASK) == MCG_C1_CLKS(0); + + SMC->PMPROT = SMC_PMPROT_AVLLS_MASK | SMC_PMPROT_ALLS_MASK | SMC_PMPROT_AVLP_MASK; + SMC->PMCTRL = SMC_PMCTRL_STOPM(2); + + //Deep sleep for ARM core: + SCB->SCR = 1<C6 & (1<S & MCG_S_LOCK0_MASK) == 0x00U); /* Wait until locked */ + MCG->C1 &= ~MCG_C1_CLKS_MASK; + } + +}