|
17 | 17 | #include "us_ticker_api.h"
|
18 | 18 | #include "PeripheralNames.h"
|
19 | 19 |
|
20 |
| -#define US_TICKER_TIMER_IRQn SCT_IRQn |
| 20 | +//New, using MRT instead of SCT, needed to free up SCT for PWM |
| 21 | +//Ported from LPC824 libs |
| 22 | +static int us_ticker_inited = 0; |
| 23 | +unsigned int ticker_fullcount_us; |
| 24 | +unsigned long int ticker_expired_count_us = 0; |
| 25 | +int MRT_Clock_MHz; |
21 | 26 |
|
22 |
| -int us_ticker_inited = 0; |
| 27 | +#define US_TICKER_TIMER_IRQn MRT_IRQn |
23 | 28 |
|
24 | 29 | void us_ticker_init(void) {
|
25 |
| - if (us_ticker_inited) return; |
26 |
| - us_ticker_inited = 1; |
27 |
| - |
28 |
| - // Enable the SCT clock |
29 |
| - LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 8); |
30 |
| - |
31 |
| - // Clear peripheral reset the SCT: |
32 |
| - LPC_SYSCON->PRESETCTRL |= (1 << 8); |
33 |
| - |
34 |
| - // Unified counter (32 bits) |
35 |
| - LPC_SCT->CONFIG |= 1; |
36 |
| - |
37 |
| - // halt and clear the counter |
38 |
| - LPC_SCT->CTRL_L |= (1 << 2) | (1 << 3); |
39 | 30 |
|
40 |
| - // System Clock (12)MHz -> us_ticker (1)MHz |
41 |
| - LPC_SCT->CTRL_L |= ((SystemCoreClock/1000000 - 1) << 5); |
| 31 | + if (us_ticker_inited) |
| 32 | + return; |
| 33 | + |
| 34 | + us_ticker_inited = 1; |
42 | 35 |
|
43 |
| - // unhalt the counter: |
44 |
| - // - clearing bit 2 of the CTRL register |
45 |
| - LPC_SCT->CTRL_L &= ~(1 << 2); |
| 36 | + // Calculate MRT clock value (MRT has no prescaler) |
| 37 | + MRT_Clock_MHz = (SystemCoreClock / 1000000); |
| 38 | + // Calculate fullcounter value in us (MRT has 31 bits and clock is 30 MHz) |
| 39 | + ticker_fullcount_us = 0x80000000UL/MRT_Clock_MHz; |
| 40 | + |
| 41 | + // Enable the MRT clock |
| 42 | + LPC_SYSCON->SYSAHBCLKCTRL |= (1 << 10); |
| 43 | + |
| 44 | + // Clear peripheral reset the MRT |
| 45 | + LPC_SYSCON->PRESETCTRL |= (1 << 7); |
| 46 | + |
| 47 | + // Force load interval value (Bit 0-30 is interval value, Bit 31 is Force Load bit) |
| 48 | + LPC_MRT->INTVAL0 = 0xFFFFFFFFUL; |
| 49 | + // Enable Ch0 interrupt, Mode 0 is Repeat Interrupt |
| 50 | + LPC_MRT->CTRL0 = (0x0 << 1) | (0x1 << 0); |
| 51 | + |
| 52 | + // Force load interval value (Bit 0-30 is interval value, Bit 31 is Force Load bit) |
| 53 | + LPC_MRT->INTVAL1 = 0x80000000UL; |
| 54 | + // Disable ch1 interrupt, Mode 0 is Repeat Interrupt |
| 55 | + LPC_MRT->CTRL1 = (0x0 << 1) | (0x0 << 0); |
46 | 56 |
|
| 57 | + // Set MRT interrupt vector |
47 | 58 | NVIC_SetVector(US_TICKER_TIMER_IRQn, (uint32_t)us_ticker_irq_handler);
|
48 | 59 | NVIC_EnableIRQ(US_TICKER_TIMER_IRQn);
|
49 | 60 | }
|
50 | 61 |
|
| 62 | +//TIMER0 is used for us ticker and timers (Timer, wait(), wait_us() etc) |
51 | 63 | uint32_t us_ticker_read() {
|
| 64 | + |
52 | 65 | if (!us_ticker_inited)
|
53 | 66 | us_ticker_init();
|
54 |
| - |
55 |
| - return LPC_SCT->COUNT_U; |
| 67 | + |
| 68 | + // Generate ticker value |
| 69 | + // MRT source clock is SystemCoreClock (30MHz) and MRT is a 31-bit countdown timer |
| 70 | + // Calculate expected value using current count and number of expired times to mimic a 32bit timer @ 1 MHz |
| 71 | + // |
| 72 | + // ticker_expired_count_us |
| 73 | + // The variable ticker_expired_count_us keeps track of the number of 31bits overflows (counted by TIMER0) and |
| 74 | + // corrects that back to us counts. |
| 75 | + // |
| 76 | + // (0x7FFFFFFFUL - LPC_MRT->TIMER0)/MRT_Clock_MHz |
| 77 | + // The counter is a 31bit downcounter from 7FFFFFFF so correct to actual count-up value and correct |
| 78 | + // for 30 counts per us. |
| 79 | + // |
| 80 | + // Added up these 2 parts result in current us time returned as 32 bits. |
| 81 | + return (0x7FFFFFFFUL - LPC_MRT->TIMER0)/MRT_Clock_MHz + ticker_expired_count_us; |
56 | 82 | }
|
57 | 83 |
|
| 84 | +//TIMER1 is used for Timestamped interrupts (Ticker(), Timeout()) |
58 | 85 | void us_ticker_set_interrupt(timestamp_t timestamp) {
|
59 |
| - // halt the counter: |
60 |
| - // - setting bit 2 of the CTRL register |
61 |
| - LPC_SCT->CTRL_L |= (1 << 2); |
62 |
| - |
63 |
| - // set timestamp in compare register |
64 |
| - LPC_SCT->MATCH[0].U = (uint32_t)timestamp; |
65 | 86 |
|
66 |
| - // unhalt the counter: |
67 |
| - // - clearing bit 2 of the CTRL register |
68 |
| - LPC_SCT->CTRL_L &= ~(1 << 2); |
| 87 | + // MRT source clock is SystemCoreClock (30MHz) and MRT is a 31-bit countdown timer |
| 88 | + // Force load interval value (Bit 0-30 is interval value, Bit 31 is Force Load bit) |
| 89 | + // Note: The MRT has less counter headroom available than the typical mbed 32bit timer @ 1 MHz. |
| 90 | + // The calculated counter interval until the next timestamp will be truncated and an |
| 91 | + // 'early' interrupt will be generated in case the max required count interval exceeds |
| 92 | + // the available 31 bits space. However, the mbed us_ticker interrupt handler will |
| 93 | + // check current time against the next scheduled timestamp and simply re-issue the |
| 94 | + // same interrupt again when needed. The calculated counter interval will now be smaller. |
| 95 | + LPC_MRT->INTVAL1 = (((timestamp - us_ticker_read()) * MRT_Clock_MHz) | 0x80000000UL); |
69 | 96 |
|
70 |
| - // if events are not enabled, enable them |
71 |
| - if (!(LPC_SCT->EVEN & 0x01)) { |
72 |
| - |
73 |
| - // comb mode = match only |
74 |
| - LPC_SCT->EVENT[0].CTRL = (1 << 12); |
75 |
| - |
76 |
| - // ref manual: |
77 |
| - // In simple applications that do not |
78 |
| - // use states, write 0x01 to this |
79 |
| - // register to enable an event |
80 |
| - LPC_SCT->EVENT[0].STATE |= 0x1; |
81 |
| - |
82 |
| - // enable events |
83 |
| - LPC_SCT->EVEN |= 0x1; |
84 |
| - } |
| 97 | + // Enable interrupt |
| 98 | + LPC_MRT->CTRL1 |= 1; |
85 | 99 | }
|
86 | 100 |
|
87 |
| -void us_ticker_disable_interrupt(void) { |
88 |
| - LPC_SCT->EVEN &= ~1; |
| 101 | +//Disable Timestamped interrupts triggered by TIMER1 |
| 102 | +void us_ticker_disable_interrupt() { |
| 103 | + //Timer1 for Timestamped interrupts (31 bits downcounter @ SystemCoreClock) |
| 104 | + LPC_MRT->CTRL1 &= ~1; |
89 | 105 | }
|
90 | 106 |
|
91 |
| -void us_ticker_clear_interrupt(void) { |
92 |
| - LPC_SCT->EVFLAG = 1; |
| 107 | +void us_ticker_clear_interrupt() { |
| 108 | + |
| 109 | + //Timer1 for Timestamped interrupts (31 bits downcounter @ SystemCoreClock) |
| 110 | + if (LPC_MRT->STAT1 & 1) |
| 111 | + LPC_MRT->STAT1 = 1; |
| 112 | + |
| 113 | + //Timer0 for us counter (31 bits downcounter @ SystemCoreClock) |
| 114 | + if (LPC_MRT->STAT0 & 1) { |
| 115 | + LPC_MRT->STAT0 = 1; |
| 116 | + // ticker_expired_count_us = (ticker_expired * 0x80000000UL) / MRT_Clock_MHz |
| 117 | + // The variable ticker_expired_count_us keeps track of the number of 31bits overflows (counted by TIMER0) and |
| 118 | + // the multiplication/division corrects that back to us counts. |
| 119 | + ticker_expired_count_us += ticker_fullcount_us; |
| 120 | + } |
93 | 121 | }
|
0 commit comments