fix for mbed lib issue 3 (i2c problem) see also https://mbed.org/users/mbed_official/code/mbed/issues/3 affected implementations: LPC812, LPC11U24, LPC1768, LPC2368, LPC4088

Fork of mbed-src by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers us_ticker.c Source File

us_ticker.c

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include <stddef.h>
00017 #include "us_ticker_api.h"
00018 #include "PeripheralNames.h"
00019 
00020 static void pit_init(void);
00021 static void lptmr_init(void);
00022 
00023 static int us_ticker_inited = 0;
00024 
00025 void us_ticker_init(void) {
00026     if (us_ticker_inited) return;
00027     us_ticker_inited = 1;
00028     
00029     pit_init();
00030     lptmr_init();
00031 }
00032 
00033 /******************************************************************************
00034  * Timer for us timing.
00035  ******************************************************************************/
00036 static void pit_init(void) {
00037     SIM->SCGC6 |= SIM_SCGC6_PIT_MASK;   // Clock PIT
00038     PIT->MCR = 0;                       // Enable PIT
00039     
00040     // Channel 1
00041     PIT->CHANNEL[1].LDVAL = 0xFFFFFFFF;
00042     PIT->CHANNEL[1].TCTRL = PIT_TCTRL_CHN_MASK;    // Chain to timer 0, disable Interrupts
00043     PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_TEN_MASK;   // Start timer 1
00044     
00045     // Use channel 0 as a prescaler for channel 1
00046     PIT->CHANNEL[0].LDVAL = 23;
00047     PIT->CHANNEL[0].TCTRL = PIT_TCTRL_TEN_MASK;    // Start timer 0, disable interrupts
00048 }
00049 
00050 uint32_t us_ticker_read() {
00051     if (!us_ticker_inited)
00052         us_ticker_init();
00053     
00054     // The PIT is a countdown timer
00055     return ~(PIT->CHANNEL[1].CVAL);
00056 }
00057 
00058 /******************************************************************************
00059  * Timer Event
00060  * 
00061  * It schedules interrupts at given (32bit)us interval of time.
00062  * It is implemented used the 16bit Low Power Timer that remains powered in all
00063  * power modes.
00064  ******************************************************************************/
00065 static void lptmr_isr(void);
00066 
00067 static void lptmr_init(void) {
00068     /* Clock the timer */
00069     SIM->SCGC5 |= SIM_SCGC5_LPTMR_MASK;
00070     
00071     /* Reset */
00072     LPTMR0->CSR = 0;
00073     
00074     /* Set interrupt handler */
00075     NVIC_SetVector(LPTimer_IRQn, (uint32_t)lptmr_isr);
00076     NVIC_EnableIRQ(LPTimer_IRQn);
00077     
00078     /* Clock at (1)MHz -> (1)tick/us */
00079     LPTMR0->PSR = LPTMR_PSR_PCS(3);       // OSCERCLK -> 8MHz
00080     LPTMR0->PSR |= LPTMR_PSR_PRESCALE(2); // divide by 8
00081 }
00082 
00083 void us_ticker_disable_interrupt(void) {
00084     LPTMR0->CSR &= ~LPTMR_CSR_TIE_MASK;
00085 }
00086 
00087 void us_ticker_clear_interrupt(void) {
00088     // we already clear interrupt in lptmr_isr
00089 }
00090 
00091 static uint32_t us_ticker_int_counter = 0;
00092 static uint16_t us_ticker_int_remainder = 0;
00093 
00094 static void lptmr_set(unsigned short count) {
00095     /* Reset */
00096     LPTMR0->CSR = 0;
00097     
00098     /* Set the compare register */
00099     LPTMR0->CMR = count;
00100     
00101     /* Enable interrupt */
00102     LPTMR0->CSR |= LPTMR_CSR_TIE_MASK;
00103     
00104     /* Start the timer */
00105     LPTMR0->CSR |= LPTMR_CSR_TEN_MASK;
00106 }
00107 
00108 static void lptmr_isr(void) {
00109     // write 1 to TCF to clear the LPT timer compare flag
00110     LPTMR0->CSR |= LPTMR_CSR_TCF_MASK;
00111     
00112     if (us_ticker_int_counter > 0) {
00113         lptmr_set(0xFFFF);
00114         us_ticker_int_counter--;
00115     
00116     } else {
00117         if (us_ticker_int_remainder > 0) {
00118             lptmr_set(us_ticker_int_remainder);
00119             us_ticker_int_remainder = 0;
00120         
00121         } else {
00122             // This function is going to disable the interrupts if there are
00123             // no other events in the queue
00124             us_ticker_irq_handler();
00125         }
00126     }
00127 }
00128 
00129 void us_ticker_set_interrupt(unsigned int timestamp) {
00130     int delta = (int)(timestamp - us_ticker_read());
00131     if (delta <= 0) {
00132         // This event was in the past:
00133         us_ticker_irq_handler();
00134         return;
00135     }
00136     
00137     us_ticker_int_counter   = (uint32_t)(delta >> 16);
00138     us_ticker_int_remainder = (uint16_t)(0xFFFF & delta);
00139     if (us_ticker_int_counter > 0) {
00140         lptmr_set(0xFFFF);
00141         us_ticker_int_counter--;
00142     } else {
00143         lptmr_set(us_ticker_int_remainder);
00144         us_ticker_int_remainder = 0;
00145     }
00146 }