SPI: Writing 20 bits of data?

All the tutorials I've seen such as: http://arduino.cc/en/Tutorial/SPIDigitalPot all send data in multiples of 8 (typically 1 or 2 bytes of data). I'm using the Max6921 which accepts 20 bits of data.

How do I send 20 bits of data if the SPI sends everything in 8-bit sections? Is it possible to do something like SPI.write(0b10101000001100101010);?

Thanks!

The SPI hardware in the ATmega only does 8 bit multiples. You can try writing 3 bytes and hope the device ignores the last 4 bits, or you will need a software SPI library.

Would something like this work? (controlling an 8-digit 7-segment display)

``````for(d=0;d<=7;d++) // go through each digit position.
{

for(b=20;b>=0;b--)  // for each digit, send the 20 bits out backwards
{
digitalWrite(DIN,send_array[i][b]); // write the value in send_array to the pin DIN
digitalWrite(clock,HIGH);           // set the clock high so that the value of send_array will be "sent" to the MAX6921
delay(1);                           // wait one millisecond
digitalWrite(clock,LOW);            // set the clock low
}//move onto the next bit

digitalWrite(LOAD,HIGH); //send this digit to the display
digitalWrite(LOAD,LOW);  //lock the digits into the display

}//move onto the next digit
``````
``````for(b=20;b>=0;b--)  // for each digit, send the 20 bits out backwards
``````

Why does it take 20 bits to define a single digit to display? For a 7 segment display, there need be only 7 bits - a segment is either on or off.

Make the `delay(1)` a `delayMicroseconds(1)`! SPI is fast (most devices support 10MHz). Also digitalWrite takes more than 1us anyhow!

Make the delay(1) a delayMicroseconds(1)! SPI is fast (most devices support 10MHz). Also digitalWrite takes more than 1us anyhow!

Thanks for the tip - Should I just remove the delay entirely then?

Why does it take 20 bits to define a single digit to display? For a 7 segment display, there need be only 7 bits - a segment is either on or off.

I'm driving a IV-18 VFD used in LadyAda's Ice Tube project. 8 bits are used to select 7 segments + decimal, 8 additional bits are used to select which digit you want to write to (0 through 7), so that's 16 total bits. The MAX6921 used for the project has 20 outputs so I assumed you had to fill all of them. However, since you asked, maybe I can just shift in the 16 bits which are actually used and then "output" the bits to the display without filling the remaining 4 bits?

SPI is not what you want to use. SPI is not some asynchronous channel through which you can just 'send' bits. It works by shifting a buffer between master and slave, simultaneously transferring a byte (1 bit at a time) from one to the other and vice versa.

The chip you have says: "Data is input using an industry standard 4-wire serial interface (CLOCK, DATA, LOAD, BLANK), compatibile with either Maxim's or industry-standard VFD driver and controller."

You need to get the specs on that and emulate it through software.

Here’s a multi-bit shiftout I wrote some time ago (can’t remember if I tested it though)

``````#define N_BITS 36
static const int dataPin = 3;
static const int clockPin = 4;

byte bytes [5] = {1,2,3,4,5}; // 5 bytes == 40 bits

byte *ptr;

void setup () {
multibitshiftOut();
}

void loop () {};

void multibitshiftOut () {
ptr = bytes;
for (int b = 0; b < N_BITS; b++) {
if ((*ptr & 0x01) == 0)
digitalWrite (dataPin, LOW);
else
digitalWrite (dataPin, HIGH);

digitalWrite (clockPin, HIGH);
digitalWrite (clockPin, LOW);

*ptr >>= 1;

if (b % 8 == 0) ptr++;

}
}
``````

As TelsaFan says you may have to mod things a little bit to drive that chip although I would think that CLOCK, DATA and LOAD are the same as everything else. As for BLANK, don’t know I’ll have a look at the data sheet.

Rob

What does the datasheet says? Is it really expecting 20bits, or at least 20 data bits?

