Simultaneous DAC and Audio output on seed not working

I’m 99.99% sure this is a me problem, as I’ve found examples with this exact same goal (see QuadEnvelope) - My goal is to output audio, and separate values on the DAC roughly at the same time.

Since updating libdaisy, I now have no DAC output whatsoever, and I’m not sure if extra configuration is needed now. From referencing daisy_patch.cpp, I have modified libdaisy from master, at the time of writing this (f82fe079255160bf62aa7b667de815c9712fbf96) to contain the following:

diff --git a/src/daisy_seed.cpp b/src/daisy_seed.cpp
index 7b903106..83e84595 100644
--- a/src/daisy_seed.cpp
+++ b/src/daisy_seed.cpp
@@ -93,7 +93,7 @@ void DaisySeed::Configure()
     // Configure internal peripherals
     ConfigureSdram();
     ConfigureQspi();
-    //ConfigureDac();
+    ConfigureDac();
     // Configure the built-in GPIOs.
     led.pin.port       = SEED_LED_PORT;
     led.pin.pin        = SEED_LED_PIN;
@@ -291,15 +291,17 @@ void DaisySeed::ConfigureAudio()
 }
 void DaisySeed::ConfigureDac()
 {
+
     // This would be the equivalent initialization as previously existed.
     // However, not all platforms have the DAC, and many use those pins
     // for other things.
-    //    DacHandle::Config cfg;
-    //    cfg.bitdepth   = DacHandle::Config::BitDepth::BITS_12;
-    //    cfg.buff_state = DacHandle::Config::BufferState::ENABLED;
-    //    cfg.mode       = DacHandle::Config::Mode::POLLING;
-    //    cfg.chn        = DacHandle::Config::Channel::BOTH;
-    //    dac.Init(cfg);
+    DacHandle::Config cfg;
+    cfg.bitdepth   = DacHandle::BitDepth::BITS_12;
+    cfg.buff_state = DacHandle::BufferState::ENABLED;
+    cfg.mode       = DacHandle::Mode::POLLING;
+    cfg.chn        = DacHandle::Channel::BOTH;
+    dac.Init(cfg);
+    dac.WriteValue(DacHandle::Channel::BOTH, 0); // changing this to 4095 does nothing
 }

 DaisySeed::BoardVersion DaisySeed::CheckBoardVersion()

The strange thing, is that I had the DAC working on an earlier version of libdaisy, which commit hash I can not find at the moment. However, it was fairly old.

Here is a small example program I wrote, my assumption was that the DAC would roughly follow the audio outputs. HOWEVER, I’m getting a strange behaviour, where if I write to the DAC right before the AudioCallback, it just dies, there is no output on the Audio pins whatsoever! Any help would be appreciated, and thank you so much for your help in advance - this is a great community :slight_smile:

#include "daisy_seed.h"
#include "daisysp.h"

using namespace daisy;
using namespace daisysp;

static DaisySeed seed;
static Oscillator osc;
float sample_rate;

