MIDI-to-CV Converter Programming Question

Hi everyone,

I built the following Arduino MIDI-to-CV Converter design on a custom PCB, which utilises the MCP4822 DAC and ATMega328P microcontroller: GitHub - elkayem/midi2cv: Arduino-based MIDI to CV converter. Originally I prototyped it using an Arduino Uno.

Everything works perfectly, however I have redesigned it to utilise a LTC2632A-LZ12 DAC instead of the MCP4822 for the note CV, as I would like one that has a lower INL and more accuracy.

My question is regarding the programming of the note CV output and how I can adapt the code to the LTC2632A-LZ12 from the MCP4822. They are both 12-bit DACs, however the LTC2632A-LZ12 has a minimum 24-bit input word, which is increased over the MCP4822, which has a 16-bit input word.

The datasheet is here:

The code for the note CV output is given below:

#define NOTE_SF 47.069f // This value can be tuned if CV output isn't exactly 1V/octave

void commandNote(int noteMsg) {
digitalWrite(GATE,HIGH);
digitalWrite(TRIG,HIGH);
trigTimer = millis();

unsigned int mV = (unsigned int) ((float) noteMsg * NOTE_SF + 0.5);
setVoltage(DAC1, 0, 1, mV); // DAC1, channel 0, gain = 2X
}

void setVoltage(int dacpin, bool channel, bool gain, unsigned int mV)
{
unsigned int command = channel ? 0x9000 : 0x1000;

command |= gain ? 0x0000 : 0x2000;
command |= (mV & 0x0FFF);

SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
digitalWrite(dacpin,LOW);
SPI.transfer(command>>8);
SPI.transfer(command&0xFF);
digitalWrite(dacpin,HIGH);
SPI.endTransaction();
}

Just curious to know if it's possible to amend the above code; specifically the setVoltage function to suit the LTC2632A-LZ12?

Forgive my lack of knowledge or if I'm going down a dead end, but I'm still learning. Any assistance with this would be appreciated.

Many thanks,
Chris

If you look at pg 17 & 18 of the datasheet, it spells out the 24 bits you need to send
4 bits = command
4 bits = address
12 bits = data
4 bits = blank

Thank you for the reply. I've read the datasheet and that makes sense. However, I'm struggling to understand how to change and manipulate the original code above to implement this difference from the MCP4822?

Once again, apologies for my lack of knowledge.

Chris

You have to send 3 bytes (24 bits). The first byte consists of the 4 bits for the operation (0011 = write & update), the next 4 bits consists of the channel (0000 or 0001), The next byte are the upper 8 bits of the value you want to write. The last byte are the 4 remaining bits of the value and then 4 0's

Something like this:

// MCP4822 Version
void setVoltage_MCP4822(int dacpin, bool channel, bool gain, unsigned int mV)
{
  unsigned int command = channel ? 0x9000 : 0x1000;

  command |= gain ? 0x0000 : 0x2000;
  command |= (mV & 0x0FFF);

  SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
  digitalWrite(dacpin, LOW);
  SPI.transfer(command >> 8);
  SPI.transfer(command & 0xFF);
  digitalWrite(dacpin, HIGH);
  SPI.endTransaction();
}

// LTC2632 Version
// Note:  There is no "gain" for this chip so that parameter is ignored
//        It could also be removed
void setVoltage_LTC2632(int dacpin, bool channel, bool gain, unsigned int mV)
{
  // 0b0011 == 0x03 == Write and Update DAC
  uint8_t command = channel ? 0x31 : 0x30;  // write and update shifted 4 bits + DAC channel

  uint16_t data = (mV << 4) & 0xFFF0;   // shift value 4 bits, lower 4 bits 0

  SPI.beginTransaction(SPISettings(8000000, MSBFIRST, SPI_MODE0));
  digitalWrite(dacpin, LOW);
  SPI.transfer(command);
  SPI.transfer(data >> 8);
  SPI.transfer(data & 0xFF);
  digitalWrite(dacpin, HIGH);
  SPI.endTransaction();
}

That's worked perfectly and makes sense now.

Thanks very much for your help with this. Much appreciated.

Chris