Skip to content

Commit 088e12b

Browse files
committed
added optional intermediate buffer to SaiHandle to allow full use of cpu in audio callback at low block sizes
1 parent bd13385 commit 088e12b

File tree

6 files changed

+88
-7
lines changed

6 files changed

+88
-7
lines changed

src/daisy_seed.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,11 @@ float DaisySeed::AudioCallbackRate() const
220220
return callback_rate_;
221221
}
222222

223+
void DaisySeed::SetIntermediateBuffers(int32_t* buffer_sai1, int32_t* buffer_sai2)
224+
{
225+
audio_handle.SetIntermediateBuffers(buffer_sai1, buffer_sai2);
226+
}
227+
223228
void DaisySeed::SetLed(bool state)
224229
{
225230
led.Write(state);

src/daisy_seed.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,21 @@ class DaisySeed
9797
/** Returns the rate in Hz that the Audio callback is called */
9898
float AudioCallbackRate() const;
9999

100+
/** Provides an intermediate buffer to store output of the audio callback in.
101+
**
102+
** The provided buffers must be of size block_size * 2.
103+
**
104+
** This option is beneficial when AudioBlockSize is small (<= 4 at 48kHz, <= 8
105+
** at 96kHz) in order to allow you to use more cpu time in your audio callback.
106+
** Without this option enabled, the DMA transfer to the DAC will start 10-15
107+
** microseconds before the next call to the audio callback, which means that if
108+
** you use more than ~60% CPU in your audio callback with a block size of 2 at
109+
** 48kHz or a block size of 4 at 96kHz then you will likely miss the deadline
110+
** and experience glitches. Enabling this option will delay your audio by an
111+
** additional block_size samples.
112+
*/
113+
void SetIntermediateBuffers(int32_t* buffer_sai1, int32_t* buffer_sai2 = nullptr);
114+
100115
/** Returns the SAI Handle for the Daisy Seed
101116
* This can be useful when adding a secondary codec,
102117
* the result of this function can be passed to the audio reinit

src/hid/audio.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ class AudioHandle::Impl
5858
: AudioHandle::Result::ERR;
5959
}
6060

61+
void SetIntermediateBuffers(int32_t* buffer_sai1, int32_t* buffer_sai2)
62+
{
63+
sai1_.SetIntermediateBuffer(buffer_sai1);
64+
sai2_.SetIntermediateBuffer(buffer_sai2);
65+
}
66+
6167
float GetSampleRate() { return sai1_.GetSampleRate(); }
6268

6369
AudioHandle::Result SetPostGain(float val)
@@ -520,6 +526,11 @@ AudioHandle::Result AudioHandle::SetBlockSize(size_t size)
520526
return pimpl_->SetBlockSize(size);
521527
}
522528

529+
void AudioHandle::SetIntermediateBuffers(int32_t* buffer_sai1, int32_t* buffer_sai2)
530+
{
531+
pimpl_->SetIntermediateBuffers(buffer_sai1, buffer_sai2);
532+
}
533+
523534
float AudioHandle::GetSampleRate()
524535
{
525536
return pimpl_->GetSampleRate();

src/hid/audio.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ class AudioHandle
122122
*/
123123
Result SetBlockSize(size_t size);
124124

125+
void SetIntermediateBuffers(int32_t* buffer_sai1, int32_t* buffer_sai2 = nullptr);
126+
125127
/** Sets the amount of gain adjustment to perform before and after callback.
126128
** useful if the hardware has additional headroom, and the nominal value shouldn't be 1.0
127129
**

src/per/sai.cpp

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "per/sai.h"
22
#include "daisy_core.h"
3+
#include <cstring>
34

45
namespace daisy
56
{
@@ -39,8 +40,15 @@ class SaiHandle::Impl
3940
/** Offset stored for weird inter-SAI stuff.*/
4041
size_t dma_offset;
4142

43+
// Optional buffer for audio callback output
44+
int32_t* buff_intermediate_ = nullptr;
45+
46+
void SetIntermediateBuffer(int32_t* buffer) { buff_intermediate_ = buffer; }
47+
4248
/** Callback that dispatches user callback from Cplt and HalfCplt DMA Callbacks */
43-
void InternalCallback(size_t offset);
49+
void InternalCallbackRx(size_t offset);
50+
51+
void InternalCallbackTx(size_t offset);
4452

4553
/** Pin Initiazlization */
4654
void InitPins();
@@ -283,15 +291,25 @@ void SaiHandle::Impl::DeInitDma(PeripheralBlock block)
283291
}
284292
}
285293

