|
1 | 1 | /* |
2 | 2 | Copyright (c) 2011 Arduino. All right reserved. |
3 | 3 | Copyright (c) 2013 by Paul Stoffregen <paul@pjrc.com> (delayMicroseconds) |
| 4 | + Copyright (c) 2018 MCCI Corporation (correct delayMicroseconds) |
4 | 5 |
|
5 | 6 | This library is free software; you can redistribute it and/or |
6 | 7 | modify it under the terms of the GNU Lesser General Public |
@@ -58,19 +59,64 @@ extern void delay( uint32_t dwMs ) ; |
58 | 59 | * \brief Pauses the program for the amount of time (in microseconds) specified as parameter. |
59 | 60 | * |
60 | 61 | * \param dwUs the number of microseconds to pause (uint32_t) |
| 62 | + * |
| 63 | + * \note This implementation does not call GetMicroseconds(), thereby avoiding |
| 64 | + * time- and power-wasting multiplies at each step of the delay. It also avoids |
| 65 | + * unnecesary register reads. Instead it does one multiply/divide to convert |
| 66 | + * us to ticks, based on the current clock setting, and waits until that many |
| 67 | + * ticks are observed. |
| 68 | + * See https://github.com/mcci-catena/Arduino_Core_STM32/issues/8 for more. |
61 | 69 | */ |
62 | 70 | static inline void delayMicroseconds(uint32_t) __attribute__((always_inline, unused)); |
63 | 71 | static inline void delayMicroseconds(uint32_t usec) |
64 | 72 | { |
65 | | - uint32_t end; |
| 73 | + // if the delay is huge, just delay by milliseconds. Assume |
| 74 | + // that the compiler will optimize this out for small constant |
| 75 | + // delays, and that it will optimize away the other branch. |
| 76 | + // Chose the limit so that the multiply for `ticks` won't |
| 77 | + // overflow. |
| 78 | + if (usec >= 10*1000) |
| 79 | + { |
| 80 | + delay((usec + 1000 - 1) / 1000); |
| 81 | + return; |
| 82 | + } |
| 83 | + |
| 84 | + // fetch initial time as a tick count. |
| 85 | + const uint32_t now = SysTick->VAL; |
| 86 | + |
| 87 | + // fetch max count, which is tics/millisecond. |
| 88 | + const uint32_t tickmax = SysTick->LOAD; |
| 89 | + |
| 90 | + // convert usec to an equivalent numer of ticks |
| 91 | + // there are tickmax/1000 ticks per microsecond. |
| 92 | + // so the following is usec * (tickmax/1000), rounded |
| 93 | + // and done in fixed point without loss of precision. |
| 94 | + const uint32_t ticks = (usec * tickmax + 500) / 1000; |
| 95 | + |
| 96 | + // val and lastval track tick counts. |
| 97 | + uint32_t val, lastVal; |
66 | 98 |
|
67 | | - if (usec == 0) |
68 | | - return; |
| 99 | + // dt tracks to the elapsed number of ticks. |
| 100 | + uint32_t dt; |
69 | 101 |
|
70 | | - end = GetCurrentMicro() + usec; |
71 | | - if (end < usec) |
72 | | - while (end < GetCurrentMicro()); |
73 | | - while (end > GetCurrentMicro()); |
| 102 | + // loop until we've observed at least `ticks` |
| 103 | + // clicks of SysTick. NB: SysTick is a down-counter. |
| 104 | + for (dt = 0, lastVal = now; |
| 105 | + dt < ticks; |
| 106 | + lastVal = val) |
| 107 | + { |
| 108 | + val = SysTick->VAL; |
| 109 | + if (val >= lastVal) |
| 110 | + { |
| 111 | + // count wrapped from 0 to tickmax, |
| 112 | + // so add the wrap-around count. |
| 113 | + dt += tickmax + lastVal - val; |
| 114 | + } |
| 115 | + else |
| 116 | + { |
| 117 | + dt += lastVal - val; |
| 118 | + } |
| 119 | + } |
74 | 120 | } |
75 | 121 |
|
76 | 122 | #ifdef __cplusplus |
|
0 commit comments