Teensy 4.1 usbmidi to cv !

Hi ! Trying to make a midi to cv with my teensy 4.1 with a MPC4822 DAC.

From now, I believe the teensy receive the messages but the outputs of the 4822 are only +- 0.5v at maximum and doesnt really follow my automations.

I feed the Dac with the 5v of the teensy.

Board set to midix4, 600mhz, fastest.

Here's my code :

#include <MIDI.h>
#include <SPI.h>

// Define the MIDI channel and CC number you want to use for CV output
const int midiChannel = 1; // MIDI channel (1-16)
const int ccNumber = 39; // Control Change (CC) number (0-127)

// Define the CV output pin
const int cvOutputPin = 16; // Digital pin number (0-39) on Teensy 4.1

// Define MCP4822-related pins
const int chipSelectPin = 10; // Chip select (CS) pin
const int dataOutPin = 11; // SPI MOSI pin
const int clockPin = 13; // SPI clock pin

MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);

void setup() {
// Initialize the CV output pin
pinMode(cvOutputPin, OUTPUT);

// Initialize MCP4822-related pins
pinMode(chipSelectPin, OUTPUT);

// Initialize SPI communication
SPI.begin();
SPI.beginTransaction(SPISettings(16000000, MSBFIRST, SPI_MODE0)); // Adjust the SPI clock speed if needed

// Initialize the MIDI interface
Serial1.begin(31250); // Set baud rate for MIDI communication
MIDI.begin(MIDI_CHANNEL_OMNI); // Set MIDI channel mode to Omni

// Set up MIDI CC callback function
MIDI.setHandleControlChange(OnControlChange);
}

void loop() {
// Process incoming MIDI messages
MIDI.read();
}

void OnControlChange(unsigned char channel, unsigned char control, unsigned char value)
{
// Check if the received MIDI message matches the specified CC number and channel
if (control == ccNumber && channel == midiChannel) {
// Map the CC value (0-127) to the desired CV range (e.g., 0-4095)
uint16_t cvValue = map(value, 0, 127, 0, 4095);

// Output the CV value to the MCP4822 chip
digitalWrite(chipSelectPin, LOW); // Enable MCP4822 communication

// Construct the 16-bit value to be sent to the MCP4822
uint16_t spiData = 0b0111000000000000 | (cvValue & 0b0000111111111111);

// Send the data to the MCP4822
SPI.transfer16(spiData);

digitalWrite(chipSelectPin, HIGH); // Disable MCP4822 communication
}
}



Im really not into code im trying to make music haha

If someone made one already and have a clue that would be incredible!

Thanks a lot !
 
As a first troubleshooting step, I'd recommend printing to the Arduino Serial Monitor so you can see the actual number before your code tries to send it to the MCP4822.

Something like this:

Code:
  // Map the CC value (0-127) to the desired CV range (e.g., 0-4095)
  uint16_t cvValue = map(value, 0, 127, 0, 4095);
  [COLOR="#FF0000"]Serial.println(cvValue);[/COLOR]
 
Ok so i dont know if this would be the proper way to do it but i add that serial print code in the loop of my code then upload into teensy. After i started Logic with my automation and then open the serial monitor but nothing is shown there.
Does this mean it even receive no cc ? Thanks !
 
Add this at the end of setup(). Or anywhere in setup()...

Code:
  Serial.begin(9600);
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("Hello World");

This won't fix anything, but it will at least confirm if Serial.println() is really sending to the Arduino Serial Monitor window.
 
When you see it print Hello World, the next step is to add something like this:

