|
23 | 23 |
|
24 | 24 | TIM_HandleTypeDef TimMasterHandle;
|
25 | 25 |
|
26 |
| -volatile uint32_t SlaveCounter = 0; |
27 |
| -volatile uint32_t oc_int_part = 0; |
| 26 | +// Declare ticker as 16 bits - mbed layer takes care of mapping to 32 or 64 |
| 27 | +// bits |
| 28 | +const ticker_info_t* us_ticker_get_info() |
| 29 | +{ |
| 30 | + static const ticker_info_t info = { |
| 31 | + 1000000, |
| 32 | + 16 |
| 33 | + }; |
| 34 | + return &info; |
| 35 | +} |
28 | 36 |
|
29 | 37 | void us_ticker_init(void)
|
30 | 38 | {
|
31 |
| - /* NOTE: assuming that HAL tick has already been initialized! */ |
| 39 | + /* NOTE: assuming thaiHAL tick has already been initialized! */ |
| 40 | + us_ticker_disable_interrupt(); |
32 | 41 | }
|
33 | 42 |
|
34 | 43 | uint32_t us_ticker_read()
|
35 | 44 | {
|
36 |
| - uint16_t cntH_old, cntH, cntL; |
37 |
| - do { |
38 |
| - cntH_old = SlaveCounter; |
39 |
| - /* SlaveCounter needs to be checked before AND after we read the |
40 |
| - * current counter TIM_MST->CNT, in case it wraps around. |
41 |
| - * there are 2 possible cases of wrap around |
42 |
| - * 1) in case this function is interrupted by timer_irq_handler and |
43 |
| - * the SlaveCounter is updated. In that case we will loop again. |
44 |
| - * 2) in case this function is called from interrupt context during |
45 |
| - * wrap-around condtion. That would prevent/delay the timer_irq_handler |
46 |
| - * from being called so we need to locally check the FLAG_UPDATE and |
47 |
| - * update the cntH accordingly. The SlaveCounter variable itself will |
48 |
| - * be updated in the interrupt handler just after ... |
49 |
| - */ |
50 |
| - if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_UPDATE) == SET) { |
51 |
| - cntH_old += 1; |
52 |
| - } |
53 |
| - cntL = TIM_MST->CNT; |
54 |
| - cntH = SlaveCounter; |
55 |
| - if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_UPDATE) == SET) { |
56 |
| - cntH += 1; |
57 |
| - } |
58 |
| - } while(cntH_old != cntH); |
59 |
| - // Glue the upper and lower part together to get a 32 bit timer |
60 |
| - return (uint32_t)(cntH << 16 | cntL); |
| 45 | + return TIM_MST->CNT; |
61 | 46 | }
|
62 | 47 |
|
63 | 48 | void us_ticker_set_interrupt(timestamp_t timestamp)
|
64 | 49 | {
|
65 | 50 | // NOTE: This function must be called with interrupts disabled to keep our
|
66 | 51 | // timer interrupt setup atomic
|
67 |
| - |
68 | 52 | // Set new output compare value
|
69 | 53 | __HAL_TIM_SET_COMPARE(&TimMasterHandle, TIM_CHANNEL_1, timestamp & 0xFFFF);
|
70 | 54 | // Ensure the compare event starts clear
|
71 | 55 | __HAL_TIM_CLEAR_FLAG(&TimMasterHandle, TIM_FLAG_CC1);
|
72 | 56 | // Enable IT
|
73 | 57 | __HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_CC1);
|
74 |
| - |
75 |
| - /* Set the number of timer wrap-around loops before the actual timestamp |
76 |
| - * is reached. If the calculated delta time is more than halfway to the |
77 |
| - * next compare event, check to see if a compare event has already been |
78 |
| - * set, and if so, add one to the wrap-around count. This is done to |
79 |
| - * ensure the correct wrap count is used in the corner cases where the |
80 |
| - * 16 bit counter passes the compare value during the process of |
81 |
| - * configuring this interrupt. |
82 |
| - * |
83 |
| - * Assumption: The time to execute this function is less than 32ms |
84 |
| - * (otherwise incorrect behaviour could result) |
85 |
| - * |
86 |
| - * Consider the following corner cases: |
87 |
| - * 1) timestamp is 1 us in the future: |
88 |
| - * oc_int_part = 0 initially |
89 |
| - * oc_int_part left at 0 because ((delta - 1) & 0xFFFF) < 0x8000 |
90 |
| - * Compare event should happen in 1 us and us_ticker_irq_handler() |
91 |
| - * called |
92 |
| - * 2) timestamp is 0x8000 us in the future: |
93 |
| - * oc_int_part = 0 initially |
94 |
| - * oc_int_part left at 0 because ((delta - 1) & 0xFFFF) < 0x8000 |
95 |
| - * There should be no possibility of the CC1 flag being set yet |
96 |
| - * (see assumption above). When the compare event does occur in |
97 |
| - * 32768 us, us_ticker_irq_handler() will be called |
98 |
| - * 3) timestamp is 0x8001 us in the future: |
99 |
| - * oc_int_part = 0 initially |
100 |
| - * ((delta - 1) & 0xFFFF) >= 0x8000 but there should be no |
101 |
| - * possibility of the CC1 flag being set yet (see assumption above), |
102 |
| - * so oc_int_part will be left at 0, and when the compare event |
103 |
| - * does occur in 32769 us, us_ticker_irq_handler() will be called |
104 |
| - * 4) timestamp is 0x10000 us in the future: |
105 |
| - * oc_int_part = 0 initially |
106 |
| - * ((delta - 1) & 0xFFFF) >= 0x8000 |
107 |
| - * There are two subcases: |
108 |
| - * a) The timer counter has not incremented past the compare |
109 |
| - * value while setting up the interrupt. In this case, the |
110 |
| - * CC1 flag will not be set, so oc_int_part will be |
111 |
| - * left at 0, and when the compare event occurs in 65536 us, |
112 |
| - * us_ticker_irq_handler() will be called |
113 |
| - * b) The timer counter has JUST incremented past the compare |
114 |
| - * value. In this case, the CC1 flag will be set, so |
115 |
| - * oc_int_part will be incremented to 1, and the interrupt will |
116 |
| - * occur immediately after this function returns, where |
117 |
| - * oc_int_part will decrement to 0 without calling |
118 |
| - * us_ticker_irq_handler(). Then about 65536 us later, the |
119 |
| - * compare event will occur again, and us_ticker_irq_handler() |
120 |
| - * will be called |
121 |
| - * 5) timestamp is 0x10001 us in the future: |
122 |
| - * oc_int_part = 1 initially |
123 |
| - * oc_int_part left at 1 because ((delta - 1) & 0xFFFF) < 0x8000 |
124 |
| - * CC1 flag will not be set (see assumption above). In 1 us the |
125 |
| - * compare event will cause an interrupt, where oc_int_part will be |
126 |
| - * decremented to 0 without calling us_ticker_irq_handler(). Then |
127 |
| - * about 65536 us later, the compare event will occur again, and |
128 |
| - * us_ticker_irq_handler() will be called |
129 |
| - * 6) timestamp is 0x18000 us in the future: |
130 |
| - * oc_int_part = 1 initially |
131 |
| - * oc_int_part left at 1 because ((delta - 1) & 0xFFFF) < 0x8000 |
132 |
| - * There should be no possibility of the CC1 flag being set yet |
133 |
| - * (see assumption above). When the compare event does occur in |
134 |
| - * 32768 us, oc_int_part will be decremented to 0 without calling |
135 |
| - * us_ticker_irq_handler(). Then about 65536 us later, the |
136 |
| - * compare event will occur again, and us_ticker_irq_handler() will |
137 |
| - * be called |
138 |
| - * 7) timestamp is 0x18001 us in the future: |
139 |
| - * oc_int_part = 1 initially |
140 |
| - * ((delta - 1) & 0xFFFF) >= 0x8000 but there should be no |
141 |
| - * possibility of the CC1 flag being set yet (see assumption above), |
142 |
| - * so oc_int_part will be left at 1, and when the compare event |
143 |
| - * does occur in 32769 us, oc_int_part will be decremented to 0 |
144 |
| - * without calling us_ticker_irq_handler(). Then about 65536 us |
145 |
| - * later, the compare event will occur again, and |
146 |
| - * us_ticker_irq_handler() will be called |
147 |
| - * |
148 |
| - * delta - 1 is used because the timer compare event happens on the |
149 |
| - * counter incrementing to match the compare value, and it won't occur |
150 |
| - * immediately when the compare value is set to the current counter |
151 |
| - * value. |
152 |
| - */ |
153 |
| - uint32_t current_time = us_ticker_read(); |
154 |
| - uint32_t delta = timestamp - current_time; |
155 |
| - /* Note: The case of delta <= 0 is handled in MBED upper layer */ |
156 |
| - oc_int_part = (delta - 1) >> 16; |
157 |
| - if ( ((delta - 1) & 0xFFFF) >= 0x8000 && |
158 |
| - __HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_CC1) == SET ) { |
159 |
| - ++oc_int_part; |
160 |
| - /* NOTE: Instead of incrementing oc_int_part here, we could clear |
161 |
| - * the CC1 flag, but then you'd have to wait to ensure the |
162 |
| - * interrupt is knocked down before returning and reenabling |
163 |
| - * interrupts. Since this is a rare case, it's not worth it |
164 |
| - * to try and optimize it, and it keeps the code simpler and |
165 |
| - * safer to just do this increment instead. |
166 |
| - */ |
167 |
| - } |
168 |
| - |
169 | 58 | }
|
170 | 59 |
|
171 | 60 | void us_ticker_fire_interrupt(void)
|
172 | 61 | {
|
173 |
| - /* When firing the event, the number of 16 bits counter wrap-ups (oc_int) |
174 |
| - * must be re-initialized */ |
175 |
| - oc_int_part = 0; |
176 |
| - HAL_TIM_GenerateEvent(&TimMasterHandle, TIM_EVENTSOURCE_CC1); |
| 62 | + // Ensure the compare event starts clear |
| 63 | + __HAL_TIM_CLEAR_FLAG(&TimMasterHandle, TIM_FLAG_CC1); |
| 64 | + LL_TIM_GenerateEvent_CC1(TimMasterHandle.Instance); |
| 65 | + // Enable IT |
| 66 | + __HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_CC1); |
| 67 | + |
177 | 68 | }
|
178 | 69 |
|
179 | 70 | /* NOTE: must be called with interrupts disabled! */
|
|
0 commit comments