286-
void SaiHandle::Impl::InternalCallback(size_t offset)
294+
void SaiHandle::Impl::InternalCallbackRx(size_t offset)
287295
{
288296
int32_t *in, *out;
289297
in = buff_rx_ + offset;
290-
out = buff_tx_ + offset;
298+
out = (buff_intermediate_ ? buff_intermediate_ : buff_tx_ + offset);
291299
if(callback_)
292300
callback_(in, out, buff_size_ / 2);
293301
}
294302

303+
void SaiHandle::Impl::InternalCallbackTx(size_t offset)
304+
{
305+
if (!buff_intermediate_) {
306+
return;
307+
}
308+
int32_t* in = buff_intermediate_;
309+
int32_t* out = buff_tx_ + offset;
310+
std::memcpy(out, in, buff_size_ / 2 * sizeof(*out));
311+
}
312+
295313
SaiHandle::Result
296314
SaiHandle::Impl::StartDmaTransfer(int32_t* buffer_rx,
297315
int32_t* buffer_tx,
@@ -503,12 +521,12 @@ extern "C" void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef* hsai)
503521
if(hsai->Instance == SAI1_Block_A || hsai->Instance == SAI1_Block_B)
504522
{
505523
sai_handles[0].dma_offset = 0;
506-
sai_handles[0].InternalCallback(0);
524+
sai_handles[0].InternalCallbackRx(0);
507525
}
508526
else if(hsai->Instance == SAI2_Block_A || hsai->Instance == SAI2_Block_B)
509527
{
510528
sai_handles[1].dma_offset = 0;
511-
sai_handles[1].InternalCallback(0);
529+
sai_handles[1].InternalCallbackRx(0);
512530
}
513531
}
514532

@@ -517,12 +535,36 @@ extern "C" void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef* hsai)
517535
if(hsai->Instance == SAI1_Block_A || hsai->Instance == SAI1_Block_B)
518536
{
519537
sai_handles[0].dma_offset = sai_handles[0].buff_size_ / 2;
520-
sai_handles[0].InternalCallback(sai_handles[0].dma_offset);
538+
sai_handles[0].InternalCallbackRx(sai_handles[0].dma_offset);
521539
}
522540
else if(hsai->Instance == SAI2_Block_A || hsai->Instance == SAI2_Block_B)
523541
{
524542
sai_handles[1].dma_offset = sai_handles[1].buff_size_ / 2;
525-
sai_handles[1].InternalCallback(sai_handles[1].dma_offset);
543+
sai_handles[1].InternalCallbackRx(sai_handles[1].dma_offset);
544+
}
545+
}
546+
547+
extern "C" void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef* hsai)
548+
{
549+
if(hsai->Instance == SAI1_Block_A || hsai->Instance == SAI1_Block_B)
550+
{
551+
sai_handles[0].InternalCallbackTx(0);
552+
}
553+
else if(hsai->Instance == SAI2_Block_A || hsai->Instance == SAI2_Block_B)
554+
{
555+
sai_handles[1].InternalCallbackTx(0);
556+
}
557+
}
558+
559+
extern "C" void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef* hsai)
560+
{
561+
if(hsai->Instance == SAI1_Block_A || hsai->Instance == SAI1_Block_B)
562+
{
563+
sai_handles[0].InternalCallbackTx(sai_handles[0].buff_size_ / 2);
564+
}
565+
else if(hsai->Instance == SAI2_Block_A || hsai->Instance == SAI2_Block_B)
566+
{
567+
sai_handles[1].InternalCallbackTx(sai_handles[1].buff_size_ / 2);
526568
}
527569
}
528570

@@ -579,5 +621,9 @@ size_t SaiHandle::GetOffset() const
579621
return pimpl_->dma_offset;
580622
}
581623

624+
void SaiHandle::SetIntermediateBuffer(int32_t* buffer) {
625+
pimpl_->SetIntermediateBuffer(buffer);
626+
}
627+
582628

583629
} // namespace daisy

src/per/sai.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ class SaiHandle
154154
/** Returns the current offset within the SAI buffer, will be either 0 or size/2 */
155155
size_t GetOffset() const;
156156

157+
void SetIntermediateBuffer(int32_t* buffer);
158+
157159
inline bool IsInitialized() const
158160
{
159161
return pimpl_ == nullptr ? false : true;

0 commit comments

Comments
 (0)