mbed library sources. Supersedes mbed-src. Fixed broken STM32F1xx RTC on rtc_api.c
Dependents: Nucleo_F103RB_RTC_battery_bkup_pwr_off_okay
Fork of mbed-dev by
targets/TARGET_STM/us_ticker_16b.c@177:619788de047e, 2017-11-07 (annotated)
- Committer:
- maxxir
- Date:
- Tue Nov 07 16:46:29 2017 +0000
- Revision:
- 177:619788de047e
- Parent:
- 174:b96e65c34a4d
To fix broken RTC on Nucleo_F103RB / STM32F103 BluePill etc..; Used direct RTC register manipulation for STM32F1xx; rtc_read() && rtc_write() (native rtc_init() - works good); also added stub for non-working on STM32F1xx rtc_read_subseconds().
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
<> | 153:fa9ff456f731 | 1 | /* mbed Microcontroller Library |
<> | 153:fa9ff456f731 | 2 | * Copyright (c) 2006-2016 ARM Limited |
<> | 153:fa9ff456f731 | 3 | * |
<> | 153:fa9ff456f731 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
<> | 153:fa9ff456f731 | 5 | * you may not use this file except in compliance with the License. |
<> | 153:fa9ff456f731 | 6 | * You may obtain a copy of the License at |
<> | 153:fa9ff456f731 | 7 | * |
<> | 153:fa9ff456f731 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
<> | 153:fa9ff456f731 | 9 | * |
<> | 153:fa9ff456f731 | 10 | * Unless required by applicable law or agreed to in writing, software |
<> | 153:fa9ff456f731 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
<> | 153:fa9ff456f731 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
<> | 153:fa9ff456f731 | 13 | * See the License for the specific language governing permissions and |
<> | 153:fa9ff456f731 | 14 | * limitations under the License. |
<> | 153:fa9ff456f731 | 15 | */ |
<> | 153:fa9ff456f731 | 16 | #include <stddef.h> |
<> | 153:fa9ff456f731 | 17 | #include "us_ticker_api.h" |
<> | 153:fa9ff456f731 | 18 | #include "PeripheralNames.h" |
<> | 153:fa9ff456f731 | 19 | #include "hal_tick.h" |
<> | 153:fa9ff456f731 | 20 | |
<> | 153:fa9ff456f731 | 21 | // A 16-bit timer is used |
<> | 153:fa9ff456f731 | 22 | #if TIM_MST_16BIT |
<> | 153:fa9ff456f731 | 23 | |
<> | 153:fa9ff456f731 | 24 | TIM_HandleTypeDef TimMasterHandle; |
<> | 153:fa9ff456f731 | 25 | |
<> | 153:fa9ff456f731 | 26 | volatile uint32_t SlaveCounter = 0; |
<> | 153:fa9ff456f731 | 27 | volatile uint32_t oc_int_part = 0; |
<> | 153:fa9ff456f731 | 28 | |
<> | 153:fa9ff456f731 | 29 | void us_ticker_init(void) |
<> | 153:fa9ff456f731 | 30 | { |
AnnaBridge | 174:b96e65c34a4d | 31 | /* NOTE: assuming that HAL tick has already been initialized! */ |
<> | 153:fa9ff456f731 | 32 | } |
<> | 153:fa9ff456f731 | 33 | |
<> | 153:fa9ff456f731 | 34 | uint32_t us_ticker_read() |
<> | 153:fa9ff456f731 | 35 | { |
<> | 153:fa9ff456f731 | 36 | uint16_t cntH_old, cntH, cntL; |
<> | 153:fa9ff456f731 | 37 | do { |
<> | 153:fa9ff456f731 | 38 | cntH_old = SlaveCounter; |
AnnaBridge | 167:e84263d55307 | 39 | /* SlaveCounter needs to be checked before AND after we read the |
AnnaBridge | 167:e84263d55307 | 40 | * current counter TIM_MST->CNT, in case it wraps around. |
AnnaBridge | 167:e84263d55307 | 41 | * there are 2 possible cases of wrap around |
AnnaBridge | 167:e84263d55307 | 42 | * 1) in case this function is interrupted by timer_irq_handler and |
AnnaBridge | 167:e84263d55307 | 43 | * the SlaveCounter is updated. In that case we will loop again. |
AnnaBridge | 167:e84263d55307 | 44 | * 2) in case this function is called from interrupt context during |
AnnaBridge | 167:e84263d55307 | 45 | * wrap-around condtion. That would prevent/delay the timer_irq_handler |
AnnaBridge | 167:e84263d55307 | 46 | * from being called so we need to locally check the FLAG_UPDATE and |
AnnaBridge | 167:e84263d55307 | 47 | * update the cntH accordingly. The SlaveCounter variable itself will |
AnnaBridge | 167:e84263d55307 | 48 | * be updated in the interrupt handler just after ... |
AnnaBridge | 167:e84263d55307 | 49 | */ |
<> | 153:fa9ff456f731 | 50 | if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_UPDATE) == SET) { |
<> | 153:fa9ff456f731 | 51 | cntH_old += 1; |
<> | 153:fa9ff456f731 | 52 | } |
<> | 153:fa9ff456f731 | 53 | cntL = TIM_MST->CNT; |
<> | 153:fa9ff456f731 | 54 | cntH = SlaveCounter; |
<> | 153:fa9ff456f731 | 55 | if (__HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_UPDATE) == SET) { |
<> | 153:fa9ff456f731 | 56 | cntH += 1; |
<> | 153:fa9ff456f731 | 57 | } |
<> | 153:fa9ff456f731 | 58 | } while(cntH_old != cntH); |
<> | 153:fa9ff456f731 | 59 | // Glue the upper and lower part together to get a 32 bit timer |
<> | 153:fa9ff456f731 | 60 | return (uint32_t)(cntH << 16 | cntL); |
<> | 153:fa9ff456f731 | 61 | } |
<> | 153:fa9ff456f731 | 62 | |
<> | 153:fa9ff456f731 | 63 | void us_ticker_set_interrupt(timestamp_t timestamp) |
<> | 153:fa9ff456f731 | 64 | { |
AnnaBridge | 167:e84263d55307 | 65 | // NOTE: This function must be called with interrupts disabled to keep our |
AnnaBridge | 167:e84263d55307 | 66 | // timer interrupt setup atomic |
AnnaBridge | 174:b96e65c34a4d | 67 | |
AnnaBridge | 167:e84263d55307 | 68 | // Set new output compare value |
AnnaBridge | 167:e84263d55307 | 69 | __HAL_TIM_SET_COMPARE(&TimMasterHandle, TIM_CHANNEL_1, timestamp & 0xFFFF); |
AnnaBridge | 167:e84263d55307 | 70 | // Ensure the compare event starts clear |
AnnaBridge | 167:e84263d55307 | 71 | __HAL_TIM_CLEAR_FLAG(&TimMasterHandle, TIM_FLAG_CC1); |
AnnaBridge | 167:e84263d55307 | 72 | // Enable IT |
AnnaBridge | 167:e84263d55307 | 73 | __HAL_TIM_ENABLE_IT(&TimMasterHandle, TIM_IT_CC1); |
<> | 153:fa9ff456f731 | 74 | |
AnnaBridge | 174:b96e65c34a4d | 75 | /* Set the number of timer wrap-around loops before the actual timestamp |
AnnaBridge | 174:b96e65c34a4d | 76 | * is reached. If the calculated delta time is more than halfway to the |
AnnaBridge | 174:b96e65c34a4d | 77 | * next compare event, check to see if a compare event has already been |
AnnaBridge | 174:b96e65c34a4d | 78 | * set, and if so, add one to the wrap-around count. This is done to |
AnnaBridge | 174:b96e65c34a4d | 79 | * ensure the correct wrap count is used in the corner cases where the |
AnnaBridge | 174:b96e65c34a4d | 80 | * 16 bit counter passes the compare value during the process of |
AnnaBridge | 174:b96e65c34a4d | 81 | * configuring this interrupt. |
AnnaBridge | 174:b96e65c34a4d | 82 | * |
AnnaBridge | 174:b96e65c34a4d | 83 | * Assumption: The time to execute this function is less than 32ms |
AnnaBridge | 174:b96e65c34a4d | 84 | * (otherwise incorrect behaviour could result) |
AnnaBridge | 174:b96e65c34a4d | 85 | * |
AnnaBridge | 174:b96e65c34a4d | 86 | * Consider the following corner cases: |
AnnaBridge | 174:b96e65c34a4d | 87 | * 1) timestamp is 1 us in the future: |
AnnaBridge | 174:b96e65c34a4d | 88 | * oc_int_part = 0 initially |
AnnaBridge | 174:b96e65c34a4d | 89 | * oc_int_part left at 0 because ((delta - 1) & 0xFFFF) < 0x8000 |
AnnaBridge | 174:b96e65c34a4d | 90 | * Compare event should happen in 1 us and us_ticker_irq_handler() |
AnnaBridge | 174:b96e65c34a4d | 91 | * called |
AnnaBridge | 174:b96e65c34a4d | 92 | * 2) timestamp is 0x8000 us in the future: |
AnnaBridge | 174:b96e65c34a4d | 93 | * oc_int_part = 0 initially |
AnnaBridge | 174:b96e65c34a4d | 94 | * oc_int_part left at 0 because ((delta - 1) & 0xFFFF) < 0x8000 |
AnnaBridge | 174:b96e65c34a4d | 95 | * There should be no possibility of the CC1 flag being set yet |
AnnaBridge | 174:b96e65c34a4d | 96 | * (see assumption above). When the compare event does occur in |
AnnaBridge | 174:b96e65c34a4d | 97 | * 32768 us, us_ticker_irq_handler() will be called |
AnnaBridge | 174:b96e65c34a4d | 98 | * 3) timestamp is 0x8001 us in the future: |
AnnaBridge | 174:b96e65c34a4d | 99 | * oc_int_part = 0 initially |
AnnaBridge | 174:b96e65c34a4d | 100 | * ((delta - 1) & 0xFFFF) >= 0x8000 but there should be no |
AnnaBridge | 174:b96e65c34a4d | 101 | * possibility of the CC1 flag being set yet (see assumption above), |
AnnaBridge | 174:b96e65c34a4d | 102 | * so oc_int_part will be left at 0, and when the compare event |
AnnaBridge | 174:b96e65c34a4d | 103 | * does occur in 32769 us, us_ticker_irq_handler() will be called |
AnnaBridge | 174:b96e65c34a4d | 104 | * 4) timestamp is 0x10000 us in the future: |
AnnaBridge | 174:b96e65c34a4d | 105 | * oc_int_part = 0 initially |
AnnaBridge | 174:b96e65c34a4d | 106 | * ((delta - 1) & 0xFFFF) >= 0x8000 |
AnnaBridge | 174:b96e65c34a4d | 107 | * There are two subcases: |
AnnaBridge | 174:b96e65c34a4d | 108 | * a) The timer counter has not incremented past the compare |
AnnaBridge | 174:b96e65c34a4d | 109 | * value while setting up the interrupt. In this case, the |
AnnaBridge | 174:b96e65c34a4d | 110 | * CC1 flag will not be set, so oc_int_part will be |
AnnaBridge | 174:b96e65c34a4d | 111 | * left at 0, and when the compare event occurs in 65536 us, |
AnnaBridge | 174:b96e65c34a4d | 112 | * us_ticker_irq_handler() will be called |
AnnaBridge | 174:b96e65c34a4d | 113 | * b) The timer counter has JUST incremented past the compare |
AnnaBridge | 174:b96e65c34a4d | 114 | * value. In this case, the CC1 flag will be set, so |
AnnaBridge | 174:b96e65c34a4d | 115 | * oc_int_part will be incremented to 1, and the interrupt will |
AnnaBridge | 174:b96e65c34a4d | 116 | * occur immediately after this function returns, where |
AnnaBridge | 174:b96e65c34a4d | 117 | * oc_int_part will decrement to 0 without calling |
AnnaBridge | 174:b96e65c34a4d | 118 | * us_ticker_irq_handler(). Then about 65536 us later, the |
AnnaBridge | 174:b96e65c34a4d | 119 | * compare event will occur again, and us_ticker_irq_handler() |
AnnaBridge | 174:b96e65c34a4d | 120 | * will be called |
AnnaBridge | 174:b96e65c34a4d | 121 | * 5) timestamp is 0x10001 us in the future: |
AnnaBridge | 174:b96e65c34a4d | 122 | * oc_int_part = 1 initially |
AnnaBridge | 174:b96e65c34a4d | 123 | * oc_int_part left at 1 because ((delta - 1) & 0xFFFF) < 0x8000 |
AnnaBridge | 174:b96e65c34a4d | 124 | * CC1 flag will not be set (see assumption above). In 1 us the |
AnnaBridge | 174:b96e65c34a4d | 125 | * compare event will cause an interrupt, where oc_int_part will be |
AnnaBridge | 174:b96e65c34a4d | 126 | * decremented to 0 without calling us_ticker_irq_handler(). Then |
AnnaBridge | 174:b96e65c34a4d | 127 | * about 65536 us later, the compare event will occur again, and |
AnnaBridge | 174:b96e65c34a4d | 128 | * us_ticker_irq_handler() will be called |
AnnaBridge | 174:b96e65c34a4d | 129 | * 6) timestamp is 0x18000 us in the future: |
AnnaBridge | 174:b96e65c34a4d | 130 | * oc_int_part = 1 initially |
AnnaBridge | 174:b96e65c34a4d | 131 | * oc_int_part left at 1 because ((delta - 1) & 0xFFFF) < 0x8000 |
AnnaBridge | 174:b96e65c34a4d | 132 | * There should be no possibility of the CC1 flag being set yet |
AnnaBridge | 174:b96e65c34a4d | 133 | * (see assumption above). When the compare event does occur in |
AnnaBridge | 174:b96e65c34a4d | 134 | * 32768 us, oc_int_part will be decremented to 0 without calling |
AnnaBridge | 174:b96e65c34a4d | 135 | * us_ticker_irq_handler(). Then about 65536 us later, the |
AnnaBridge | 174:b96e65c34a4d | 136 | * compare event will occur again, and us_ticker_irq_handler() will |
AnnaBridge | 174:b96e65c34a4d | 137 | * be called |
AnnaBridge | 174:b96e65c34a4d | 138 | * 7) timestamp is 0x18001 us in the future: |
AnnaBridge | 174:b96e65c34a4d | 139 | * oc_int_part = 1 initially |
AnnaBridge | 174:b96e65c34a4d | 140 | * ((delta - 1) & 0xFFFF) >= 0x8000 but there should be no |
AnnaBridge | 174:b96e65c34a4d | 141 | * possibility of the CC1 flag being set yet (see assumption above), |
AnnaBridge | 174:b96e65c34a4d | 142 | * so oc_int_part will be left at 1, and when the compare event |
AnnaBridge | 174:b96e65c34a4d | 143 | * does occur in 32769 us, oc_int_part will be decremented to 0 |
AnnaBridge | 174:b96e65c34a4d | 144 | * without calling us_ticker_irq_handler(). Then about 65536 us |
AnnaBridge | 174:b96e65c34a4d | 145 | * later, the compare event will occur again, and |
AnnaBridge | 174:b96e65c34a4d | 146 | * us_ticker_irq_handler() will be called |
AnnaBridge | 174:b96e65c34a4d | 147 | * |
AnnaBridge | 174:b96e65c34a4d | 148 | * delta - 1 is used because the timer compare event happens on the |
AnnaBridge | 174:b96e65c34a4d | 149 | * counter incrementing to match the compare value, and it won't occur |
AnnaBridge | 174:b96e65c34a4d | 150 | * immediately when the compare value is set to the current counter |
AnnaBridge | 174:b96e65c34a4d | 151 | * value. |
AnnaBridge | 174:b96e65c34a4d | 152 | */ |
AnnaBridge | 174:b96e65c34a4d | 153 | uint32_t current_time = us_ticker_read(); |
AnnaBridge | 174:b96e65c34a4d | 154 | uint32_t delta = timestamp - current_time; |
AnnaBridge | 174:b96e65c34a4d | 155 | /* Note: The case of delta <= 0 is handled in MBED upper layer */ |
AnnaBridge | 174:b96e65c34a4d | 156 | oc_int_part = (delta - 1) >> 16; |
AnnaBridge | 174:b96e65c34a4d | 157 | if ( ((delta - 1) & 0xFFFF) >= 0x8000 && |
AnnaBridge | 174:b96e65c34a4d | 158 | __HAL_TIM_GET_FLAG(&TimMasterHandle, TIM_FLAG_CC1) == SET ) { |
AnnaBridge | 174:b96e65c34a4d | 159 | ++oc_int_part; |
AnnaBridge | 174:b96e65c34a4d | 160 | /* NOTE: Instead of incrementing oc_int_part here, we could clear |
AnnaBridge | 174:b96e65c34a4d | 161 | * the CC1 flag, but then you'd have to wait to ensure the |
AnnaBridge | 174:b96e65c34a4d | 162 | * interrupt is knocked down before returning and reenabling |
AnnaBridge | 174:b96e65c34a4d | 163 | * interrupts. Since this is a rare case, it's not worth it |
AnnaBridge | 174:b96e65c34a4d | 164 | * to try and optimize it, and it keeps the code simpler and |
AnnaBridge | 174:b96e65c34a4d | 165 | * safer to just do this increment instead. |
AnnaBridge | 167:e84263d55307 | 166 | */ |
<> | 153:fa9ff456f731 | 167 | } |
AnnaBridge | 174:b96e65c34a4d | 168 | |
<> | 153:fa9ff456f731 | 169 | } |
<> | 153:fa9ff456f731 | 170 | |
AnnaBridge | 174:b96e65c34a4d | 171 | void us_ticker_fire_interrupt(void) |
AnnaBridge | 174:b96e65c34a4d | 172 | { |
AnnaBridge | 174:b96e65c34a4d | 173 | /* When firing the event, the number of 16 bits counter wrap-ups (oc_int) |
AnnaBridge | 174:b96e65c34a4d | 174 | * must be re-initialized */ |
AnnaBridge | 174:b96e65c34a4d | 175 | oc_int_part = 0; |
AnnaBridge | 174:b96e65c34a4d | 176 | HAL_TIM_GenerateEvent(&TimMasterHandle, TIM_EVENTSOURCE_CC1); |
AnnaBridge | 174:b96e65c34a4d | 177 | } |
AnnaBridge | 174:b96e65c34a4d | 178 | |
AnnaBridge | 174:b96e65c34a4d | 179 | /* NOTE: must be called with interrupts disabled! */ |
<> | 153:fa9ff456f731 | 180 | void us_ticker_disable_interrupt(void) |
<> | 153:fa9ff456f731 | 181 | { |
<> | 153:fa9ff456f731 | 182 | __HAL_TIM_DISABLE_IT(&TimMasterHandle, TIM_IT_CC1); |
<> | 153:fa9ff456f731 | 183 | } |
<> | 153:fa9ff456f731 | 184 | |
AnnaBridge | 174:b96e65c34a4d | 185 | /* NOTE: must be called with interrupts disabled! */ |
<> | 153:fa9ff456f731 | 186 | void us_ticker_clear_interrupt(void) |
<> | 153:fa9ff456f731 | 187 | { |
AnnaBridge | 167:e84263d55307 | 188 | __HAL_TIM_CLEAR_FLAG(&TimMasterHandle, TIM_FLAG_CC1); |
<> | 153:fa9ff456f731 | 189 | } |
<> | 153:fa9ff456f731 | 190 | |
<> | 153:fa9ff456f731 | 191 | #endif // TIM_MST_16BIT |