Skip to content

Commit e5cbb70

Browse files
committed
stmhal: Make enable_irq and disable_irq inline functions.
These functions are generally 1 machine instruction, and are used in critical code, so makes sense to have them inline. Also leave these functions uninverted (ie 0 means enable, 1 means disable) and provide macro constants if you really need to distinguish the states. This makes for smaller code as well (combined with inlining). Applied to teensy port as well.
1 parent 9480138 commit e5cbb70

File tree

6 files changed

+76
-46
lines changed

6 files changed

+76
-46
lines changed

py/objexcept.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,10 @@ mp_obj_t mp_alloc_emergency_exception_buf(mp_obj_t size_in) {
8888

8989
// Update the 2 variables atomically so that an interrupt can't occur
9090
// between the assignments.
91-
mp_int_t enabled = MICROPY_BEGIN_ATOMIC_SECTION();
91+
mp_uint_t irq_state = MICROPY_BEGIN_ATOMIC_SECTION();
9292
mp_emergency_exception_buf_size = size;
9393
mp_emergency_exception_buf = buf;
94-
MICROPY_END_ATOMIC_SECTION(enabled);
94+
MICROPY_END_ATOMIC_SECTION(irq_state);
9595

9696
if (old_buf != NULL) {
9797
m_free(old_buf, old_size);

stmhal/irq.c

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,6 @@
3333

3434
#include MICROPY_HAL_H
3535

36-
void enable_irq(mp_int_t enable) {
37-
// With __set_PRIMASK 1 = disable, 0 = enable
38-
__set_PRIMASK(!enable);
39-
}
40-
41-
mp_int_t disable_irq(void) {
42-
mp_int_t enabled = !__get_PRIMASK();
43-
__disable_irq();
44-
return enabled;
45-
}
46-
4736
/// \function wfi()
4837
/// Wait for an interrupt.
4938
/// This executies a `wfi` instruction which reduces power consumption
@@ -56,19 +45,22 @@ MP_DEFINE_CONST_FUN_OBJ_0(pyb_wfi_obj, pyb_wfi);
5645

5746
/// \function disable_irq()
5847
/// Disable interrupt requests.
48+
/// Returns the previous IRQ state: `False`/`True` for disabled/enabled IRQs
49+
/// respectively. This return value can be passed to enable_irq to restore
50+
/// the IRQ to its original state.
5951
STATIC mp_obj_t pyb_disable_irq(void) {
60-
return MP_BOOL(disable_irq());
52+
return MP_BOOL(disable_irq() == IRQ_STATE_ENABLED);
6153
}
6254
MP_DEFINE_CONST_FUN_OBJ_0(pyb_disable_irq_obj, pyb_disable_irq);
6355

64-
/// \function enable_irq()
56+
/// \function enable_irq(state=True)
6557
/// Enable interrupt requests.
58+
/// If `state` is `True` (the default value) then IRQs are enabled.
59+
/// If `state` is `False` then IRQs are disabled. The most common use of
60+
/// this function is to pass it the value returned by `disable_irq` to
61+
/// exit a critical section.
6662
STATIC mp_obj_t pyb_enable_irq(uint n_args, const mp_obj_t *arg) {
67-
mp_int_t enabled = true;
68-
if (n_args > 0) {
69-
enabled = mp_obj_is_true(arg[0]);
70-
}
71-
enable_irq(enabled);
63+
enable_irq((n_args == 0 || mp_obj_is_true(arg[0])) ? IRQ_STATE_ENABLED : IRQ_STATE_DISABLED);
7264
return mp_const_none;
7365
}
7466
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_enable_irq_obj, 0, 1, pyb_enable_irq);

stmhal/irq.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,11 @@
2424
* THE SOFTWARE.
2525
*/
2626

27-
// The prototypes for disable_irq/enable_irq are in mpconfigport.h
28-
// Once we switch around to using traitional #include headers, then they
29-
// can be move back into here.
27+
// these states correspond to values from enable_irq and disable_irq
28+
#define IRQ_STATE_DISABLED (0x00000001)
29+
#define IRQ_STATE_ENABLED (0x00000000)
3030

31-
// mp_int_t disable_irq(void);
32-
// void enable_irq(mp_int_t enabled);
31+
// enable_irq and disable_irq are defined inline in mpconfigport.h
3332

3433
MP_DECLARE_CONST_FUN_OBJ(pyb_wfi_obj);
3534
MP_DECLARE_CONST_FUN_OBJ(pyb_disable_irq_obj);

stmhal/mpconfigport.h

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424
* THE SOFTWARE.
2525
*/
2626

27+
#pragma once
28+
#ifndef __INCLUDED_MPCONFIGPORT_H
29+
#define __INCLUDED_MPCONFIGPORT_H
30+
2731
// options to control how Micro Python is built
2832

2933
#define MICROPY_ALLOC_PATH_MAX (128)
@@ -96,11 +100,28 @@ typedef unsigned int mp_uint_t; // must be pointer size
96100
typedef void *machine_ptr_t; // must be of pointer size
97101
typedef const void *machine_const_ptr_t; // must be of pointer size
98102

99-
mp_int_t disable_irq(void);
100-
void enable_irq(mp_int_t enable);
103+
// We have inlined IRQ functions for efficiency (they are generally
104+
// 1 machine instruction).
105+
//
106+
// Note on IRQ state: you should not need to know the specific
107+
// value of the state variable, but rather just pass the return
108+
// value from disable_irq back to enable_irq. If you really need
109+
// to know the machine-specific values, see irq.h.
110+
111+
#include <stm32f4xx_hal.h>
112+
113+
static inline void enable_irq(mp_uint_t state) {
114+
__set_PRIMASK(state);
115+
}
101116

102-
#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq()
103-
#define MICROPY_END_ATOMIC_SECTION(enable) enable_irq(enable)
117+
static inline mp_uint_t disable_irq(void) {
118+
mp_uint_t state = __get_PRIMASK();
119+
__disable_irq();
120+
return state;
121+
}
122+
123+
#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq()
124+
#define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state)
104125

105126
// There is no classical C heap in bare-metal ports, only Python
106127
// garbage-collected heap. For completeness, emulate C heap via
@@ -121,3 +142,5 @@ void enable_irq(mp_int_t enable);
121142

122143
#define MICROPY_HAL_H "mphal.h"
123144
#define MICROPY_PIN_DEFS_PORT_H "pin_defs_stmhal.h"
145+
146+
#endif // __INCLUDED_MPCONFIGPORT_H

teensy/mpconfigport.h

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,40 @@ typedef unsigned int mp_uint_t; // must be pointer size
5151
typedef void *machine_ptr_t; // must be of pointer size
5252
typedef const void *machine_const_ptr_t; // must be of pointer size
5353

54-
mp_int_t disable_irq(void);
55-
void enable_irq(mp_int_t enable);
54+
// We have inlined IRQ functions for efficiency (they are generally
55+
// 1 machine instruction).
56+
//
57+
// Note on IRQ state: you should not need to know the specific
58+
// value of the state variable, but rather just pass the return
59+
// value from disable_irq back to enable_irq. If you really need
60+
// to know the machine-specific values, see irq.h.
61+
62+
#ifndef __disable_irq
63+
#define __disable_irq() __asm__ volatile("CPSID i");
64+
#endif
65+
66+
__attribute__(( always_inline )) static inline uint32_t __get_PRIMASK(void) {
67+
uint32_t result;
68+
__asm volatile ("MRS %0, primask" : "=r" (result));
69+
return(result);
70+
}
71+
72+
__attribute__(( always_inline )) static inline void __set_PRIMASK(uint32_t priMask) {
73+
__asm volatile ("MSR primask, %0" : : "r" (priMask) : "memory");
74+
}
75+
76+
__attribute__(( always_inline )) static inline void enable_irq(mp_uint_t state) {
77+
__set_PRIMASK(state);
78+
}
79+
80+
__attribute__(( always_inline )) static inline mp_uint_t disable_irq(void) {
81+
mp_uint_t state = __get_PRIMASK();
82+
__disable_irq();
83+
return state;
84+
}
5685

57-
#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq()
58-
#define MICROPY_END_ATOMIC_SECTION(enable) enable_irq(enable)
86+
#define MICROPY_BEGIN_ATOMIC_SECTION() disable_irq()
87+
#define MICROPY_END_ATOMIC_SECTION(state) enable_irq(state)
5988

6089
// There is no classical C heap in bare-metal ports, only Python
6190
// garbage-collected heap. For completeness, emulate C heap via

teensy/teensy_hal.h

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -119,19 +119,6 @@ __attribute__(( always_inline )) static inline void __WFI(void)
119119
__asm volatile ("wfi");
120120
}
121121

122-
__attribute__(( always_inline )) static inline uint32_t __get_PRIMASK(void)
123-
{
124-
uint32_t result;
125-
__asm volatile ("MRS %0, primask" : "=r" (result));
126-
return(result);
127-
}
128-
129-
__attribute__(( always_inline )) static inline void __set_PRIMASK(uint32_t priMask)
130-
{
131-
__asm volatile ("MSR primask, %0" : : "r" (priMask) : "memory");
132-
}
133-
134-
135122
uint32_t HAL_GetTick(void);
136123
void HAL_Delay(uint32_t Delay);
137124

0 commit comments

Comments
 (0)