usbtest/src/delay.h

144 lines
4.5 KiB
C
Raw Permalink Normal View History

2021-09-30 16:33:59 +03:00
/*
* 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 <http://www.gnu.org/licenses/>.
*/
/** @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 <libopencm3/cm3/common.h>
#include <libopencm3/stm32/rcc.h>
/**@{*/
/*****************************************************************************/
/* 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 */