SPI with 12 bit word

Hi mates! Let's start by hopping you a good week. I'm trying to send 12 bits data over SPI using arduino Mega, in mode0 for the DAC LTC1451. I'm using two transfer operations, in MSB, and using an output pin to select the DAC and latch the register. But it's not working. It is possible to send two bytes, with the four high bits to zero? Cause the voltage in this configuration is not changed. Could you point me in the right direction? Free beer! :D Thank you all!

Post the code you are trying. Usually, you would send a command byte from the master, then read two bytes. That is three SPI.transfer() calls.

  1. The LTC1451 chip supports Serial Interface, and accordingly the data sheets has given the timing diagram. It does not necessarily mean that the chip is compatible with SPI Protocol.

  2. I have an alternative solution which bypasses the SPI Protocol. I applied this mechanism to communicate with 24-bit Serial ADC of Type-HX710B; it worked. You can try it.

  3. In this scheme, all the Timing Functions will be generated using program instruction in full compliance with the Timing Diagram of LTC1451 chip.

  4. The Timing Diagram of LTC1451 (Re-drawn)

  5. Let us now convert the Timing Diagram of Step-4 into Program Instructions.

//--initialize everything as needed as per Step-4
unsigned int x = inputData;

for (int n = 11; n=>0; n--)
   digitalWrite(DIN, bitRead(x[sub]n[/sub]));
   digitalWrite(CLK, HIGH);
   digitalWrite(CLK, LOW);

digitalWrite(CS/-LD, HIGH);

Ohh thank you for the code!. I will try it out! The other thing is that I already check for other entries in this forum before post this entry. The thing is that there is people using SPI commands on the same family chips, LTC1454, but using an Arduino Due. They got it, so I’m thinking that maybe is my arduino, cause I don’t have the ExtendedSPI functions.

here is my code. // I choose now a very low clock rate so I can debug it on an oscilloscope.

#include <SPI.h>

//Maximum SPI speed the device can use > 
//Data is Shifted in MSB or LSB > MSB
//Clock Phase (data is shifted in and out on the rising or falling edge > Rising edge
//Clock Polarity (clock is idle when High or Low) > Low

//SPI Mode0 (0 (CPOL), 0(CPHA)) -> Output Edge: Falling, Data Capture: Rising.

//Mega 2560 - 50 (MISO), 51 (MOSI), 52 (SCK), 53 (SS).
//MISO -> The slave line for sending data to the master.
//MOSI -> The master line for sending data to the slave.
//SCK -> Serial Clock.
//SS -> Slave Select.

#define LTC1451_CS 23
#define LTC1451_CLR 22

void setup() {
  // put your setup code here, to run once:

  //Serial comunication
  Serial.println("Init SPI DAC Interface");
  //SPI init
  pinMode(LTC1451_CLR, OUTPUT);
  //Clear Values of DAC.
  digitalWrite(LTC1451_CLR, LOW);
  digitalWrite(LTC1451_CLR, HIGH);//Dac Will output the voltage;

  //Given Time the system to set up.
  //Write 8BitCommand.

void loop() {
  // put your main code here, to run repeatedly:

//Sends a write command to DAC.
void write8BitColor(int colorRed, int colorGreen, int colorBlue){
  //Adapt the ColorBits to the System.
  byte *pointerColorData;
  pointerColorData = adaptColorBytesToSystem(colorRed,colorGreen,colorBlue); //Gets the pointer Color Data.
  SPI.beginTransaction(SPISettings(10000,MSBFIRST,SPI_MODE0)); //Gain control of SPI bus.
    digitalWrite(LTC1451_CLR, LOW); //DAC Will be ready for read.
  for(int i = 0; i<5; i++){ //TODO - Need To implement Array Length so I can decouple the code.
    SPI.transfer(20,*(pointerColorData+i)); //Get the pointed value.
    digitalWrite(LTC1451_CLR, HIGH); //Dac Will output the voltage;
    SPI.endTransaction(); //Release the SPI bus.

byte *adaptColorBytesToSystem(int colorRed, int colorGreen, int colorBlue){
  //We need 5 bytes to send the information.
  //Example colors.
  //There is 12 bits by 3 DAC-> 36 bits of information.
  //The Sender will write Byte by Byte, so we need to write at least 5 Bytes.
  //But there will be remained 4 bits.
  //We need to send the information of 3DACs, the first will be virtual.
  //12x4 -> 48
  //The Sender will write Byte by Byte, so we need to write at least 6 Bytes.
  //Color red _ 0x01FF, green _ 0x01FF, blue _ 0x01FF
  //For debug purpouses we will write 0 as 1.
  static byte bytes[6]; //Static is necesary to keep data.
  bytes[0] = 0x11; //First Byte of 0
  bytes[1] = 0x10 | highByte(colorRed); //4 Bits of 0, 4 Bits of color Red, 0x01 = 0x11
  bytes[2] = lowByte(colorRed); //8 Bits of color Red, 0xFF
  bytes[3] = highByte(colorGreen << 4); //8 first Bits of color Green, 0x1F
  bytes[4] = lowByte(colorGreen << 4) | highByte(colorBlue); //4 last Bits of color Green, 0xF0, 4 first Bits of color Blue, 0x01
  bytes[5] = lowByte(colorBlue);// 8 last Bits of color Blue.
  Serial.println(bytes[0], HEX);
  Serial.println(bytes[1], HEX);
  Serial.println(bytes[2], HEX);
  Serial.println(bytes[3], HEX);
  Serial.println(bytes[4], HEX);
  Serial.println(bytes[5], HEX);

  return bytes;

Another Thing is I would like, not to implement Bitbanging, cause I need high speed implementation.

  1. As I have understood that you want to load 12-bit data in your DAC.

  2. So, Read the data bit-by-bit with MS-bit first and transfer it into your using a CLK pulse.

  3. Repeat Step-2 until all the bits are shifted out.

  4. Then, why so many lines and so many things in your post. What are they doing is beyond my understanding.

What you describe is called Bit Banging. The Thing is digitalWrite is a very expensive function in terms of UC cicles. I need something faster, so I try to use SPI. But I'm giving a try right now ;). Ty!

I'd go with SPI, looks to me that the last 12 bits shifted in get latched when chip select goes high. https://www.digikey.com/product-detail/en/linear-technology/LTC1451CN8-PBF/LTC1451CN8-PBF-ND/891794 Put your data an int, with top 4 not used.

digitalWrite (ssPin, LOW);
SPI.transfer (highByte(yourData));
digitalWrite (ssPin, HIGH);

SPI default modes are 4 MHz clock, SPI Mode 0 (so SCK is low when not used), and MSBFIRST, so those don't need to be touched. You could speed up to SPI clock divisor of 2 for 8 MHz updates even, the resulting 62.5nS High & Low times of the clock will still meet the 40nS min times needed for LTC1451.

And you could use Direct Port Manipulation for the slave select to go even faster: PORTB = PORTB & 0b11111011; // clear D10 (ssPin, LOW), leaving the rest alone

PORTB = PORTB | 0b00000100; // set 10 (ssPin, HIGH), leaving the rest alone