diff options
Diffstat (limited to 'src/drivers')
| -rw-r--r-- | src/drivers/dac.cpp | 64 | ||||
| -rw-r--r-- | src/drivers/display.cpp | 8 | ||||
| -rw-r--r-- | src/drivers/display_init.cpp | 2 | ||||
| -rw-r--r-- | src/drivers/include/dac.hpp | 10 |
4 files changed, 63 insertions, 21 deletions
diff --git a/src/drivers/dac.cpp b/src/drivers/dac.cpp index 214feb28..eec1959f 100644 --- a/src/drivers/dac.cpp +++ b/src/drivers/dac.cpp @@ -10,6 +10,7 @@ #include "driver/i2s_types.h" #include "esp_err.h" #include "esp_log.h" +#include "freertos/portmacro.h" #include "hal/i2c_types.h" #include "gpio_expander.hpp" @@ -27,14 +28,22 @@ static const AudioDac::SampleRate kDefaultSampleRate = AudioDac::SAMPLE_RATE_44_1; static const AudioDac::BitsPerSample kDefaultBps = AudioDac::BPS_16; +extern "C" { +bool dma_callback(i2s_chan_handle_t handle, + i2s_event_data_t* event, + void* user_ctx) { + AudioDac* dac = static_cast<AudioDac*>(user_ctx); + return dac->WriteDataFromISR(static_cast<std::byte*>(event->data), + event->size); +} +} + auto AudioDac::create(GpioExpander* expander) -> cpp::result<std::unique_ptr<AudioDac>, Error> { // TODO: tune. i2s_chan_handle_t i2s_handle; i2s_chan_config_t channel_config = I2S_CHANNEL_DEFAULT_CONFIG(kI2SPort, I2S_ROLE_MASTER); - // Auto clear to trigger soft-mute when we run out of data. - channel_config.auto_clear = true; ESP_ERROR_CHECK(i2s_new_channel(&channel_config, &i2s_handle, NULL)); // // First, instantiate the instance so it can do all of its power on @@ -99,7 +108,8 @@ AudioDac::AudioDac(GpioExpander* gpio, i2s_chan_handle_t i2s_handle) i2s_handle_(i2s_handle), clock_config_(I2S_STD_CLK_DEFAULT_CONFIG(44100)), slot_config_(I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, - I2S_SLOT_MODE_STEREO)) { + I2S_SLOT_MODE_STEREO)), + dma_queue_(nullptr) { gpio_->set_pin(GpioExpander::AUDIO_POWER_ENABLE, true); gpio_->Write(); } @@ -157,7 +167,9 @@ bool AudioDac::WaitForPowerState( return has_matched; } -auto AudioDac::Reconfigure(BitsPerSample bps, SampleRate rate) -> bool { +auto AudioDac::Reconfigure(BitsPerSample bps, + SampleRate rate, + QueueHandle_t dma_queue) -> std::size_t { // TODO(jacqueline): investigate how reliable the auto-clocking of the dac // is. We might need to explicit reconfigure the dac here as well if it's not // good enough. @@ -171,20 +183,44 @@ auto AudioDac::Reconfigure(BitsPerSample bps, SampleRate rate) -> bool { bps == BPS_24 ? I2S_MCLK_MULTIPLE_384 : I2S_MCLK_MULTIPLE_256; ESP_ERROR_CHECK(i2s_channel_reconfig_std_clock(i2s_handle_, &clock_config_)); + dma_queue_ = dma_queue; + + // TODO: less spooky action here plz. + // dma_buffer_size = dma_frame_num (channel config) * slot_num (always 2?) * + // slot_bit_width / 8 + //size_t dma_size = 240 * 2 * slot_config_.slot_bit_width / 8; + size_t dma_size = 960; + ESP_LOGI(kTag, "new dma size: %u bytes", dma_size); + + i2s_event_callbacks_t callbacks = { + .on_recv = NULL, + .on_recv_q_ovf = NULL, + .on_sent = &dma_callback, + .on_send_q_ovf = NULL, + }; + ESP_ERROR_CHECK( + i2s_channel_register_event_callback(i2s_handle_, &callbacks, this)); + ESP_ERROR_CHECK(i2s_channel_enable(i2s_handle_)); - return true; + + return dma_size; } -auto AudioDac::WriteData(const cpp::span<std::byte>& data, TickType_t max_wait) - -> std::size_t { - std::size_t res = 0; - esp_err_t err = - i2s_channel_write(i2s_handle_, data.data(), data.size(), &res, max_wait); - if (err == ESP_ERR_TIMEOUT) { - return res; +auto AudioDac::WriteDataFromISR(std::byte* data, std::size_t size) -> bool { + std::byte* new_data; + BaseType_t high_priority_task_awoken = pdFALSE; + + if (xQueueReceiveFromISR(dma_queue_, &new_data, &high_priority_task_awoken)) { + // Item was received. Copy it into the DMA buffer. + memcpy(data, new_data, size); + free(new_data); + ESP_DRAM_LOGI(kTag, "wrote dma"); + } else { + // No item was received. Write empty data. + memset(data, 0, size); } - ESP_ERROR_CHECK(err); - return res; + + return high_priority_task_awoken; } void AudioDac::WriteRegister(Register reg, uint8_t val) { diff --git a/src/drivers/display.cpp b/src/drivers/display.cpp index 2ada4a3e..8d62cda2 100644 --- a/src/drivers/display.cpp +++ b/src/drivers/display.cpp @@ -49,7 +49,7 @@ namespace drivers { namespace callback { static std::atomic<Display*> instance = nullptr; -static void flush_cb(lv_disp_drv_t* disp_drv, +extern "C" void flush_cb(lv_disp_drv_t* disp_drv, const lv_area_t* area, lv_color_t* color_map) { auto instance_unwrapped = instance.load(); @@ -74,8 +74,9 @@ static void IRAM_ATTR post_cb(spi_transaction_t* transaction) { auto Display::create(GpioExpander* expander, const displays::InitialisationData& init_data) -> cpp::result<std::unique_ptr<Display>, Error> { - expander->with( - [&](auto& gpio) { gpio.set_pin(GpioExpander::DISPLAY_LED, 1); }); + expander->set_pin(GpioExpander::DISPLAY_LED, 0); + expander->set_pin(GpioExpander::DISPLAY_POWER_ENABLE, 1); + expander->Write(); // Next, init the SPI device spi_device_interface_config_t spi_cfg = { @@ -182,6 +183,7 @@ void Display::SendTransaction(TransactionType type, if (length == 0) { return; } + ESP_LOGI(kTag, "lvgl transaction"); // TODO: Use a memory pool for these. spi_transaction_t* transaction = (spi_transaction_t*)heap_caps_calloc( diff --git a/src/drivers/display_init.cpp b/src/drivers/display_init.cpp index e66d6a47..293ea5a2 100644 --- a/src/drivers/display_init.cpp +++ b/src/drivers/display_init.cpp @@ -96,7 +96,7 @@ static const uint8_t kST7735RCommonFooter[]{ const InitialisationData kST7735R = { .num_sequences = 3, - .sequences = {kST7735RCommonHeader, kST7735RCommonRed, + .sequences = {kST7735RCommonHeader, kST7735RCommonGreen, kST7735RCommonFooter}}; } // namespace displays diff --git a/src/drivers/include/dac.hpp b/src/drivers/include/dac.hpp index aec89c72..698019b7 100644 --- a/src/drivers/include/dac.hpp +++ b/src/drivers/include/dac.hpp @@ -4,6 +4,7 @@ #include <functional> #include <memory> +#include <optional> #include <utility> #include "driver/i2s_std.h" @@ -66,11 +67,11 @@ class AudioDac { }; // TODO(jacqueline): worth supporting channels here as well? - auto Reconfigure(BitsPerSample bps, SampleRate rate) -> bool; - - auto WriteData(const cpp::span<std::byte>& data, TickType_t max_wait) + auto Reconfigure(BitsPerSample bps, SampleRate rate, QueueHandle_t dma_queue) -> std::size_t; + auto WriteDataFromISR(std::byte* data, std::size_t size) -> bool; + // Not copyable or movable. AudioDac(const AudioDac&) = delete; AudioDac& operator=(const AudioDac&) = delete; @@ -82,6 +83,9 @@ class AudioDac { i2s_std_clk_config_t clock_config_; i2s_std_slot_config_t slot_config_; + // TODO: volatile? + volatile QueueHandle_t dma_queue_; + /* * Pools the power state for up to 10ms, waiting for the given predicate to * be true. |
