Hardware SPI: how to shift out less than 1 byte?

Hello everyone.
I'm interfacing 12-bit Serial DAC (DAC8512), and it seems from datasheet that it expects exactly 12 bits of data clocked in by SPI bus.

Clocking out 12 significant bits and then 4 zeroes (8+8 bits) results in weird waveform on my scope.

So I'm just curious: is it possible to clock out exactly 12 bits?

is it possible to clock out exactly 12 bits?

Not with the hardware SPI.
You will have to bit bang the signals to get your 12 bits.

Did you try putting the 4 zeroes BEFORE your data? SPI devices often take the last N bits.

An alternative is to use software SPI but that will be relatively slow.

John is right much easier to send it as an int and mask off the unwanted bits.

Doc

Judging by the datasheet you can send 12 bits followed by a few "don't care":

The 74HC161 counter in incremented on every rising edge of the clock. Additionally, the data is loaded into the DAC8512 on the falling edge of the clock by inverting the serial clock using gate “Y.” The timing diagram shows that after the twelfth bit has been clocked the output of the counter is binary 1011. On the very next rising clock edge, the output of the counter changes to binary 1100 upon which the output of gate “X” goes LOW to generate the LD pulse. The LD signal is connected to both the DAC’s LD and the counter’s LOAD pins to prevent the thirteenth rising clock edge from advancing the DAC’s internal shift register. This prevents false loading of data into the DAC8512.

I would be very surprised if modern designers expected exactly 12 bits. More like 16 bits with a provision to ignore some of them, as the above seems to state.

If I'm wrong (and I've been wrong before :wink: ) here is some code for bit-banged SPI:

You would need to adapt it a bit to do 12 bits.

johnwasser, thanks, that resolved some issue, but now other problem occurs.

Here is my code:

//Init SPI
	pinMode (SPI_DAC_CS_PIN, OUTPUT);
	pinMode (DAC_LD_PIN,OUTPUT);

	SPI.begin();
	SPI.setClockDivider(SPI_CLOCK_DIV128);
	SPI.setBitOrder(MSBFIRST);
	SPI.setDataMode(SPI_MODE0);

while(1){
	for (int b=0;b<4095;b++)
	{
//Prepare to output 2 bytes: SPI CS assert LOW, DAC latch set high.

	digitalWrite(DAC_LD_PIN,HIGH);
	digitalWrite(SPI_DAC_CS_PIN,LOW);

//  send in the value via SPI:
	SPI.transfer((b>>8));  // High byte
	SPI.transfer((b&0xFF)); //Low byte

//Assert CS low
	digitalWrite(SPI_DAC_CS_PIN,HIGH);
	delayMicroseconds(1);

//Now set the DAC to load register to output (LD Low->High).
	digitalWrite(DAC_LD_PIN,LOW);
	delayMicroseconds(1);
	digitalWrite(DAC_LD_PIN,HIGH);

	delayMicroseconds(10);//Set a delay to simplify scope analysis
	}
	delay(200); //200ms delay between cycles
}

The DAC is 12-bit, so, by datasheet, should get values between 0 and 4095. When we send some zeroes before valuable data, the DAC input shift register just shifts that zeroes to the left out of register, so only 12 bits remain.

That code is supposed to go from 0 to 4095, resulting in 0-to-4.095V "saw" with delay between each cycle.

The problem is that DAC seems to read only 11 bit, so I get not single "saw", but a double "saw". Attached is info from my scope:

So I'm curious: Does the SPI send something other than my 2 bytes to line? Maybe some control bits between each of my byte?

NewFile0.gif

Solved. Changing SPI to MODE3 instead of MODE0 helped.
However, it seems to me that MODE0 is the right mode, according to datasheet.

Page 4 of the datasheet shows the clock normally high, so modes 2 or 3 would be appropriate.

Then the first diagram on that page shows the sampling of D11 on the leading edge, so it seems to me that mode 2 is possibly more correct.

kosha:
Solved. Changing SPI to MODE3 instead of MODE0 helped.
However, it seems to me that MODE0 is the right mode, according to datasheet.

Not the way I see it. Page 4 of the datasheet says clock is HIGH with LOW pulses (CPOL=1) and captures on the rising edge and propagates on the falling edge (CPHA=1).
That is mode 3.

edit: Here is how to compute mode. The phase (CPHA) isn't based on rising or falling edge as I might have implied above, but first or second edge after the slave select is activated (LOW).

If clock is LOW with HIGH pulses, then CPOL = 0.
If clock is HIGH with LOW pulses, then CPOL = 1.

If it captures on the first edge (rising or falling) after SS goes LOW, then CPHA=0
If it captures on the second edge (rising or falling) after SS goes LOW, then CPHA=1

MODE = 2CPOL + CPHA

Thank you for making it clear :slight_smile: