Skip to content

Commit c4985d3

Browse files
author
Kevin J Walters
committed
Making Bluetooth Great Again
GalacticUnicorn init now takes optional audio rate and pio to allow audio to be disabled and pio selected to avoid clashes. Fixing Bluetooth device name which was broken by some carelessness in cmake renovation.
1 parent 72b8e66 commit c4985d3

File tree

5 files changed

+123
-68
lines changed

5 files changed

+123
-68
lines changed

CMakeLists.txt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,18 +105,23 @@ target_link_libraries(${NAME2}
105105
hardware_dma
106106
)
107107

108-
message(NOTICE "Display: ${DISPLAY_NAME}")
108+
# Create the Bluetooth device name with upper case first character
109+
string(SUBSTRING ${UNICORN_MODEL} 0 1 FIRST_LETTER)
110+
string(TOUPPER ${FIRST_LETTER} FIRST_LETTER)
111+
string(REGEX REPLACE "^.(.*)" "${FIRST_LETTER}\\1 Unicorn" BLUETOOTH_DEVICE_NAME "${UNICORN_MODEL}")
112+
113+
message(NOTICE "Bluetooth device name: ${BLUETOOTH_DEVICE_NAME}")
109114

110115
target_compile_definitions(${NAME1} PRIVATE
111116
PICO_AUDIO_I2S_DATA_PIN=9
112117
PICO_AUDIO_I2S_CLOCK_PIN_BASE=10
113-
BLUETOOTH_DEVICE_NAME="${DISPLAY_NAME}"
118+
BLUETOOTH_DEVICE_NAME="${BLUETOOTH_DEVICE_NAME}"
114119
AUDIO_SOURCES=AudioSourceBluetooth
115120
)
116121
target_compile_definitions(${NAME2} PRIVATE
117122
PICO_AUDIO_I2S_DATA_PIN=9
118123
PICO_AUDIO_I2S_CLOCK_PIN_BASE=10
119-
BLUETOOTH_DEVICE_NAME="${DISPLAY_NAME}"
124+
BLUETOOTH_DEVICE_NAME="${BLUETOOTH_DEVICE_NAME}"
120125
AUDIO_SOURCES=AudioSourceDMAADC
121126
)
122127

libraries/galactic_unicorn/galactic_unicorn.cpp

Lines changed: 79 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
#include <math.h>
2-
#include <cstring>
3-
2+
#include <cstring>
3+
#include <cstddef>
4+
5+
#include "pico.h"
6+
#include "hardware/address_mapped.h"
7+
#include "hardware/structs/pio.h"
8+
#include "hardware/gpio.h"
9+
#include "hardware/regs/dreq.h"
10+
#include "hardware/pio_instructions.h"
411
#include "hardware/dma.h"
512
#include "hardware/irq.h"
613
#include "hardware/adc.h"
@@ -48,10 +55,10 @@ static uint32_t audio_dma_channel;
4855
namespace pimoroni {
4956

5057
GalacticUnicorn* GalacticUnicorn::unicorn = nullptr;
51-
PIO GalacticUnicorn::bitstream_pio = pio0;
58+
PIO GalacticUnicorn::bitstream_pio = nullptr;
5259
uint GalacticUnicorn::bitstream_sm = 0;
5360
uint GalacticUnicorn::bitstream_sm_offset = 0;
54-
PIO GalacticUnicorn::audio_pio = pio0;
61+
PIO GalacticUnicorn::audio_pio = nullptr;
5562
uint GalacticUnicorn::audio_sm = 0;
5663
uint GalacticUnicorn::audio_sm_offset = 0;
5764

@@ -75,13 +82,15 @@ namespace pimoroni {
7582
pio_sm_unclaim(bitstream_pio, bitstream_sm);
7683
pio_remove_program(bitstream_pio, &galactic_unicorn_program, bitstream_sm_offset);
7784

78-
dma_channel_unclaim(audio_dma_channel); // This works now the teardown behaves correctly
79-
pio_sm_unclaim(audio_pio, audio_sm);
80-
pio_remove_program(audio_pio, &audio_i2s_program, audio_sm_offset);
81-
//irq_remove_handler(DMA_IRQ_0, dma_complete);
82-
irq_remove_handler(DMA_IRQ_1, dma_complete);
85+
if (audio_rate > 0) {
86+
dma_channel_unclaim(audio_dma_channel); // This works now the teardown behaves correctly
87+
pio_sm_unclaim(audio_pio, audio_sm);
88+
pio_remove_program(audio_pio, &audio_i2s_program, audio_sm_offset);
89+
//irq_remove_handler(DMA_IRQ_0, dma_complete);
90+
irq_remove_handler(DMA_IRQ_1, dma_complete);
8391

84-
unicorn = nullptr;
92+
unicorn = nullptr;
93+
}
8594
}
8695
}
8796

