Skip to content

Commit 4c6160d

Browse files
committed
Change pinmode implementation to use array and improve API usability. Makes releasing pins safe in interrupts. Fix music module's pin releasing.
1 parent bfbfe87 commit 4c6160d

11 files changed

+290
-243
lines changed

inc/microbit/microbitobj.h

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,9 @@
2929
extern "C" {
3030

3131
#include "py/obj.h"
32+
#include "microbitpin.h"
3233
#include "PinNames.h"
3334

34-
typedef struct _microbit_pin_obj_t {
35-
mp_obj_base_t base;
36-
uint8_t number; // The pin number on microbit board
37-
PinName name; // The pin number in the GPIO port.
38-
} microbit_pin_obj_t;
39-
4035
const microbit_pin_obj_t *microbit_obj_get_pin(mp_obj_t o);
4136
PinName microbit_obj_get_pin_name(mp_obj_t o);
4237

inc/microbit/microbitpin.h

Lines changed: 43 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,39 +26,68 @@
2626
#ifndef __MICROPY_INCLUDED_MICROBIT_MICROBITPIN_H__
2727
#define __MICROPY_INCLUDED_MICROBIT_MICROBITPIN_H__
2828

29-
#ifndef MICROBIT_PIN_P0
29+
#include "py/obj.h"
3030

31-
#define MICROBIT_PIN_P0 (P0_3)
32-
#define MICROBIT_PIN_P1 (P0_2)
33-
#define MICROBIT_PIN_P13 (P0_23)
34-
#define MICROBIT_PIN_P14 (P0_22)
35-
#define MICROBIT_PIN_P15 (P0_21)
31+
typedef struct _microbit_pin_obj_t {
32+
mp_obj_base_t base;
33+
uint8_t number; // The pin number on microbit board
34+
uint8_t name; // The pin number in the GPIO port.
35+
uint8_t initial_mode;
36+
} microbit_pin_obj_t;
3637

37-
#endif
38-
39-
#include "microbit/microbitobj.h"
40-
41-
mp_obj_t microbit_pin_write_digital(mp_obj_t self_in, mp_obj_t value_in);
42-
mp_obj_t microbit_pin_read_digital(mp_obj_t self_in);
4338
typedef void(*release_func)(const microbit_pin_obj_t *pin);
4439

4540
typedef struct _pinmode {
4641
qstr name;
4742
release_func release; /* Call this function to release pin */
4843
} microbit_pinmode_t;
4944

45+
extern const microbit_pinmode_t microbit_pinmodes[];
46+
47+
/* Leave 0 to mean default mode. */
48+
#define MODE_UNUSED 1
49+
#define MODE_READ_DIGITAL 2
50+
#define MODE_WRITE_DIGITAL 3
51+
#define MODE_DISPLAY 4
52+
#define MODE_BUTTON 5
53+
#define MODE_MUSIC 6
54+
#define MODE_AUDIO_PLAY 7
55+
#define MODE_TOUCH 8
56+
#define MODE_I2C 9
57+
#define MODE_SPI 10
58+
#define MODE_WRITE_ANALOG 11
5059

60+
#define microbit_pin_mode_unused (&microbit_pinmodes[MODE_UNUSED])
61+
#define microbit_pin_mode_write_analog (&microbit_pinmodes[MODE_WRITE_ANALOG])
62+
#define microbit_pin_mode_read_digital (&microbit_pinmodes[MODE_READ_DIGITAL])
63+
#define microbit_pin_mode_write_digital (&microbit_pinmodes[MODE_WRITE_DIGITAL])
64+
#define microbit_pin_mode_display (&microbit_pinmodes[MODE_DISPLAY])
65+
#define microbit_pin_mode_button (&microbit_pinmodes[MODE_BUTTON])
66+
#define microbit_pin_mode_music (&microbit_pinmodes[MODE_MUSIC])
67+
#define microbit_pin_mode_audio_play (&microbit_pinmodes[MODE_AUDIO_PLAY])
68+
#define microbit_pin_mode_touch (&microbit_pinmodes[MODE_TOUCH])
69+
#define microbit_pin_mode_i2c (&microbit_pinmodes[MODE_I2C])
70+
#define microbit_pin_mode_spi (&microbit_pinmodes[MODE_SPI])
71+
72+
/** Can this pin be acquired? Safe to call in an interrupt. Not safe to call in an interrupt. */
5173
void microbit_obj_pin_fail_if_cant_acquire(const microbit_pin_obj_t *pin);
5274

75+
/** Release pin for use by other modes. Safe to call in an interrupt.
76+
* If pin is NULL or pin already unused, then this is a no-op
77+
*/
5378
void microbit_obj_pin_free(const microbit_pin_obj_t *pin);
5479

55-
void microbit_obj_pin_acquire(const microbit_pin_obj_t *pin, qstr name);
80+
/** Acquire pin (causing analog/digital modes to release) for mode.
81+
* If pin is already in specified mode, this is a no-op.
82+
* Not safe to call in an interrupt as it may raise. */
83+
void microbit_obj_pin_acquire(const microbit_pin_obj_t *pin, const microbit_pinmode_t *mode);
5684

5785
bool microbit_pin_high_debounced(microbit_pin_obj_t *pin);
5886

59-
qstr microbit_obj_pin_get_mode(const microbit_pin_obj_t *pin);
87+
const microbit_pinmode_t *microbit_pin_get_mode(const microbit_pin_obj_t *pin);
6088

6189
bool microbit_obj_pin_can_be_acquired(const microbit_pin_obj_t *pin);
6290

91+
void pinmode_error(const microbit_pin_obj_t *pin);
6392

6493
#endif // __MICROPY_INCLUDED_MICROBIT_MICROBITPIN_H__

source/microbit/microbitbutton.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,6 @@ const microbit_button_obj_t microbit_button_b_obj = {
109109
.index = 1,
110110
};
111111

112-
extern uint8_t microbit_pinmodes[];
113-
114112
enum PinTransition
115113
{
116114
LOW_LOW = 0,
@@ -162,11 +160,11 @@ void microbit_button_tick(void) {
162160
pressed[microbit_button_a_obj.index] = (pressed[microbit_button_a_obj.index] + 2) | 1;
163161
if (update(microbit_button_b_obj.pin) == HIGH_LOW)
164162
pressed[microbit_button_b_obj.index] = (pressed[microbit_button_b_obj.index] + 2) | 1;
165-
if (microbit_obj_pin_get_mode(&microbit_p0_obj) == MP_QSTR_touch)
163+
if (microbit_pin_get_mode(&microbit_p0_obj) == microbit_pin_mode_touch)
166164
update(&microbit_p0_obj);
167-
if (microbit_obj_pin_get_mode(&microbit_p1_obj) == MP_QSTR_touch)
165+
if (microbit_pin_get_mode(&microbit_p1_obj) == microbit_pin_mode_touch)
168166
update(&microbit_p1_obj);
169-
if (microbit_obj_pin_get_mode(&microbit_p2_obj) == MP_QSTR_touch)
167+
if (microbit_pin_get_mode(&microbit_p2_obj) == microbit_pin_mode_touch)
170168
update(&microbit_p2_obj);
171169
}
172170

source/microbit/microbitdisplay.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -431,12 +431,12 @@ mp_obj_t microbit_display_on_func(mp_obj_t obj) {
431431
microbit_obj_pin_fail_if_cant_acquire(&microbit_p7_obj);
432432
microbit_obj_pin_fail_if_cant_acquire(&microbit_p9_obj);
433433
microbit_obj_pin_fail_if_cant_acquire(&microbit_p10_obj);
434-
microbit_obj_pin_acquire(&microbit_p3_obj, MP_QSTR_display);
435-
microbit_obj_pin_acquire(&microbit_p4_obj, MP_QSTR_display);
436-
microbit_obj_pin_acquire(&microbit_p6_obj, MP_QSTR_display);
437-
microbit_obj_pin_acquire(&microbit_p7_obj, MP_QSTR_display);
438-
microbit_obj_pin_acquire(&microbit_p9_obj, MP_QSTR_display);
439-
microbit_obj_pin_acquire(&microbit_p10_obj, MP_QSTR_display);
434+
microbit_obj_pin_acquire(&microbit_p3_obj, microbit_pin_mode_display);
435+
microbit_obj_pin_acquire(&microbit_p4_obj, microbit_pin_mode_display);
436+
microbit_obj_pin_acquire(&microbit_p6_obj, microbit_pin_mode_display);
437+
microbit_obj_pin_acquire(&microbit_p7_obj, microbit_pin_mode_display);
438+
microbit_obj_pin_acquire(&microbit_p9_obj, microbit_pin_mode_display);
439+
microbit_obj_pin_acquire(&microbit_p10_obj, microbit_pin_mode_display);
440440
/* Make sure all pins are in the correct state */
441441
microbit_display_init();
442442
/* Re-enable the display loop. This will resume any animations in

source/microbit/microbitmusic.cpp

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ static uint32_t async_music_wait_ticks;
7070
static bool async_music_loop;
7171
static uint16_t async_music_notes_len;
7272
static uint16_t async_music_notes_index;
73-
static const microbit_pin_obj_t *async_music_pin;
73+
static const microbit_pin_obj_t *async_music_pin = NULL;
7474

7575
extern uint32_t ticks;
7676

@@ -100,6 +100,7 @@ void microbit_music_tick(void) {
100100
} else {
101101
async_music_state = ASYNC_MUSIC_STATE_IDLE;
102102
microbit_obj_pin_free(async_music_pin);
103+
async_music_pin = NULL;
103104
return;
104105
}
105106
}
@@ -275,9 +276,11 @@ STATIC mp_obj_t microbit_music_stop(mp_uint_t n_args, const mp_obj_t *args) {
275276
} else {
276277
pin = microbit_obj_get_pin(args[0]);
277278
}
279+
// Raise exception if the pin we are trying to stop is not in a compatible mode.
280+
microbit_obj_pin_acquire(pin, microbit_pin_mode_music);
278281
pwm_set_duty_cycle(pin->name, 0);
279282
microbit_obj_pin_free(pin);
280-
283+
async_music_pin = NULL;
281284
async_music_state = ASYNC_MUSIC_STATE_IDLE;
282285

283286
return mp_const_none;
@@ -296,6 +299,10 @@ STATIC mp_obj_t microbit_music_play(mp_uint_t n_args, const mp_obj_t *pos_args,
296299
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
297300
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
298301

302+
// reset octave and duration so tunes always play the same
303+
music_state.last_octave = DEFAULT_OCTAVE;
304+
music_state.last_duration = DEFAULT_DURATION;
305+
299306
// get either a single note or a list of notes
300307
mp_uint_t len;
301308
mp_obj_t *items;
@@ -306,21 +313,13 @@ STATIC mp_obj_t microbit_music_play(mp_uint_t n_args, const mp_obj_t *pos_args,
306313
mp_obj_get_array(args[0].u_obj, &len, &items);
307314
}
308315

316+
// Release the previous pin
317+
microbit_obj_pin_free(async_music_pin);
318+
async_music_pin = NULL;
319+
309320
// get the pin to play on
310321
const microbit_pin_obj_t *pin = microbit_obj_get_pin(args[1].u_obj);
311-
312-
if (async_music_state != ASYNC_MUSIC_STATE_IDLE) {
313-
// Stop the current music before starting new music.
314-
async_music_state = ASYNC_MUSIC_STATE_IDLE;
315-
pwm_set_duty_cycle(pin->name, 0);
316-
microbit_obj_pin_free(pin);
317-
}
318-
319-
// reset octave and duration so tunes always play the same
320-
music_state.last_octave = DEFAULT_OCTAVE;
321-
music_state.last_duration = DEFAULT_DURATION;
322-
323-
microbit_obj_pin_acquire(pin, MP_QSTR_music);
322+
microbit_obj_pin_acquire(pin, microbit_pin_mode_music);
324323

325324
// start the tune running in the background
326325
async_music_state = ASYNC_MUSIC_STATE_IDLE;
@@ -364,11 +363,19 @@ STATIC mp_obj_t microbit_music_pitch(mp_uint_t n_args, const mp_obj_t *pos_args,
364363
mp_uint_t frequency = args[0].u_int;
365364
mp_int_t duration = args[1].u_int;
366365
const microbit_pin_obj_t *pin = microbit_obj_get_pin(args[2].u_obj);
367-
microbit_obj_pin_acquire(pin, MP_QSTR_music);
366+
367+
// Update pin modes
368+
microbit_obj_pin_free(async_music_pin);
369+
async_music_pin = NULL;
370+
microbit_obj_pin_acquire(pin, microbit_pin_mode_music);
368371
bool wait = args[3].u_bool;
369372
pwm_set_duty_cycle(pin->name, 128);
370-
if (pwm_set_period_us(1000000/frequency))
371-
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "pitch too extreme"));
373+
if (frequency == 0) {
374+
pwm_release(pin->name);
375+
} else if (pwm_set_period_us(1000000/frequency)) {
376+
pwm_release(pin->name);
377+
nlr_raise(mp_obj_new_exception_msg(&mp_type_ValueError, "invalid pitch"));
378+
}
372379
if (duration >= 0) {
373380
// use async machinery to stop the pitch after the duration
374381
async_music_state = ASYNC_MUSIC_STATE_IDLE;

0 commit comments

Comments
 (0)