stmhal: Make pyb.[u]delay use systick with IRQs, busy loop otherwise.
pyb.delay and pyb.udelay now use systick if IRQs are enabled, otherwise they use a busy loop. Thus they work correctly when IRQs are disabled. The busy loop is computed from the current CPU frequency, so works no matter the CPU frequency.
This commit is contained in:
parent
c7ca01ad96
commit
1960475ed7
@ -24,10 +24,14 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// these states correspond to values from enable_irq and disable_irq
|
// these states correspond to values from query_irq, enable_irq and disable_irq
|
||||||
#define IRQ_STATE_DISABLED (0x00000001)
|
#define IRQ_STATE_DISABLED (0x00000001)
|
||||||
#define IRQ_STATE_ENABLED (0x00000000)
|
#define IRQ_STATE_ENABLED (0x00000000)
|
||||||
|
|
||||||
|
static inline mp_uint_t query_irq(void) {
|
||||||
|
return __get_PRIMASK();
|
||||||
|
}
|
||||||
|
|
||||||
// enable_irq and disable_irq are defined inline in mpconfigport.h
|
// enable_irq and disable_irq are defined inline in mpconfigport.h
|
||||||
|
|
||||||
MP_DECLARE_CONST_FUN_OBJ(pyb_wfi_obj);
|
MP_DECLARE_CONST_FUN_OBJ(pyb_wfi_obj);
|
||||||
|
@ -402,10 +402,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_delay_obj, pyb_delay);
|
|||||||
STATIC mp_obj_t pyb_udelay(mp_obj_t usec_in) {
|
STATIC mp_obj_t pyb_udelay(mp_obj_t usec_in) {
|
||||||
mp_int_t usec = mp_obj_get_int(usec_in);
|
mp_int_t usec = mp_obj_get_int(usec_in);
|
||||||
if (usec > 0) {
|
if (usec > 0) {
|
||||||
uint32_t count = 0;
|
sys_tick_udelay(usec);
|
||||||
const uint32_t utime = (168 * usec / 4);
|
|
||||||
while (++count <= utime) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
@ -36,12 +36,39 @@
|
|||||||
// We provide our own version of HAL_Delay that calls __WFI while waiting, in
|
// We provide our own version of HAL_Delay that calls __WFI while waiting, in
|
||||||
// order to reduce power consumption.
|
// order to reduce power consumption.
|
||||||
void HAL_Delay(uint32_t Delay) {
|
void HAL_Delay(uint32_t Delay) {
|
||||||
extern __IO uint32_t uwTick;
|
if (query_irq() == IRQ_STATE_ENABLED) {
|
||||||
uint32_t start = uwTick;
|
// IRQs enabled, so can use systick counter to do the delay
|
||||||
// Wraparound of tick is taken care of by 2's complement arithmetic.
|
extern __IO uint32_t uwTick;
|
||||||
while (uwTick - start < Delay) {
|
uint32_t start = uwTick;
|
||||||
// Enter sleep mode, waiting for (at least) the SysTick interrupt.
|
// Wraparound of tick is taken care of by 2's complement arithmetic.
|
||||||
__WFI();
|
while (uwTick - start < Delay) {
|
||||||
|
// Enter sleep mode, waiting for (at least) the SysTick interrupt.
|
||||||
|
__WFI();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// IRQs disabled, so need to use a busy loop for the delay.
|
||||||
|
// To prevent possible overflow of the counter we use a double loop.
|
||||||
|
const uint32_t count_1ms = HAL_RCC_GetSysClockFreq() / 4000;
|
||||||
|
for (int i = 0; i < Delay; i++) {
|
||||||
|
for (uint32_t count = 0; ++count <= count_1ms;) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// delay for given number of microseconds
|
||||||
|
void sys_tick_udelay(uint32_t usec) {
|
||||||
|
if (query_irq() == IRQ_STATE_ENABLED) {
|
||||||
|
// IRQs enabled, so can use systick counter to do the delay
|
||||||
|
uint32_t start = sys_tick_get_microseconds();
|
||||||
|
while (sys_tick_get_microseconds() - start < usec) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// IRQs disabled, so need to use a busy loop for the delay
|
||||||
|
// sys freq is always a multiple of 2MHz, so division here won't lose precision
|
||||||
|
const uint32_t ucount = HAL_RCC_GetSysClockFreq() / 2000000 * usec / 2;
|
||||||
|
for (uint32_t count = 0; ++count <= ucount;) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void sys_tick_udelay(uint32_t usec);
|
||||||
void sys_tick_wait_at_least(uint32_t stc, uint32_t delay_ms);
|
void sys_tick_wait_at_least(uint32_t stc, uint32_t delay_ms);
|
||||||
bool sys_tick_has_passed(uint32_t stc, uint32_t delay_ms);
|
bool sys_tick_has_passed(uint32_t stc, uint32_t delay_ms);
|
||||||
uint32_t sys_tick_get_microseconds(void);
|
uint32_t sys_tick_get_microseconds(void);
|
||||||
|
Loading…
Reference in New Issue
Block a user