Skip to content

Commit e6e43f1

Browse files
committed
codal_port: Support selecting pin/speaker in audio/music/speech modules.
The default selection for sound output is (pin0, pin_speaker) but this can be changed by specifying the "pin" keyword-argument to the relevant sound functions/methods.
1 parent b24d9e5 commit e6e43f1

File tree

9 files changed

+157
-129
lines changed

9 files changed

+157
-129
lines changed

src/codal_port/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ SRC_C += \
6666
microbit_constimage.c \
6767
microbit_microphone.c \
6868
microbit_pin.c \
69+
microbit_pinaudio.c \
6970
microbit_pinmode.c \
7071
microbit_soundevent.c \
7172
microbit_spi.c \

src/codal_port/microbit_pin.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ const microbit_pin_obj_t microbit_p20_obj = {{&microbit_dig_pin_type}, 20, MICR
5050

5151
const microbit_pin_obj_t microbit_pin_logo_obj = {{&microbit_touch_only_pin_type}, 30, MICROBIT_HAL_PIN_FACE, MODE_UNUSED};
5252
const microbit_pin_obj_t microbit_pin_speaker_obj = {{&microbit_dig_pin_type}, 31, MICROBIT_HAL_PIN_SPEAKER, MODE_UNUSED};
53-
const microbit_pin_obj_t microbit_pin_audio_obj = {{&microbit_dig_pin_type}, 33, MICROBIT_HAL_PIN_AUDIO, MODE_UNUSED};
5453

5554
static mp_obj_t microbit_pin_get_mode_func(mp_obj_t self_in) {
5655
microbit_pin_obj_t *self = (microbit_pin_obj_t*)self_in;

src/codal_port/microbit_pinaudio.c

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* This file is part of the MicroPython project, http://micropython.org/
3+
*
4+
* The MIT License (MIT)
5+
*
6+
* Copyright (c) 2020 Damien P. George
7+
*
8+
* Permission is hereby granted, free of charge, to any person obtaining a copy
9+
* of this software and associated documentation files (the "Software"), to deal
10+
* in the Software without restriction, including without limitation the rights
11+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
* copies of the Software, and to permit persons to whom the Software is
13+
* furnished to do so, subject to the following conditions:
14+
*
15+
* The above copyright notice and this permission notice shall be included in
16+
* all copies or substantial portions of the Software.
17+
*
18+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24+
* THE SOFTWARE.
25+
*/
26+
27+
#include "microbithal.h"
28+
#include "modmicrobit.h"
29+
30+
const mp_obj_tuple_t microbit_pin_default_audio_obj = {
31+
{ &mp_type_tuple },
32+
2,
33+
{
34+
(mp_obj_t)MP_ROM_PTR(&microbit_p0_obj),
35+
(mp_obj_t)MP_ROM_PTR(&microbit_pin_speaker_obj),
36+
}
37+
};
38+
39+
// Whether the speaker is enabled or not. If true, this overrides any selection
40+
// of the speaker to act as though it was not selected.
41+
STATIC bool audio_speaker_enabled = true;
42+
43+
// The currently selected pin and/or speaker output for the audio.
44+
STATIC const microbit_pin_obj_t *audio_routed_pin = NULL;
45+
STATIC bool audio_routed_speaker = false;
46+
47+
STATIC void microbit_pin_audio_get_pins(mp_const_obj_t select, const microbit_pin_obj_t **pin_selected, bool *speaker_selected) {
48+
// Convert the "select" object into an array of items (which should be pins).
49+
size_t len;
50+
mp_obj_t *items;
51+
if (mp_obj_is_type(select, &mp_type_tuple)) {
52+
mp_obj_get_array((mp_obj_t)select, &len, &items);
53+
if (len > 2) {
54+
mp_raise_ValueError(MP_ERROR_TEXT("maximum of 2 pins allowed"));
55+
}
56+
} else {
57+
len = 1;
58+
items = (mp_obj_t *)&select;
59+
}
60+
61+
// Work out which pins are selected for the audio output.
62+
*pin_selected = NULL;
63+
*speaker_selected = false;
64+
if (len == 1 || len == 2) {
65+
if (items[0] == &microbit_pin_speaker_obj) {
66+
*speaker_selected = true;
67+
} else {
68+
*pin_selected = microbit_obj_get_pin(items[0]);
69+
}
70+
if (len == 2) {
71+
if (items[1] == &microbit_pin_speaker_obj) {
72+
if (*speaker_selected) {
73+
mp_raise_ValueError(MP_ERROR_TEXT("speaker selected twice"));
74+
}
75+
*speaker_selected = true;
76+
} else {
77+
if (*pin_selected != NULL) {
78+
mp_raise_ValueError(MP_ERROR_TEXT("can only select one non-speaker pin"));
79+
}
80+
*pin_selected = microbit_obj_get_pin(items[1]);
81+
}
82+
}
83+
}
84+
85+
// Apply global override to enable/disable speaker.
86+
*speaker_selected = *speaker_selected && audio_speaker_enabled;
87+
}
88+
89+
void microbit_pin_audio_select(mp_const_obj_t select) {
90+
// Work out which pins are selected.
91+
const microbit_pin_obj_t *pin_selected;
92+
bool speaker_selected;
93+
microbit_pin_audio_get_pins(select, &pin_selected, &speaker_selected);
94+
95+
// Change the pin if needed.
96+
if (pin_selected != audio_routed_pin) {
97+
if (audio_routed_pin != NULL) {
98+
microbit_obj_pin_free(audio_routed_pin);
99+
}
100+
audio_routed_pin = pin_selected;
101+
if (audio_routed_pin == NULL) {
102+
microbit_hal_audio_select_pin(-1);
103+
} else {
104+
microbit_obj_pin_acquire(audio_routed_pin, microbit_pin_mode_music);
105+
microbit_hal_audio_select_pin(audio_routed_pin->name);
106+
}
107+
}
108+
109+
// Change the speaker mode if needed.
110+
if (speaker_selected != audio_routed_speaker) {
111+
audio_routed_speaker = speaker_selected;
112+
microbit_hal_audio_select_speaker(audio_routed_speaker);
113+
}
114+
}
115+
116+
void microbit_pin_audio_free(void) {
117+
if (audio_routed_pin != NULL) {
118+
microbit_obj_pin_free(audio_routed_pin);
119+
audio_routed_pin = NULL;
120+
}
121+
}

src/codal_port/modaudio.c

Lines changed: 10 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -41,34 +41,13 @@
4141
#define BUFFER_EXPANSION (16)
4242

4343
static volatile bool running = false;
44-
static bool double_pin = true;
45-
static const microbit_pin_obj_t *pin0 = NULL;
46-
static const microbit_pin_obj_t *pin1 = NULL;
47-
static const microbit_pin_obj_t *big_pins[3] = { &microbit_p0_obj, &microbit_p1_obj, &microbit_p2_obj };
4844

4945
microbit_audio_frame_obj_t *microbit_audio_frame_make_new(void);
5046

5147
void microbit_audio_stop(void) {
5248
audio_source_iter = NULL;
5349
running = false;
54-
microbit_obj_pin_free(pin0);
55-
if (double_pin) {
56-
microbit_obj_pin_free(pin1);
57-
}
58-
}
59-
60-
static void init_pin(const microbit_pin_obj_t *p0) {
61-
microbit_obj_pin_acquire(p0, microbit_pin_mode_audio_play);
62-
pin0 = p0;
63-
double_pin = false;
64-
}
65-
66-
static void init_pins(const microbit_pin_obj_t *p0, const microbit_pin_obj_t *p1) {
67-
microbit_obj_pin_acquire(p1, microbit_pin_mode_audio_play);
68-
microbit_obj_pin_acquire(p0, microbit_pin_mode_audio_play);
69-
pin0 = p0;
70-
pin1 = p1;
71-
double_pin = true;
50+
microbit_pin_audio_free();
7251
}
7352

7453
STATIC void audio_data_fetcher(void) {
@@ -131,68 +110,6 @@ void microbit_hal_audio_ready_callback(void) {
131110
mp_sched_schedule(MP_OBJ_FROM_PTR(&audio_data_fetcher_wrapper_obj), mp_const_none);
132111
}
133112

134-
static void audio_set_pins(mp_obj_t pin0_obj, mp_obj_t pin1_obj) {
135-
const microbit_pin_obj_t *p0 = microbit_obj_get_pin(pin0_obj);
136-
if (pin1_obj == mp_const_none) {
137-
init_pin(p0);
138-
} else {
139-
const microbit_pin_obj_t *p1 = microbit_obj_get_pin(pin1_obj);
140-
init_pins(p0, p1);
141-
}
142-
}
143-
144-
static int32_t pin_read_digital(const microbit_pin_obj_t *pin) {
145-
nrf_gpio_cfg_input(pin->name, NRF_GPIO_PIN_NOPULL);
146-
// Allow 1us to settle.
147-
mp_hal_delay_us(1);
148-
return nrf_gpio_pin_read(pin->name);
149-
}
150-
151-
static void audio_auto_set_pins(void) {
152-
audio_set_pins((mp_obj_t)&microbit_pin_speaker_obj, mp_const_none);
153-
return;
154-
// Test to see if two of the "big" pins are connected by some sort of resistor.
155-
uint32_t i, j, count;
156-
bool usable[3];
157-
if (microbit_obj_pin_can_be_acquired(&microbit_p0_obj)) {
158-
usable[0] = true;
159-
microbit_obj_pin_acquire(&microbit_p0_obj, microbit_pin_mode_unused);
160-
}
161-
if (microbit_obj_pin_can_be_acquired(&microbit_p1_obj)) {
162-
usable[1] = true;
163-
microbit_obj_pin_acquire(&microbit_p1_obj, microbit_pin_mode_unused);
164-
}
165-
if (microbit_obj_pin_can_be_acquired(&microbit_p2_obj)) {
166-
usable[2] = true;
167-
microbit_obj_pin_acquire(&microbit_p2_obj, microbit_pin_mode_unused);
168-
}
169-
for (i = 0; i < 2; i++) {
170-
if (!usable[i])
171-
continue;
172-
const microbit_pin_obj_t *pin1 = big_pins[i];
173-
nrf_gpio_cfg_output(pin1->name);
174-
for (j = i+1; j < 3; j++) {
175-
if (!usable[j])
176-
continue;
177-
const microbit_pin_obj_t *pin2 = big_pins[j];
178-
for (count = 0; count < 4; count++) {
179-
nrf_gpio_pin_set(pin1->name);
180-
if (pin_read_digital(pin2) != 1)
181-
break;
182-
nrf_gpio_pin_clear(pin1->name);
183-
if (pin_read_digital(pin2) != 0)
184-
break;
185-
}
186-
if (count == 4) {
187-
init_pins(pin1, pin2);
188-
return;
189-
}
190-
}
191-
}
192-
/* Set to default: single pin0 */
193-
audio_set_pins((mp_obj_t)&microbit_p0_obj, mp_const_none);
194-
}
195-
196113
static void audio_init(uint32_t sample_rate) {
197114
if (audio_buffer_ptr == NULL) {
198115
audio_source_iter = NULL;
@@ -201,22 +118,12 @@ static void audio_init(uint32_t sample_rate) {
201118
microbit_hal_audio_init(BUFFER_EXPANSION / 4 * sample_rate);
202119
}
203120

204-
void microbit_audio_play_source(mp_obj_t src, mp_obj_t pin1, mp_obj_t pin2, bool wait, uint32_t sample_rate) {
121+
void microbit_audio_play_source(mp_obj_t src, mp_obj_t pin_select, bool wait, uint32_t sample_rate) {
205122
if (running) {
206123
microbit_audio_stop();
207124
}
208125
audio_init(sample_rate);
209-
if (0) {
210-
if (pin1 == mp_const_none) {
211-
if (pin2 == mp_const_none) {
212-
audio_auto_set_pins();
213-
} else {
214-
mp_raise_TypeError("cannot set return_pin without pin");
215-
}
216-
} else {
217-
audio_set_pins(pin1, pin2);
218-
}
219-
}
126+
microbit_pin_audio_select(pin_select);
220127

221128
audio_source_iter = NULL;
222129

@@ -254,10 +161,14 @@ STATIC mp_obj_t play(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
254161
// parse args
255162
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
256163
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
164+
165+
// The return_pin argument from micro:bit v1 is no longer supported.
166+
if (args[3].u_obj != mp_const_none) {
167+
mp_raise_ValueError("return_pin not supported");
168+
}
169+
257170
mp_obj_t src = args[0].u_obj;
258-
mp_obj_t pin1 = args[2].u_obj;
259-
mp_obj_t pin2 = args[3].u_obj;
260-
microbit_audio_play_source(src, pin1, pin2, args[1].u_bool, DEFAULT_SAMPLE_RATE);
171+
microbit_audio_play_source(src, args[2].u_obj, args[1].u_bool, DEFAULT_SAMPLE_RATE);
261172
return mp_const_none;
262173
}
263174
MP_DEFINE_CONST_FUN_OBJ_KW(microbit_audio_play_obj, 0, play);

src/codal_port/modaudio.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ typedef struct _microbit_audio_frame_obj_t {
3939

4040
extern const mp_obj_type_t microbit_audio_frame_type;
4141

42-
void microbit_audio_play_source(mp_obj_t src, mp_obj_t pin1, mp_obj_t pin2, bool wait, uint32_t sample_rate);
42+
void microbit_audio_play_source(mp_obj_t src, mp_obj_t pin_select, bool wait, uint32_t sample_rate);
4343
void microbit_audio_stop(void);
4444
bool microbit_audio_is_playing(void);
4545
microbit_audio_frame_obj_t *microbit_audio_frame_make_new(void);

src/codal_port/modmicrobit.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,6 @@ STATIC const mp_rom_map_elem_t microbit_module_globals_table[] = {
136136
{ MP_ROM_QSTR(MP_QSTR_pin20), MP_ROM_PTR(&microbit_p20_obj) },
137137
{ MP_ROM_QSTR(MP_QSTR_pin_logo), MP_ROM_PTR(&microbit_pin_logo_obj) },
138138
{ MP_ROM_QSTR(MP_QSTR_pin_speaker), MP_ROM_PTR(&microbit_pin_speaker_obj) },
139-
{ MP_ROM_QSTR(MP_QSTR_pin_audio), MP_ROM_PTR(&microbit_pin_audio_obj) },
140139
};
141140

142141
STATIC MP_DEFINE_CONST_DICT(microbit_module_globals, microbit_module_globals_table);

src/codal_port/modmicrobit.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ extern const struct _microbit_pin_obj_t microbit_p19_obj;
100100
extern const struct _microbit_pin_obj_t microbit_p20_obj;
101101
extern const struct _microbit_pin_obj_t microbit_pin_logo_obj;
102102
extern const struct _microbit_pin_obj_t microbit_pin_speaker_obj;
103-
extern const struct _microbit_pin_obj_t microbit_pin_audio_obj;
104103

105104
extern const struct _microbit_i2c_obj_t microbit_i2c_obj;
106105
extern const struct _microbit_uart_obj_t microbit_uart_obj;
@@ -182,7 +181,8 @@ extern const struct _microbit_microphone_obj_t microbit_microphone_obj;
182181
extern const struct _microbit_button_obj_t microbit_button_a_obj;
183182
extern const struct _microbit_button_obj_t microbit_button_b_obj;
184183

185-
extern uint16_t microbit_volume_global;
184+
//extern uint16_t microbit_volume_global;
185+
extern const mp_obj_tuple_t microbit_pin_default_audio_obj;
186186

187187
const microbit_pin_obj_t *microbit_obj_get_pin(mp_obj_t o);
188188

@@ -202,6 +202,9 @@ bool microbit_obj_pin_acquire(const microbit_pin_obj_t *pin, const microbit_pinm
202202
const microbit_pinmode_t *microbit_pin_get_mode(const microbit_pin_obj_t *pin);
203203
void pinmode_error(const microbit_pin_obj_t *pin);
204204

205+
void microbit_pin_audio_select(mp_const_obj_t select);
206+
void microbit_pin_audio_free(void);
207+
205208
MP_DECLARE_CONST_FUN_OBJ_0(microbit_reset_obj);
206209

207210
#endif // MICROPY_INCLUDED_MICROBIT_MODMICROBIT_H

0 commit comments

Comments
 (0)