Skip to content

Commit e8d9131

Browse files
markshannondpgeorge
authored andcommitted
Make accelerometer and compass updates safe for interrupts.
1 parent 81ea004 commit e8d9131

File tree

4 files changed

+52
-38
lines changed

4 files changed

+52
-38
lines changed

inc/microbit/microbitobj.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ extern "C" {
3535
MicroBitPin *microbit_obj_get_pin(mp_obj_t o);
3636
MicroBitImage *microbit_obj_get_image(mp_obj_t o);
3737

38+
extern volatile bool compass_up_to_date;
39+
extern volatile bool compass_updating;
40+
41+
extern volatile bool accelerometer_up_to_date;
42+
extern volatile bool accelerometer_updating;
43+
3844
}
3945

4046
#endif // __MICROPY_INCLUDED_MICROBIT_MICROBITOBJ_H__

source/microbit/main.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "MicroBit.h"
2+
#include "microbitobj.h"
23
#include "microbitdisplay.h"
34

45
extern "C" {
@@ -30,15 +31,15 @@ void app_main() {
3031
}
3132
}
3233

33-
extern bool compass_up_to_date;
34-
extern bool accelerometer_up_to_date;
35-
3634
static void ticker(void) {
3735

3836
// increment our real-time counter.
3937
ticks += FIBER_TICK_PERIOD_MS;
4038

41-
if (uBit.compass.isCalibrating()) {
39+
/** Update compass if it is calibrating, but not if it is still
40+
* updating as compass.idleTick() is not reentrant.
41+
*/
42+
if (uBit.compass.isCalibrating() && !compass_updating) {
4243
uBit.compass.idleTick();
4344
}
4445

source/microbit/microbitaccelerometer.cpp

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,45 +36,49 @@ typedef struct _microbit_accelerometer_obj_t {
3636
MicroBitAccelerometer *accelerometer;
3737
} microbit_accelerometer_obj_t;
3838

39-
bool accelerometer_up_to_date = false;
39+
volatile bool accelerometer_up_to_date = false;
40+
volatile bool accelerometer_updating = false;
4041

41-
mp_obj_t microbit_accelerometer_get_x(mp_obj_t self_in) {
42-
microbit_accelerometer_obj_t *self = (microbit_accelerometer_obj_t*)self_in;
43-
if (!accelerometer_up_to_date) {
44-
self->accelerometer->idleTick();
42+
static void update(microbit_accelerometer_obj_t *self) {
43+
/* The only time it is possible for accelerometer_updating to be true here
44+
* is if this is called in an interrupt when it is already updating in
45+
* the main execution thread. This is extremely unlikely, so we just
46+
* accept that a slightly out-of-date result will be returned
47+
*/
48+
if (!accelerometer_up_to_date && !accelerometer_updating) {
4549
accelerometer_up_to_date = true;
50+
accelerometer_updating = true;
51+
self->accelerometer->idleTick();
52+
accelerometer_updating = false;
4653
}
54+
}
55+
56+
57+
mp_obj_t microbit_accelerometer_get_x(mp_obj_t self_in) {
58+
microbit_accelerometer_obj_t *self = (microbit_accelerometer_obj_t*)self_in;
59+
update(self);
4760
return mp_obj_new_int(self->accelerometer->getX());
4861
}
4962
MP_DEFINE_CONST_FUN_OBJ_1(microbit_accelerometer_get_x_obj, microbit_accelerometer_get_x);
5063

5164
mp_obj_t microbit_accelerometer_get_y(mp_obj_t self_in) {
5265
microbit_accelerometer_obj_t *self = (microbit_accelerometer_obj_t*)self_in;
53-
if (!accelerometer_up_to_date) {
54-
self->accelerometer->idleTick();
55-
accelerometer_up_to_date = true;
56-
}
66+
update(self);
5767
return mp_obj_new_int(self->accelerometer->getY());
5868
}
5969
MP_DEFINE_CONST_FUN_OBJ_1(microbit_accelerometer_get_y_obj, microbit_accelerometer_get_y);
6070

6171
mp_obj_t microbit_accelerometer_get_z(mp_obj_t self_in) {
6272
microbit_accelerometer_obj_t *self = (microbit_accelerometer_obj_t*)self_in;
63-
if (!accelerometer_up_to_date) {
64-
self->accelerometer->idleTick();
65-
accelerometer_up_to_date = true;
66-
}
73+
update(self);
6774
return mp_obj_new_int(self->accelerometer->getZ());
6875
}
6976
MP_DEFINE_CONST_FUN_OBJ_1(microbit_accelerometer_get_z_obj, microbit_accelerometer_get_z);
7077

7178
mp_obj_t microbit_accelerometer_get_values(mp_obj_t self_in) {
7279
microbit_accelerometer_obj_t *self = (microbit_accelerometer_obj_t*)self_in;
7380
mp_obj_tuple_t *tuple = (mp_obj_tuple_t *)mp_obj_new_tuple(3, NULL);
74-
if (!accelerometer_up_to_date) {
75-
self->accelerometer->idleTick();
76-
accelerometer_up_to_date = true;
77-
}
81+
update(self);
7882
tuple->items[0] = mp_obj_new_int(self->accelerometer->getX());
7983
tuple->items[1] = mp_obj_new_int(self->accelerometer->getY());
8084
tuple->items[2] = mp_obj_new_int(self->accelerometer->getZ());

source/microbit/microbitcompass.cpp

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -62,44 +62,47 @@ mp_obj_t microbit_compass_clear_calibration(mp_obj_t self_in) {
6262
}
6363
MP_DEFINE_CONST_FUN_OBJ_1(microbit_compass_clear_calibration_obj, microbit_compass_clear_calibration);
6464

65-
bool compass_up_to_date = false;
66-
67-
mp_obj_t microbit_compass_heading(mp_obj_t self_in) {
68-
microbit_compass_obj_t *self = (microbit_compass_obj_t*)self_in;
69-
if (!compass_up_to_date) {
65+
volatile bool compass_up_to_date = false;
66+
volatile bool compass_updating = false;
67+
68+
static void update(microbit_compass_obj_t *self) {
69+
/* The only time it is possible for compass_updating to be true here
70+
* is if this is called in an interrupt when it is already updating in
71+
* the main execution thread. This is extremely unlikely, so we just
72+
* accept that a slightly out-of-date result will be returned
73+
*/
74+
if (!compass_up_to_date && !compass_updating) {
75+
compass_updating = true;
7076
self->compass->idleTick();
77+
compass_updating = false;
7178
compass_up_to_date = true;
7279
}
80+
}
81+
82+
mp_obj_t microbit_compass_heading(mp_obj_t self_in) {
83+
microbit_compass_obj_t *self = (microbit_compass_obj_t*)self_in;
84+
update(self);
7385
return mp_obj_new_int(self->compass->heading());
7486
}
7587
MP_DEFINE_CONST_FUN_OBJ_1(microbit_compass_heading_obj, microbit_compass_heading);
7688

7789
mp_obj_t microbit_compass_get_x(mp_obj_t self_in) {
7890
microbit_compass_obj_t *self = (microbit_compass_obj_t*)self_in;
79-
if (!compass_up_to_date) {
80-
self->compass->idleTick();
81-
compass_up_to_date = true;
82-
}
91+
update(self);
8392
return mp_obj_new_int(self->compass->getX());
8493
}
8594
MP_DEFINE_CONST_FUN_OBJ_1(microbit_compass_get_x_obj, microbit_compass_get_x);
8695

8796
mp_obj_t microbit_compass_get_y(mp_obj_t self_in) {
8897
microbit_compass_obj_t *self = (microbit_compass_obj_t*)self_in;
89-
if (!compass_up_to_date) {
90-
self->compass->idleTick();
91-
compass_up_to_date = true;
92-
}
98+
update(self);
9399
return mp_obj_new_int(self->compass->getY());
94100
}
95101
MP_DEFINE_CONST_FUN_OBJ_1(microbit_compass_get_y_obj, microbit_compass_get_y);
96102

97103
mp_obj_t microbit_compass_get_z(mp_obj_t self_in) {
98104
microbit_compass_obj_t *self = (microbit_compass_obj_t*)self_in;
99-
if (!compass_up_to_date) {
100-
self->compass->idleTick();
101-
compass_up_to_date = true;
102-
}
105+
update(self);
103106
return mp_obj_new_int(self->compass->getZ());
104107
}
105108
MP_DEFINE_CONST_FUN_OBJ_1(microbit_compass_get_z_obj, microbit_compass_get_z);

0 commit comments

Comments
 (0)