MPR121, Daisy Seed, VS Code

Hi, I am relatively new to the Daisy and coding as well.

I managed to build a little synth, and now I want to control it with the MPR121 touch controller.

Unfortunately I cannot find examples for VS Code / C++ so far.

Can someone help me?

Basically I want to trigger “gate” to starte the ADSR and create a pitch for the Osc.

Thanks!

Try the Simple Touch examples: GitHub - Synthux-Academy/simple-touch-instruments: Instruments for the Simple Touch board

Thanks!
This thing is very adorable.
I had a look into simple-daisy-touch.h, why is it using the adc (and mentions many digital pins as well)?
I expected it to have the mpr121 talk via scl and sda?

Because it has slide+rotary pots as user input as well.

It uses the default config in which you don’t have to setup these pins explicitly.

You can find more examples here: GitHub - Synthux-Academy/synthmas-2023: Synthmas 2023 contest results (Simple Touch instruments designed by community members)

thank you!

unfortunately these examples are hard to understand, for example simple-touch.h gives no clue if the mpr121 is connected to the correct pins.

anyway, I found a decent Mpr121 tester on github:

but it only triggers on the first 4 pins, while the serial monitor shows that all 12 pins are received.

what could be the problem here? I extended the switch cases, but to no avail.

#include “daisy_seed.h”
#include “daisysp.h”
#include “dev/mpr121.h”

using namespace daisy;
using namespace daisysp;

uint16_t currTouched;
uint16_t lastTouched;

// Define the frequencies for the two octaves surrounding middle C
double scale[12] = {
// Octave below middle C
{130.81, 138.59, 146.83, 155.56, 164.81, 174.61, 185.00, 196.00, 207.65, 220.00, 233.08, 246.94},
// Middle C and the octave above
{261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00, 466.16, 493.88},
// Octave above middle C
{523.25, 554.37, 587.33, 622.25, 659.26, 698.46, 739.99, 783.99, 830.61, 880.00, 932.33, 987.77}};

DaisySeed hw;
Mpr121I2C mpr121;
Oscillator osc;

static void AudioCallback(AudioHandle::InterleavingInputBuffer in,
AudioHandle::InterleavingOutputBuffer out,
size_t size)
{
float sig;
for(size_t i = 0; i < size; i += 2)
{
sig = osc.Process();

    // left out
    out[i] = sig;

    // right out
    out[i + 1] = sig;
}

}

int main(void)
{
hw.Init();
hw.StartLog();
hw.SetAudioBlockSize(4); // number of samples handled per callback
hw.SetAudioSampleRate(SaiHandle::Config::SampleRate::SAI_48KHZ);
hw.StartAudio(AudioCallback);

//How many samples we'll output per second
float samplerate = hw.AudioSampleRate();

// Initialize MPR121 with I2C configuration
Mpr121I2C::Config mprConfig;
mprConfig.transport_config.periph = I2CHandle::Config::Peripheral::I2C_1;
mprConfig.transport_config.speed = I2CHandle::Config::Speed::I2C_400KHZ;
mprConfig.transport_config.scl = Pin(PORTB,8);  // Replace with your SCL pin
mprConfig.transport_config.sda = Pin(PORTB,9);  // Replace with your SDA pin

// Set additional MPR121 configuration if needed
mprConfig.touch_threshold = 12;
mprConfig.release_threshold = 6;

//Set up oscillator
osc.Init(samplerate);
osc.SetWaveform(osc.WAVE_SIN);
osc.SetAmp(1.f);
//osc.SetFreq(440);

if(mpr121.Init(mprConfig) != Mpr121I2C::OK)
{
    // Handle initialization error
    while(1)
    {
        // Error handling code (blinking LED, etc.)
    }
}
// Setup to print 
hw.StartLog();

while(1) 
{
	// Read touch status
    currTouched = mpr121.Touched();

    // Process the touch status as needed
    for(int i = 0; i < 12; i++)
    {
        if((currTouched & (1 << i)) && !(lastTouched& (1 << i)))
        {
            // Channel i is touched, print the channel number
            hw.PrintLine("Channel %d touched", i);
        }
        if(!(currTouched & (1 << i)) && (lastTouched& (1 << i)))
        {
            // Channel i is released, print the channel number
            hw.PrintLine("Channel %d released", i);
        }
    }
    lastTouched = currTouched;

    switch (currTouched)
    {
    case 0:
        osc.SetFreq(scale[0][0]);
        break;
    
    case 1:
        osc.SetFreq(scale[0][1]);
        break;
    case 2:
        osc.SetFreq(scale[0][2]);
        break;
    case 3:
        osc.SetFreq(scale[0][3]);
        break;
    case 4:
        osc.SetFreq(scale[0][4]);
        break;
    case 5:
        osc.SetFreq(scale[0][5]);
        break;
    case 6:
        osc.SetFreq(scale[0][6]);
        break;
    case 7:
        osc.SetFreq(scale[0][7]);
        break;
    case 8:
        osc.SetFreq(scale[0][8]);
        break;
    case 9:
        osc.SetFreq(scale[0][9]);
        break;
    case 10:
        osc.SetFreq(scale[0][10]);
        break;
    default:
        break;
    }
    // Add necessary delay or other code here...
}

}

another question, is there pressure sensitivity possible in order to set velocity and sustain level?

(I got this to work by abandoning the switch cases and use is-touched for setting the pitch and gate, and use is-released for releasing the gate)

The MPR121 does not register anything like “pressure”. You basically only get on or off.
(there is a “raw” output option, but in practice this doesn’t give any useful value)

This is incorrect. The MPR121 does indeed measure something exactly like “pressure” as it is usually marketed on capacitive touch synths. You can use this function:

int16_t Mpr121::GetBaselineDeviation(uint8_t channel) {
      if (channel > 11) return 0; 

      uint16_t baseline = BaselineData(channel);


      uint16_t filtered = FilteredData(channel);


      return (int16_t)(baseline - filtered); 
}

To measure the difference in capacitance between the FilteredData and BaselineData functions. with a bit of smoothing (and reading the values at an appropriate speed) the output gives an incredible response which I’m having a lot of fun using to modulate a port of MI Plaits on the Daisy.

1 Like

Do you mind opening a PR to libDaisy that fixes the bug?

There is an open issue and forum post here which I was referring to after having a similar issue. Anyway, happy to help anyone with reading the variable pressure sensing data on the MPR121 who may come across this.

I’m still not able to get useful mpr121 data with libDaisy.

There seems to be a difference between the Arduino and libdaisy’s way of reading the I2c communications- seems like maybe libdaisy isn’t optimized for continuous reads but Arduino is? A few tweaks to the registers as well. Run these instead of the stock libdaisy files and it should work just fine with reading FilteredData, and using the BaselineDeviation function I mentioned.

mpr121_daisy.h.txt (2.4 KB)
mpr121_daisy.cpp.txt (3.3 KB)

There is definitely a difference between I2C in libDaisy, and in Arduino.

Where did those files come from? I take it that you didn’t write them?

I realized there was an issue with the libdaisy implementation after reading your issue and made a copy in my IDE, poked around the registers and I2C communications with copilot and got it running.

1 Like