Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/daisy_seed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,11 @@ float DaisySeed::AudioCallbackRate() const
return callback_rate_;
}

void DaisySeed::SetIntermediateBuffers(int32_t* buffer_sai1, int32_t* buffer_sai2)
{
audio_handle.SetIntermediateBuffers(buffer_sai1, buffer_sai2);
}

void DaisySeed::SetLed(bool state)
{
led.Write(state);
Expand Down
15 changes: 15 additions & 0 deletions src/daisy_seed.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,21 @@ class DaisySeed
/** Returns the rate in Hz that the Audio callback is called */
float AudioCallbackRate() const;

/** Provides an intermediate buffer to store output of the audio callback in.
**
** The provided buffers must be of size block_size * 2.
**
** This option is beneficial when AudioBlockSize is small (<= 4 at 48kHz, <= 8
** at 96kHz) in order to allow you to use more cpu time in your audio callback.
** Without this option enabled, the DMA transfer to the DAC will start 10-15
** microseconds before the next call to the audio callback, which means that if
** you use more than ~60% CPU in your audio callback with a block size of 2 at
** 48kHz or a block size of 4 at 96kHz then you will likely miss the deadline
** and experience glitches. Enabling this option will delay your audio by an
** additional block_size samples.
*/
void SetIntermediateBuffers(int32_t* buffer_sai1, int32_t* buffer_sai2 = nullptr);

/** Returns the SAI Handle for the Daisy Seed
* This can be useful when adding a secondary codec,
* the result of this function can be passed to the audio reinit
Expand Down
11 changes: 11 additions & 0 deletions src/hid/audio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ class AudioHandle::Impl
: AudioHandle::Result::ERR;
}

void SetIntermediateBuffers(int32_t* buffer_sai1, int32_t* buffer_sai2)
{
sai1_.SetIntermediateBuffer(buffer_sai1);
sai2_.SetIntermediateBuffer(buffer_sai2);
}

float GetSampleRate() { return sai1_.GetSampleRate(); }

AudioHandle::Result SetPostGain(float val)
Expand Down Expand Up @@ -520,6 +526,11 @@ AudioHandle::Result AudioHandle::SetBlockSize(size_t size)
return pimpl_->SetBlockSize(size);
}

void AudioHandle::SetIntermediateBuffers(int32_t* buffer_sai1, int32_t* buffer_sai2)
{
pimpl_->SetIntermediateBuffers(buffer_sai1, buffer_sai2);
}

float AudioHandle::GetSampleRate()
{
return pimpl_->GetSampleRate();
Expand Down
2 changes: 2 additions & 0 deletions src/hid/audio.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,8 @@ class AudioHandle
*/
Result SetBlockSize(size_t size);

void SetIntermediateBuffers(int32_t* buffer_sai1, int32_t* buffer_sai2 = nullptr);

/** Sets the amount of gain adjustment to perform before and after callback.
** useful if the hardware has additional headroom, and the nominal value shouldn't be 1.0
**
Expand Down
60 changes: 53 additions & 7 deletions src/per/sai.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "per/sai.h"
#include "daisy_core.h"
#include <cstring>

namespace daisy
{
Expand Down Expand Up @@ -39,8 +40,15 @@ class SaiHandle::Impl
/** Offset stored for weird inter-SAI stuff.*/
size_t dma_offset;

// Optional buffer for audio callback output
int32_t* buff_intermediate_ = nullptr;

void SetIntermediateBuffer(int32_t* buffer) { buff_intermediate_ = buffer; }

/** Callback that dispatches user callback from Cplt and HalfCplt DMA Callbacks */
void InternalCallback(size_t offset);
void InternalCallbackRx(size_t offset);

void InternalCallbackTx(size_t offset);

/** Pin Initiazlization */
void InitPins();
Expand Down Expand Up @@ -283,15 +291,25 @@ void SaiHandle::Impl::DeInitDma(PeripheralBlock block)
}
}

void SaiHandle::Impl::InternalCallback(size_t offset)
void SaiHandle::Impl::InternalCallbackRx(size_t offset)
{
int32_t *in, *out;
in = buff_rx_ + offset;
out = buff_tx_ + offset;
out = (buff_intermediate_ ? buff_intermediate_ : buff_tx_ + offset);
if(callback_)
callback_(in, out, buff_size_ / 2);
}

void SaiHandle::Impl::InternalCallbackTx(size_t offset)
{
if (!buff_intermediate_) {
return;
}
int32_t* in = buff_intermediate_;
int32_t* out = buff_tx_ + offset;
std::memcpy(out, in, buff_size_ / 2 * sizeof(*out));
}

SaiHandle::Result
SaiHandle::Impl::StartDmaTransfer(int32_t* buffer_rx,
int32_t* buffer_tx,
Expand Down Expand Up @@ -503,12 +521,12 @@ extern "C" void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef* hsai)
if(hsai->Instance == SAI1_Block_A || hsai->Instance == SAI1_Block_B)
{
sai_handles[0].dma_offset = 0;
sai_handles[0].InternalCallback(0);
sai_handles[0].InternalCallbackRx(0);
}
else if(hsai->Instance == SAI2_Block_A || hsai->Instance == SAI2_Block_B)
{
sai_handles[1].dma_offset = 0;
sai_handles[1].InternalCallback(0);
sai_handles[1].InternalCallbackRx(0);
}
}

Expand All @@ -517,12 +535,36 @@ extern "C" void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef* hsai)
if(hsai->Instance == SAI1_Block_A || hsai->Instance == SAI1_Block_B)
{
sai_handles[0].dma_offset = sai_handles[0].buff_size_ / 2;
sai_handles[0].InternalCallback(sai_handles[0].dma_offset);
sai_handles[0].InternalCallbackRx(sai_handles[0].dma_offset);
}
else if(hsai->Instance == SAI2_Block_A || hsai->Instance == SAI2_Block_B)
{
sai_handles[1].dma_offset = sai_handles[1].buff_size_ / 2;
sai_handles[1].InternalCallback(sai_handles[1].dma_offset);
sai_handles[1].InternalCallbackRx(sai_handles[1].dma_offset);
}
}

extern "C" void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef* hsai)
{
if(hsai->Instance == SAI1_Block_A || hsai->Instance == SAI1_Block_B)
{
sai_handles[0].InternalCallbackTx(0);
}
else if(hsai->Instance == SAI2_Block_A || hsai->Instance == SAI2_Block_B)
{
sai_handles[1].InternalCallbackTx(0);
}
}

extern "C" void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef* hsai)
{
if(hsai->Instance == SAI1_Block_A || hsai->Instance == SAI1_Block_B)
{
sai_handles[0].InternalCallbackTx(sai_handles[0].buff_size_ / 2);
}
else if(hsai->Instance == SAI2_Block_A || hsai->Instance == SAI2_Block_B)
{
sai_handles[1].InternalCallbackTx(sai_handles[1].buff_size_ / 2);
}
}

Expand Down Expand Up @@ -579,5 +621,9 @@ size_t SaiHandle::GetOffset() const
return pimpl_->dma_offset;
}

void SaiHandle::SetIntermediateBuffer(int32_t* buffer) {
pimpl_->SetIntermediateBuffer(buffer);
}


} // namespace daisy
2 changes: 2 additions & 0 deletions src/per/sai.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ class SaiHandle
/** Returns the current offset within the SAI buffer, will be either 0 or size/2 */
size_t GetOffset() const;

void SetIntermediateBuffer(int32_t* buffer);

inline bool IsInitialized() const
{
return pimpl_ == nullptr ? false : true;
Expand Down