summaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/i2s_dac.cpp91
-rw-r--r--src/drivers/include/i2s_dac.hpp3
-rw-r--r--src/drivers/include/storage.hpp4
-rw-r--r--src/drivers/spi.cpp5
-rw-r--r--src/drivers/storage.cpp58
5 files changed, 39 insertions, 122 deletions
diff --git a/src/drivers/i2s_dac.cpp b/src/drivers/i2s_dac.cpp
index 6ffc9e7b..74760543 100644
--- a/src/drivers/i2s_dac.cpp
+++ b/src/drivers/i2s_dac.cpp
@@ -5,7 +5,9 @@
*/
#include "i2s_dac.hpp"
-#include <sys/unistd.h>
+
+#include <stdint.h>
+#include <sys/_stdint.h>
#include <cmath>
#include <cstdint>
@@ -21,6 +23,7 @@
#include "esp_log.h"
#include "freertos/portmacro.h"
#include "freertos/projdefs.h"
+#include "freertos/ringbuf.h"
#include "hal/gpio_types.h"
#include "hal/i2c_types.h"
@@ -28,7 +31,6 @@
#include "hal/i2s_types.h"
#include "i2c.hpp"
#include "soc/clk_tree_defs.h"
-#include "sys/_stdint.h"
namespace drivers {
@@ -62,14 +64,6 @@ auto I2SDac::create(IGpios* expander) -> std::optional<I2SDac*> {
i2s_chan_config_t channel_config =
I2S_CHANNEL_DEFAULT_CONFIG(kI2SPort, I2S_ROLE_MASTER);
- // Use the maximum possible DMA buffer size, since a smaller number of large
- // copies is faster than a large number of small copies.
- channel_config.dma_frame_num = 1024;
- // Triple buffering should be enough to keep samples flowing smoothly.
- // TODO(jacqueline): verify this with 192kHz 32bps.
- channel_config.dma_desc_num = 4;
- // 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
@@ -90,7 +84,7 @@ auto I2SDac::create(IGpios* expander) -> std::optional<I2SDac*> {
{
.mclk_inv = false,
.bclk_inv = false,
- .ws_inv = true,
+ .ws_inv = false,
}},
};
@@ -107,10 +101,9 @@ I2SDac::I2SDac(IGpios* gpio, i2s_chan_handle_t i2s_handle)
: gpio_(gpio),
i2s_handle_(i2s_handle),
i2s_active_(false),
- active_page_(),
- clock_config_(I2S_STD_CLK_DEFAULT_CONFIG(44100)),
+ clock_config_(I2S_STD_CLK_DEFAULT_CONFIG(48000)),
slot_config_(I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT,
- I2S_SLOT_MODE_STEREO)) {
+ I2S_SLOT_MODE_STEREO)) {
clock_config_.clk_src = I2S_CLK_SRC_PLL_160M;
// Keep the 5V circuity off until it's needed.
@@ -122,6 +115,12 @@ I2SDac::I2SDac(IGpios* gpio, i2s_chan_handle_t i2s_handle)
// Power up the charge pump.
write_register(kPsCtrl, 0, 0b01);
+
+ // TODO: testing
+ // write_register(kDacGainLeft, 0b01, 0x50);
+ // write_register(kDacGainRight, 0b11, 0x50);
+ write_register(kDacGainLeft, 0b01, 0x80);
+ write_register(kDacGainRight, 0b11, 0x78);
}
I2SDac::~I2SDac() {
@@ -167,14 +166,18 @@ auto I2SDac::Reconfigure(Channels ch, BitsPerSample bps, SampleRate rate)
switch (bps) {
case BPS_16:
slot_config_.data_bit_width = I2S_DATA_BIT_WIDTH_16BIT;
+ slot_config_.ws_width = 16;
word_length = 0b00;
break;
case BPS_24:
slot_config_.data_bit_width = I2S_DATA_BIT_WIDTH_24BIT;
+ slot_config_.ws_width = 24;
word_length = 0b10;
break;
case BPS_32:
+ // TODO(jacqueline): Error on this? It's not supported anymore.
slot_config_.data_bit_width = I2S_DATA_BIT_WIDTH_32BIT;
+ slot_config_.ws_width = 32;
word_length = 0b11;
break;
}
@@ -189,9 +192,9 @@ auto I2SDac::Reconfigure(Channels ch, BitsPerSample bps, SampleRate rate)
ESP_ERROR_CHECK(i2s_channel_reconfig_std_clock(i2s_handle_, &clock_config_));
// Set the correct word size, and set the input format to I2S-justified.
- write_register(kAifCtrl1, 0, (word_length << 3) & 0b10);
+ write_register(kAifCtrl1, 0, (word_length << 3) | 0b10);
// Tell the DAC the clock ratio instead of waiting for it to auto detect.
- write_register(kAifCtrl2, 0, bps == BPS_24 ? 0b100 : 0b011);
+ // write_register(kAifCtrl2, 0, bps == BPS_24 ? 0b100 : 0b011);
if (i2s_active_) {
i2s_channel_enable(i2s_handle_);
@@ -208,12 +211,6 @@ auto I2SDac::WriteData(const cpp::span<const std::byte>& data) -> void {
}
}
-static constexpr double increment = (2.0 * 3.141592) / (44100.0 / 500.0);
-static constexpr double amplitude = 16'777'216.0 * 0.6;
-static double current = 0;
-static uint8_t leftover = 0;
-static bool left = false;
-
extern "C" IRAM_ATTR auto callback(i2s_chan_handle_t handle,
i2s_event_data_t* event,
void* user_ctx) -> bool {
@@ -223,52 +220,20 @@ extern "C" IRAM_ATTR auto callback(i2s_chan_handle_t handle,
if (event->data == nullptr || event->size == 0) {
return false;
}
- /*
uint8_t** buf = reinterpret_cast<uint8_t**>(event->data);
- StreamBufferHandle_t src = reinterpret_cast<StreamBufferHandle_t>(user_ctx);
+ auto src = reinterpret_cast<StreamBufferHandle_t>(user_ctx);
+
BaseType_t ret = false;
- std::size_t bytes_received =
+ size_t bytes_written =
xStreamBufferReceiveFromISR(src, *buf, event->size, &ret);
- if (bytes_received < event->size) {
- memset(*buf + bytes_received, 0, event->size - bytes_received);
+
+ // If we ran out of data, then make sure we clear out the DMA buffers rather
+ // than continuing to repreat the last few samples.
+ if (bytes_written < event->size) {
+ std::memset((*buf) + bytes_written, 0, event->size - bytes_written);
}
+
return ret;
- */
- uint8_t* buf = *(reinterpret_cast<uint8_t**>(event->data));
- std::size_t i = 0;
- while (i < event->size) {
- uint32_t sample = amplitude * std::sin(current);
- if (leftover > 0) {
- if (leftover == 2) {
- buf[i++] = (sample >> 8) & 0xFF;
- leftover--;
- }
- if (leftover == 1) {
- buf[i++] = sample & 0xFF;
- leftover--;
- }
- continue;
- }
-
- buf[i++] = (sample >> 16) & 0xFF;
- if (i == event->size) {
- leftover = 2;
- return false;
- }
- buf[i++] = (sample >> 8) & 0xFF;
- if (i == event->size) {
- leftover = 1;
- return false;
- }
- buf[i++] = sample & 0xFF;
- if (left) {
- current += increment;
- left = false;
- } else {
- left = true;
- }
- }
- return false;
}
auto I2SDac::SetSource(StreamBufferHandle_t buffer) -> void {
diff --git a/src/drivers/include/i2s_dac.hpp b/src/drivers/include/i2s_dac.hpp
index 39eb9c4c..06c0dc16 100644
--- a/src/drivers/include/i2s_dac.hpp
+++ b/src/drivers/include/i2s_dac.hpp
@@ -18,6 +18,7 @@
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/portmacro.h"
+#include "freertos/ringbuf.h"
#include "freertos/stream_buffer.h"
#include "result.hpp"
#include "span.hpp"
@@ -73,7 +74,7 @@ class I2SDac {
IGpios* gpio_;
i2s_chan_handle_t i2s_handle_;
bool i2s_active_;
- std::optional<uint8_t> active_page_;
+ StreamBufferHandle_t buffer_;
i2s_std_clk_config_t clock_config_;
i2s_std_slot_config_t slot_config_;
diff --git a/src/drivers/include/storage.hpp b/src/drivers/include/storage.hpp
index a9269261..65be75f1 100644
--- a/src/drivers/include/storage.hpp
+++ b/src/drivers/include/storage.hpp
@@ -34,7 +34,6 @@ class SdStorage {
static auto Create(IGpios* gpio) -> cpp::result<SdStorage*, Error>;
SdStorage(IGpios* gpio,
- esp_err_t (*do_transaction)(sdspi_dev_handle_t, sdmmc_command_t*),
sdspi_dev_handle_t handle_,
std::unique_ptr<sdmmc_host_t> host_,
std::unique_ptr<sdmmc_card_t> card_,
@@ -47,15 +46,12 @@ class SdStorage {
auto GetFs() -> FATFS*;
// Not copyable or movable.
- // TODO: maybe this could be movable?
SdStorage(const SdStorage&) = delete;
SdStorage& operator=(const SdStorage&) = delete;
private:
IGpios* gpio_;
- esp_err_t (*do_transaction_)(sdspi_dev_handle_t, sdmmc_command_t*) = nullptr;
-
// SPI and SD driver info
sdspi_dev_handle_t handle_;
std::unique_ptr<sdmmc_host_t> host_;
diff --git a/src/drivers/spi.cpp b/src/drivers/spi.cpp
index 1e9323ae..b31d1460 100644
--- a/src/drivers/spi.cpp
+++ b/src/drivers/spi.cpp
@@ -38,8 +38,9 @@ esp_err_t init_spi(void) {
// manages its down use of DMA-capable memory.
.max_transfer_sz = 128 * 16 * 2, // TODO: hmm
.flags = SPICOMMON_BUSFLAG_MASTER | SPICOMMON_BUSFLAG_IOMUX_PINS,
- .intr_flags =
- ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED | ESP_INTR_FLAG_IRAM,
+ .intr_flags = ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM,
+ //.intr_flags = ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_SHARED |
+ // ESP_INTR_FLAG_IRAM,
};
if (esp_err_t err = spi_bus_initialize(kSpiHost, &config, SPI_DMA_CH_AUTO)) {
diff --git a/src/drivers/storage.cpp b/src/drivers/storage.cpp
index 04da8819..db257dee 100644
--- a/src/drivers/storage.cpp
+++ b/src/drivers/storage.cpp
@@ -32,37 +32,12 @@ namespace drivers {
const char* kStoragePath = "/sdcard";
-// Static functions for interrop with the ESP IDF API, which requires a
-// function pointer.
-namespace callback {
-static std::atomic<SdStorage*> instance = nullptr;
-static std::atomic<esp_err_t (*)(sdspi_dev_handle_t, sdmmc_command_t*)>
- bootstrap = nullptr;
-
-static esp_err_t do_transaction(sdspi_dev_handle_t handle,
- sdmmc_command_t* cmdinfo) {
- auto bootstrap_fn = bootstrap.load();
- if (bootstrap_fn != nullptr) {
- return bootstrap_fn(handle, cmdinfo);
- }
- auto instance_unwrapped = instance.load();
- if (instance_unwrapped == nullptr) {
- ESP_LOGW(kTag, "uncaught sdspi transaction");
- return ESP_OK;
- }
- // TODO: what if a transaction comes in right now?
- return instance_unwrapped->HandleTransaction(handle, cmdinfo);
-}
-} // namespace callback
-
auto SdStorage::Create(IGpios* gpio) -> cpp::result<SdStorage*, Error> {
gpio->WriteSync(IGpios::Pin::kSdPowerEnable, 1);
gpio->WriteSync(IGpios::Pin::kSdMuxSwitch, IGpios::SD_MUX_ESP);
gpio->WriteSync(IGpios::Pin::kSdMuxDisable, 0);
sdspi_dev_handle_t handle;
- std::unique_ptr<sdmmc_host_t> host;
- std::unique_ptr<sdmmc_card_t> card;
FATFS* fs = nullptr;
// Now we can init the driver and set up the SD card into SPI mode.
@@ -80,17 +55,10 @@ auto SdStorage::Create(IGpios* gpio) -> cpp::result<SdStorage*, Error> {
return cpp::fail(Error::FAILED_TO_INIT);
}
- host = std::make_unique<sdmmc_host_t>(sdmmc_host_t SDSPI_HOST_DEFAULT());
- card = std::make_unique<sdmmc_card_t>();
+ auto host = std::make_unique<sdmmc_host_t>(sdmmc_host_t SDSPI_HOST_DEFAULT());
+ auto card = std::make_unique<sdmmc_card_t>();
- // We manage the CS pin ourselves via the GPIO expander. To do this safely in
- // a multithreaded environment, we wrap the ESP IDF do_transaction function
- // with our own that acquires the CS mutex for the duration of the SPI
- // transaction.
- auto do_transaction = host->do_transaction;
- host->do_transaction = &callback::do_transaction;
host->slot = handle;
- callback::bootstrap = do_transaction;
// Will return ESP_ERR_INVALID_RESPONSE if there is no card
esp_err_t err = sdmmc_card_init(host.get(), card.get());
@@ -101,6 +69,7 @@ auto SdStorage::Create(IGpios* gpio) -> cpp::result<SdStorage*, Error> {
ESP_ERROR_CHECK(esp_vfs_fat_register(kStoragePath, "", kMaxOpenFiles, &fs));
ff_diskio_register_sdmmc(fs->pdrv, card.get());
+ ff_sdmmc_set_disk_status_check(fs->pdrv, true);
// Mount right now, not on first operation.
FRESULT ferr = f_mount(fs, "", 1);
@@ -109,26 +78,19 @@ auto SdStorage::Create(IGpios* gpio) -> cpp::result<SdStorage*, Error> {
return cpp::fail(Error::FAILED_TO_MOUNT);
}
- return new SdStorage(gpio, do_transaction, handle, std::move(host),
- std::move(card), fs);
+ return new SdStorage(gpio, handle, std::move(host), std::move(card), fs);
}
SdStorage::SdStorage(IGpios* gpio,
- esp_err_t (*do_transaction)(sdspi_dev_handle_t,
- sdmmc_command_t*),
sdspi_dev_handle_t handle,
std::unique_ptr<sdmmc_host_t> host,
std::unique_ptr<sdmmc_card_t> card,
FATFS* fs)
: gpio_(gpio),
- do_transaction_(do_transaction),
handle_(handle),
host_(std::move(host)),
card_(std::move(card)),
- fs_(fs) {
- callback::instance = this;
- callback::bootstrap = nullptr;
-}
+ fs_(fs) {}
SdStorage::~SdStorage() {
// Unmount and unregister the filesystem
@@ -137,22 +99,14 @@ SdStorage::~SdStorage() {
esp_vfs_fat_unregister_path(kStoragePath);
fs_ = nullptr;
- callback::instance = nullptr;
-
// Uninstall the SPI driver
sdspi_host_remove_device(this->handle_);
sdspi_host_deinit();
- gpio_->WriteSync(IGpios::Pin::kSdPowerEnable, 0);
+ gpio_->WriteSync(IGpios::Pin::kSdPowerEnable, 1);
gpio_->WriteSync(IGpios::Pin::kSdMuxDisable, 1);
}
-auto SdStorage::HandleTransaction(sdspi_dev_handle_t handle,
- sdmmc_command_t* cmdinfo) -> esp_err_t {
- // TODO: not needed anymore?
- return do_transaction_(handle, cmdinfo);
-}
-
auto SdStorage::GetFs() -> FATFS* {
return fs_;
}