int map(float x, float in_min, float in_max, int out_min, int out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

int cvCh1;
int cvCh2;

void AudioCallback(AudioHandle::InputBuffer in, AudioHandle::OutputBuffer out, size_t size)
{
	for (size_t i = 0; i < size; i++)
	{
		float y = osc.Process();
		cvCh1 = map(y, -1.0, 1.0, 0, 4095);
		cvCh2 =	map(y * -1.0f, -1.0, 1.0, 0, 4095);

		out[0][i] = y;
		out[1][i] = y * -1.0f;
	}
}

int main(void)
{
	seed.Configure(); // This should run ConfigureDac()
	seed.Init();
	sample_rate = seed.AudioSampleRate();
	osc.Init(sample_rate);

	osc.SetWaveform(osc.WAVE_SIN);
	osc.SetFreq(1);
	osc.SetAmp(1);

        // If uncommented, nothing happens on DAC, AudioCallback will NOT run
	// seed.dac.WriteValue(DacHandle::Channel::ONE, 0);
	// seed.dac.WriteValue(DacHandle::Channel::TWO, 4095);

	seed.StartAudio(AudioCallback);

        // If uncommented, nothing happens on DAC, but AudioCallback will run
	// seed.dac.WriteValue(DacHandle::Channel::ONE, 0);
	// seed.dac.WriteValue(DacHandle::Channel::TWO, 4095);

	for(;;)
	{
		// Send the latest envelope values to the CV outs
                // Nothing happens
		seed.dac.WriteValue(DacHandle::Channel::ONE, cvCh1);
		seed.dac.WriteValue(DacHandle::Channel::TWO, cvCh2);
		seed.DelayMs(1);
	}
}

Welcome to the forum, @rafaelkhan!

Short answer: I write to both DACs as well as audio out in my project: OscPocketD/Base 1+2/MIDI - fx unit, synth, sampler, modulator - #6 by StaffanMelin

Check my code, see how I have configured stuff. If you do not understand it, my fault, get back to me and I will explain! :slight_smile:

And revert the changes to the lib files!

Cheers,

Staffan

1 Like

Thank you so much for sharing your code @StaffanMelin <3 I’m going to get back to this thread as soon as I’m done reading :slight_smile:

Your youtube videos look and sound amazing!

1 Like

Thanks alot!

Please get back with any questions, and we will get it to work! :+1:

So I spent a day or so reviewing your code (specifically code_base/main.cpp) and pared it down to a sample application that I hoped would achieve the goal of writing to the DAC and audio simultaneously. It still unfortunately seems as though I’m only ever able to write to the DAC once… very strange. At least I am getting DAC output though hahaha! It’s a start.

I’ve matched the DAC configuration, removed the libdaisy changes, and added the Sleep call you have in your main().

Here is my example program:

#include "daisy_seed.h"
#include "daisysp.h"

using namespace daisy;
using namespace daisysp;

static DaisySeed seed;
static Oscillator osc;
float sampleRate;

uint16_t map(float x, float in_min, float in_max, int out_min, int out_max) {
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

float cvCh1 = 0;
float cvCh2 = 0;

void AudioCallback(AudioHandle::InputBuffer in, AudioHandle::OutputBuffer out, size_t size)
{
	for (size_t i = 0; i < size; i++)
	{
		float y = osc.Process();
		cvCh1 = y;
		cvCh2 =	y * -1.0f;
		out[0][i] = y;
		out[1][i] = y * -1.0f;
	}
}

int main(void)
{
	seed.Configure();
	seed.Init();
	sampleRate = seed.AudioSampleRate();

	// init DAC outputs
	DacHandle::Config cfg;
	cfg.bitdepth   = DacHandle::BitDepth::BITS_12;
	cfg.buff_state = DacHandle::BufferState::ENABLED;
	cfg.mode       = DacHandle::Mode::POLLING;
	cfg.chn        = DacHandle::Channel::BOTH;
	seed.dac.Init(cfg);
	seed.dac.WriteValue(DacHandle::Channel::BOTH, 0);
	seed.dac.WriteValue(DacHandle::Channel::ONE, 0); // CV0
	seed.dac.WriteValue(DacHandle::Channel::TWO, 0); // CV1
 
	System::Delay(100);

	osc.Init(sampleRate);
	osc.SetWaveform(osc.WAVE_SIN);
	osc.SetFreq(3);
	osc.SetAmp(1);

	seed.StartAudio(AudioCallback);

	for(;;)
	{
		//Send the latest envelope values to the CV outs
		uint16_t y1 = map(cvCh1, -1.0, 1.0, 0, 4095);
		uint16_t y2 =	map(cvCh2, -1.0, 1.0, 0, 4095);
		seed.dac.WriteValue(DacHandle::Channel::ONE, y1);
		seed.dac.WriteValue(DacHandle::Channel::TWO, y2);
		seed.DelayMs(25);
	}
}

When I run the debugger, I also see this:

So it appears that the values are correct on every iteration. But the writes still never happen. I’m wondering if there’s any potential configuration that I’ve missed…

Thanks so much for your help thus far! Your code has been an awesome reference and I learned quite a lot.

Side note: On every iteration of the debugger, I also see the AC coupled outputs pulse correctly on my oscilloscope, on every click.

You code seems fine.

Just to eliminate one thing (the ref to something happening in the ACB), what happens if you change your code to:

	uint16_t aCnt = 0;
	for(;;)
	{
		seed.dac.WriteValue(DacHandle::Channel::ONE, aCnt);
		seed.dac.WriteValue(DacHandle::Channel::TWO, aCnt);
		aCnt++; // it will overflow but that is ok
		seed.DelayMs(25);
	}

I will run your code later today, I’ve also updated libdaisy this weekend which has broken my Flash handling. Maybe this will affect my DAC code too? I’ll test it and get back to you.

Your ACB seems a bit funky… If I change it to this:

void AudioCallback(AudioHandle::InterleavingInputBuffer in,
AudioHandle::InterleavingOutputBuffer out,
size_t size)

//void AudioCallback(AudioHandle::InputBuffer in, AudioHandle::OutputBuffer out, size_t size)
{

for (size_t n = 0; n < size; n += 2)
// for (size_t i = 0; i < size; i++)
{
float y = osc.Process();
cvCh1 = y;
cvCh2 = y * -1.0f;
out[n] = y;
out[n + 1] = y * -1.0f;

// out[0][i] = y;
// out[1][i] = y * -1.0f;
}
}

the program works, and I get variable outputs from the DACs (only measured by multimeter, but it is still changing values).

If I change the last part of the program to:

osc.Init(sampleRate);
osc.SetWaveform(osc.WAVE_SIN);
osc.SetFreq(220); // audible freq
osc.SetAmp(1);

seed.StartAudio(AudioCallback);

size_t test_counter = 0;
for( ; ; )
{

  test_counter++;
  //Send the latest envelope values to the CV outs
  //uint16_t y1 = map(cvCh1, -1.0, 1.0, 0, 4095);
  //uint16_t y2 =	map(cvCh2, -1.0, 1.0, 0, 4095);
  seed.dac.WriteValue(DacHandle::Channel::ONE, test_counter);
  seed.dac.WriteValue(DacHandle::Channel::TWO, test_counter);

  seed.DelayMs(25);

}
}

I get a continously rising voltage out from the DACs.

Staffan, I don’t think he’s trying to interleave. He’s sending a signal to the left output and an inverted signal to the right output.

2 Likes

Correct!

and @StaffanMelin thank you so much for your responses and patience - it’s been a long week and I wasn’t able to sit down and test this for real. It looks like I’m stuck in the same predicament, where I’m only able to observe the rising voltage on the DAC when the audio callback is not running.

Here is the sum of our programs:

#include "daisy_seed.h"
#include "daisysp.h"

using namespace daisy;
using namespace daisysp;

static DaisySeed seed;
static Oscillator osc;
float sampleRate;

uint16_t map(float x, float in_min, float in_max, int out_min, int out_max)
{
	return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

float cvCh1 = 0;
float cvCh2 = 0;

void AudioCallback(AudioHandle::InterleavingInputBuffer in,
									 AudioHandle::InterleavingOutputBuffer out,
									 size_t size)

//void AudioCallback(AudioHandle::InputBuffer in, AudioHandle::OutputBuffer out, size_t size)
{

	for (size_t n = 0; n < size; n += 2)
	// for (size_t i = 0; i < size; i++)
	{
		float y = osc.Process();
		cvCh1 = y;
		cvCh2 = y * -1.0f;
		out[n] = y;
		out[n + 1] = y * -1.0f;

		// out[0][i] = y;
		// out[1][i] = y * -1.0f;
	}
}

int main(void)
{
	seed.Configure();
	seed.Init();
	sampleRate = seed.AudioSampleRate();

	// init DAC outputs
	DacHandle::Config cfg;
	cfg.bitdepth = DacHandle::BitDepth::BITS_12;
	cfg.buff_state = DacHandle::BufferState::ENABLED;
	cfg.mode = DacHandle::Mode::POLLING;
	cfg.chn = DacHandle::Channel::BOTH;
	seed.dac.Init(cfg);
	seed.dac.WriteValue(DacHandle::Channel::BOTH, 0);
	seed.dac.WriteValue(DacHandle::Channel::ONE, 0); // CV0
	seed.dac.WriteValue(DacHandle::Channel::TWO, 0); // CV1

	System::Delay(100);

	osc.Init(sampleRate);
	osc.SetWaveform(osc.WAVE_SIN);
	osc.SetFreq(220); // audible freq
	osc.SetAmp(1);

	seed.StartAudio(AudioCallback);

	size_t test_counter = 0;
	for (;;)
	{

		test_counter++;
		//Send the latest envelope values to the CV outs
		//uint16_t y1 = map(cvCh1, -1.0, 1.0, 0, 4095);
		//uint16_t y2 =	map(cvCh2, -1.0, 1.0, 0, 4095);
		seed.dac.WriteValue(DacHandle::Channel::ONE, test_counter);
		seed.dac.WriteValue(DacHandle::Channel::TWO, test_counter);

		seed.DelayMs(25);
	}
}

I might try another Daisy at this point honestly! But before I do, @StaffanMelin - do you by any chance know the hash of the libdaisy / daisySP repositories you built yours with?

Thanks again for all of the support, it means the world to me :slight_smile: <3

1 Like

I am referencing daisy examples dbff640eb0db70cd82f3c11336e431037980415a
libdaisy e795e4fde3422ffa650943597d5c1f496812469d
and daisysp 0a70b5a189a08b04c68d22b34e51639fda231dfa

Have you tried removing as much of that block as possible? I’m on Petal but I don’t think all that is necessary.

Strange. I am starting to think you have some fault in your Seed. If you have another one available, could you try it?

And you are sure that you’ve made the right connections? And connected AGND to DGND?

I don’t know the hash numbers but I know I updated libdaisy 9-10 days ago.