@@ -103,29 +112,37 @@ namespace pimoroni {
103112
dma_safe_abort(dma_channel);
104113

105114

106-
// Stop the audio SM
107-
pio_sm_set_enabled(audio_pio, audio_sm, false);
108-
109-
// Reset the I2S pins to avoid popping when audio is suddenly stopped
110-
const uint pins_to_clear = 1 << I2S_DATA | 1 << I2S_BCLK | 1 << I2S_LRCLK;
111-
pio_sm_set_pins_with_mask(audio_pio, audio_sm, 0, pins_to_clear);
112-
113-
// Abort any in-progress DMA transfer
114-
dma_safe_abort(audio_dma_channel);
115+
// Stop the audio SM if enabled
116+
if (audio_rate > 0) {
117+
pio_sm_set_enabled(audio_pio, audio_sm, false);
118+
119+
// Reset the I2S pins to avoid popping when audio is suddenly stopped
120+
const uint pins_to_clear = 1 << I2S_DATA | 1 << I2S_BCLK | 1 << I2S_LRCLK;
121+
pio_sm_set_pins_with_mask(audio_pio, audio_sm, 0, pins_to_clear);
122+
123+
// Abort any in-progress DMA transfer
124+
dma_safe_abort(audio_dma_channel);
125+
}
115126
}
116127

117128
uint16_t GalacticUnicorn::light() {
118129
adc_select_input(2);
119130
return adc_read();
120131
}
121132

