2 ******************************************************************************
3 * @addtogroup PIOS PIOS Core hardware abstraction layer
5 * @addtogroup PIOS_DELAY Delay Functions
6 * @brief PiOS Delay functionality
10 * @author Michael Smith Copyright (C) 2011
11 * @brief Delay Functions
12 * - Provides a micro-second granular delay using the CPU
14 * @see The GNU Public License (GPL) Version 3
16 *****************************************************************************/
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 3 of the License, or
21 * (at your option) any later version.
23 * This program is distributed in the hope that it will be useful, but
24 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
28 * You should have received a copy of the GNU General Public License along
29 * with this program; if not, write to the Free Software Foundation, Inc.,
30 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35 #ifdef PIOS_INCLUDE_DELAY
37 /* these should be defined by CMSIS, but they aren't */
38 #define DWT_CTRL (*(volatile uint32_t *)0xe0001000)
39 #define CYCCNTENA (1 << 0)
40 #define DWT_CYCCNT (*(volatile uint32_t *)0xe0001004)
43 /* cycles per microsecond */
44 static uint32_t us_ticks
;
47 * Initialises the Timer used by PIOS_DELAY functions.
49 * \return always zero (success)
52 int32_t PIOS_DELAY_Init(void)
54 RCC_ClocksTypeDef clocks
;
56 /* compute the number of system clocks per microsecond */
57 RCC_GetClocksFreq(&clocks
);
58 us_ticks
= clocks
.SYSCLK_Frequency
/ 1000000;
59 PIOS_DEBUG_Assert(us_ticks
> 1);
61 /* turn on access to the DWT registers */
62 CoreDebug
->DEMCR
|= CoreDebug_DEMCR_TRCENA_Msk
;
64 /* enable the CPU cycle counter */
65 DWT_CTRL
|= CYCCNTENA
;
71 * Waits for a specific number of uS
76 * PIOS_DELAY_Wait_uS(500);
79 * \return < 0 on errors
81 int32_t PIOS_DELAY_WaituS(uint32_t uS
)
84 uint32_t last_count
= DWT_CYCCNT
;
87 uint32_t current_count
= DWT_CYCCNT
;
90 /* measure the time elapsed since the last time we checked */
91 elapsed
+= current_count
- last_count
;
92 last_count
= current_count
;
94 /* convert to microseconds */
95 elapsed_uS
= elapsed
/ us_ticks
;
96 if (elapsed_uS
>= uS
) {
100 /* reduce the delay by the elapsed time */
103 /* keep fractional microseconds for the next iteration */
112 * Waits for a specific number of mS
117 * PIOS_DELAY_Wait_mS(500);
119 * \param[in] mS delay
120 * \return < 0 on errors
122 int32_t PIOS_DELAY_WaitmS(uint32_t mS
)
125 PIOS_DELAY_WaituS(1000);
133 * @brief Query the Delay timer for the current uS
134 * @return A microsecond value
136 uint32_t PIOS_DELAY_GetuS(void)
138 return DWT_CYCCNT
/ us_ticks
;
142 * @brief Calculate time in microseconds since a previous time
143 * @param[in] t previous time
144 * @return time in us since previous time t.
146 uint32_t PIOS_DELAY_GetuSSince(uint32_t t
)
148 return PIOS_DELAY_GetuS() - t
;
152 * @brief Get the raw delay timer, useful for timing
153 * @return Unitless value (uint32 wrap around)
155 uint32_t PIOS_DELAY_GetRaw()
161 * @brief Compare to raw times to and convert to us
162 * @return A microsecond value
164 uint32_t PIOS_DELAY_DiffuS(uint32_t raw
)
166 uint32_t diff
= DWT_CYCCNT
- raw
;
168 return diff
/ us_ticks
;
171 #endif /* PIOS_INCLUDE_DELAY */