What does the datasheet says?

Well who would have thought to look at that :)

OK the chip is effectively just a 20-bit shift register, no smarts at all.

So one of the above bit-bang functions should work.

Another way is to use the SPI library to shift 3 bytes but offset your data within those 3 bytes, put your 20 bits in the upper 20 of the 24 bits you shift.

Rob

Graynomad: Well who would have thought to look at that :)

Indeed. The datasheet doesn't mention SPI anywhere.

The Max6921 has 20 outputs but I only need to use 16 of them. Do I need to fill all 20 outputs before "pushing" the data to the output pins or can I just shift in 16 bits and then output the data?

From looking at the block diagram on page 6 timing diagram on page 8 of the datasheet, I can see that it might work if you only care about setting the outputs for OUT0-OUT15. You will notice the following:

-DOUT will be offset by 4 bits of junk data

-OUT16-OUT19 will be set by the previous loaded data

Regards,

Scott Maxim Applications Engineer

So it looks like it's okay to use SPI and just shift in 16 bits of data, then output the bits without any issues.

If you only have 1 chip and only need 16 bits that will work.

But look at the title of this thread, I've (we've?) been assuming you need all twenty bits. So I reread all the posts and back in #5 I see

the 16 bits which are actually used

I didn't spot that before.

Rob

I’ve (we’ve?) been assuming you need all twenty bits.

Ah, sorry I didn’t make that more clear. Correct - I’m not using the DOUT pin and I’m only using bits 0-15 so looks like I can use SPI after all.

SPI is not what you want to use. SPI is not some asynchronous channel through which you can just 'send' bits. It works by shifting a buffer between master and slave, simultaneously transferring a byte (1 bit at a time) from one to the other and vice versa.

I beg to disagree, you can use the hardware anyway that works, its not sacrosanct! You could use it to just send, to just receive, to send and receive, or just to send clock pulses (in sets of 8 at certain defined rates only). If the 'slave' has a select line the SPI bus can be shared with other more compliant SPI devices. On the ATmega the SPI hardware is a great way to offload cycles when clocking shift registers and the like.

On the Arduino you can even use the SPI hardware just to flash the pin13 LED!

Hi,

Im not sure if thats the right part of the forum… so im sorry if its not
Im biulding myself a VFD tube clock with 6 IV-6 tubes, and two really small ones for the dots.
Ive got the theory alv figured out, BUT I only have 2 max6921, so thats for driving 4 tubes right?
ive been thinking… can I multyplex those tubes? As together, Bs together, Cs together… and only switching Grounds on and off, either with high transistors or spare outputs on 6921?

Am I thinking in a right direction. Is this even possible?

regards from Slovenia

MAX6921 is 20 outputs, two are 40 outputs. http://www.maximintegrated.com/solutions/led_vfd_drivers/parts.mvp/scpk/1336/pl_pk/0

tube datasheet http://www.tube-tester.com/sites/nixie/dat_arch/IV-6.pdf

So you appear to need 7 segment drivers/tube 6 x 7 = 42m, so you're a couple short.

Do you need 6 full digits? Perhaps have the left-most digit just be 1 or Off, and only use 2 segments. Then 5 digits * 7 + 2 segments = 37, and you can use 3 remaining for periods in between pairs of digits: 1H.MM.SS,

You might try modifying a Soft SPI library if you need custom word length.

I needed to shift out 25 bits of serial data to two 16 bit serial series connected shift registers wired to the SPI pins. I just would do the transaction as four consecutive 8 bit write operations and just let the first 7 bits sent fall out to the bit bucket of the far shift register.

Lefty

MarkT: Make the `delay(1)` a `delayMicroseconds(1)`! SPI is fast (most devices support 10MHz). Also digitalWrite takes more than 1us anyhow!

Agreed. Digital read and write are HORRIBLY slow. I replaced some "digitalWrite" lines in a VFD driver with PORT = xxx and got an almost TENFOLD increase in speed!