Code:
void OnControlChange(unsigned char channel, unsigned char control, unsigned char value)
{
  [COLOR="#FF0000"]Serial.println("received CC message");[/COLOR]

so you can tell if any CC messages are really arriving. This can tell you if your input circuitry is working. No point messing with the software side if the input circuit is bad.

You can also add printing of their parameters, if that helps to figure why messages you are getting don't give the expected result.
 
It writes Hello world at the start. Then I add the next code to print cc message in the loop but nothing again !

This is the code from now :

#include <MIDI.h>
#include <SPI.h>

// Define the MIDI channel and CC number you want to use for CV output
const int midiChannel = 1; // MIDI channel (1-16)
const int ccNumber = 39; // Control Change (CC) number (0-127)

// Define the CV output pin
const int cvOutputPin = 16; // Digital pin number (0-39) on Teensy 4.1

// Define MCP4822-related pins
const int chipSelectPin = 10; // Chip select (CS) pin
const int dataOutPin = 11; // SPI MOSI pin
const int clockPin = 13; // SPI clock pin

MIDI_CREATE_INSTANCE(HardwareSerial, Serial1, MIDI);

void setup() {
// Initialize the CV output pin
pinMode(cvOutputPin, OUTPUT);

// Initialize MCP4822-related pins
pinMode(chipSelectPin, OUTPUT);

// Initialize SPI communication
SPI.begin();
SPI.beginTransaction(SPISettings(16000000, MSBFIRST, SPI_MODE0)); // Adjust the SPI clock speed if needed

// Initialize the MIDI interface
Serial1.begin(31250); // Set baud rate for MIDI communication
MIDI.begin(MIDI_CHANNEL_OMNI); // Set MIDI channel mode to Omni

// Set up MIDI CC callback function
MIDI.setHandleControlChange(OnControlChange);

Serial.begin(9600);
while (!Serial) ; // wait for Arduino Serial Monitor
Serial.println("Hello World");
}

void loop() {
// Process incoming MIDI messages
MIDI.read();
}

void OnControlChange(unsigned char channel, unsigned char control, unsigned char value)
{

Serial.println("received CC message");
// Check if the received MIDI message matches the specified CC number and channel
if (control == ccNumber && channel == midiChannel) {
// Map the CC value (0-127) to the desired CV range (e.g., 0-4095)
uint16_t cvValue = map(value, 0, 127, 0, 4095);

// Output the CV value to the MCP4822 chip
digitalWrite(chipSelectPin, LOW); // Enable MCP4822 communication

// Construct the 16-bit value to be sent to the MCP4822
uint16_t spiData = 0b0111000000000000 | (cvValue & 0b0000111111111111);

// Send the data to the MCP4822
SPI.transfer16(spiData);

digitalWrite(chipSelectPin, HIGH); // Disable MCP4822 communication
}

// Map the CC value (0-127) to the desired CV range (e.g., 0-4095)
uint16_t cvValue = map(value, 0, 127, 0, 4095);
Serial.println(cvValue);

}

Thanks !
 
In Arduino, click File > Examples > Teensy > Serial > EchoBoth. Change the baud rate from 38400 to 31250 and upload.

Optional, add the Hello World stuff, so you can be sure it is really running.

Does it print anything at all while your MIDI messages are incoming? If nothing, then you probably have a hardware issue with the MIDI input circuitry. We can help, but only if we're able to see it. Photos are best...
 
I understand ! So I did what you said , Hello world appeared ! But yea no midi cc..

On thing is each time i upload, Logic give me a notification that its see the 4 midi i/o so i believe the midi implementation is working ! Well I hope haha
 
Screen Shot 2023-05-31 at 7.10.43 PM.jpg The actual set up !
 
Oh ayaye haha I though because of the Midix4 set up it would communicate ! Thanks for your help! Ill try another one :) Have a good day !
 
Ok ! So back on track with another take ! Things seems to be going good except that I cannot get the 4822 to deliver 5v at 127 value.
But it follows the automation ( maybe it could be faster but will see that later )

Here's the code:

#include <SPI.h>


// Define the MIDI channel and CC number you want to use for CV output
const int midiChannel = 1; // MIDI channel (1-16)
const int ccNumber = 20; // Control Change (CC) number (0-127)

// Define the CV output pin
const int cvOutputPin = 16; // Digital pin number (0-39) on Teensy 4.1

// Define MCP4822-related pins
const int chipSelectPin = 10; // Chip select (CS) pin
const int dataOutPin = 11; // SPI MOSI pin
const int clockPin = 13; // SPI clock pin

void setup() {
// Initialize the CV output pin
pinMode(cvOutputPin, OUTPUT);

// Initialize MCP4822-related pins
pinMode(chipSelectPin, OUTPUT);

// Initialize SPI communication
SPI.begin();
SPI.beginTransaction(SPISettings(16000000, MSBFIRST, SPI_MODE0)); // Adjust the SPI clock speed if needed

// Start USB MIDI communication
usbMIDI.begin();

// Set up MIDI CC callback function
usbMIDI.setHandleControlChange(OnControlChangeWrapper);


}

