/* * This file is part of the HAL project, inline library above libopencm3. * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library. If not, see . */ /** @defgroup DELAY_module DELAY module * * @brief Spin-waiting blocking API * * @ingroup modules * * LGPL License Terms @ref lgpl_license */ #ifndef HAL_DELAY_H_INCLUDED #define HAL_DELAY_H_INCLUDED #include #include /**@{*/ /*****************************************************************************/ /* API definitions */ /*****************************************************************************/ /*****************************************************************************/ /* API Functions */ /*****************************************************************************/ BEGIN_DECLS /*---------------------------------------------------------------------------*/ /** @brief Spin-wait delay, spinning specified amount of processor cycles * * @note this function can be used for delays of max 2500000 cycles. * For larger delays, please consider using timers or other waiting techniques. * * @param[in] cycles Cycles count need to spent in spin-wait */ static void delay_cycles(const int64_t cycles); /*---------------------------------------------------------------------------*/ /** @brief Spin-wait delay, spinning specified amount of microseconds * * @note this function can be used for delays max 25 sec @ 168MHz CPU clock, or * max 525 sec @ 8MHz CPU clock! For larger delays, please consider using * timers or other waiting techniques. * * @param[in] us Microseconds needed to spin wait. * @param[in] cpufreq Current CPU frequency in Hz */ static void delay_us(uint32_t us); /*---------------------------------------------------------------------------*/ /** @brief Spin-wait delay, spinning specified amount of microseconds * * @note this function can be used for delays max 25 sec @ 168MHz CPU clock, or * max 525 sec @ 8MHz CPU clock! For larger delays, please consider using * timers or other waiting techniques. * * @param[in] ms Milliseconds needed to spin wait. * @param[in] cpufreq Current CPU frequency in Hz */ static void delay_ms(uint32_t ms); END_DECLS /**@}*/ /*****************************************************************************/ /* Architecture dependent implementations */ /*****************************************************************************/ static void _delay_3t(uint32_t cycles) __attribute__((naked)); /* 3 Tcyc per tick, 4Tcyc call/ret, 1Tcyc hidden reg assignment */ static void _delay_3t(uint32_t cycles) { asm __volatile__ ( ".syntax unified\n" "1: \n" " subs %[cyc],#1 \n" /* 1Tck */ " bne 1b \n" /* 2Tck */ " bx lr \n" ".syntax divided\n" : /* No output */ : [cyc] "r" (cycles) : /* No memory */ ); } static inline __attribute__((always_inline)) void delay_cycles(const int64_t cycles) { if (cycles <= 0) return; switch (cycles % 3) { default: case 0: break; case 1: asm __volatile__ ("nop"); break; case 2: asm __volatile__ ("nop\nnop"); break; } if (cycles > 3) _delay_3t((uint32_t)(cycles / 3)); else /* same delay as the function call */ asm __volatile__ ("nop\nnop\nnop\nnop\nnop\nnop\n"); } /* max 25 sec @ 168MHz! */ /* max 525 sec @ 8MHz! */ static inline __attribute__((always_inline)) void delay_us(uint32_t us) { if (us == 0) return; delay_cycles(us * rcc_ahb_frequency / 1000000 - 6); } /* max 25 sec @ 168MHz! */ /* max 525 sec @ 8MHz! */ static inline __attribute__((always_inline)) void delay_ms(uint32_t ms) { if (ms == 0) return; delay_cycles(ms * rcc_ahb_frequency / 1000 - 6); } #endif /* HAL_DELAY_H_INCLUDED */