From 029416548159c7dfb110b120a1298782332e413c Mon Sep 17 00:00:00 2001 From: Jared Boone Date: Fri, 5 Feb 2016 16:25:43 -0800 Subject: [PATCH] Extract LOTS of stuff into an audio API. Prevent all manner of type and implementation leakage. --- firmware/application/analog_audio_app.cpp | 19 +-- firmware/application/audio.cpp | 148 ++++++++++++++++++++++ firmware/application/audio.hpp | 97 ++++++-------- firmware/application/portapack.cpp | 17 +-- firmware/application/portapack.hpp | 3 - firmware/application/receiver_model.cpp | 10 +- firmware/application/ui_debug.cpp | 6 +- firmware/common/portapack_hal.hpp | 4 - 8 files changed, 208 insertions(+), 96 deletions(-) diff --git a/firmware/application/analog_audio_app.cpp b/firmware/application/analog_audio_app.cpp index 37c1e308..361e5e80 100644 --- a/firmware/application/analog_audio_app.cpp +++ b/firmware/application/analog_audio_app.cpp @@ -25,8 +25,7 @@ #include "portapack_shared_memory.hpp" using namespace portapack; -#include "i2s.hpp" -using namespace lpc43xx; +#include "audio.hpp" #include "utility.hpp" @@ -128,20 +127,20 @@ AnalogAudioView::AnalogAudioView( this->on_show_options_modulation(); }; - field_volume.set_value((receiver_model.headphone_volume() - wolfson::wm8731::headphone_gain_range.max).decibel() + 99); + field_volume.set_value((receiver_model.headphone_volume() - audio::headphone::volume_range().max).decibel() + 99); field_volume.on_change = [this](int32_t v) { this->on_headphone_volume_changed(v); }; + audio::output::start(); + update_modulation(static_cast(modulation)); } AnalogAudioView::~AnalogAudioView() { // TODO: Manipulating audio codec here, and in ui_receiver.cpp. Good to do // both? - i2s::i2s0::tx_mute(); - - audio_codec.headphone_mute(); + audio::output::stop(); receiver_model.disable(); } @@ -286,11 +285,13 @@ void AnalogAudioView::on_reference_ppm_correction_changed(int32_t v) { } void AnalogAudioView::on_headphone_volume_changed(int32_t v) { - const auto new_volume = volume_t::decibel(v - 99) + wolfson::wm8731::headphone_gain_range.max; + const auto new_volume = volume_t::decibel(v - 99) + audio::headphone::volume_range().max; receiver_model.set_headphone_volume(new_volume); } void AnalogAudioView::update_modulation(const ReceiverModel::Mode modulation) { + audio::output::mute(); + const auto is_wideband_spectrum_mode = (modulation == ReceiverModel::Mode::SpectrumAnalysis); receiver_model.set_baseband_configuration({ .mode = toUType(modulation), @@ -300,7 +301,9 @@ void AnalogAudioView::update_modulation(const ReceiverModel::Mode modulation) { receiver_model.set_baseband_bandwidth(is_wideband_spectrum_mode ? 12000000 : 1750000); receiver_model.enable(); - i2s::i2s0::tx_unmute(); + if( !is_wideband_spectrum_mode ) { + audio::output::unmute(); + } } } /* namespace ui */ diff --git a/firmware/application/audio.cpp b/firmware/application/audio.cpp index 2f7f17ed..ac04e106 100644 --- a/firmware/application/audio.cpp +++ b/firmware/application/audio.cpp @@ -21,6 +21,154 @@ #include "audio.hpp" +#include "portapack.hpp" +using portapack::i2c0; +using portapack::clock_manager; + +#include "wm8731.hpp" +using wolfson::wm8731::WM8731; + +#include "i2s.hpp" +using namespace lpc43xx; + namespace audio { +namespace { + +constexpr i2s::ConfigTX i2s0_config_tx { + .dao = i2s::DAO { + .wordwidth = i2s::WordWidth::Bits16, + .mono = 0, + .stop = 1, + .reset = 0, + .ws_sel = 0, + .ws_halfperiod = 0x0f, + .mute = 1, + }, + .txrate = i2s::MCLKRate { + .x_divider = 0, + .y_divider = 0, + }, + .txbitrate = i2s::BitRate { + .bitrate = 7, + }, + .txmode = i2s::Mode { + .clksel = i2s::ClockSelect::BaseAudioClkOrExternalMCLK, + .four_pin = 0, + .mclk_out_en = 1, + }, +}; + +constexpr i2s::ConfigRX i2s0_config_rx { + .dai = i2s::DAI { + .wordwidth = i2s::WordWidth::Bits16, + .mono = 0, + .stop = 1, + .reset = 0, + .ws_sel = 1, + .ws_halfperiod = 0x0f, + }, + .rxrate = i2s::MCLKRate { + .x_divider = 0, + .y_divider = 0, + }, + .rxbitrate = i2s::BitRate { + .bitrate = 7, + }, + .rxmode = i2s::Mode { + .clksel = i2s::ClockSelect::BaseAudioClkOrExternalMCLK, + .four_pin = 1, + .mclk_out_en = 0, + }, +}; + +constexpr i2s::ConfigDMA i2s0_config_dma { + .dma1 = i2s::DMA { + .rx_enable = 1, + .tx_enable = 0, + .rx_depth = 4, + .tx_depth = 0, + }, + .dma2 = i2s::DMA { + .rx_enable = 0, + .tx_enable = 1, + .rx_depth = 0, + .tx_depth = 4, + }, +}; + +constexpr uint8_t wm8731_i2c_address = 0x1a; + +WM8731 audio_codec { i2c0, wm8731_i2c_address }; + +} /* namespace */ + +namespace output { + +void start() { + i2s::i2s0::tx_start(); + unmute(); +} + +void stop() { + mute(); + i2s::i2s0::tx_stop(); +} + +void mute() { + i2s::i2s0::tx_mute(); + + audio_codec.headphone_mute(); +} + +void unmute() { + i2s::i2s0::tx_unmute(); +} + +} /* namespace output */ + +namespace headphone { + +volume_range_t volume_range() { + return wolfson::wm8731::headphone_gain_range; +} + +void set_volume(const volume_t volume) { + audio_codec.set_headphone_volume(volume); +} + +} /* namespace headphone */ + +namespace debug { + +int reg_count() { + return wolfson::wm8731::reg_count; +} + +uint16_t reg_read(const int register_number) { + return audio_codec.read(register_number); +} + +} /* namespace debug */ + +void init() { + clock_manager.start_audio_pll(); + audio_codec.init(); + + i2s::i2s0::configure( + i2s0_config_tx, + i2s0_config_rx, + i2s0_config_dma + ); +} + +void shutdown() { + audio_codec.reset(); + output::stop(); +} + +void set_rate(const Rate rate) { + clock_manager.set_base_audio_clock_divider(toUType(rate)); +} + } /* namespace audio */ diff --git a/firmware/application/audio.hpp b/firmware/application/audio.hpp index d672f744..e3d7544f 100644 --- a/firmware/application/audio.hpp +++ b/firmware/application/audio.hpp @@ -22,72 +22,47 @@ #ifndef __AUDIO_H__ #define __AUDIO_H__ -#include "i2s.hpp" -using namespace lpc43xx; +#include "volume.hpp" + +#include namespace audio { -constexpr i2s::ConfigTX i2s0_config_tx { - .dao = i2s::DAO { - .wordwidth = i2s::WordWidth::Bits16, - .mono = 0, - .stop = 1, - .reset = 0, - .ws_sel = 0, - .ws_halfperiod = 0x0f, - .mute = 1, - }, - .txrate = i2s::MCLKRate { - .x_divider = 0, - .y_divider = 0, - }, - .txbitrate = i2s::BitRate { - .bitrate = 7, - }, - .txmode = i2s::Mode { - .clksel = i2s::ClockSelect::BaseAudioClkOrExternalMCLK, - .four_pin = 0, - .mclk_out_en = 1, - }, +namespace output { + +void start(); +void stop(); + +void mute(); +void unmute(); + +} /* namespace output */ + +namespace headphone { + +volume_range_t volume_range(); + +void set_volume(const volume_t volume); + +} /* namespace headphone */ + +namespace debug { + +int reg_count(); +uint16_t reg_read(const int register_number); + +} /* namespace debug */ + +void init(); +void shutdown(); + +enum class Rate { + Hz_12000 = 4, + Hz_24000 = 2, + Hz_48000 = 1, }; -constexpr i2s::ConfigRX i2s0_config_rx { - .dai = i2s::DAI { - .wordwidth = i2s::WordWidth::Bits16, - .mono = 0, - .stop = 1, - .reset = 0, - .ws_sel = 1, - .ws_halfperiod = 0x0f, - }, - .rxrate = i2s::MCLKRate { - .x_divider = 0, - .y_divider = 0, - }, - .rxbitrate = i2s::BitRate { - .bitrate = 7, - }, - .rxmode = i2s::Mode { - .clksel = i2s::ClockSelect::BaseAudioClkOrExternalMCLK, - .four_pin = 1, - .mclk_out_en = 0, - }, -}; - -constexpr i2s::ConfigDMA i2s0_config_dma { - .dma1 = i2s::DMA { - .rx_enable = 1, - .tx_enable = 0, - .rx_depth = 4, - .tx_depth = 0, - }, - .dma2 = i2s::DMA { - .rx_enable = 0, - .tx_enable = 1, - .rx_depth = 0, - .tx_depth = 4, - }, -}; +void set_rate(const Rate rate); } /* namespace audio */ diff --git a/firmware/application/portapack.cpp b/firmware/application/portapack.cpp index 9f8f9c4f..12bae224 100644 --- a/firmware/application/portapack.cpp +++ b/firmware/application/portapack.cpp @@ -50,8 +50,6 @@ I2C i2c0(&I2CD0); SPI ssp0(&SPID1); SPI ssp1(&SPID2); -wolfson::wm8731::WM8731 audio_codec { i2c0, portapack::wm8731_i2c_address }; - si5351::Si5351 clock_generator { i2c0, hackrf::one::si5351_i2c_address }; @@ -129,17 +127,8 @@ void init() { clock_manager.set_reference_ppb(persistent_memory::correction_ppb()); clock_manager.run_at_full_speed(); - clock_manager.start_audio_pll(); - audio_codec.init(); - - i2s::i2s0::configure( - audio::i2s0_config_tx, - audio::i2s0_config_rx, - audio::i2s0_config_dma - ); - i2s::i2s0::tx_start(); - i2s::i2s0::rx_start(); - + audio::init(); + clock_manager.enable_first_if_clock(); clock_manager.enable_second_if_clock(); clock_manager.enable_codec_clocks(); @@ -152,7 +141,7 @@ void shutdown() { display.shutdown(); radio::disable(); - audio_codec.reset(); + audio::shutdown(); clock_manager.shutdown(); power.shutdown(); diff --git a/firmware/application/portapack.hpp b/firmware/application/portapack.hpp index bb8e0042..004ab5e9 100644 --- a/firmware/application/portapack.hpp +++ b/firmware/application/portapack.hpp @@ -25,7 +25,6 @@ #include "i2c_pp.hpp" #include "spi_pp.hpp" -#include "wm8731.hpp" #include "si5351.hpp" #include "lcd_ili9341.hpp" @@ -43,8 +42,6 @@ extern I2C i2c0; extern SPI ssp0; extern SPI ssp1; -extern wolfson::wm8731::WM8731 audio_codec; - extern si5351::Si5351 clock_generator; extern ClockManager clock_manager; diff --git a/firmware/application/receiver_model.cpp b/firmware/application/receiver_model.cpp index 7947a652..89e43eb7 100644 --- a/firmware/application/receiver_model.cpp +++ b/firmware/application/receiver_model.cpp @@ -26,6 +26,8 @@ #include "portapack.hpp" using namespace portapack; +#include "audio.hpp" + #include "dsp_fir_taps.hpp" #include "dsp_iir.hpp" #include "dsp_iir_config.hpp" @@ -62,7 +64,7 @@ void AMConfig::apply() const { audio_12k_hpf_300hz_config }; shared_memory.baseband_queue.push(message); - clock_manager.set_base_audio_clock_divider(4); + audio::set_rate(audio::Rate::Hz_12000); } void NBFMConfig::apply() const { @@ -76,7 +78,7 @@ void NBFMConfig::apply() const { audio_24k_deemph_300_6_config }; shared_memory.baseband_queue.push(message); - clock_manager.set_base_audio_clock_divider(2); + audio::set_rate(audio::Rate::Hz_24000); } void WFMConfig::apply() const { @@ -89,7 +91,7 @@ void WFMConfig::apply() const { audio_48k_deemph_2122_6_config }; shared_memory.baseband_queue.push(message); - clock_manager.set_base_audio_clock_divider(1); + audio::set_rate(audio::Rate::Hz_48000); } static constexpr std::array am_configs { { @@ -314,7 +316,7 @@ void ReceiverModel::update_headphone_volume() { // TODO: Manipulating audio codec here, and in ui_receiver.cpp. Good to do // both? - audio_codec.set_headphone_volume(headphone_volume_); + audio::headphone::set_volume(headphone_volume_); } void ReceiverModel::update_modulation_configuration() { diff --git a/firmware/application/ui_debug.cpp b/firmware/application/ui_debug.cpp index 7dde4ab3..4b76080f 100644 --- a/firmware/application/ui_debug.cpp +++ b/firmware/application/ui_debug.cpp @@ -26,6 +26,8 @@ #include "radio.hpp" #include "string_format.hpp" +#include "audio.hpp" + namespace ui { /* DebugMemoryView *******************************************************/ @@ -260,8 +262,8 @@ DebugMenuView::DebugMenuView(NavigationView& nav) { [](const size_t register_number) { return portapack::clock_generator.read_register(register_number); } ); } }, { "WM8731", [&nav](){ nav.push( - "WM8731", RegistersWidgetConfig { wolfson::wm8731::reg_count, 1, 3, 4 }, - [](const size_t register_number) { return portapack::audio_codec.read(register_number); } + "WM8731", RegistersWidgetConfig { audio::debug::reg_count(), 1, 3, 4 }, + [](const size_t register_number) { return audio::debug::reg_read(register_number); } ); } }, { "Temperature", [&nav](){ nav.push(); } }, } }); diff --git a/firmware/common/portapack_hal.hpp b/firmware/common/portapack_hal.hpp index ccf88656..00098f23 100644 --- a/firmware/common/portapack_hal.hpp +++ b/firmware/common/portapack_hal.hpp @@ -56,10 +56,6 @@ constexpr GPIO gpio_cpld_tdo = gpio[GPIO1_8]; // P1_5 constexpr GPIO gpio_cpld_tck = gpio[GPIO3_0]; // P6_1 constexpr GPIO gpio_cpld_tdi = gpio[GPIO3_1]; // P6_2 -/* I2C0 */ - -constexpr uint8_t wm8731_i2c_address = 0x1a; - } /* namespace portapack */ #endif/*__PORTAPACK_HAL_H__*/