void loop() {
// Check for incoming USB MIDI messages
usbMIDI.read();
}

void OnControlChangeWrapper(byte channel, byte control, byte value) {
// Convert data types and call the actual OnControlChange function
OnControlChange(channel, control, value);
}

void OnControlChange(byte channel, byte control, byte value) {
// Check if the received MIDI message matches the specified CC number and channel
if (control == ccNumber && channel == midiChannel) {
// Map the CC value (0-127) to the desired CV range (e.g., 0-4095)
uint16_t cvValue = map(value, 0, 127, 0, 4095);

// Output the CV value to the MCP4822 chip
digitalWrite(chipSelectPin, LOW); // Enable MCP4822 communication

// Construct the 16-bit value to be sent to the MCP4822
uint16_t spiData = 0b0111000000000000 | (cvValue & 0b0000111111111111);

// Send the data to the MCP4822
SPI.transfer16(spiData);

digitalWrite(chipSelectPin, HIGH); // Disable MCP4822 communication

}
}

Im about to add an op amp to get the 5v or would it be simpler ( codewise ) to get a 4922/21 ( with a voltage ref ) to achieve the 5v ? Or is there a way to get the 5v with the 4822 just in modifying this code ?

Thanks a lot !
 
Code:
#include <SPI.h>

// Define the MIDI channel and CC number you want to use for CV output
const int midiChannel = 1; // MIDI channel (1-16)
const int ccNumber = 20; // Control Change (CC) number (0-127)

// Define the CV output pin
const int cvOutputPin = 16; // Digital pin number (0-39) on Teensy 4.1

// Define MCP4822-related pins
const int chipSelectPin = 10; // Chip select (CS) pin
const int dataOutPin = 11; // SPI MOSI pin
const int clockPin = 13; // SPI clock pin

void setup() {
	// Initialize the CV output pin
	pinMode(cvOutputPin, OUTPUT);

	// Initialize MCP4822-related pins
	pinMode(chipSelectPin, OUTPUT);

	// Initialize SPI communication
	SPI.begin();
	SPI.beginTransaction(SPISettings(16000000, MSBFIRST, SPI_MODE0)); // Adjust the SPI clock speed if needed

	// Start USB MIDI communication
	usbMIDI.begin();

	// Set up MIDI CC callback function
	usbMIDI.setHandleControlChange(OnControlChangeWrapper);
}

void loop() {
	// Check for incoming USB MIDI messages
	usbMIDI.read();
}

void OnControlChangeWrapper(byte channel, byte control, byte value) {
	// Convert data types and call the actual OnControlChange function
	OnControlChange(channel, control, value);
}

void OnControlChange(byte channel, byte control, byte value) {
	// Check if the received MIDI message matches the specified CC number and channel
	if (control == ccNumber && channel == midiChannel) {
		// Map the CC value (0-127) to the desired CV range (e.g., 0-4095)
		uint16_t cvValue = map(value, 0, 127, 0, 4095);

		// Output the CV value to the MCP4822 chip
		digitalWrite(chipSelectPin, LOW); // Enable MCP4822 communication

		// Construct the 16-bit value to be sent to the MCP4822
		uint16_t spiData = 0b0111000000000000 | (cvValue & 0b0000111111111111);

		// Send the data to the MCP4822
		SPI.transfer16(spiData);

		digitalWrite(chipSelectPin, HIGH); // Disable MCP4822 communication

	}
}
Hi, glad you are making some progress.
In future when you are posting code could you enclose it between CODE tags (can be entered by using the # on the reply form) it makes your code easier to read and help those who might be able to help you.
 
Quick look at the MCP4822 datasheet says it has an internal 2.048V reference, and you can select either unity gain or 2X gain output. So the output range ought to be 0 to 2.048V or 0 to 4.096V. Does not seem to be any way to get 0 to 5V output. You could add an opamp circuit to amplify the voltage.

If you use a different chip that takes an external reference voltage, check the specs on the DAC and the VREF chip. Often chips need power that at a higher voltage to output their maximum. Most Opamps also have this requirement.
 
Back
Top