summaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-02-10 15:32:21 +1100
committerjacqueline <me@jacqueline.id.au>2023-02-10 15:32:21 +1100
commit61c91b3cdb2c9dd655f3adf0f461f5cefb3b2e9b (patch)
tree8d0bb288781f86455f02219d0b7ac8cee493eeb3 /src/drivers
parentcabfd4b75ecc733bdf36997606a686c4d2bc277d (diff)
downloadtangara-fw-61c91b3cdb2c9dd655f3adf0f461f5cefb3b2e9b.tar.gz
Mostly working pipeline, including proper EOF signalling
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/dac.cpp64
-rw-r--r--src/drivers/display.cpp8
-rw-r--r--src/drivers/display_init.cpp2
-rw-r--r--src/drivers/include/dac.hpp10
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.