mbed library sources, include can_api for nucleo-f091rc

Dependents:   CanNucleoF0_example

Fork of mbed-src by mbed official

Committer:
mbed_official
Date:
Fri Sep 25 14:15:10 2015 +0100
Revision:
627:4fa1328d9c60
Parent:
526:7c4bdfe6a168
Synchronized with git revision fe238a91ab7a4d1d72c4cab9da04967c619d54ad

Full URL: https://github.com/mbedmicro/mbed/commit/fe238a91ab7a4d1d72c4cab9da04967c619d54ad/

Silicon Labs - Add support for low-power async Serial

Who changed what in which revision?

UserRevisionLine numberNew contents of line
mbed_official 627:4fa1328d9c60 1 /***************************************************************************//**
mbed_official 627:4fa1328d9c60 2 * @file us_ticker.c
mbed_official 627:4fa1328d9c60 3 *******************************************************************************
mbed_official 627:4fa1328d9c60 4 * @section License
mbed_official 627:4fa1328d9c60 5 * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
mbed_official 627:4fa1328d9c60 6 *******************************************************************************
mbed_official 525:c320967f86b9 7 *
mbed_official 627:4fa1328d9c60 8 * Permission is granted to anyone to use this software for any purpose,
mbed_official 627:4fa1328d9c60 9 * including commercial applications, and to alter it and redistribute it
mbed_official 627:4fa1328d9c60 10 * freely, subject to the following restrictions:
mbed_official 525:c320967f86b9 11 *
mbed_official 627:4fa1328d9c60 12 * 1. The origin of this software must not be misrepresented; you must not
mbed_official 627:4fa1328d9c60 13 * claim that you wrote the original software.
mbed_official 627:4fa1328d9c60 14 * 2. Altered source versions must be plainly marked as such, and must not be
mbed_official 627:4fa1328d9c60 15 * misrepresented as being the original software.
mbed_official 627:4fa1328d9c60 16 * 3. This notice may not be removed or altered from any source distribution.
mbed_official 525:c320967f86b9 17 *
mbed_official 627:4fa1328d9c60 18 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
mbed_official 627:4fa1328d9c60 19 * obligation to support this Software. Silicon Labs is providing the
mbed_official 627:4fa1328d9c60 20 * Software "AS IS", with no express or implied warranties of any kind,
mbed_official 627:4fa1328d9c60 21 * including, but not limited to, any implied warranties of merchantability
mbed_official 627:4fa1328d9c60 22 * or fitness for any particular purpose or warranties against infringement
mbed_official 627:4fa1328d9c60 23 * of any proprietary rights of a third party.
mbed_official 627:4fa1328d9c60 24 *
mbed_official 627:4fa1328d9c60 25 * Silicon Labs will not be liable for any consequential, incidental, or
mbed_official 627:4fa1328d9c60 26 * special damages, or any other relief, or for any claim by any third party,
mbed_official 627:4fa1328d9c60 27 * arising from your use of this Software.
mbed_official 627:4fa1328d9c60 28 *
mbed_official 627:4fa1328d9c60 29 ******************************************************************************/
mbed_official 627:4fa1328d9c60 30
mbed_official 525:c320967f86b9 31 #include <stddef.h>
mbed_official 525:c320967f86b9 32 #include "us_ticker_api.h"
mbed_official 525:c320967f86b9 33 #include "cmsis.h"
mbed_official 525:c320967f86b9 34 #include "mbed_assert.h"
mbed_official 525:c320967f86b9 35 #include "em_cmu.h"
mbed_official 525:c320967f86b9 36 #include "em_timer.h"
mbed_official 525:c320967f86b9 37 #include "device_peripherals.h"
mbed_official 525:c320967f86b9 38 #include "device.h"
mbed_official 525:c320967f86b9 39 #include "clocking.h"
mbed_official 525:c320967f86b9 40 #include "sleep_api.h"
mbed_official 526:7c4bdfe6a168 41 #include "sleepmodes.h"
mbed_official 525:c320967f86b9 42
mbed_official 525:c320967f86b9 43 #define TIMER_LEAST_ACTIVE_SLEEPMODE EM1
mbed_official 525:c320967f86b9 44 /**
mbed_official 525:c320967f86b9 45 * Timer functions for microsecond ticker.
mbed_official 525:c320967f86b9 46 * mbed expects a 32-bit timer. Since the EFM32 only has 16-bit timers,
mbed_official 525:c320967f86b9 47 * the upper 16 bits are implemented in software.
mbed_official 525:c320967f86b9 48 */
mbed_official 525:c320967f86b9 49
mbed_official 525:c320967f86b9 50 static uint8_t us_ticker_inited = 0; // Is ticker initialized yet
mbed_official 525:c320967f86b9 51
mbed_official 525:c320967f86b9 52 static volatile uint32_t ticker_cnt = 0x2ff00; //Internal overflow count, used to extend internal 16-bit counter to (MHz * 32-bit)
mbed_official 525:c320967f86b9 53 static volatile uint16_t ticker_int_rem = 0; //Timer match value for user interrupt
mbed_official 525:c320967f86b9 54 static volatile uint32_t ticker_int_cnt = 0; //Amount of overflows until user interrupt
mbed_official 525:c320967f86b9 55 static volatile uint8_t ticker_freq_mhz = 0; //Frequency of timer in MHz
mbed_official 525:c320967f86b9 56
mbed_official 525:c320967f86b9 57 void us_ticker_irq_handler_internal(void)
mbed_official 525:c320967f86b9 58 {
mbed_official 525:c320967f86b9 59 /* Check for user interrupt expiration */
mbed_official 525:c320967f86b9 60 if (TIMER_IntGet(US_TICKER_TIMER) & TIMER_IF_CC0) {
mbed_official 525:c320967f86b9 61 if (ticker_int_rem > 0) {
mbed_official 525:c320967f86b9 62 TIMER_CompareSet(US_TICKER_TIMER, 0, ticker_int_rem);
mbed_official 525:c320967f86b9 63 ticker_int_rem = 0;
mbed_official 525:c320967f86b9 64 TIMER_IntClear(US_TICKER_TIMER, TIMER_IF_CC0);
mbed_official 525:c320967f86b9 65 } else if (ticker_int_cnt > 0) {
mbed_official 525:c320967f86b9 66 ticker_int_cnt--;
mbed_official 525:c320967f86b9 67 TIMER_IntClear(US_TICKER_TIMER, TIMER_IF_CC0);
mbed_official 525:c320967f86b9 68 } else {
mbed_official 525:c320967f86b9 69 us_ticker_irq_handler();
mbed_official 525:c320967f86b9 70 }
mbed_official 525:c320967f86b9 71 }
mbed_official 525:c320967f86b9 72
mbed_official 525:c320967f86b9 73 /* Handle timer overflow */
mbed_official 525:c320967f86b9 74 if (TIMER_IntGet(US_TICKER_TIMER) & TIMER_IF_OF) {
mbed_official 525:c320967f86b9 75 ticker_cnt++;
mbed_official 525:c320967f86b9 76 if(ticker_cnt >= (((uint32_t)ticker_freq_mhz) << 16)) ticker_cnt = 0;
mbed_official 525:c320967f86b9 77 TIMER_IntClear(US_TICKER_TIMER, TIMER_IF_OF);
mbed_official 525:c320967f86b9 78 }
mbed_official 525:c320967f86b9 79 }
mbed_official 525:c320967f86b9 80
mbed_official 525:c320967f86b9 81 void us_ticker_init(void)
mbed_official 525:c320967f86b9 82 {
mbed_official 525:c320967f86b9 83 if (us_ticker_inited) {
mbed_official 525:c320967f86b9 84 return;
mbed_official 525:c320967f86b9 85 }
mbed_official 525:c320967f86b9 86 us_ticker_inited = 1;
mbed_official 525:c320967f86b9 87
mbed_official 525:c320967f86b9 88 /* Enable clock for TIMERs */
mbed_official 525:c320967f86b9 89 CMU_ClockEnable(US_TICKER_TIMER_CLOCK, true);
mbed_official 525:c320967f86b9 90
mbed_official 525:c320967f86b9 91 /* Clear TIMER counter value */
mbed_official 525:c320967f86b9 92 TIMER_CounterSet(US_TICKER_TIMER, 0);
mbed_official 525:c320967f86b9 93
mbed_official 525:c320967f86b9 94 /* Get frequency of clock in MHz for scaling ticks to microseconds */
mbed_official 525:c320967f86b9 95 ticker_freq_mhz = (REFERENCE_FREQUENCY / 1000000);
mbed_official 525:c320967f86b9 96 MBED_ASSERT(ticker_freq_mhz > 0);
mbed_official 525:c320967f86b9 97
mbed_official 525:c320967f86b9 98 /*
mbed_official 525:c320967f86b9 99 * Calculate maximum prescaler that gives at least 1 MHz frequency, while keeping clock as an integer multiple of 1 MHz.
mbed_official 525:c320967f86b9 100 * Example: 14 MHz => prescaler = 1 (i.e. DIV2), ticker_freq_mhz = 7;
mbed_official 525:c320967f86b9 101 * 24 MHz => prescaler = 3 (i.e. DIV8), ticker_freq_mhz = 3;
mbed_official 525:c320967f86b9 102 * 48 MHz => prescaler = 4 (i.e. DIV16), ticker_freq_mhz = 3;
mbed_official 525:c320967f86b9 103 * Limit prescaling to maximum prescaler value, which is 10 (DIV1024).
mbed_official 525:c320967f86b9 104 */
mbed_official 525:c320967f86b9 105 uint32_t prescaler = 0;
mbed_official 525:c320967f86b9 106 while((ticker_freq_mhz & 1) == 0 && prescaler <= 10) {
mbed_official 525:c320967f86b9 107 ticker_freq_mhz = ticker_freq_mhz >> 1;
mbed_official 525:c320967f86b9 108 prescaler++;
mbed_official 525:c320967f86b9 109 }
mbed_official 525:c320967f86b9 110
mbed_official 525:c320967f86b9 111 /* Set prescaler */
mbed_official 525:c320967f86b9 112 US_TICKER_TIMER->CTRL = (US_TICKER_TIMER->CTRL & ~_TIMER_CTRL_PRESC_MASK) | (prescaler << _TIMER_CTRL_PRESC_SHIFT);
mbed_official 525:c320967f86b9 113
mbed_official 525:c320967f86b9 114 /* Select Compare Channel parameters */
mbed_official 525:c320967f86b9 115 TIMER_InitCC_TypeDef timerCCInit = TIMER_INITCC_DEFAULT;
mbed_official 525:c320967f86b9 116 timerCCInit.mode = timerCCModeCompare;
mbed_official 525:c320967f86b9 117
mbed_official 525:c320967f86b9 118 /* Configure Compare Channel 0 */
mbed_official 525:c320967f86b9 119 TIMER_InitCC(US_TICKER_TIMER, 0, &timerCCInit);
mbed_official 525:c320967f86b9 120
mbed_official 525:c320967f86b9 121 /* Enable interrupt vector in NVIC */
mbed_official 525:c320967f86b9 122 TIMER_IntEnable(US_TICKER_TIMER, TIMER_IEN_OF);
mbed_official 525:c320967f86b9 123 NVIC_SetVector(US_TICKER_TIMER_IRQ, (uint32_t) us_ticker_irq_handler_internal);
mbed_official 525:c320967f86b9 124 NVIC_EnableIRQ(US_TICKER_TIMER_IRQ);
mbed_official 525:c320967f86b9 125
mbed_official 525:c320967f86b9 126 /* Set top value */
mbed_official 525:c320967f86b9 127 TIMER_TopSet(US_TICKER_TIMER, 0xFFFF);
mbed_official 525:c320967f86b9 128
mbed_official 525:c320967f86b9 129 /* Start TIMER */
mbed_official 525:c320967f86b9 130 TIMER_Enable(US_TICKER_TIMER, true);
mbed_official 525:c320967f86b9 131 }
mbed_official 525:c320967f86b9 132
mbed_official 525:c320967f86b9 133 uint32_t us_ticker_read()
mbed_official 525:c320967f86b9 134 {
mbed_official 525:c320967f86b9 135 uint32_t volatile countH_old, countH, countL;
mbed_official 525:c320967f86b9 136
mbed_official 525:c320967f86b9 137 if (!us_ticker_inited) {
mbed_official 525:c320967f86b9 138 us_ticker_init();
mbed_official 525:c320967f86b9 139 }
mbed_official 525:c320967f86b9 140
mbed_official 525:c320967f86b9 141 /* Avoid jumping in time by reading high bits twice */
mbed_official 525:c320967f86b9 142 do {
mbed_official 525:c320967f86b9 143 countH_old = ticker_cnt;
mbed_official 525:c320967f86b9 144 /* If the counter overflowed while in the IRQ handler for the CC0 interrupt,
mbed_official 525:c320967f86b9 145 * it hasn't had time to update ticker_cnt yet. Take this into account here. */
mbed_official 525:c320967f86b9 146 if (TIMER_IntGet(US_TICKER_TIMER) & TIMER_IF_OF) {
mbed_official 525:c320967f86b9 147 countH_old += 1;
mbed_official 525:c320967f86b9 148 }
mbed_official 525:c320967f86b9 149 countL = US_TICKER_TIMER->CNT;
mbed_official 525:c320967f86b9 150 countH = ticker_cnt;
mbed_official 525:c320967f86b9 151 /* If the counter overflowed while in the IRQ handler for the CC0 interrupt,
mbed_official 525:c320967f86b9 152 * it hasn't had time to update ticker_cnt yet. Take this into account here. */
mbed_official 525:c320967f86b9 153 if (TIMER_IntGet(US_TICKER_TIMER) & TIMER_IF_OF) {
mbed_official 525:c320967f86b9 154 countH += 1;
mbed_official 525:c320967f86b9 155 }
mbed_official 525:c320967f86b9 156 } while (countH_old != countH);
mbed_official 525:c320967f86b9 157
mbed_official 525:c320967f86b9 158 /* Merge upper (mhz * 16-bit) and lower 16-bit into 64bit */
mbed_official 525:c320967f86b9 159 uint64_t count = ((uint64_t)countH << 16) | (uint64_t)countL;
mbed_official 525:c320967f86b9 160 /* Divide by ticker_freq_mhz to get 32-bit 1MHz timestamp */
mbed_official 525:c320967f86b9 161 return (count / ticker_freq_mhz);
mbed_official 525:c320967f86b9 162 }
mbed_official 525:c320967f86b9 163
mbed_official 525:c320967f86b9 164 void us_ticker_set_interrupt(timestamp_t timestamp)
mbed_official 525:c320967f86b9 165 {
mbed_official 525:c320967f86b9 166 int32_t delta = 0, ts = timestamp, time = us_ticker_read();
mbed_official 525:c320967f86b9 167
mbed_official 525:c320967f86b9 168 if((US_TICKER_TIMER->IEN & TIMER_IEN_CC0) == 0) {
mbed_official 525:c320967f86b9 169 //Timer was disabled, but is going to be enabled. Set sleep mode.
mbed_official 525:c320967f86b9 170 blockSleepMode(TIMER_LEAST_ACTIVE_SLEEPMODE);
mbed_official 525:c320967f86b9 171 }
mbed_official 525:c320967f86b9 172 TIMER_IntDisable(US_TICKER_TIMER, TIMER_IEN_CC0);
mbed_official 525:c320967f86b9 173
mbed_official 525:c320967f86b9 174 delta = ts - time;
mbed_official 525:c320967f86b9 175 if(delta <= ticker_freq_mhz) {
mbed_official 525:c320967f86b9 176 delta = ticker_freq_mhz;
mbed_official 525:c320967f86b9 177 timestamp = us_ticker_read() + 0x100;
mbed_official 525:c320967f86b9 178 }
mbed_official 525:c320967f86b9 179
mbed_official 525:c320967f86b9 180 /* Multiply by ticker_freq_mhz to get clock ticks */
mbed_official 525:c320967f86b9 181 delta *= ticker_freq_mhz;
mbed_official 525:c320967f86b9 182 /* Overflowing this doesn't matter, since we only need the lower 16 bits */
mbed_official 525:c320967f86b9 183 ts *= ticker_freq_mhz;
mbed_official 525:c320967f86b9 184
mbed_official 525:c320967f86b9 185 /* Split delta between timers */
mbed_official 525:c320967f86b9 186 ticker_int_cnt = (((uint64_t)delta) >> 16) & 0xFFFFFFFF;
mbed_official 525:c320967f86b9 187 ticker_int_rem = ts & 0xFFFF;
mbed_official 525:c320967f86b9 188
mbed_official 525:c320967f86b9 189 /* Set compare channel 0 to (current position + lower 16 bits of delta).
mbed_official 525:c320967f86b9 190 * If lower 16 bits is a small number, we a do one compare of (current + lower 16 + 0x8000)
mbed_official 525:c320967f86b9 191 * and then one of (current + lower 16). Else, we simply use (current + lower 16).
mbed_official 525:c320967f86b9 192 *
mbed_official 525:c320967f86b9 193 * When time from lower 16 bits have elapsed, run complete cycles with ticker_int_rem as
mbed_official 525:c320967f86b9 194 * reference ticker_int_cnt times. */
mbed_official 525:c320967f86b9 195 if ((delta & 0xFFFF) < 0x8000 && ticker_int_cnt > 0) {
mbed_official 525:c320967f86b9 196 TIMER_CompareSet(US_TICKER_TIMER, 0, ticker_int_rem + 0x8000);
mbed_official 525:c320967f86b9 197 ticker_int_cnt--;
mbed_official 525:c320967f86b9 198 } else {
mbed_official 525:c320967f86b9 199 TIMER_CompareSet(US_TICKER_TIMER, 0, ticker_int_rem);
mbed_official 525:c320967f86b9 200 ticker_int_rem = 0;
mbed_official 525:c320967f86b9 201 }
mbed_official 525:c320967f86b9 202 TIMER_IntClear(US_TICKER_TIMER, TIMER_IFC_CC0);
mbed_official 525:c320967f86b9 203 TIMER_IntEnable(US_TICKER_TIMER, TIMER_IEN_CC0);
mbed_official 525:c320967f86b9 204 }
mbed_official 525:c320967f86b9 205
mbed_official 525:c320967f86b9 206 void us_ticker_disable_interrupt(void)
mbed_official 525:c320967f86b9 207 {
mbed_official 525:c320967f86b9 208 if((US_TICKER_TIMER->IEN & TIMER_IEN_CC0) != 0) {
mbed_official 525:c320967f86b9 209 //Timer was enabled, but is going to get disabled. Clear sleepmode.
mbed_official 525:c320967f86b9 210 unblockSleepMode(TIMER_LEAST_ACTIVE_SLEEPMODE);
mbed_official 525:c320967f86b9 211 }
mbed_official 525:c320967f86b9 212 /* Disable compare channel interrupts */
mbed_official 525:c320967f86b9 213 TIMER_IntDisable(US_TICKER_TIMER, TIMER_IEN_CC0);
mbed_official 525:c320967f86b9 214 }
mbed_official 525:c320967f86b9 215
mbed_official 525:c320967f86b9 216 void us_ticker_clear_interrupt(void)
mbed_official 525:c320967f86b9 217 {
mbed_official 525:c320967f86b9 218 /* Clear compare channel interrupts */
mbed_official 525:c320967f86b9 219 TIMER_IntClear(US_TICKER_TIMER, TIMER_IFC_CC0);
mbed_official 525:c320967f86b9 220 }