ESP32s2 demultiplexing a single dac to multiple outputs using holding capacitors

Hello,

I want to expant the number of outputs from a single dac to 16 analog voltages using a CD74HC4067 board and holding capactiors going to a op amp buffer.
But deffinitly need some pointers because i cannot seem to get the order right.

I want to turn 16 midi cc messages on 16 channels to control voltages and depending on the midi channel i want to port them to a sertain demux output.
So i want to map midi channel spesific cc data to dacwrite where the midi channel follows the currentchannel of the demux. Hope this makes sense.
When demux channel is at lets say 5 i want to only map cc messages from midichannel 6 to the dacwrite function.

The sketch i made now has some problems. and i am not at all sure if im on the right track. i get a super stepped output from the dac so i think it only maps cc to the dac for a short burst of time.
And one problem i am having is that the dac does not reset to 0v after communication with the midi to dacwrite (channel specific) stops. So all these values are keps at the last written value and thus bleed into other demux outputs pins.

I dont think i have the ''/ Only write to the DAC if the current mux channel matches the MIDI channel'' part right. And wonder if there is a better way to do this. maybe even in the setup.

I found the following on how to set up the dac of the esp32s2 but tried to install the different dac drivers to no avail. Are they compatible with the arduino ide? I would like to try the oneshot.h driver.

hosted on github but linked and explained here: Analog to Digital Converter (ADC) Oneshot Mode Driver - ESP32-S2 - — ESP-IDF Programming Guide latest documentation

The holding capacitor and buffer should work a bit like a sample and hold. or a slewlimited to slew the sudo stepped output from the 4067.

This is my sketch:

#include <Arduino.h>
#include <USB.h>
#include <ESPNATIVEUSBMIDI.h>
#include <MIDI.h>

const int S0 = 33;
const int S1 = 35;
const int S2 = 37;
const int S3 = 39;

int currentChannel = 0;

ESPNATIVEUSBMIDI espnativeusbmidi;

MIDI_CREATE_INSTANCE(ESPNATIVEUSBMIDI, espnativeusbmidi, MIDI)

void handleControlChange(byte channel, byte control, byte value);



void setup() {
  espnativeusbmidi.begin();
  USB.productName("ESP Native MIDI");
  USB.begin();
  MIDI.begin(MIDI_CHANNEL_OMNI);
  MIDI.setHandleControlChange(handleControlChange);

  dacWrite(DAC1, 0);

  pinMode(S0, OUTPUT);
  pinMode(S1, OUTPUT);
  pinMode(S2, OUTPUT);
  pinMode(S3, OUTPUT);

  Serial.begin(115200);
}

void setPin(int outputPin) {


  digitalWrite(S0, (outputPin & 0x01) ? HIGH : LOW);
  digitalWrite(S1, (outputPin & 0x02) ? HIGH : LOW);
  digitalWrite(S2, (outputPin & 0x04) ? HIGH : LOW);
  digitalWrite(S3, (outputPin & 0x08) ? HIGH : LOW);
}

void loop() {
  static unsigned long previousMillis = 0;
  const unsigned long channelSwitchInterval = 10; // Delay between channel switches (milliseconds)

  unsigned long currentMillis = millis();

  // Check if it's time to switch channels
  if (currentMillis - previousMillis >= channelSwitchInterval) {
    previousMillis = currentMillis;

    // Switch to the next channel
    currentChannel = (currentChannel + 1) % 16;
    setPin(currentChannel);

        //Serial.print("Current Channel: ");
        //Serial.println(currentChannel);

  }
 
  // Process incoming MIDI messages
  MIDI.read();
}

void handleControlChange(byte channel, byte control, byte value) {
  // Check if the received control change is from CC3
  if (control == 3) {
    // Map the MIDI value to the DAC range
    int dacValue = map(value, 0, 127, 0, 255);
    
    // Only write to the DAC if the current mux channel matches the MIDI channel
    if (currentChannel + 1 == channel) {
      dacWrite(DAC1, dacValue);
      
    }
  }


}

Right, that's what to have to add to your multiplexer on each channel.

Please provide a circuit diagram of your project for more specific advice.

Sure, I made a little schematic of what i have on a breadboard hooked up to an oscilloscope.
for testing i only have one op amp attached. but i can put the op amp on different outputs of the demux to see what happens there.

and how many capacitors, how many different channel voltages?

You'll run into problems without a powerful enough amplifier to load the capacitors, possibly after the mux to keep the current through the mux inside the specs.

So the idea is that the demux cycles thrue its outputs and thus switches whatever is comming from the dac (0-3v3max). I want to make the mapping midi cc messages to dac voltages follow the cycling of the demux so i can expant the number of outputs from 1 dac to 16dacs. The holding capacitors are there to hold the last voltage for a short period.. because the buffer is there and the switch opens when the demux is at another channel.. I think this is pritty common.

I dont think the circuit is a problem.. I would like some guidance on the programming side of things. I have trouble getting the order of things right. I dont want to build in delays but want to make sure that the voltage mapped from a certain midi channel does not bleed when the demux is somewhere else in the cycle.

I think i need to reset the dac to 0 when for instance i only play midi cc messages on midi channel 1 and the mux is at any other than c0. But when i play on multiple channels it should follow the demux and represend the voltages acordingly as well.

I hope you understand what i am doing. Like i mentioned above i also found a oneshot.h driver. I thied to add it to my sketch but it did not work. I linked the header file to a tap in my sketch but there seem to be some dependeties and header files the header file uses that the ide cannot find.

Your code does not make sense to me, missing DAC output.
Better have an array of 16 channel values and output these in sequence.

I assume @DrDiettrich means to add another buffering op-amp between each output of the multiplexer and its corresponding capacitor. Are you sure the TL072 you are using is fit for that purpose? I mean, in the data sheet I don't see it being rail-to-rail, and that means an output differnce of probably a few hundred millivolts - for example, when there is 0 volts at the input, the output will be, for example, 0.2 volts or something like that.

No not sure! another buffer per channel? I was hoping to keep it simple. I dont see how that is different from a buffer before the input (before the mux signal pin) . But that asside. I would be able to theoritically test the sketch without anything on the output of the mux, just a scope. I need some guidance with the sketch :).

The goal is that the charge/discharge current of the capacitor does not pass through the multiplexer, otherwise it is possible to damage the multiplexer. For an op-amp, it might be good to see the AD8052 - rail-to-rail and with a high slew rate.

Oke noted! thank you. I got the idea from an paia midi to cv module
I dont like the idea of adding another 16 op amps. even in a package with 4 thats an aditional 4 op amps. hmm.
(https://www.cykong.com/Synths/PAiA%209700%20Midi2CV8/Images/PAiA%209700%20midi2cv8%20Schematics.gif)

It might be easier to just use pwm somthing like the following.. Do you have an idea what resolution i can expect? I wanted to scale the dac to about 8v.. So with the 8bit dac that would be about 0.1v resolution (3.3v/256x8. How does this compare to pwm?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.