Manh Pham / Mbed OS Nucleo_rtos_basic_ir_controller
Committer:
manhpham
Date:
Sat Apr 07 09:22:54 2018 +0000
Revision:
0:c8673aa96267
Nucleo_rtos_basic_ir_controller

Who changed what in which revision?

UserRevisionLine numberNew contents of line
manhpham 0:c8673aa96267 1 /* mbed Microcontroller Library
manhpham 0:c8673aa96267 2 * Copyright (c) 2006-2013 ARM Limited
manhpham 0:c8673aa96267 3 *
manhpham 0:c8673aa96267 4 * Licensed under the Apache License, Version 2.0 (the "License");
manhpham 0:c8673aa96267 5 * you may not use this file except in compliance with the License.
manhpham 0:c8673aa96267 6 * You may obtain a copy of the License at
manhpham 0:c8673aa96267 7 *
manhpham 0:c8673aa96267 8 * http://www.apache.org/licenses/LICENSE-2.0
manhpham 0:c8673aa96267 9 *
manhpham 0:c8673aa96267 10 * Unless required by applicable law or agreed to in writing, software
manhpham 0:c8673aa96267 11 * distributed under the License is distributed on an "AS IS" BASIS,
manhpham 0:c8673aa96267 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
manhpham 0:c8673aa96267 13 * See the License for the specific language governing permissions and
manhpham 0:c8673aa96267 14 * limitations under the License.
manhpham 0:c8673aa96267 15 */
manhpham 0:c8673aa96267 16 #include <stddef.h>
manhpham 0:c8673aa96267 17 #include "us_ticker_api.h"
manhpham 0:c8673aa96267 18 #include "PeripheralNames.h"
manhpham 0:c8673aa96267 19 #include "clk_freqs.h"
manhpham 0:c8673aa96267 20
manhpham 0:c8673aa96267 21 static void pit_init(void);
manhpham 0:c8673aa96267 22 static void lptmr_init(void);
manhpham 0:c8673aa96267 23
manhpham 0:c8673aa96267 24 static int us_ticker_inited = 0;
manhpham 0:c8673aa96267 25
manhpham 0:c8673aa96267 26 void us_ticker_init(void) {
manhpham 0:c8673aa96267 27 if (us_ticker_inited) return;
manhpham 0:c8673aa96267 28 us_ticker_inited = 1;
manhpham 0:c8673aa96267 29
manhpham 0:c8673aa96267 30 pit_init();
manhpham 0:c8673aa96267 31 lptmr_init();
manhpham 0:c8673aa96267 32 }
manhpham 0:c8673aa96267 33
manhpham 0:c8673aa96267 34 /******************************************************************************
manhpham 0:c8673aa96267 35 * Timer for us timing.
manhpham 0:c8673aa96267 36 ******************************************************************************/
manhpham 0:c8673aa96267 37 static void pit_init(void) {
manhpham 0:c8673aa96267 38 SIM->SCGC6 |= SIM_SCGC6_PIT_MASK; // Clock PIT
manhpham 0:c8673aa96267 39 PIT->MCR = 0; // Enable PIT
manhpham 0:c8673aa96267 40
manhpham 0:c8673aa96267 41 // Channel 1
manhpham 0:c8673aa96267 42 PIT->CHANNEL[1].LDVAL = 0xFFFFFFFF;
manhpham 0:c8673aa96267 43 PIT->CHANNEL[1].TCTRL = PIT_TCTRL_CHN_MASK; // Chain to timer 0, disable Interrupts
manhpham 0:c8673aa96267 44 PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_TEN_MASK; // Start timer 1
manhpham 0:c8673aa96267 45
manhpham 0:c8673aa96267 46 // Use channel 0 as a prescaler for channel 1
manhpham 0:c8673aa96267 47 PIT->CHANNEL[0].LDVAL = (bus_frequency() + 500000) / 1000000 - 1;
manhpham 0:c8673aa96267 48 PIT->CHANNEL[0].TCTRL = PIT_TCTRL_TEN_MASK; // Start timer 0, disable interrupts
manhpham 0:c8673aa96267 49 }
manhpham 0:c8673aa96267 50
manhpham 0:c8673aa96267 51 uint32_t us_ticker_read() {
manhpham 0:c8673aa96267 52 if (!us_ticker_inited)
manhpham 0:c8673aa96267 53 us_ticker_init();
manhpham 0:c8673aa96267 54
manhpham 0:c8673aa96267 55 // The PIT is a countdown timer
manhpham 0:c8673aa96267 56 return ~(PIT->CHANNEL[1].CVAL);
manhpham 0:c8673aa96267 57 }
manhpham 0:c8673aa96267 58
manhpham 0:c8673aa96267 59 /******************************************************************************
manhpham 0:c8673aa96267 60 * Timer Event
manhpham 0:c8673aa96267 61 *
manhpham 0:c8673aa96267 62 * It schedules interrupts at given (32bit)us interval of time.
manhpham 0:c8673aa96267 63 * It is implemented used the 16bit Low Power Timer that remains powered in all
manhpham 0:c8673aa96267 64 * power modes.
manhpham 0:c8673aa96267 65 ******************************************************************************/
manhpham 0:c8673aa96267 66 static void lptmr_isr(void);
manhpham 0:c8673aa96267 67
manhpham 0:c8673aa96267 68 static void lptmr_init(void) {
manhpham 0:c8673aa96267 69 uint32_t extosc;
manhpham 0:c8673aa96267 70
manhpham 0:c8673aa96267 71 /* Clock the timer */
manhpham 0:c8673aa96267 72 SIM->SCGC5 |= SIM_SCGC5_LPTMR_MASK;
manhpham 0:c8673aa96267 73
manhpham 0:c8673aa96267 74 /* Reset */
manhpham 0:c8673aa96267 75 LPTMR0->CSR = 0;
manhpham 0:c8673aa96267 76
manhpham 0:c8673aa96267 77 #if defined(TARGET_KL43Z)
manhpham 0:c8673aa96267 78 /* Set interrupt handler */
manhpham 0:c8673aa96267 79 NVIC_SetVector(LPTMR0_IRQn, (uint32_t)lptmr_isr);
manhpham 0:c8673aa96267 80 NVIC_EnableIRQ(LPTMR0_IRQn);
manhpham 0:c8673aa96267 81
manhpham 0:c8673aa96267 82
manhpham 0:c8673aa96267 83 MCG->C1 |= MCG_C1_IRCLKEN_MASK;
manhpham 0:c8673aa96267 84 extosc = mcgirc_frequency();
manhpham 0:c8673aa96267 85 #else
manhpham 0:c8673aa96267 86 /* Set interrupt handler */
manhpham 0:c8673aa96267 87 NVIC_SetVector(LPTimer_IRQn, (uint32_t)lptmr_isr);
manhpham 0:c8673aa96267 88 NVIC_EnableIRQ(LPTimer_IRQn);
manhpham 0:c8673aa96267 89
manhpham 0:c8673aa96267 90 /* Clock at (1)MHz -> (1)tick/us */
manhpham 0:c8673aa96267 91 /* Check if the external oscillator can be divided to 1MHz */
manhpham 0:c8673aa96267 92 extosc = extosc_frequency();
manhpham 0:c8673aa96267 93 #endif
manhpham 0:c8673aa96267 94 if (extosc != 0) { //If external oscillator found
manhpham 0:c8673aa96267 95 if (extosc % 1000000u == 0) { //If it is a multiple if 1MHz
manhpham 0:c8673aa96267 96 extosc /= 1000000;
manhpham 0:c8673aa96267 97 if (extosc == 1) { //1MHz, set timerprescaler in bypass mode
manhpham 0:c8673aa96267 98 LPTMR0->PSR = LPTMR_PSR_PCS(3) | LPTMR_PSR_PBYP_MASK;
manhpham 0:c8673aa96267 99 return;
manhpham 0:c8673aa96267 100 } else { //See if we can divide it to 1MHz
manhpham 0:c8673aa96267 101 uint32_t divider = 0;
manhpham 0:c8673aa96267 102 extosc >>= 1;
manhpham 0:c8673aa96267 103 while (1) {
manhpham 0:c8673aa96267 104 if (extosc == 1) {
manhpham 0:c8673aa96267 105 LPTMR0->PSR = LPTMR_PSR_PCS(3) | LPTMR_PSR_PRESCALE(divider);
manhpham 0:c8673aa96267 106 return;
manhpham 0:c8673aa96267 107 }
manhpham 0:c8673aa96267 108 if (extosc % 2 != 0) //If we can't divide by two anymore
manhpham 0:c8673aa96267 109 break;
manhpham 0:c8673aa96267 110 divider++;
manhpham 0:c8673aa96267 111 extosc >>= 1;
manhpham 0:c8673aa96267 112 }
manhpham 0:c8673aa96267 113 }
manhpham 0:c8673aa96267 114 }
manhpham 0:c8673aa96267 115 }
manhpham 0:c8673aa96267 116 #if defined(TARGET_KL43Z)
manhpham 0:c8673aa96267 117 //No suitable actual IRC oscillator clock -> Set it to (8MHz / divider)
manhpham 0:c8673aa96267 118 MCG->SC &= ~MCG_SC_FCRDIV_MASK;
manhpham 0:c8673aa96267 119 MCG->MC &= ~MCG->MC & MCG_MC_LIRC_DIV2_MASK;
manhpham 0:c8673aa96267 120 LPTMR0->PSR = LPTMR_PSR_PCS(0) | LPTMR_PSR_PRESCALE(2);
manhpham 0:c8673aa96267 121 #else
manhpham 0:c8673aa96267 122 //No suitable external oscillator clock -> Use fast internal oscillator (4MHz / divider)
manhpham 0:c8673aa96267 123 MCG->C1 |= MCG_C1_IRCLKEN_MASK;
manhpham 0:c8673aa96267 124 MCG->C2 |= MCG_C2_IRCS_MASK;
manhpham 0:c8673aa96267 125 LPTMR0->PSR = LPTMR_PSR_PCS(0);
manhpham 0:c8673aa96267 126 switch (MCG->SC & MCG_SC_FCRDIV_MASK) {
manhpham 0:c8673aa96267 127 case MCG_SC_FCRDIV(0): //4MHz
manhpham 0:c8673aa96267 128 LPTMR0->PSR |= LPTMR_PSR_PRESCALE(1);
manhpham 0:c8673aa96267 129 break;
manhpham 0:c8673aa96267 130 case MCG_SC_FCRDIV(1): //2MHz
manhpham 0:c8673aa96267 131 LPTMR0->PSR |= LPTMR_PSR_PRESCALE(0);
manhpham 0:c8673aa96267 132 break;
manhpham 0:c8673aa96267 133 default: //1MHz or anything else, in which case we put it on 1MHz
manhpham 0:c8673aa96267 134 MCG->SC &= ~MCG_SC_FCRDIV_MASK;
manhpham 0:c8673aa96267 135 MCG->SC |= MCG_SC_FCRDIV(2);
manhpham 0:c8673aa96267 136 LPTMR0->PSR |= LPTMR_PSR_PBYP_MASK;
manhpham 0:c8673aa96267 137 }
manhpham 0:c8673aa96267 138 #endif
manhpham 0:c8673aa96267 139 }
manhpham 0:c8673aa96267 140
manhpham 0:c8673aa96267 141 void us_ticker_disable_interrupt(void) {
manhpham 0:c8673aa96267 142 LPTMR0->CSR &= ~LPTMR_CSR_TIE_MASK;
manhpham 0:c8673aa96267 143 }
manhpham 0:c8673aa96267 144
manhpham 0:c8673aa96267 145 void us_ticker_clear_interrupt(void) {
manhpham 0:c8673aa96267 146 // we already clear interrupt in lptmr_isr
manhpham 0:c8673aa96267 147 }
manhpham 0:c8673aa96267 148
manhpham 0:c8673aa96267 149 static uint32_t us_ticker_int_counter = 0;
manhpham 0:c8673aa96267 150 static uint16_t us_ticker_int_remainder = 0;
manhpham 0:c8673aa96267 151
manhpham 0:c8673aa96267 152 static void lptmr_set(unsigned short count) {
manhpham 0:c8673aa96267 153 /* Reset */
manhpham 0:c8673aa96267 154 LPTMR0->CSR = 0;
manhpham 0:c8673aa96267 155
manhpham 0:c8673aa96267 156 /* Set the compare register */
manhpham 0:c8673aa96267 157 LPTMR0->CMR = count;
manhpham 0:c8673aa96267 158
manhpham 0:c8673aa96267 159 /* Enable interrupt */
manhpham 0:c8673aa96267 160 LPTMR0->CSR |= LPTMR_CSR_TIE_MASK;
manhpham 0:c8673aa96267 161
manhpham 0:c8673aa96267 162 /* Start the timer */
manhpham 0:c8673aa96267 163 LPTMR0->CSR |= LPTMR_CSR_TEN_MASK;
manhpham 0:c8673aa96267 164 }
manhpham 0:c8673aa96267 165
manhpham 0:c8673aa96267 166 static void lptmr_isr(void) {
manhpham 0:c8673aa96267 167 // write 1 to TCF to clear the LPT timer compare flag
manhpham 0:c8673aa96267 168 LPTMR0->CSR |= LPTMR_CSR_TCF_MASK;
manhpham 0:c8673aa96267 169
manhpham 0:c8673aa96267 170 if (us_ticker_int_counter > 0) {
manhpham 0:c8673aa96267 171 lptmr_set(0xFFFF);
manhpham 0:c8673aa96267 172 us_ticker_int_counter--;
manhpham 0:c8673aa96267 173
manhpham 0:c8673aa96267 174 } else {
manhpham 0:c8673aa96267 175 if (us_ticker_int_remainder > 0) {
manhpham 0:c8673aa96267 176 lptmr_set(us_ticker_int_remainder);
manhpham 0:c8673aa96267 177 us_ticker_int_remainder = 0;
manhpham 0:c8673aa96267 178
manhpham 0:c8673aa96267 179 } else {
manhpham 0:c8673aa96267 180 // This function is going to disable the interrupts if there are
manhpham 0:c8673aa96267 181 // no other events in the queue
manhpham 0:c8673aa96267 182 us_ticker_irq_handler();
manhpham 0:c8673aa96267 183 }
manhpham 0:c8673aa96267 184 }
manhpham 0:c8673aa96267 185 }
manhpham 0:c8673aa96267 186
manhpham 0:c8673aa96267 187 void us_ticker_set_interrupt(timestamp_t timestamp) {
manhpham 0:c8673aa96267 188 uint32_t delta = timestamp - us_ticker_read();
manhpham 0:c8673aa96267 189 us_ticker_int_counter = (uint32_t)(delta >> 16);
manhpham 0:c8673aa96267 190 us_ticker_int_remainder = (uint16_t)(0xFFFF & delta);
manhpham 0:c8673aa96267 191 if (us_ticker_int_counter > 0) {
manhpham 0:c8673aa96267 192 lptmr_set(0xFFFF);
manhpham 0:c8673aa96267 193 us_ticker_int_counter--;
manhpham 0:c8673aa96267 194 } else {
manhpham 0:c8673aa96267 195 lptmr_set(us_ticker_int_remainder);
manhpham 0:c8673aa96267 196 us_ticker_int_remainder = 0;
manhpham 0:c8673aa96267 197 }
manhpham 0:c8673aa96267 198 }
manhpham 0:c8673aa96267 199
manhpham 0:c8673aa96267 200 void us_ticker_fire_interrupt(void)
manhpham 0:c8673aa96267 201 {
manhpham 0:c8673aa96267 202 us_ticker_int_counter = 0;
manhpham 0:c8673aa96267 203 us_ticker_int_remainder = 0;
manhpham 0:c8673aa96267 204
manhpham 0:c8673aa96267 205 #if defined(TARGET_KL43Z)
manhpham 0:c8673aa96267 206 NVIC_SetPendingIRQ(LPTMR0_IRQn);
manhpham 0:c8673aa96267 207 #else
manhpham 0:c8673aa96267 208 NVIC_SetPendingIRQ(LPTimer_IRQn);
manhpham 0:c8673aa96267 209
manhpham 0:c8673aa96267 210 #endif
manhpham 0:c8673aa96267 211 }