122-
void GalacticUnicorn::init() {
133+
void GalacticUnicorn::init(uint audio_rate_, PIO pio) {
123134

124135
if(unicorn != nullptr) {
125136
// Tear down the old GU instance's hardware resources
126137
partial_teardown();
127138
}
128-
139+
140+
audio_rate = audio_rate_;
141+
bitstream_pio = pio;
142+
if (audio_rate > 0) {
143+
audio_pio = pio;
144+
}
145+
129146
// for each row:
130147
// for each bcd frame:
131148
// 0: 00110110 // row pixel count (minus one)
@@ -233,7 +250,6 @@ namespace pimoroni {
233250
gpio_init(SWITCH_VOLUME_DOWN); gpio_pull_up(SWITCH_VOLUME_DOWN);
234251

235252
// setup the pio if it has not previously been set up
236-
bitstream_pio = pio0;
237253
if(unicorn == nullptr) {
238254
bitstream_sm = pio_claim_unused_sm(bitstream_pio, true);
239255
bitstream_sm_offset = pio_add_program(bitstream_pio, &galactic_unicorn_program);
@@ -310,38 +326,38 @@ namespace pimoroni {
310326
// start the control channel
311327
dma_start_channel_mask(1u << dma_ctrl_channel);
312328

313-
314-
// setup audio pio program
315-
audio_pio = pio0;
316-
if(unicorn == nullptr) {
317-
audio_sm = pio_claim_unused_sm(audio_pio, true);
318-
audio_sm_offset = pio_add_program(audio_pio, &audio_i2s_program);
319-
}
320-
321-
pio_gpio_init(audio_pio, I2S_DATA);
322-
pio_gpio_init(audio_pio, I2S_BCLK);
323-
pio_gpio_init(audio_pio, I2S_LRCLK);
324-
325-
audio_i2s_program_init(audio_pio, audio_sm, audio_sm_offset, I2S_DATA, I2S_BCLK);
326-
uint32_t system_clock_frequency = clock_get_hz(clk_sys);
327-
uint32_t divider = system_clock_frequency * 4 / SYSTEM_FREQ; // avoid arithmetic overflow
328-
pio_sm_set_clkdiv_int_frac(audio_pio, audio_sm, divider >> 8u, divider & 0xffu);
329-
330-
audio_dma_channel = dma_claim_unused_channel(true);
331-
dma_channel_config audio_config = dma_channel_get_default_config(audio_dma_channel);
332-
channel_config_set_transfer_data_size(&audio_config, DMA_SIZE_16);
333-
//channel_config_set_bswap(&audio_config, false); // byte swap to reverse little endian
334-
channel_config_set_dreq(&audio_config, pio_get_dreq(audio_pio, audio_sm, true));
335-
dma_channel_configure(audio_dma_channel, &audio_config, &audio_pio->txf[audio_sm], NULL, 0, false);
336-
337-
//dma_channel_set_irq0_enabled(audio_dma_channel, true);
338-
dma_channel_set_irq1_enabled(audio_dma_channel, true);
339-
340-
if(unicorn == nullptr) {
341-
//irq_add_shared_handler(DMA_IRQ_0, dma_complete, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
342-
//irq_set_enabled(DMA_IRQ_0, true);
343-
irq_add_shared_handler(DMA_IRQ_1, dma_complete, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
344-
irq_set_enabled(DMA_IRQ_1, true);
329+
// setup audio pio program if enabled
330+
if (audio_rate > 0) {
331+
if(unicorn == nullptr) {
332+
audio_sm = pio_claim_unused_sm(audio_pio, true);
333+
audio_sm_offset = pio_add_program(audio_pio, &audio_i2s_program);
334+
}
335+
336+
pio_gpio_init(audio_pio, I2S_DATA);
337+
pio_gpio_init(audio_pio, I2S_BCLK);
338+
pio_gpio_init(audio_pio, I2S_LRCLK);
339+
340+
audio_i2s_program_init(audio_pio, audio_sm, audio_sm_offset, I2S_DATA, I2S_BCLK);
341+
uint32_t system_clock_frequency = clock_get_hz(clk_sys);
342+
uint32_t divider = system_clock_frequency * 4 / audio_rate; // avoid arithmetic overflow
343+
pio_sm_set_clkdiv_int_frac(audio_pio, audio_sm, divider >> 8u, divider & 0xffu);
344+
345+
audio_dma_channel = dma_claim_unused_channel(true);
346+
dma_channel_config audio_config = dma_channel_get_default_config(audio_dma_channel);
347+
channel_config_set_transfer_data_size(&audio_config, DMA_SIZE_16);
348+
//channel_config_set_bswap(&audio_config, false); // byte swap to reverse little endian
349+
channel_config_set_dreq(&audio_config, pio_get_dreq(audio_pio, audio_sm, true));
350+
dma_channel_configure(audio_dma_channel, &audio_config, &audio_pio->txf[audio_sm], NULL, 0, false);
351+
352+
//dma_channel_set_irq0_enabled(audio_dma_channel, true);
353+
dma_channel_set_irq1_enabled(audio_dma_channel, true);
354+
355+
if(unicorn == nullptr) {
356+
//irq_add_shared_handler(DMA_IRQ_0, dma_complete, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
357+
//irq_set_enabled(DMA_IRQ_0, true);
358+
irq_add_shared_handler(DMA_IRQ_1, dma_complete, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
359+
irq_set_enabled(DMA_IRQ_1, true);
360+
}
345361
}
346362

347363
unicorn = this;
@@ -379,6 +395,8 @@ namespace pimoroni {
379395
}
380396

381397
void GalacticUnicorn::play_sample(uint8_t *data, uint32_t length) {
398+
if (audio_rate == 0) { return; }
399+
382400
stop_playing();
383401

384402
if(unicorn == this) {
@@ -390,6 +408,8 @@ namespace pimoroni {
390408
}
391409

392410
void GalacticUnicorn::play_synth() {
411+
if (audio_rate == 0) { return; }
412+
393413
if(play_mode != PLAYING_SYNTH) {
394414
stop_playing();
395415
}
@@ -410,6 +430,8 @@ namespace pimoroni {
410430
}
411431

412432
void GalacticUnicorn::next_audio_sequence() {
433+
if (audio_rate == 0) { return; }
434+
413435
// Clear any interrupt request caused by our channel
414436
//dma_channel_acknowledge_irq0(audio_dma_channel);
415437
// NOTE Temporary replacement of the above until this reaches pico-sdk main:
@@ -429,14 +451,16 @@ namespace pimoroni {
429451
}
430452

431453
void GalacticUnicorn::populate_next_synth() {
454+
if (audio_rate == 0) { return; }
455+
432456
int16_t *samples = tone_buffers[current_buffer];
433457
for(uint i = 0; i < TONE_BUFFER_SIZE; i++) {
434458
samples[i] = synth.get_audio_frame();
435459
}
436460
}
437461

438462
void GalacticUnicorn::stop_playing() {
439-
if(unicorn == this) {
463+
if(unicorn == this && audio_rate != 0) {
440464
// Stop the audio SM
441465
pio_sm_set_enabled(audio_pio, audio_sm, false);
442466

libraries/galactic_unicorn/galactic_unicorn.hpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
#pragma once
22

3+
#include "pico.h"
4+
#include "hardware/address_mapped.h"
5+
#include "hardware/structs/pio.h"
6+
#include "hardware/gpio.h"
7+
#include "hardware/regs/dreq.h"
8+
#include "hardware/pio_instructions.h"
39
#include "hardware/pio.h"
10+
411
#include "pico_graphics.hpp"
512
#include "common/pimoroni_common.hpp"
613
#include "../pico_synth/pico_synth.hpp"
@@ -53,7 +60,7 @@ namespace pimoroni {
5360
static const uint32_t BCD_FRAME_BYTES = 60;
5461
static const uint32_t ROW_BYTES = BCD_FRAME_COUNT * BCD_FRAME_BYTES;
5562
static const uint32_t BITSTREAM_LENGTH = (ROW_COUNT * ROW_BYTES);
56-
static const uint SYSTEM_FREQ = 22050;
63+
static const uint DEFAULT_SYSTEM_FREQ = 22050;
5764

5865
private:
5966
static PIO bitstream_pio;
@@ -64,6 +71,7 @@ namespace pimoroni {
6471
static uint audio_sm;
6572
static uint audio_sm_offset;
6673

74+
uint audio_rate = 0;
6775
uint16_t brightness = 256;
6876
uint16_t volume = 127;
6977

@@ -91,7 +99,7 @@ namespace pimoroni {
9199
public:
92100
~GalacticUnicorn();
93101

94-
void init();
102+
void init(uint audio_rate_ = DEFAULT_SYSTEM_FREQ, PIO = pio0);
95103
static inline void pio_program_init(PIO pio, uint sm, uint offset);
96104

97105
void clear();
@@ -126,4 +134,4 @@ namespace pimoroni {
126134
void populate_next_synth();
127135
};
128136

129-
}
137+
}

uad/audiosourcebluetooth.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ static audio_buffer_pool_t *init_audio(uint32_t sample_frequency, uint8_t channe
6969
// num channels requested by application
7070
btstack_audio_pico_channel_count = channel_count;
7171

72+
printf("init_audio 1\n");
7273
// This is the output format for i2s and is passed to pico-extras audio_i2s_setup
7374
// always use stereo
7475
btstack_audio_pico_audio_format.format = AUDIO_BUFFER_FORMAT_PCM_S16;
@@ -88,17 +89,24 @@ static audio_buffer_pool_t *init_audio(uint32_t sample_frequency, uint8_t channe
8889
config.clock_pin_base = PICO_AUDIO_I2S_CLOCK_PIN_BASE;
8990
config.dma_channel = (int8_t) dma_claim_unused_channel(true);
9091
config.pio_sm = 0;
92+
printf("init_audio 2\n");
93+
sleep_ms(100);
9194

9295
// audio_i2s_setup claims the channel again https://github.com/raspberrypi/pico-extras/issues/48
9396
dma_channel_unclaim(config.dma_channel);
97+
printf("init_audio 3\n");
98+
sleep_ms(100);
9499
const audio_format_t * output_format = audio_i2s_setup(&btstack_audio_pico_audio_format, &config);
95100
if (!output_format) {
96101
panic("PicoAudio: Unable to open audio device.\n");
97102
}
103+
printf("init_audio 4\n");
104+
sleep_ms(100);
98105

99106
bool ok = audio_i2s_connect(producer_pool);
100107
assert(ok);
101108
(void)ok;
109+
printf("init_audio 5\n");
102110

103111
return producer_pool;
104112
}

0 commit comments

Comments
 (0)